From 00f0b2e1406658a89800b6f1318b69a5ad659883 Mon Sep 17 00:00:00 2001
From: CMK
Date: Thu, 22 Jul 2021 19:34:24 +0800
Subject: [PATCH 1/9] feat: set status name animated
---
Mastodon.xcodeproj/project.pbxproj | 50 +++++++----------
.../xcschemes/xcschememanagement.plist | 8 +--
.../xcshareddata/swiftpm/Package.resolved | 21 +++++---
.../Compose/ComposeStatusSection.swift | 2 +-
.../Section/Status/StatusSection.swift | 31 ++++++++---
Mastodon/Extension/MetaLabel.swift | 53 +++++++++++++++++++
...Provider+StatusTableViewCellDelegate.swift | 2 +-
.../StatusProvider/StatusProviderFacade.swift | 2 +-
.../ComposeStatusContentTableViewCell.swift | 2 +-
.../Scene/Compose/ComposeViewController.swift | 2 +-
.../Compose/ComposeViewModel+DataSource.swift | 2 +-
.../CustomEmojiPickerInputViewModel.swift | 2 +-
.../Compose/View/ReplicaStatusView.swift | 2 +-
.../NotificationViewController.swift | 2 +-
.../NotificationStatusTableViewCell.swift | 2 +-
.../Header/View/ProfileHeaderView.swift | 2 +-
.../Report/ReportedStatusTableviewCell.swift | 2 +-
.../Scene/Share/View/Content/StatusView.swift | 34 ++++++------
.../TableviewCell/StatusTableViewCell.swift | 2 +-
19 files changed, 145 insertions(+), 78 deletions(-)
create mode 100644 Mastodon/Extension/MetaLabel.swift
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index fa8b06c3d..0f7d85276 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -179,12 +179,12 @@
DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB00CA962632DDB600A54956 /* CommonOSLog */; };
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB0140BC25C40D7500F9F3CF /* CommonOSLog */; };
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; };
+ DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23226A98F0900C3965B /* MastodonMeta */; };
+ DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23426A98F0900C3965B /* MetaTextKit */; };
DB023295267F0AB800031745 /* ASMetaEditableTextNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023294267F0AB800031745 /* ASMetaEditableTextNode.swift */; };
DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB029E94266A20430062874E /* MastodonAuthenticationController.swift */; };
DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; };
DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; };
- DB03F7EB268976B5007B274C /* MastodonMeta in Frameworks */ = {isa = PBXBuildFile; productRef = DB03F7EA268976B5007B274C /* MastodonMeta */; };
- DB03F7ED268976B5007B274C /* MetaTextView in Frameworks */ = {isa = PBXBuildFile; productRef = DB03F7EC268976B5007B274C /* MetaTextView */; };
DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; };
DB03F7F52689B782007B274C /* ComposeTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F42689B782007B274C /* ComposeTableView.swift */; };
DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ED026538E3C00BEE9D8 /* Trie.swift */; };
@@ -196,6 +196,7 @@
DB0C946F26A7D2A80088FB11 /* AvatarImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C946E26A7D2A80088FB11 /* AvatarImageView.swift */; };
DB0C947226A7D2D70088FB11 /* AvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947126A7D2D70088FB11 /* AvatarButton.swift */; };
DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; };
+ DB0E91EA26A9675100BD2ACC /* MetaLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0E91E926A9675100BD2ACC /* MetaLabel.swift */; };
DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */; };
DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */; };
DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D186B25EF5BA7003F1F23 /* PollTableView.swift */; };
@@ -227,8 +228,6 @@
DB3667A8268AE2900027D07F /* ComposeStatusPollItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */; };
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; };
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB3D100F25BAA75E00EAA174 /* Localizable.strings */; };
- DB41ED8226A54D8A00F58330 /* MastodonMeta in Frameworks */ = {isa = PBXBuildFile; productRef = DB41ED8126A54D8A00F58330 /* MastodonMeta */; };
- DB41ED8426A54D8A00F58330 /* MetaTextView in Frameworks */ = {isa = PBXBuildFile; productRef = DB41ED8326A54D8A00F58330 /* MetaTextView */; };
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; };
DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; };
DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; };
@@ -896,6 +895,7 @@
DB0C946E26A7D2A80088FB11 /* AvatarImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarImageView.swift; sourceTree = ""; };
DB0C947126A7D2D70088FB11 /* AvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarButton.swift; sourceTree = ""; };
DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = ""; };
+ DB0E91E926A9675100BD2ACC /* MetaLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetaLabel.swift; sourceTree = ""; };
DB0F814D264CFFD300F2A12B /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; };
DB0F814E264CFFD300F2A12B /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; };
DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerLoaderTableViewCell.swift; sourceTree = ""; };
@@ -1257,7 +1257,6 @@
buildActionMask = 2147483647;
files = (
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */,
- DB03F7ED268976B5007B274C /* MetaTextView in Frameworks */,
DB89BA0325C10FD0008580ED /* CoreDataStack.framework in Frameworks */,
DBC6462B26A1738900B0E31B /* MastodonUI in Frameworks */,
2D42FF6125C8177C004A627A /* ActiveLabel in Frameworks */,
@@ -1269,14 +1268,15 @@
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */,
DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */,
2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */,
+ DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */,
DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */,
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */,
DBAC649E267DFE43007FE9FD /* DiffableDataSources in Frameworks */,
2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */,
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
DB6804C82637CE2F00430867 /* AppShared.framework in Frameworks */,
- DB03F7EB268976B5007B274C /* MastodonMeta in Frameworks */,
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */,
+ DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1329,8 +1329,6 @@
DBBC24B826A5421800398BB9 /* CommonOSLog in Frameworks */,
DBC6462526A1720B00B0E31B /* MastodonUI in Frameworks */,
DBC6463726A195DB00B0E31B /* CoreDataStack.framework in Frameworks */,
- DB41ED8426A54D8A00F58330 /* MetaTextView in Frameworks */,
- DB41ED8226A54D8A00F58330 /* MastodonMeta in Frameworks */,
DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */,
DBBC24AA26A5301B00398BB9 /* MastodonSDK in Frameworks */,
DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */,
@@ -2502,6 +2500,7 @@
DB6C8C0525F0921200AAA452 /* MastodonSDK */,
DB44384E25E8C1FA008912A2 /* CALayer.swift */,
2DF123A625C3B0210020F248 /* ActiveLabel.swift */,
+ DB0E91E926A9675100BD2ACC /* MetaLabel.swift */,
DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */,
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */,
DB68A06225E905E000CFDF14 /* UIApplication.swift */,
@@ -2999,9 +2998,9 @@
DBAC649D267DFE43007FE9FD /* DiffableDataSources */,
DBAC64A0267E6D02007FE9FD /* Fuzi */,
DBF7A0FB26830C33004176A2 /* FPSIndicator */,
- DB03F7EA268976B5007B274C /* MastodonMeta */,
- DB03F7EC268976B5007B274C /* MetaTextView */,
DBC6462A26A1738900B0E31B /* MastodonUI */,
+ DB01E23226A98F0900C3965B /* MastodonMeta */,
+ DB01E23426A98F0900C3965B /* MetaTextKit */,
);
productName = Mastodon;
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
@@ -3127,8 +3126,6 @@
DBBC24A926A5301B00398BB9 /* MastodonSDK */,
DBBC24B726A5421800398BB9 /* CommonOSLog */,
DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */,
- DB41ED8126A54D8A00F58330 /* MastodonMeta */,
- DB41ED8326A54D8A00F58330 /* MetaTextView */,
DB0C946426A6FD4D0088FB11 /* AlamofireImage */,
);
productName = ShareActionExtension;
@@ -3226,7 +3223,7 @@
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */,
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */,
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
- DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */,
+ DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */,
);
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
projectDirPath = "";
@@ -3752,6 +3749,7 @@
DB4F096C269EFA2000D62E92 /* SearchResultViewController+StatusProvider.swift in Sources */,
DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */,
DB6D9F7D26358ED4008423CD /* SettingsSection.swift in Sources */,
+ DB0E91EA26A9675100BD2ACC /* MetaLabel.swift in Sources */,
DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */,
DB9D6BE925E4F5340051B173 /* SearchViewController.swift in Sources */,
2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */,
@@ -5349,12 +5347,12 @@
minimumVersion = 0.1.1;
};
};
- DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */ = {
+ DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */ = {
isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/TwidereProject/MetaTextView.git";
+ repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git";
requirement = {
kind = exactVersion;
- version = 1.4.0;
+ version = 2.0.0;
};
};
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
@@ -5474,15 +5472,15 @@
package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */;
productName = CommonOSLog;
};
- DB03F7EA268976B5007B274C /* MastodonMeta */ = {
+ DB01E23226A98F0900C3965B /* MastodonMeta */ = {
isa = XCSwiftPackageProductDependency;
- package = DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */;
+ package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */;
productName = MastodonMeta;
};
- DB03F7EC268976B5007B274C /* MetaTextView */ = {
+ DB01E23426A98F0900C3965B /* MetaTextKit */ = {
isa = XCSwiftPackageProductDependency;
- package = DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */;
- productName = MetaTextView;
+ package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */;
+ productName = MetaTextKit;
};
DB0C946426A6FD4D0088FB11 /* AlamofireImage */ = {
isa = XCSwiftPackageProductDependency;
@@ -5494,16 +5492,6 @@
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
productName = AlamofireImage;
};
- DB41ED8126A54D8A00F58330 /* MastodonMeta */ = {
- isa = XCSwiftPackageProductDependency;
- package = DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */;
- productName = MastodonMeta;
- };
- DB41ED8326A54D8A00F58330 /* MetaTextView */ = {
- isa = XCSwiftPackageProductDependency;
- package = DB03F7E9268976B5007B274C /* XCRemoteSwiftPackageReference "MetaTextView" */;
- productName = MetaTextView;
- };
DB68050F2637D0F800430867 /* KeychainAccess */ = {
isa = XCSwiftPackageProductDependency;
package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */;
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index fd09596bc..1220300f7 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,7 +12,7 @@
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 22
+ 24
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -22,7 +22,7 @@
Mastodon - RTL.xcscheme_^#shared#^_
orderHint
- 3
+ 4
Mastodon - Release.xcscheme_^#shared#^_
@@ -37,12 +37,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 23
+ 22
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 21
+ 23
SuppressBuildableAutocreation
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 55f7d7113..45f1697c9 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/Alamofire/Alamofire.git",
"state": {
"branch": null,
- "revision": "4d19ad82f80cc71ff829b941ded114c56f4f604c",
- "version": "5.4.2"
+ "revision": "f96b619bcb2383b43d898402283924b80e2c4bae",
+ "version": "5.4.3"
}
},
{
@@ -110,12 +110,12 @@
}
},
{
- "package": "MetaTextView",
- "repositoryURL": "https://github.com/TwidereProject/MetaTextView.git",
+ "package": "MetaTextKit",
+ "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git",
"state": {
"branch": null,
- "revision": "4c16bc639652a7e1bff4f75e1eba2fcf40213974",
- "version": "1.4.0"
+ "revision": "44fc5111269d9862369348870835e17907062115",
+ "version": "2.0.0"
}
},
{
@@ -145,6 +145,15 @@
"version": "3.6.2"
}
},
+ {
+ "package": "SDWebImage",
+ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
+ "state": {
+ "branch": null,
+ "revision": "76dd4b49110b8624317fc128e7fa0d8a252018bc",
+ "version": "5.11.1"
+ }
+ },
{
"package": "swift-nio",
"repositoryURL": "https://github.com/apple/swift-nio.git",
diff --git a/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift b/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
index 6a9dd2b3b..bacc5097c 100644
--- a/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
+++ b/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
@@ -9,7 +9,7 @@ import UIKit
import Combine
import CoreData
import CoreDataStack
-import MetaTextView
+import MetaTextKit
import MastodonMeta
import AlamofireImage
diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift
index 18406da66..9bb34466e 100644
--- a/Mastodon/Diffiable/Section/Status/StatusSection.swift
+++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift
@@ -113,7 +113,7 @@ extension StatusSection {
accessibilityViews.append(cell.statusView.headerInfoLabel)
}
accessibilityViews.append(contentsOf: [
- cell.statusView.nameLabel,
+ cell.statusView.nameMetaLabel,
cell.statusView.dateLabel,
cell.statusView.contentMetaText.textView,
])
@@ -171,7 +171,7 @@ extension StatusSection {
cell.statusView.contentMetaText.textView.isAccessibilityElement = false
var accessibilityElements: [Any] = []
accessibilityElements.append(cell.statusView.avatarView)
- accessibilityElements.append(cell.statusView.nameLabel)
+ accessibilityElements.append(cell.statusView.nameMetaLabel)
accessibilityElements.append(cell.statusView.dateLabel)
// TODO: a11y
accessibilityElements.append(cell.statusView.contentMetaText.textView)
@@ -652,7 +652,13 @@ extension StatusSection {
return L10n.Common.Controls.Status.userReblogged(name)
}()
// sync set display name to avoid layout issue
- cell.statusView.headerInfoLabel.configure(content: headerText, emojiDict: status.author.emojiDict)
+ do {
+ let mastodonContent = MastodonContent(content: headerText, emojis: status.author.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.headerInfoLabel.configure(content: metaContent)
+ } catch {
+ cell.statusView.headerInfoLabel.reset()
+ }
cell.statusView.headerInfoLabel.accessibilityLabel = headerText
cell.statusView.headerInfoLabel.isAccessibilityElement = true
} else if status.inReplyToID != nil {
@@ -666,7 +672,13 @@ extension StatusSection {
let name = author.displayName.isEmpty ? author.username : author.displayName
return L10n.Common.Controls.Status.userRepliedTo(name)
}()
- cell.statusView.headerInfoLabel.configure(content: headerText, emojiDict: status.replyTo?.author.emojiDict ?? [:])
+ do {
+ let mastodonContent = MastodonContent(content: headerText, emojis: status.replyTo?.author.emojiMeta ?? [:])
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.headerInfoLabel.configure(content: metaContent)
+ } catch {
+ cell.statusView.headerInfoLabel.reset()
+ }
cell.statusView.headerInfoLabel.accessibilityLabel = headerText
cell.statusView.headerInfoLabel.isAccessibilityElement = status.replyTo != nil
} else {
@@ -682,8 +694,15 @@ extension StatusSection {
// name
let author = (status.reblog ?? status).author
let nameContent = author.displayNameWithFallback
- cell.statusView.nameLabel.configure(content: nameContent, emojiDict: author.emojiDict)
- cell.statusView.nameLabel.accessibilityLabel = nameContent
+ do {
+ let mastodonContent = MastodonContent(content: nameContent, emojis: author.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.nameMetaLabel.configure(content: metaContent)
+ cell.statusView.nameMetaLabel.accessibilityLabel = metaContent.trimmed
+ } catch {
+ cell.statusView.nameMetaLabel.reset()
+ cell.statusView.nameMetaLabel.accessibilityLabel = ""
+ }
// username
cell.statusView.usernameLabel.text = "@" + author.acct
// avatar
diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift
new file mode 100644
index 000000000..67200874b
--- /dev/null
+++ b/Mastodon/Extension/MetaLabel.swift
@@ -0,0 +1,53 @@
+//
+// MetaText.swift
+// Mastodon
+//
+// Created by MainasuK Cirno on 2021-7-22.
+//
+
+import UIKit
+import MetaTextKit
+
+extension MetaLabel {
+ enum Style {
+ case statusHeader
+ case statusName
+// case profileFieldName
+// case profileFieldValue
+ }
+
+ convenience init(style: Style) {
+ self.init()
+
+ layer.masksToBounds = true
+ textContainer.lineBreakMode = .byTruncatingTail
+
+ let font: UIFont
+ let textColor: UIColor
+
+ switch style {
+ case .statusHeader:
+ font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium), maximumPointSize: 17)
+ textColor = Asset.Colors.Label.secondary.color
+
+ case .statusName:
+ font = .systemFont(ofSize: 17, weight: .semibold)
+ textColor = Asset.Colors.Label.primary.color
+// case .profileFieldName:
+// font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20)
+// textColor = Asset.Colors.Label.primary.color
+// numberOfLines = 1
+// case .profileFieldValue:
+// font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20)
+// textColor = Asset.Colors.Label.primary.color
+// numberOfLines = 1
+ }
+
+ self.font = font
+ self.textColor = textColor
+
+ textAttributes = [
+ .font: font,
+ .foregroundColor: textColor
+ ]
+ }}
diff --git a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
index a752f2180..544de8893 100644
--- a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
+++ b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
@@ -13,7 +13,7 @@ import CoreDataStack
import MastodonSDK
import ActiveLabel
import Meta
-import MetaTextView
+import MetaTextKit
// MARK: - StatusViewDelegate
extension StatusTableViewCellDelegate where Self: StatusProvider {
diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
index 40f0f6bb8..e5bb15a80 100644
--- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
+++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
@@ -13,7 +13,7 @@ import CoreDataStack
import MastodonSDK
import ActiveLabel
import Meta
-import MetaTextView
+import MetaTextKit
#if ASDK
import AsyncDisplayKit
diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
index 7dbda5b36..d970b6734 100644
--- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
+++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
@@ -8,7 +8,7 @@
import os.log
import UIKit
import Combine
-import MetaTextView
+import MetaTextKit
import UITextView_Placeholder
final class ComposeStatusContentTableViewCell: UITableViewCell {
diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift
index 4ce020837..156680496 100644
--- a/Mastodon/Scene/Compose/ComposeViewController.swift
+++ b/Mastodon/Scene/Compose/ComposeViewController.swift
@@ -10,7 +10,7 @@ import UIKit
import Combine
import PhotosUI
import MastodonSDK
-import MetaTextView
+import MetaTextKit
import MastodonMeta
import Meta
import MastodonUI
diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
index 4b4e80c52..2642808d1 100644
--- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
+++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
@@ -12,7 +12,7 @@ import CoreDataStack
import TwitterTextEditor
import MastodonSDK
import MastodonMeta
-import MetaTextView
+import MetaTextKit
extension ComposeViewModel {
diff --git a/Mastodon/Scene/Compose/View/CustomEmojiPickerInputViewModel.swift b/Mastodon/Scene/Compose/View/CustomEmojiPickerInputViewModel.swift
index d421759b1..d258ff7b8 100644
--- a/Mastodon/Scene/Compose/View/CustomEmojiPickerInputViewModel.swift
+++ b/Mastodon/Scene/Compose/View/CustomEmojiPickerInputViewModel.swift
@@ -7,7 +7,7 @@
import UIKit
import Combine
-import MetaTextView
+import MetaTextKit
final class CustomEmojiPickerInputViewModel {
diff --git a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
index 609e4bcc6..8e6d46878 100644
--- a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
+++ b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
@@ -9,7 +9,7 @@ import os.log
import UIKit
import ActiveLabel
import FLAnimatedImage
-import MetaTextView
+import MetaTextKit
final class ReplicaStatusView: UIView {
diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift
index 658c5fcab..5528adf68 100644
--- a/Mastodon/Scene/Notification/NotificationViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationViewController.swift
@@ -14,7 +14,7 @@ import OSLog
import UIKit
import ActiveLabel
import Meta
-import MetaTextView
+import MetaTextKit
final class NotificationViewController: UIViewController, NeedsDependency {
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
index 684d9187c..6afc61e9a 100644
--- a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
+++ b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
@@ -11,7 +11,7 @@ import Foundation
import CoreDataStack
import UIKit
import ActiveLabel
-import MetaTextView
+import MetaTextKit
import Meta
import FLAnimatedImage
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
index 95a91b994..043e1b665 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
@@ -11,7 +11,7 @@ import Combine
import ActiveLabel
import TwitterTextEditor
import FLAnimatedImage
-import MetaTextView
+import MetaTextKit
protocol ProfileHeaderViewDelegate: AnyObject {
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView)
diff --git a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
index 639167684..32d096a33 100644
--- a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
+++ b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
@@ -13,7 +13,7 @@ import CoreData
import CoreDataStack
import ActiveLabel
import Meta
-import MetaTextView
+import MetaTextKit
final class ReportedStatusTableViewCell: UITableViewCell, StatusCell {
diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift
index a12a7bd28..0964ee3ba 100644
--- a/Mastodon/Scene/Share/View/Content/StatusView.swift
+++ b/Mastodon/Scene/Share/View/Content/StatusView.swift
@@ -12,7 +12,7 @@ import AVKit
import ActiveLabel
import AlamofireImage
import FLAnimatedImage
-import MetaTextView
+import MetaTextKit
import Meta
import MastodonSDK
@@ -81,12 +81,7 @@ final class StatusView: UIView {
return label
}()
- let headerInfoLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusHeader)
- label.text = "Bob reblogged"
- label.layer.masksToBounds = false
- return label
- }()
+ let headerInfoLabel = MetaLabel(style: .statusHeader)
let avatarView: UIView = {
let view = UIView()
@@ -98,8 +93,8 @@ final class StatusView: UIView {
let avatarButton = AvatarButton()
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
- let nameLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusName)
+ let nameMetaLabel: MetaLabel = {
+ let label = MetaLabel(style: .statusName)
return label
}()
@@ -343,24 +338,27 @@ extension StatusView {
titleContainerStackView.axis = .horizontal
titleContainerStackView.alignment = .center
titleContainerStackView.spacing = 4
- nameLabel.translatesAutoresizingMaskIntoConstraints = false
- titleContainerStackView.addArrangedSubview(nameLabel)
+ nameMetaLabel.translatesAutoresizingMaskIntoConstraints = false
+ titleContainerStackView.addArrangedSubview(nameMetaLabel)
NSLayoutConstraint.activate([
- nameLabel.heightAnchor.constraint(equalToConstant: 22).priority(.defaultHigh),
+ nameMetaLabel.heightAnchor.constraint(equalToConstant: 22).priority(.defaultHigh),
])
- titleContainerStackView.alignment = .firstBaseline
titleContainerStackView.addArrangedSubview(nameTrialingDotLabel)
titleContainerStackView.addArrangedSubview(dateLabel)
- titleContainerStackView.addArrangedSubview(UIView()) // padding
+ let padding = UIView()
+ padding.translatesAutoresizingMaskIntoConstraints = false
+ titleContainerStackView.addArrangedSubview(padding) // padding
titleContainerStackView.addArrangedSubview(visibilityImageView)
- nameLabel.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
+ nameMetaLabel.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
nameTrialingDotLabel.setContentHuggingPriority(.defaultHigh + 2, for: .horizontal)
nameTrialingDotLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
dateLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
- dateLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
- visibilityImageView.setContentHuggingPriority(.required - 1, for: .horizontal)
+ dateLabel.setContentCompressionResistancePriority(.required - 10, for: .horizontal)
+ padding.setContentHuggingPriority(.defaultLow, for: .horizontal)
+ padding.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
+ visibilityImageView.setContentHuggingPriority(.required - 9, for: .horizontal)
+ visibilityImageView.setContentCompressionResistancePriority(.required - 9, for: .horizontal)
visibilityImageView.setContentHuggingPriority(.required - 1, for: .vertical)
- visibilityImageView.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
// subtitle container: [username]
let subtitleContainerStackView = UIStackView()
diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
index 508d928e1..3a186f00b 100644
--- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
+++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
@@ -13,7 +13,7 @@ import CoreData
import CoreDataStack
import ActiveLabel
import Meta
-import MetaTextView
+import MetaTextKit
protocol StatusTableViewCellDelegate: AnyObject {
var context: AppContext! { get }
From 9577512ed5bc611a4db9bf20882f30b54cd98d19 Mon Sep 17 00:00:00 2001
From: CMK
Date: Thu, 22 Jul 2021 19:36:41 +0800
Subject: [PATCH 2/9] chore: update version to 0.9.3 (44)
---
Mastodon.xcodeproj/project.pbxproj | 48 +++++++++++++++---------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 0f7d85276..7d42a6e85 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -4306,7 +4306,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4314,7 +4314,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4333,7 +4333,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4341,7 +4341,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4598,7 +4598,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4606,7 +4606,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4622,7 +4622,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4630,7 +4630,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4646,7 +4646,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4654,7 +4654,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4670,7 +4670,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4678,7 +4678,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4759,7 +4759,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4767,7 +4767,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4874,7 +4874,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4882,7 +4882,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4993,7 +4993,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -5001,7 +5001,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -5108,7 +5108,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5116,7 +5116,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -5162,7 +5162,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5170,7 +5170,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -5185,7 +5185,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 43;
+ CURRENT_PROJECT_VERSION = 44;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5193,7 +5193,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.2;
+ MARKETING_VERSION = 0.9.3;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
From cfc598752811a909f77c228660493169aa91fd33 Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 19:10:27 +0800
Subject: [PATCH 3/9] feat: add APNG supports for more label
---
Mastodon.xcodeproj/project.pbxproj | 46 +--
.../xcschemes/xcschememanagement.plist | 8 +-
.../xcshareddata/swiftpm/Package.resolved | 27 --
.../Diffiable/Item/ComposeStatusItem.swift | 5 +-
.../Diffiable/Item/ProfileFieldItem.swift | 3 +-
.../Compose/ComposeStatusSection.swift | 15 +-
.../Compose/CustomEmojiPickerSection.swift | 7 +-
.../Section/ProfileFieldSection.swift | 49 ++-
.../Section/Status/NotificationSection.swift | 11 +-
Mastodon/Extension/ActiveLabel.swift | 229 ++++--------
Mastodon/Extension/CoreDataStack/Emojis.swift | 9 -
.../MastodonSDK/Mastodon+Entity+Account.swift | 11 +
Mastodon/Extension/MetaLabel.swift | 69 +++-
Mastodon/Helper/MastodonField.swift | 63 ----
.../MastodonStatusContent+Appearance.swift | 17 -
.../MastodonStatusContent+ParseResult.swift | 108 ------
Mastodon/Helper/MastodonStatusContent.swift | 332 ------------------
.../StatusProvider+StatusNodeDelegate.swift | 5 +-
...Provider+StatusTableViewCellDelegate.swift | 5 -
.../StatusProvider/StatusProviderFacade.swift | 55 ---
.../ComposeStatusContentTableViewCell.swift | 5 +-
...tomEmojiPickerItemCollectionViewCell.swift | 6 +-
.../Compose/ComposeViewModel+DataSource.swift | 26 +-
Mastodon/Scene/Compose/ComposeViewModel.swift | 2 +-
.../Compose/View/ReplicaStatusView.swift | 13 +-
.../HashtagTimelineViewController.swift | 6 +-
.../HashtagTimelineViewModel+Diffable.swift | 2 +-
.../HashtagTimelineViewModel.swift | 2 +-
...cHomeTimelineViewController+Provider.swift | 6 +
.../AsyncHomeTimelineViewController.swift | 6 +-
.../AsyncHomeTimelineViewModel+Diffable.swift | 2 +-
.../AsyncHomeTimelineViewModel.swift | 3 +-
.../HomeTimelineViewController.swift | 2 +-
.../HomeTimelineViewModel+Diffable.swift | 2 +-
.../HomeTimeline/HomeTimelineViewModel.swift | 3 +-
.../NotificationViewController.swift | 8 +-
.../Notification/NotificationViewModel.swift | 2 +-
.../NotificationStatusTableViewCell.swift | 15 +-
.../Favorite/FavoriteViewController.swift | 2 +-
.../Header/ProfileHeaderViewController.swift | 76 ++--
.../Header/ProfileHeaderViewModel.swift | 9 +-
...ofileFieldAddEntryCollectionViewCell.swift | 8 +-
.../View/ProfileFieldCollectionViewCell.swift | 16 +-
.../Header/View/ProfileFieldView.swift | 32 +-
.../Header/View/ProfileHeaderView.swift | 104 +++---
.../Scene/Profile/ProfileViewController.swift | 54 +--
Mastodon/Scene/Profile/ProfileViewModel.swift | 7 +-
.../Report/ReportedStatusTableviewCell.swift | 4 -
...hRecommendAccountsCollectionViewCell.swift | 21 +-
.../SearchResultTableViewCell.swift | 29 +-
.../Settings/SettingsViewController.swift | 41 ++-
...ubleTitleLabelNavigationBarTitleView.swift | 24 +-
.../Scene/Share/View/Content/StatusView.swift | 17 +-
.../Share/View/Node/Status/StatusNode.swift | 78 ++--
.../TableviewCell/StatusTableViewCell.swift | 6 -
.../SuggestionAccountTableViewCell.swift | 22 +-
.../Scene/Thread/ThreadViewController.swift | 32 +-
Mastodon/Scene/Thread/ThreadViewModel.swift | 11 +-
.../Service/StatusContentCacheService.swift | 77 ----
Mastodon/State/AppContext.swift | 1 -
60 files changed, 562 insertions(+), 1294 deletions(-)
delete mode 100644 Mastodon/Helper/MastodonField.swift
delete mode 100644 Mastodon/Helper/MastodonStatusContent+Appearance.swift
delete mode 100644 Mastodon/Helper/MastodonStatusContent+ParseResult.swift
delete mode 100755 Mastodon/Helper/MastodonStatusContent.swift
delete mode 100644 Mastodon/Service/StatusContentCacheService.swift
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 7d42a6e85..d42733555 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -65,7 +65,6 @@
2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F1FD25CD481700561493 /* StatusProvider.swift */; };
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */; };
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */; };
- 2D42FF6125C8177C004A627A /* ActiveLabel in Frameworks */ = {isa = PBXBuildFile; productRef = 2D42FF6025C8177C004A627A /* ActiveLabel */; };
2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF7D25C82218004A627A /* ActionToolBarContainer.swift */; };
2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */; };
2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF8E25C8228A004A627A /* UIButton.swift */; };
@@ -309,7 +308,6 @@
DB6804872637CD4C00430867 /* AppShared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DB6804922637CD8700430867 /* AppName.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804912637CD8700430867 /* AppName.swift */; };
DB6804A52637CDCC00430867 /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; };
- DB6804C82637CE2F00430867 /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; };
DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804D02637CE4700430867 /* UserDefaults.swift */; };
DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804FC2637CFEC00430867 /* AppSecret.swift */; };
DB6805102637D0F800430867 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB68050F2637D0F800430867 /* KeychainAccess */; };
@@ -442,7 +440,6 @@
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */; };
DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */; };
DBAEDE5C267A058D00D25FF5 /* BlurhashImageCacheService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAEDE5B267A058D00D25FF5 /* BlurhashImageCacheService.swift */; };
- DBAEDE61267B342D00D25FF5 /* StatusContentCacheService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAEDE60267B342D00D25FF5 /* StatusContentCacheService.swift */; };
DBAFB7352645463500371D5F /* Emojis.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBAFB7342645463500371D5F /* Emojis.swift */; };
DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */; };
DBB3BA2B26A81D060004F2D4 /* FLAnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */; };
@@ -479,11 +476,7 @@
DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; };
DBBC24D226A5488600398BB9 /* AvatarConfigurableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24B426A540AE00398BB9 /* AvatarConfigurableView.swift */; };
DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; };
- DBBC24DD26A54BCB00398BB9 /* MastodonStatusContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D726A54BCB00398BB9 /* MastodonStatusContent.swift */; };
DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */; };
- DBBC24DF26A54BCB00398BB9 /* MastodonStatusContent+ParseResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D926A54BCB00398BB9 /* MastodonStatusContent+ParseResult.swift */; };
- DBBC24E026A54BCB00398BB9 /* MastodonField.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24DA26A54BCB00398BB9 /* MastodonField.swift */; };
- DBBC24E126A54BCB00398BB9 /* MastodonStatusContent+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24DB26A54BCB00398BB9 /* MastodonStatusContent+Appearance.swift */; };
DBBE1B4525F3474B0081417A /* MastodonPickServerAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */; };
DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */; };
DBBF1DC226524D2900E5B703 /* AutoCompleteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DC126524D2900E5B703 /* AutoCompleteTableViewCell.swift */; };
@@ -930,6 +923,7 @@
DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollItem.swift; sourceTree = ""; };
DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = ""; };
DB3D100E25BAA75E00EAA174 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; };
+ DB3F693926AA97BD00C883AB /* MetaTextKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = MetaTextKit; path = ../MetaTextKit; sourceTree = ""; };
DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; };
DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
@@ -1143,7 +1137,6 @@
DBAE3F9D2616E308004B8251 /* APIService+Mute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Mute.swift"; sourceTree = ""; };
DBAE3FAE26172FC0004B8251 /* RemoteProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteProfileViewModel.swift; sourceTree = ""; };
DBAEDE5B267A058D00D25FF5 /* BlurhashImageCacheService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurhashImageCacheService.swift; sourceTree = ""; };
- DBAEDE60267B342D00D25FF5 /* StatusContentCacheService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentCacheService.swift; sourceTree = ""; };
DBAFB7342645463500371D5F /* Emojis.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emojis.swift; sourceTree = ""; };
DBB3BA2926A81C020004F2D4 /* FLAnimatedImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLAnimatedImageView.swift; sourceTree = ""; };
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = ""; };
@@ -1168,11 +1161,7 @@
DBBC24C326A544B900398BB9 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; };
DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThemeService+Appearance.swift"; sourceTree = ""; };
DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonRegex.swift; sourceTree = ""; };
- DBBC24D726A54BCB00398BB9 /* MastodonStatusContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonStatusContent.swift; sourceTree = ""; };
DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = ""; };
- DBBC24D926A54BCB00398BB9 /* MastodonStatusContent+ParseResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MastodonStatusContent+ParseResult.swift"; sourceTree = ""; };
- DBBC24DA26A54BCB00398BB9 /* MastodonField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonField.swift; sourceTree = ""; };
- DBBC24DB26A54BCB00398BB9 /* MastodonStatusContent+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MastodonStatusContent+Appearance.swift"; sourceTree = ""; };
DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPickServerAppearance.swift; sourceTree = ""; };
DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewModel.swift; sourceTree = ""; };
DBBF1DC126524D2900E5B703 /* AutoCompleteTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTableViewCell.swift; sourceTree = ""; };
@@ -1259,7 +1248,6 @@
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */,
DB89BA0325C10FD0008580ED /* CoreDataStack.framework in Frameworks */,
DBC6462B26A1738900B0E31B /* MastodonUI in Frameworks */,
- 2D42FF6125C8177C004A627A /* ActiveLabel in Frameworks */,
DB9A487E2603456B008B817C /* UITextView+Placeholder in Frameworks */,
2D939AC825EE14620076FA61 /* CropViewController in Frameworks */,
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */,
@@ -1274,7 +1262,6 @@
DBAC649E267DFE43007FE9FD /* DiffableDataSources in Frameworks */,
2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */,
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
- DB6804C82637CE2F00430867 /* AppShared.framework in Frameworks */,
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */,
DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */,
);
@@ -1600,7 +1587,6 @@
DBA5E7A2263AD0A3004598BB /* PhotoLibraryService.swift */,
DB297B1A2679FAE200704C90 /* PlaceholderImageCacheService.swift */,
DBAEDE5B267A058D00D25FF5 /* BlurhashImageCacheService.swift */,
- DBAEDE60267B342D00D25FF5 /* StatusContentCacheService.swift */,
DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */,
);
path = Service;
@@ -1974,6 +1960,7 @@
children = (
DBF53F5F25C14E88008AAC7B /* Mastodon.xctestplan */,
DBF53F6025C14E9D008AAC7B /* MastodonSDK.xctestplan */,
+ DB3F693926AA97BD00C883AB /* MetaTextKit */,
DB3D0FED25BAA42200EAA174 /* MastodonSDK */,
DB427DD425BAA00100D1B89D /* Mastodon */,
DB427DEB25BAA00100D1B89D /* MastodonTests */,
@@ -2771,11 +2758,7 @@
isa = PBXGroup;
children = (
DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */,
- DBBC24D726A54BCB00398BB9 /* MastodonStatusContent.swift */,
DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */,
- DBBC24D926A54BCB00398BB9 /* MastodonStatusContent+ParseResult.swift */,
- DBBC24DA26A54BCB00398BB9 /* MastodonField.swift */,
- DBBC24DB26A54BCB00398BB9 /* MastodonStatusContent+Appearance.swift */,
DBFEF07626A691FB006D7ED1 /* MastodonAuthenticationBox.swift */,
);
path = Helper;
@@ -2988,7 +2971,6 @@
DB3D0FF225BAA61700EAA174 /* AlamofireImage */,
5D526FE125BE9AC400460CB9 /* MastodonSDK */,
2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */,
- 2D42FF6025C8177C004A627A /* ActiveLabel */,
DB0140BC25C40D7500F9F3CF /* CommonOSLog */,
2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */,
2D939AC725EE14620076FA61 /* CropViewController */,
@@ -3163,7 +3145,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1250;
- LastUpgradeCheck = 1240;
+ LastUpgradeCheck = 1250;
TargetAttributes = {
DB427DD125BAA00100D1B89D = {
CreatedOnToolsVersion = 12.4;
@@ -3210,7 +3192,6 @@
packageReferences = (
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */,
2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */,
- 2D42FF5F25C8177C004A627A /* XCRemoteSwiftPackageReference "ActiveLabel" */,
DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */,
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */,
2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */,
@@ -3552,7 +3533,6 @@
DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */,
- DBAEDE61267B342D00D25FF5 /* StatusContentCacheService.swift in Sources */,
DB0C946F26A7D2A80088FB11 /* AvatarImageView.swift in Sources */,
2D38F1F125CD477D00561493 /* HomeTimelineViewModel+LoadMiddleState.swift in Sources */,
DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */,
@@ -3712,7 +3692,6 @@
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */,
5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */,
5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */,
- DBBC24DF26A54BCB00398BB9 /* MastodonStatusContent+ParseResult.swift in Sources */,
2D694A7425F9EB4E0038ADDC /* ContentWarningOverlayView.swift in Sources */,
DBAE3F682615DD60004B8251 /* UserProvider.swift in Sources */,
DBAC6488267D388B007FE9FD /* ASTableNode.swift in Sources */,
@@ -3726,7 +3705,6 @@
DB44768B260B3F2100B66B82 /* CustomEmojiPickerItem.swift in Sources */,
2DF75BA125D0E29D00694EC8 /* StatusProvider+StatusTableViewCellDelegate.swift in Sources */,
5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */,
- DBBC24E126A54BCB00398BB9 /* MastodonStatusContent+Appearance.swift in Sources */,
DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */,
2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */,
DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */,
@@ -3786,7 +3764,6 @@
DBA465932696B495002B41DB /* APIService+WebFinger.swift in Sources */,
DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */,
DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */,
- DBBC24DD26A54BCB00398BB9 /* MastodonStatusContent.swift in Sources */,
2DAC9E46262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift in Sources */,
DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */,
DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */,
@@ -3838,7 +3815,6 @@
DB36679D268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift in Sources */,
DB0C947226A7D2D70088FB11 /* AvatarButton.swift in Sources */,
DB98336B25C9420100AD9700 /* APIService+App.swift in Sources */,
- DBBC24E026A54BCB00398BB9 /* MastodonField.swift in Sources */,
DBFEF07B26A6BCE8006D7ED1 /* APIService+Status+Publish.swift in Sources */,
DBCBCC032680AF6E000F5B51 /* AsyncHomeTimelineViewController+DebugAction.swift in Sources */,
DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */,
@@ -4746,6 +4722,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = ASDK;
+ SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = "ASDK - Release";
@@ -5307,14 +5284,6 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
- 2D42FF5F25C8177C004A627A /* XCRemoteSwiftPackageReference "ActiveLabel" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/TwidereProject/ActiveLabel.swift";
- requirement = {
- kind = exactVersion;
- version = 5.0.3;
- };
- };
2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/vtourraine/ThirdPartyMailer.git";
@@ -5352,7 +5321,7 @@
repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git";
requirement = {
kind = exactVersion;
- version = 2.0.0;
+ version = 2.1.0;
};
};
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
@@ -5438,11 +5407,6 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
- 2D42FF6025C8177C004A627A /* ActiveLabel */ = {
- isa = XCSwiftPackageProductDependency;
- package = 2D42FF5F25C8177C004A627A /* XCRemoteSwiftPackageReference "ActiveLabel" */;
- productName = ActiveLabel;
- };
2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */ = {
isa = XCSwiftPackageProductDependency;
package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */;
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 1220300f7..d551bebb6 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,7 +12,7 @@
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 24
+ 25
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -22,7 +22,7 @@
Mastodon - RTL.xcscheme_^#shared#^_
orderHint
- 4
+ 3
Mastodon - Release.xcscheme_^#shared#^_
@@ -37,12 +37,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 22
+ 23
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 23
+ 24
SuppressBuildableAutocreation
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 45f1697c9..56f675a6d 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,15 +1,6 @@
{
"object": {
"pins": [
- {
- "package": "ActiveLabel",
- "repositoryURL": "https://github.com/TwidereProject/ActiveLabel.swift",
- "state": {
- "branch": null,
- "revision": "d503eb3bfabc54a70139618ab2ba09ebb8c09672",
- "version": "5.0.3"
- }
- },
{
"package": "Alamofire",
"repositoryURL": "https://github.com/Alamofire/Alamofire.git",
@@ -100,24 +91,6 @@
"version": "4.2.2"
}
},
- {
- "package": "Kingfisher",
- "repositoryURL": "https://github.com/onevcat/Kingfisher.git",
- "state": {
- "branch": null,
- "revision": "44450a8f564d7c0165f736ba2250649ff8d3e556",
- "version": "6.3.0"
- }
- },
- {
- "package": "MetaTextKit",
- "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git",
- "state": {
- "branch": null,
- "revision": "44fc5111269d9862369348870835e17907062115",
- "version": "2.0.0"
- }
- },
{
"package": "Nuke",
"repositoryURL": "https://github.com/kean/Nuke.git",
diff --git a/Mastodon/Diffiable/Item/ComposeStatusItem.swift b/Mastodon/Diffiable/Item/ComposeStatusItem.swift
index 7c916b166..c2c3f46d8 100644
--- a/Mastodon/Diffiable/Item/ComposeStatusItem.swift
+++ b/Mastodon/Diffiable/Item/ComposeStatusItem.swift
@@ -8,6 +8,7 @@
import Foundation
import Combine
import CoreData
+import MastodonMeta
/// Note: update Equatable when change case
enum ComposeStatusItem {
@@ -25,7 +26,7 @@ extension ComposeStatusItem {
let avatarURL = CurrentValueSubject(nil)
let displayName = CurrentValueSubject(nil)
- let emojiDict = CurrentValueSubject([:])
+ let emojiMeta = CurrentValueSubject([:])
let username = CurrentValueSubject(nil)
let composeContent = CurrentValueSubject(nil)
@@ -35,7 +36,7 @@ extension ComposeStatusItem {
static func == (lhs: ComposeStatusAttribute, rhs: ComposeStatusAttribute) -> Bool {
return lhs.avatarURL.value == rhs.avatarURL.value &&
lhs.displayName.value == rhs.displayName.value &&
- lhs.emojiDict.value == rhs.emojiDict.value &&
+ lhs.emojiMeta.value == rhs.emojiMeta.value &&
lhs.username.value == rhs.username.value &&
lhs.composeContent.value == rhs.composeContent.value &&
lhs.isContentWarningComposing.value == rhs.isContentWarningComposing.value &&
diff --git a/Mastodon/Diffiable/Item/ProfileFieldItem.swift b/Mastodon/Diffiable/Item/ProfileFieldItem.swift
index 4c6b37da8..781da1851 100644
--- a/Mastodon/Diffiable/Item/ProfileFieldItem.swift
+++ b/Mastodon/Diffiable/Item/ProfileFieldItem.swift
@@ -8,6 +8,7 @@
import Foundation
import Combine
import MastodonSDK
+import MastodonMeta
enum ProfileFieldItem {
case field(field: FieldValue, attribute: FieldItemAttribute)
@@ -56,7 +57,7 @@ extension ProfileFieldItem {
extension ProfileFieldItem {
class FieldItemAttribute: Equatable, ProfileFieldListSeparatorLineConfigurable {
- let emojiDict = CurrentValueSubject([:])
+ let emojiMeta = CurrentValueSubject([:])
var isEditing = false
var isLast = false
diff --git a/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift b/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
index bacc5097c..45b0656f4 100644
--- a/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
+++ b/Mastodon/Diffiable/Section/Compose/ComposeStatusSection.swift
@@ -45,12 +45,19 @@ extension ComposeStatusSection {
// set display name and username
Publishers.CombineLatest3(
attribute.displayName,
- attribute.emojiDict,
- attribute.username.eraseToAnyPublisher()
+ attribute.emojiMeta,
+ attribute.username
)
.receive(on: DispatchQueue.main)
- .sink { displayName, emojiDict, username in
- cell.statusView.nameLabel.configure(content: displayName ?? " ", emojiDict: emojiDict)
+ .sink { displayName, emojiMeta, username in
+ do {
+ let mastodonContent = MastodonContent(content: displayName ?? " ", emojis: emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.nameLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: " ")
+ cell.statusView.nameLabel.configure(content: metaContent)
+ }
cell.statusView.usernameLabel.text = username.flatMap { "@" + $0 } ?? " "
}
.store(in: &cell.disposeBag)
diff --git a/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift b/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
index 70de18c6b..251b52f3a 100644
--- a/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
+++ b/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
@@ -25,7 +25,12 @@ extension CustomEmojiPickerSection {
.af.imageRounded(withCornerRadius: 4)
let url = URL(string: attribute.emoji.url)
- cell.emojiImageView.setImage(url: url, placeholder: placeholder, scaleToSize: CustomEmojiPickerItemCollectionViewCell.itemSize)
+ cell.emojiImageView.sd_setImage(
+ with: url,
+ placeholderImage: placeholder,
+ options: [],
+ context: nil
+ )
cell.accessibilityLabel = attribute.emoji.shortcode
return cell
}
diff --git a/Mastodon/Diffiable/Section/ProfileFieldSection.swift b/Mastodon/Diffiable/Section/ProfileFieldSection.swift
index 1c8546eb3..e96a16e9e 100644
--- a/Mastodon/Diffiable/Section/ProfileFieldSection.swift
+++ b/Mastodon/Diffiable/Section/ProfileFieldSection.swift
@@ -8,6 +8,7 @@
import os
import UIKit
import Combine
+import MastodonMeta
enum ProfileFieldSection: Equatable, Hashable {
case main
@@ -29,32 +30,60 @@ extension ProfileFieldSection {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: ProfileFieldCollectionViewCell.self), for: indexPath) as! ProfileFieldCollectionViewCell
// set key
- cell.fieldView.titleActiveLabel.configure(field: field.name.value, emojiDict: attribute.emojiDict.value)
+ do {
+ let mastodonContent = MastodonContent(content: field.name.value, emojis: attribute.emojiMeta.value)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.fieldView.titleMetaLabel.configure(content: metaContent)
+ } catch {
+ let content = PlaintextMetaContent(string: field.name.value)
+ cell.fieldView.titleMetaLabel.configure(content: content)
+ }
cell.fieldView.titleTextField.text = field.name.value
Publishers.CombineLatest(
field.name.removeDuplicates(),
- attribute.emojiDict.removeDuplicates()
+ attribute.emojiMeta.removeDuplicates()
)
.receive(on: RunLoop.main)
- .sink { [weak cell] name, emojiDict in
+ .sink { [weak cell] name, emojiMeta in
guard let cell = cell else { return }
- cell.fieldView.titleActiveLabel.configure(field: name, emojiDict: emojiDict)
+ do {
+ let mastodonContent = MastodonContent(content: name, emojis: emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.fieldView.titleMetaLabel.configure(content: metaContent)
+ } catch {
+ let content = PlaintextMetaContent(string: name)
+ cell.fieldView.titleMetaLabel.configure(content: content)
+ }
// only bind label. The text field should only set once
}
.store(in: &cell.disposeBag)
// set value
- cell.fieldView.valueActiveLabel.configure(field: field.value.value, emojiDict: attribute.emojiDict.value)
+ do {
+ let mastodonContent = MastodonContent(content: field.value.value, emojis: attribute.emojiMeta.value)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.fieldView.valueMetaLabel.configure(content: metaContent)
+ } catch {
+ let content = PlaintextMetaContent(string: field.value.value)
+ cell.fieldView.valueMetaLabel.configure(content: content)
+ }
cell.fieldView.valueTextField.text = field.value.value
Publishers.CombineLatest(
field.value.removeDuplicates(),
- attribute.emojiDict.removeDuplicates()
+ attribute.emojiMeta.removeDuplicates()
)
.receive(on: RunLoop.main)
- .sink { [weak cell] value, emojiDict in
+ .sink { [weak cell] value, emojiMeta in
guard let cell = cell else { return }
- cell.fieldView.valueActiveLabel.configure(field: value, emojiDict: emojiDict)
+ do {
+ let mastodonContent = MastodonContent(content: value, emojis: emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.fieldView.valueMetaLabel.configure(content: metaContent)
+ } catch {
+ let content = PlaintextMetaContent(string: value)
+ cell.fieldView.valueMetaLabel.configure(content: content)
+ }
// only bind label. The text field should only set once
}
.store(in: &cell.disposeBag)
@@ -76,8 +105,8 @@ extension ProfileFieldSection {
// setup editing state
cell.fieldView.titleTextField.isHidden = !attribute.isEditing
cell.fieldView.valueTextField.isHidden = !attribute.isEditing
- cell.fieldView.titleActiveLabel.isHidden = attribute.isEditing
- cell.fieldView.valueActiveLabel.isHidden = attribute.isEditing
+ cell.fieldView.titleMetaLabel.isHidden = attribute.isEditing
+ cell.fieldView.valueMetaLabel.isHidden = attribute.isEditing
// set control hidden
let isHidden = !attribute.isEditing
diff --git a/Mastodon/Diffiable/Section/Status/NotificationSection.swift b/Mastodon/Diffiable/Section/Status/NotificationSection.swift
index 01229235b..3113a4462 100644
--- a/Mastodon/Diffiable/Section/Status/NotificationSection.swift
+++ b/Mastodon/Diffiable/Section/Status/NotificationSection.swift
@@ -11,6 +11,8 @@ import CoreDataStack
import Foundation
import MastodonSDK
import UIKit
+import MetaTextKit
+import MastodonMeta
enum NotificationSection: Equatable, Hashable {
case main
@@ -66,7 +68,14 @@ extension NotificationSection {
.store(in: &cell.disposeBag)
// configure author name, notification description, timestamp
- cell.nameLabel.configure(content: notification.account.displayNameWithFallback, emojiDict: notification.account.emojiDict)
+ do {
+ let mastodonContent = MastodonContent(content: notification.account.displayNameWithFallback, emojis: notification.account.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.nameLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: notification.account.displayNameWithFallback)
+ cell.nameLabel.configure(content: metaContent)
+ }
let createAt = notification.createAt
let actionText = notification.notificationType.actionText
cell.actionLabel.text = actionText + " · " + createAt.timeAgoSinceNow
diff --git a/Mastodon/Extension/ActiveLabel.swift b/Mastodon/Extension/ActiveLabel.swift
index 584888195..4b23d4eb3 100644
--- a/Mastodon/Extension/ActiveLabel.swift
+++ b/Mastodon/Extension/ActiveLabel.swift
@@ -1,173 +1,66 @@
+//extension ActiveEntity {
//
-// ActiveLabel.swift
-// Mastodon
+// var accessibilityLabelDescription: String {
+// switch self.type {
+// case .email: return L10n.Common.Controls.Status.Tag.email
+// case .hashtag: return L10n.Common.Controls.Status.Tag.hashtag
+// case .mention: return L10n.Common.Controls.Status.Tag.mention
+// case .url: return L10n.Common.Controls.Status.Tag.url
+// case .emoji: return L10n.Common.Controls.Status.Tag.emoji
+// }
+// }
//
-// Created by sxiaojian on 2021/1/29.
+// var accessibilityValueDescription: String {
+// switch self.type {
+// case .email(let text, _): return text
+// case .hashtag(let text, _): return text
+// case .mention(let text, _): return text
+// case .url(_, let trimmed, _, _): return trimmed
+// case .emoji(let text, _, _): return text
+// }
+// }
//
+// func accessibilityElement(in accessibilityContainer: Any) -> ActiveLabelAccessibilityElement? {
+// if case .emoji = self.type {
+// return nil
+// }
+//
+// let element = ActiveLabelAccessibilityElement(accessibilityContainer: accessibilityContainer)
+// element.accessibilityTraits = .button
+// element.accessibilityLabel = accessibilityLabelDescription
+// element.accessibilityValue = accessibilityValueDescription
+// return element
+// }
+//}
-import UIKit
-import Foundation
-import ActiveLabel
-import os.log
-import MastodonUI
-
-extension ActiveLabel {
-
- enum Style {
- case `default`
- case statusHeader
- case statusName
- case profileFieldName
- case profileFieldValue
- }
-
- convenience init(style: Style) {
- self.init()
-
- numberOfLines = 0
- lineSpacing = 5
- mentionColor = Asset.Colors.brandBlue.color
- hashtagColor = Asset.Colors.brandBlue.color
- URLColor = Asset.Colors.brandBlue.color
- emojiPlaceholderColor = .systemFill
-
- accessibilityContainerType = .semanticGroup
-
- switch style {
- case .default:
- font = .preferredFont(forTextStyle: .body)
- textColor = Asset.Colors.Label.primary.color
- case .statusHeader:
- font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium), maximumPointSize: 17)
- 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 .profileFieldName:
- font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20)
- textColor = Asset.Colors.Label.primary.color
- numberOfLines = 1
- case .profileFieldValue:
- font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20)
- textColor = Asset.Colors.Label.primary.color
- numberOfLines = 1
- }
- }
-
-}
-
-extension ActiveLabel {
- public func configure(text: String) {
- attributedText = nil
- activeEntities.removeAll()
- self.text = text
- accessibilityLabel = text
- }
-}
-
-extension ActiveLabel {
-
- /// status content
- public func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
- attributedText = nil
- activeEntities.removeAll()
-
- if let parseResult = try? MastodonStatusContent.parse(content: content, emojiDict: emojiDict) {
- text = parseResult.trimmed
- activeEntities = parseResult.activeEntities
- accessibilityLabel = parseResult.original
- } else {
- text = ""
- accessibilityLabel = nil
- }
- }
-
- public func configure(contentParseResult parseResult: MastodonStatusContent.ParseResult?) {
- attributedText = nil
- activeEntities.removeAll()
- text = parseResult?.trimmed ?? ""
- activeEntities = parseResult?.activeEntities ?? []
- accessibilityLabel = parseResult?.original ?? nil
- }
-
- /// account note
- public func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
- configure(content: note, emojiDict: emojiDict)
- }
-}
-
-extension ActiveLabel {
- /// account field
- public func configure(field: String, emojiDict: MastodonStatusContent.EmojiDict) {
- configure(content: field, emojiDict: emojiDict)
- }
-}
-
-extension ActiveEntity {
-
- var accessibilityLabelDescription: String {
- switch self.type {
- case .email: return L10n.Common.Controls.Status.Tag.email
- case .hashtag: return L10n.Common.Controls.Status.Tag.hashtag
- case .mention: return L10n.Common.Controls.Status.Tag.mention
- case .url: return L10n.Common.Controls.Status.Tag.url
- case .emoji: return L10n.Common.Controls.Status.Tag.emoji
- }
- }
-
- var accessibilityValueDescription: String {
- switch self.type {
- case .email(let text, _): return text
- case .hashtag(let text, _): return text
- case .mention(let text, _): return text
- case .url(_, let trimmed, _, _): return trimmed
- case .emoji(let text, _, _): return text
- }
- }
-
- func accessibilityElement(in accessibilityContainer: Any) -> ActiveLabelAccessibilityElement? {
- if case .emoji = self.type {
- return nil
- }
-
- let element = ActiveLabelAccessibilityElement(accessibilityContainer: accessibilityContainer)
- element.accessibilityTraits = .button
- element.accessibilityLabel = accessibilityLabelDescription
- element.accessibilityValue = accessibilityValueDescription
- return element
- }
-}
-
-final class ActiveLabelAccessibilityElement: UIAccessibilityElement {
- var index: Int!
-}
-
+//final class ActiveLabelAccessibilityElement: UIAccessibilityElement {
+// var index: Int!
+//}
+//
// MARK: - UIAccessibilityContainer
-extension ActiveLabel {
-
- func createAccessibilityElements() -> [UIAccessibilityElement] {
- var elements: [UIAccessibilityElement] = []
-
- let element = ActiveLabelAccessibilityElement(accessibilityContainer: self)
- element.accessibilityTraits = .staticText
- element.accessibilityLabel = accessibilityLabel
- element.accessibilityFrame = superview!.convert(frame, to: nil)
- element.accessibilityLanguage = accessibilityLanguage
- elements.append(element)
-
- for entity in activeEntities {
- guard let element = entity.accessibilityElement(in: self) else { continue }
- var glyphRange = NSRange()
- layoutManager.characterRange(forGlyphRange: entity.range, actualGlyphRange: &glyphRange)
- let rect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
- element.accessibilityFrame = self.convert(rect, to: nil)
- element.accessibilityContainer = self
- elements.append(element)
- }
-
- return elements
- }
-
-}
+//extension ActiveLabel {
+//
+// func createAccessibilityElements() -> [UIAccessibilityElement] {
+// var elements: [UIAccessibilityElement] = []
+//
+// let element = ActiveLabelAccessibilityElement(accessibilityContainer: self)
+// element.accessibilityTraits = .staticText
+// element.accessibilityLabel = accessibilityLabel
+// element.accessibilityFrame = superview!.convert(frame, to: nil)
+// element.accessibilityLanguage = accessibilityLanguage
+// elements.append(element)
+//
+// for entity in activeEntities {
+// guard let element = entity.accessibilityElement(in: self) else { continue }
+// var glyphRange = NSRange()
+// layoutManager.characterRange(forGlyphRange: entity.range, actualGlyphRange: &glyphRange)
+// let rect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
+// element.accessibilityFrame = self.convert(rect, to: nil)
+// element.accessibilityContainer = self
+// elements.append(element)
+// }
+//
+// return elements
+// }
+//
+//}
diff --git a/Mastodon/Extension/CoreDataStack/Emojis.swift b/Mastodon/Extension/CoreDataStack/Emojis.swift
index 8d7c29753..2f45880bd 100644
--- a/Mastodon/Extension/CoreDataStack/Emojis.swift
+++ b/Mastodon/Extension/CoreDataStack/Emojis.swift
@@ -23,15 +23,6 @@ extension EmojiContainer {
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
- }
var emojiMeta: MastodonContent.Emojis {
var dict = MastodonContent.Emojis()
diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
index 8109371c4..de703fd16 100644
--- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
+++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
@@ -7,6 +7,7 @@
import UIKit
import MastodonSDK
+import MastodonMeta
extension Mastodon.Entity.Account: Hashable {
public func hash(into hasher: inout Hasher) {
@@ -28,3 +29,13 @@ extension Mastodon.Entity.Account {
return avatarImageURL() ?? URL(string: "https://\(domain)/avatars/original/missing.png")!
}
}
+
+extension Mastodon.Entity.Account {
+ var emojiMeta: MastodonContent.Emojis {
+ var dict = MastodonContent.Emojis()
+ for emoji in emojis ?? [] {
+ dict[emoji.shortcode] = emoji.url
+ }
+ return dict
+ }
+}
diff --git a/Mastodon/Extension/MetaLabel.swift b/Mastodon/Extension/MetaLabel.swift
index 67200874b..27f04e068 100644
--- a/Mastodon/Extension/MetaLabel.swift
+++ b/Mastodon/Extension/MetaLabel.swift
@@ -6,14 +6,19 @@
//
import UIKit
+import Meta
import MetaTextKit
extension MetaLabel {
enum Style {
case statusHeader
case statusName
-// case profileFieldName
-// case profileFieldValue
+ case notificationName
+ case profileFieldName
+ case profileFieldValue
+ case recommendAccountName
+ case titleView
+ case settingTableFooter
}
convenience init(style: Style) {
@@ -33,14 +38,37 @@ extension MetaLabel {
case .statusName:
font = .systemFont(ofSize: 17, weight: .semibold)
textColor = Asset.Colors.Label.primary.color
-// case .profileFieldName:
-// font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20)
-// textColor = Asset.Colors.Label.primary.color
-// numberOfLines = 1
-// case .profileFieldValue:
-// font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20)
-// textColor = Asset.Colors.Label.primary.color
-// numberOfLines = 1
+
+ case .notificationName:
+ font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20)
+ textColor = Asset.Colors.brandBlue.color
+
+ case .profileFieldName:
+ font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20)
+ textColor = Asset.Colors.Label.primary.color
+
+ case .profileFieldValue:
+ font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20)
+ textColor = Asset.Colors.Label.primary.color
+ textAlignment = .right
+
+
+ case .titleView:
+ font = .systemFont(ofSize: 17, weight: .semibold)
+ textColor = Asset.Colors.Label.primary.color
+ textAlignment = .center
+ paragraphStyle.alignment = .center
+
+ case .recommendAccountName:
+ font = .systemFont(ofSize: 18, weight: .semibold)
+ textColor = .white
+
+ case .settingTableFooter:
+ font = .preferredFont(forTextStyle: .body)
+ textColor = Asset.Colors.Label.primary.color
+ numberOfLines = 0
+ textContainer.maximumNumberOfLines = 0
+ paragraphStyle.alignment = .center
}
self.font = font
@@ -50,4 +78,23 @@ extension MetaLabel {
.font: font,
.foregroundColor: textColor
]
- }}
+ linkAttributes = [
+ .font: font,
+ .foregroundColor: Asset.Colors.brandBlue.color
+ ]
+ }
+
+}
+
+struct PlaintextMetaContent: MetaContent {
+ let string: String
+ let entities: [Meta.Entity] = []
+
+ init(string: String) {
+ self.string = string
+ }
+
+ func metaAttachment(for entity: Meta.Entity) -> MetaAttachment? {
+ return nil
+ }
+}
diff --git a/Mastodon/Helper/MastodonField.swift b/Mastodon/Helper/MastodonField.swift
deleted file mode 100644
index 86bc2cc9b..000000000
--- a/Mastodon/Helper/MastodonField.swift
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// MastodonField.swift
-// Mastodon
-//
-// Created by MainasuK Cirno on 2021-3-30.
-//
-
-//import Foundation
-//import ActiveLabel
-//
-//enum MastodonField {
-//
-// @available(*, deprecated, message: "rely on server meta rendering")
-// public static func parse(field string: String, emojiDict: MastodonStatusContent.EmojiDict) -> ParseResult {
-// // use content parser get emoji entities
-// let value = string
-//
-// var string = string
-// var entities: [ActiveEntity] = []
-//
-// do {
-// let contentParseresult = try MastodonStatusContent.parse(content: string, emojiDict: emojiDict)
-// string = contentParseresult.trimmed
-// entities.append(contentsOf: contentParseresult.activeEntities)
-// } catch {
-// // assertionFailure(error.localizedDescription)
-// }
-//
-// let mentionMatches = string.matches(pattern: "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?)")
-// let hashtagMatches = string.matches(pattern: "(?:#([^\\s.]+))")
-// let urlMatches = string.matches(pattern: "(?i)https?://\\S+(?:/|\\b)")
-//
-//
-// for match in mentionMatches {
-// guard let text = string.substring(with: match, at: 0) else { continue }
-// let entity = ActiveEntity(range: match.range, type: .mention(text, userInfo: nil))
-// entities.append(entity)
-// }
-//
-// for match in hashtagMatches {
-// guard let text = string.substring(with: match, at: 0) else { continue }
-// let entity = ActiveEntity(range: match.range, type: .hashtag(text, userInfo: nil))
-// entities.append(entity)
-// }
-//
-// for match in urlMatches {
-// guard let text = string.substring(with: match, at: 0) else { continue }
-// let entity = ActiveEntity(range: match.range, type: .url(text, trimmed: text, url: text, userInfo: nil))
-// entities.append(entity)
-// }
-//
-// return ParseResult(value: value, trimmed: string, activeEntities: entities)
-// }
-//
-//}
-//
-//extension MastodonField {
-// public struct ParseResult {
-// let value: String
-// let trimmed: String
-// let activeEntities: [ActiveEntity]
-// }
-//}
diff --git a/Mastodon/Helper/MastodonStatusContent+Appearance.swift b/Mastodon/Helper/MastodonStatusContent+Appearance.swift
deleted file mode 100644
index d82d68b85..000000000
--- a/Mastodon/Helper/MastodonStatusContent+Appearance.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// MastodonStatusContent+Appearance.swift
-// Mastodon
-//
-// Created by Cirno MainasuK on 2021-6-20.
-//
-
-import UIKit
-
-extension MastodonStatusContent {
- public struct Appearance {
- let attributes: [NSAttributedString.Key: Any]
- let urlAttributes: [NSAttributedString.Key: Any]
- let hashtagAttributes: [NSAttributedString.Key: Any]
- let mentionAttributes: [NSAttributedString.Key: Any]
- }
-}
diff --git a/Mastodon/Helper/MastodonStatusContent+ParseResult.swift b/Mastodon/Helper/MastodonStatusContent+ParseResult.swift
deleted file mode 100644
index 9de0b341f..000000000
--- a/Mastodon/Helper/MastodonStatusContent+ParseResult.swift
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// MastodonStatusContent+ParseResult.swift
-// Mastodon
-//
-// Created by Cirno MainasuK on 2021-6-20.
-//
-
-import Foundation
-import ActiveLabel
-
-extension MastodonStatusContent {
- public struct ParseResult: Hashable {
- public let document: String
- public let original: String
- public let trimmed: String
- public let activeEntities: [ActiveEntity]
-
- public static func == (lhs: MastodonStatusContent.ParseResult, rhs: MastodonStatusContent.ParseResult) -> Bool {
- return lhs.document == rhs.document
- && lhs.original == rhs.original
- && lhs.trimmed == rhs.trimmed
- && lhs.activeEntities.count == rhs.activeEntities.count // FIXME:
- }
-
- public func hash(into hasher: inout Hasher) {
- hasher.combine(document)
- hasher.combine(original)
- hasher.combine(trimmed)
- hasher.combine(activeEntities.count) // FIXME:
- }
-
- func trimmedAttributedString(appearance: MastodonStatusContent.Appearance) -> NSAttributedString {
- let attributedString = NSMutableAttributedString(string: trimmed, attributes: appearance.attributes)
- for entity in activeEntities {
- switch entity.type {
- case .url:
- attributedString.addAttributes(appearance.urlAttributes, range: entity.range)
- case .hashtag:
- attributedString.addAttributes(appearance.hashtagAttributes, range: entity.range)
- case .mention:
- attributedString.addAttributes(appearance.mentionAttributes, range: entity.range)
- default:
- break
- }
- if let uri = entity.type.uri {
- attributedString.addAttributes([
- .link: uri
- ], range: entity.range)
- }
- }
- return attributedString
- }
- }
-}
-
-extension ActiveEntityType {
-
- static let appScheme = "mastodon"
-
- public init?(url: URL) {
- guard let scheme = url.scheme?.lowercased() else { return nil }
- guard scheme == ActiveEntityType.appScheme else {
- self = .url("", trimmed: "", url: url.absoluteString, userInfo: nil)
- return
- }
-
- guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
- let parameters = components.queryItems else { return nil }
-
- if let hashtag = parameters.first(where: { $0.name == "hashtag" }), let encoded = hashtag.value, let value = String(base64Encoded: encoded) {
- self = .hashtag(value, userInfo: nil)
- return
- }
- if let mention = parameters.first(where: { $0.name == "mention" }), let encoded = mention.value, let value = String(base64Encoded: encoded) {
- self = .mention(value, userInfo: nil)
- return
- }
- return nil
- }
-
- public var uri: URL? {
- switch self {
- case .url(_, _, let url, _):
- return URL(string: url)
- case .hashtag(let hashtag, _):
- return URL(string: "\(ActiveEntityType.appScheme)://meta?hashtag=\(hashtag.base64Encoded)")
- case .mention(let mention, _):
- return URL(string: "\(ActiveEntityType.appScheme)://meta?mention=\(mention.base64Encoded)")
- default:
- return nil
- }
- }
-
-}
-
-extension String {
- fileprivate var base64Encoded: String {
- return Data(self.utf8).base64EncodedString()
- }
-
- init?(base64Encoded: String) {
- guard let data = Data(base64Encoded: base64Encoded),
- let string = String(data: data, encoding: .utf8) else {
- return nil
- }
- self = string
- }
-}
diff --git a/Mastodon/Helper/MastodonStatusContent.swift b/Mastodon/Helper/MastodonStatusContent.swift
deleted file mode 100755
index 917c456d2..000000000
--- a/Mastodon/Helper/MastodonStatusContent.swift
+++ /dev/null
@@ -1,332 +0,0 @@
-//
-// MastodonStatusContent.swift
-// Mastodon
-//
-// Created by MainasuK Cirno on 2021/2/1.
-//
-
-import UIKit
-import Combine
-import ActiveLabel
-import Fuzi
-
-public enum MastodonStatusContent {
-
- public typealias EmojiShortcode = String
- public typealias EmojiDict = [EmojiShortcode: URL]
-
- static let workingQueue = DispatchQueue(label: "org.joinmastodon.app.ActiveLabel.working-queue", qos: .userInteractive, attributes: .concurrent)
-
- public static func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> AnyPublisher {
- return Future { promise in
- self.workingQueue.async {
- let parseResult = try? MastodonStatusContent.parse(content: content, emojiDict: emojiDict)
- promise(.success(parseResult))
- }
- }
- .eraseToAnyPublisher()
- }
-
- public static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
- let document: String = {
- var content = content.replacingOccurrences(of: "
", with: "\r\n")
- for (shortcode, url) in emojiDict {
- let emojiNode = "\(shortcode)"
- let pattern = ":\(shortcode):"
- content = content.replacingOccurrences(of: pattern, with: emojiNode)
- }
- return content.trimmingCharacters(in: .whitespacesAndNewlines)
- }()
- let rootNode = try Node.parse(document: document)
- let text = String(rootNode.text)
-
- var activeEntities: [ActiveEntity] = []
- let entities = MastodonStatusContent.Node.entities(in: rootNode)
- for entity in entities {
- let range = NSRange(entity.text.startIndex.. String {
- guard self.hasPrefix(prefix) else { return self }
- return String(self.dropFirst(prefix.count))
- }
-}
-
-extension MastodonStatusContent {
-
- class Node {
-
- let level: Int
- let type: Type?
-
- // substring text
- let text: Substring
-
- // range in parent String
- var range: Range {
- return text.startIndex.. = {
- guard let className = attributes["class"] else { return Set() }
- return Set(className.components(separatedBy: " "))
- }()
- let _type: Type? = {
- if tagName == "a" {
- if _classNames.contains("u-url") {
- return .mention
- }
- if _classNames.contains("hashtag") {
- return .hashtag
- }
- return .url
- } else {
- if _classNames.contains("emoji") {
- return .emoji
- }
- return nil
- }
- }()
- self.level = level
- self.type = _type
- self.text = text
- self.tagName = tagName
- self.attributes = attributes
- self.href = href
- self.hrefEllipsis = hrefEllipsis
- self.children = children
- }
-
- static func parse(document: String) throws -> MastodonStatusContent.Node {
- let document = document.replacingOccurrences(of: "
|
", with: "\r\n", options: .regularExpression, range: nil)
- let html = try HTMLDocument(string: document)
-
- let body = html.body ?? nil
- let text = body?.stringValue ?? ""
- let level = 0
- let children: [MastodonStatusContent.Node] = body.flatMap { body in
- return Node.parse(element: body, parentText: text[...], parentLevel: level + 1)
- } ?? []
- let node = Node(
- level: level,
- text: text[...],
- tagName: body?.tag,
- attributes: body?.attributes ?? [:],
- href: nil,
- hrefEllipsis: nil,
- children: children
- )
-
- return node
- }
-
- static func parse(element: XMLElement, parentText: Substring, parentLevel: Int) -> [Node] {
- let parent = element
- let scanner = Scanner(string: String(parentText))
- scanner.charactersToBeSkipped = .none
-
- var children: [Node] = []
- for _element in parent.children {
- let _text = _element.stringValue
-
- // scan element text
- _ = scanner.scanUpToString(_text)
- let startIndexOffset = scanner.currentIndex.utf16Offset(in: scanner.string)
- guard scanner.scanString(_text) != nil else {
- assertionFailure()
- continue
- }
- let endIndexOffset = scanner.currentIndex.utf16Offset(in: scanner.string)
-
- // locate substring
- let startIndex = parentText.utf16.index(parentText.utf16.startIndex, offsetBy: startIndexOffset)
- let endIndex = parentText.utf16.index(parentText.utf16.startIndex, offsetBy: endIndexOffset)
- let text = Substring(parentText.utf16[startIndex.. Bool
- ) -> [Node] {
- var nodes: [Node] = []
-
- if predicate(node) {
- nodes.append(node)
- }
-
- for child in node.children {
- nodes.append(contentsOf: Node.collect(node: child, where: predicate))
- }
- return nodes
- }
-
- }
-
-}
-
-extension MastodonStatusContent.Node {
- enum `Type` {
- case url
- case mention
- case hashtag
- case emoji
- }
-
- static func entities(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
- return MastodonStatusContent.Node.collect(node: node) { node in node.type != nil }
- }
-
- static func hashtags(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
- return MastodonStatusContent.Node.collect(node: node) { node in node.type == .hashtag }
- }
-
- static func mentions(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
- return MastodonStatusContent.Node.collect(node: node) { node in node.type == .mention }
- }
-
- static func urls(in node: MastodonStatusContent.Node) -> [MastodonStatusContent.Node] {
- return MastodonStatusContent.Node.collect(node: node) { node in node.type == .url }
- }
-
-}
-
-extension MastodonStatusContent.Node: CustomDebugStringConvertible {
- var debugDescription: String {
- let linkInfo: String = {
- switch (href, hrefEllipsis) {
- case (nil, nil):
- return ""
- case (let href, let hrefEllipsis):
- return "(\(href ?? "nil") - \(hrefEllipsis ?? "nil"))"
- }
- }()
- let classNamesInfo: String = {
- guard let className = attributes["class"] else { return "" }
- return "@[\(className)]"
- }()
- let nodeDescription = String(
- format: "<%@>%@%@: %@",
- tagName ?? "",
- classNamesInfo,
- linkInfo,
- String(text)
- )
- guard !children.isEmpty else {
- return nodeDescription
- }
-
- let indent = Array(repeating: " ", count: level).joined()
- let childrenDescription = children
- .map { indent + $0.debugDescription }
- .joined(separator: "\n")
-
- return nodeDescription + "\n" + childrenDescription
- }
-}
diff --git a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusNodeDelegate.swift b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusNodeDelegate.swift
index 918e960f4..3c6d7da19 100644
--- a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusNodeDelegate.swift
+++ b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusNodeDelegate.swift
@@ -8,13 +8,10 @@
#if ASDK
import Foundation
-import ActiveLabel
// MARK: - StatusViewDelegate
extension StatusNodeDelegate where Self: StatusProvider {
- func statusNode(_ node: StatusNode, statusContentTextNode: ASMetaEditableTextNode, didSelectActiveEntityType type: ActiveEntityType) {
- StatusProviderFacade.responseToStatusActiveLabelAction(provider: self, node: node, didSelectActiveEntityType: type)
- }
+
}
#endif
diff --git a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
index 544de8893..5dab05295 100644
--- a/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
+++ b/Mastodon/Protocol/StatusProvider/StatusProvider+StatusTableViewCellDelegate.swift
@@ -11,7 +11,6 @@ import Combine
import CoreData
import CoreDataStack
import MastodonSDK
-import ActiveLabel
import Meta
import MetaTextKit
@@ -25,10 +24,6 @@ extension StatusTableViewCellDelegate where Self: StatusProvider {
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView) {
StatusProviderFacade.coordinateToStatusAuthorProfileScene(for: .primary, provider: self, cell: cell)
}
-
- func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- StatusProviderFacade.responseToStatusActiveLabelAction(provider: self, cell: cell, activeLabel: activeLabel, didTapEntity: entity)
- }
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
StatusProviderFacade.responseToStatusMetaTextAction(provider: self, cell: cell, metaText: metaText, didSelectMeta: meta)
diff --git a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
index e5bb15a80..e115151ea 100644
--- a/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
+++ b/Mastodon/Protocol/StatusProvider/StatusProviderFacade.swift
@@ -11,7 +11,6 @@ import Combine
import CoreData
import CoreDataStack
import MastodonSDK
-import ActiveLabel
import Meta
import MetaTextKit
@@ -125,35 +124,6 @@ extension StatusProviderFacade {
}
extension StatusProviderFacade {
-
- static func responseToStatusActiveLabelAction(provider: StatusProvider, cell: UITableViewCell, activeLabel: ActiveLabel, didTapEntity entity: ActiveEntity) {
- switch entity.type {
- case .url(_, _, let url, _),
- .mention(let url, _) where url.lowercased().hasPrefix("http"):
- // note:
- // some server mark the normal url as "u-url" class. :
- guard let url = URL(string: url) else { return }
- if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain,
- url.pathComponents.count >= 4,
- url.pathComponents[0] == "/",
- url.pathComponents[1] == "web",
- url.pathComponents[2] == "statuses" {
- let statusID = url.pathComponents[3]
- let threadViewModel = RemoteThreadViewModel(context: provider.context, statusID: statusID)
- provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
- } else {
- provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- }
- case .hashtag(let text, _):
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: text)
- provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)
- case .mention(let text, let userInfo):
- let href = userInfo?["href"] as? String
- coordinateToStatusMentionProfileScene(for: .primary, provider: provider, cell: cell, mention: text, href: href)
- default:
- break
- }
- }
static func responseToStatusMetaTextAction(provider: StatusProvider, cell: UITableViewCell, metaText: MetaText, didSelectMeta meta: Meta) {
switch meta {
@@ -185,31 +155,6 @@ extension StatusProviderFacade {
}
#if ASDK
- static func responseToStatusActiveLabelAction(provider: StatusProvider, node: ASCellNode, didSelectActiveEntityType type: ActiveEntityType) {
- switch type {
- case .hashtag(let text, _):
- let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, hashtag: text)
- provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show)
- case .mention(let text, _):
- coordinateToStatusMentionProfileScene(for: .primary, provider: provider, node: node, mention: text)
- case .url(_, _, let url, _):
- guard let url = URL(string: url) else { return }
- if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain,
- url.pathComponents.count >= 4,
- url.pathComponents[0] == "/",
- url.pathComponents[1] == "web",
- url.pathComponents[2] == "statuses" {
- let statusID = url.pathComponents[3]
- let threadViewModel = RemoteThreadViewModel(context: provider.context, statusID: statusID)
- provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show)
- } else {
- provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- }
- default:
- break
- }
- }
-
private static func coordinateToStatusMentionProfileScene(for target: Target, provider: StatusProvider, node: ASCellNode, mention: String) {
guard let status = provider.status(node: node, indexPath: nil) else { return }
coordinateToStatusMentionProfileScene(for: target, provider: provider, status: status, mention: mention, href: nil)
diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
index d970b6734..ffeae7678 100644
--- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
+++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentTableViewCell.swift
@@ -40,20 +40,19 @@ final class ComposeStatusContentTableViewCell: UITableViewCell {
attributes: attributes
)
}()
- let paragraphStyle: NSMutableParagraphStyle = {
+ metaText.paragraphStyle = {
let style = NSMutableParagraphStyle()
style.lineSpacing = 5
+ style.paragraphSpacing = 8
return style
}()
metaText.textAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)),
.foregroundColor: Asset.Colors.Label.primary.color,
- .paragraphStyle: paragraphStyle,
]
metaText.linkAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)),
.foregroundColor: Asset.Colors.brandBlue.color,
- .paragraphStyle: paragraphStyle,
]
return metaText
}()
diff --git a/Mastodon/Scene/Compose/CollectionViewCell/CustomEmojiPickerItemCollectionViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/CustomEmojiPickerItemCollectionViewCell.swift
index d88b919f4..c92e689bc 100644
--- a/Mastodon/Scene/Compose/CollectionViewCell/CustomEmojiPickerItemCollectionViewCell.swift
+++ b/Mastodon/Scene/Compose/CollectionViewCell/CustomEmojiPickerItemCollectionViewCell.swift
@@ -6,14 +6,14 @@
//
import UIKit
-import FLAnimatedImage
+import SDWebImage
final class CustomEmojiPickerItemCollectionViewCell: UICollectionViewCell {
static let itemSize = CGSize(width: 44, height: 44)
- let emojiImageView: FLAnimatedImageView = {
- let imageView = FLAnimatedImageView()
+ let emojiImageView: SDAnimatedImageView = {
+ let imageView = SDAnimatedImageView()
imageView.contentMode = .scaleAspectFit
imageView.layer.masksToBounds = true
return imageView
diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
index 2642808d1..79fe538d3 100644
--- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
+++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
@@ -193,8 +193,15 @@ extension ComposeViewModel: UITableViewDataSource {
// set avatar
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: status.author.avatarImageURL()))
- // set name username
- cell.statusView.nameLabel.configure(content: status.author.displayNameWithFallback, emojiDict: status.author.emojiDict)
+ // set name, username
+ do {
+ let mastodonContent = MastodonContent(content: status.author.displayNameWithFallback, emojis: status.author.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.nameLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: status.author.displayNameWithFallback)
+ cell.statusView.nameLabel.configure(content: metaContent)
+ }
cell.statusView.usernameLabel.text = "@" + status.author.acct
// set text
let content = MastodonContent(content: status.content, emojis: status.emojiMeta)
@@ -226,13 +233,14 @@ extension ComposeViewModel: UITableViewDataSource {
let name = author.displayName.isEmpty ? author.username : author.displayName
return L10n.Scene.Compose.replyingToUser(name)
}()
- MastodonStatusContent.parseResult(content: headerText, emojiDict: replyTo.author.emojiDict)
- .receive(on: DispatchQueue.main)
- .sink { [weak cell] parseResult in
- guard let cell = cell else { return }
- cell.statusView.headerInfoLabel.configure(contentParseResult: parseResult)
- }
- .store(in: &cell.disposeBag)
+ do {
+ let mastodonContent = MastodonContent(content: headerText, emojis: replyTo.author.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ cell.statusView.headerInfoLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: headerText)
+ cell.statusView.headerInfoLabel.configure(content: metaContent)
+ }
}
// configure author
ComposeStatusSection.configureStatusContent(cell: cell, attribute: composeStatusAttribute)
diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift
index 2e059c1a3..52af2cb67 100644
--- a/Mastodon/Scene/Compose/ComposeViewModel.swift
+++ b/Mastodon/Scene/Compose/ComposeViewModel.swift
@@ -181,7 +181,7 @@ final class ComposeViewModel: NSObject {
}
return displayName
}()
- self.composeStatusAttribute.emojiDict.value = mastodonUser?.emojiDict ?? [:]
+ self.composeStatusAttribute.emojiMeta.value = mastodonUser?.emojiMeta ?? [:]
self.composeStatusAttribute.username.value = username
}
.store(in: &disposeBag)
diff --git a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
index 8e6d46878..8948a2f6a 100644
--- a/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
+++ b/Mastodon/Scene/Compose/View/ReplicaStatusView.swift
@@ -7,7 +7,6 @@
import os.log
import UIKit
-import ActiveLabel
import FLAnimatedImage
import MetaTextKit
@@ -52,12 +51,7 @@ final class ReplicaStatusView: UIView {
return label
}()
- let headerInfoLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusHeader)
- label.text = "Bob reblogged"
- label.layer.masksToBounds = false
- return label
- }()
+ let headerInfoLabel = MetaLabel(style: .statusHeader)
let avatarView: UIView = {
let view = UIView()
@@ -68,10 +62,7 @@ final class ReplicaStatusView: UIView {
}()
let avatarImageView = FLAnimatedImageView()
- let nameLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusName)
- return label
- }()
+ let nameLabel = MetaLabel(style: .statusName)
let nameTrialingDotLabel: UILabel = {
let label = UILabel()
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
index c0de5c532..8d4a8b37f 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift
@@ -56,7 +56,7 @@ extension HashtagTimelineViewController {
super.viewDidLoad()
title = "#\(viewModel.hashtag)"
- titleView.update(title: viewModel.hashtag, subtitle: nil, emojiDict: [:])
+ titleView.update(title: viewModel.hashtag, subtitle: nil)
navigationItem.titleView = titleView
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
@@ -150,7 +150,7 @@ extension HashtagTimelineViewController {
private func updatePromptTitle() {
var subtitle: String?
defer {
- titleView.update(title: "#" + viewModel.hashtag, subtitle: subtitle, emojiDict: [:])
+ titleView.update(title: "#" + viewModel.hashtag, subtitle: subtitle)
}
guard let histories = viewModel.hashtagEntity.value?.history else {
return
@@ -209,7 +209,7 @@ extension HashtagTimelineViewController: LoadMoreConfigurableTableViewContainer
typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
typealias LoadingState = HashtagTimelineViewModel.LoadOldestState.Loading
var loadMoreConfigurableTableView: UITableView { return tableView }
- var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadoldestStateMachine }
+ var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadOldestStateMachine }
}
// MARK: - UITableViewDelegate
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
index a90afdad0..093258733 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift
@@ -84,7 +84,7 @@ extension HashtagTimelineViewModel {
newSnapshot.appendItems(statusItemList, toSection: .main)
}
- if !(self.loadoldestStateMachine.currentState is LoadOldestState.NoMore) {
+ if !(self.loadOldestStateMachine.currentState is LoadOldestState.NoMore) {
newSnapshot.appendItems([.bottomLoader], toSection: .main)
}
diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
index 54acbf4fe..c1698f5dc 100644
--- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
+++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift
@@ -46,7 +46,7 @@ final class HashtagTimelineViewModel: NSObject {
}()
lazy var loadLatestStateMachinePublisher = CurrentValueSubject(nil)
// bottom loader
- private(set) lazy var loadoldestStateMachine: GKStateMachine = {
+ private(set) lazy var loadOldestStateMachine: GKStateMachine = {
// exclude timeline middle fetcher state
let stateMachine = GKStateMachine(states: [
LoadOldestState.Initial(viewModel: self),
diff --git a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController+Provider.swift b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController+Provider.swift
index 4896c58b9..5f97ebead 100644
--- a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController+Provider.swift
+++ b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController+Provider.swift
@@ -109,6 +109,12 @@ extension AsyncHomeTimelineViewController: StatusProvider {
return nil
}
}
+
+ func statusObjectItems(indexPaths: [IndexPath]) -> [StatusObjectItem] {
+ guard let diffableDataSource = self.viewModel.diffableDataSource else { return [] }
+ let items = indexPaths.compactMap { diffableDataSource.itemIdentifier(for: $0)?.statusObjectItem }
+ return items
+ }
}
diff --git a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController.swift
index c8ccfdd3d..c90b703e5 100644
--- a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController.swift
+++ b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewController.swift
@@ -86,7 +86,7 @@ extension AsyncHomeTimelineViewController {
node.allowsSelection = true
title = L10n.Scene.HomeTimeline.title
- view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
+ view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
navigationItem.leftBarButtonItem = settingBarButtonItem
navigationItem.titleView = titleView
titleView.delegate = self
@@ -341,7 +341,7 @@ extension AsyncHomeTimelineViewController {
// typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
// typealias LoadingState = HomeTimelineViewModel.LoadOldestState.Loading
// var loadMoreConfigurableTableView: UITableView { return tableView }
-// var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadoldestStateMachine }
+// var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadOldestStateMachine }
//}
// MARK: - UITableViewDelegate
@@ -556,7 +556,7 @@ extension AsyncHomeTimelineViewController: ASTableDelegate {
}
func tableNode(_ tableNode: ASTableNode, willBeginBatchFetchWith context: ASBatchContext) {
- viewModel.loadoldestStateMachine.enter(HomeTimelineViewModel.LoadOldestState.Loading.self)
+ viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadOldestState.Loading.self)
context.completeBatchFetching(true)
}
diff --git a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel+Diffable.swift
index fbd5c1438..7799c2163 100644
--- a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel+Diffable.swift
@@ -106,7 +106,7 @@ extension AsyncHomeTimelineViewModel: NSFetchedResultsControllerDelegate {
let endSnapshot = CACurrentMediaTime()
- if shouldAddBottomLoader, !(self.loadoldestStateMachine.currentState is LoadOldestState.NoMore) {
+ if shouldAddBottomLoader, !(self.loadLatestStateMachine.currentState is LoadOldestState.NoMore) {
newSnapshot.appendItems([.bottomLoader], toSection: .main)
}
diff --git a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel.swift
index c33b91c02..d7ed0b10d 100644
--- a/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel.swift
+++ b/Mastodon/Scene/HomeTimeline/AsyncHomeTimeline/AsyncHomeTimelineViewModel.swift
@@ -18,7 +18,6 @@ import CoreDataStack
import GameplayKit
import AlamofireImage
import DateToolsSwift
-import ActiveLabel
import AsyncDisplayKit
final class AsyncHomeTimelineViewModel: NSObject {
@@ -59,7 +58,7 @@ final class AsyncHomeTimelineViewModel: NSObject {
}()
lazy var loadLatestStateMachinePublisher = CurrentValueSubject(nil)
// bottom loader
- private(set) lazy var loadoldestStateMachine: GKStateMachine = {
+ private(set) lazy var loadOldestStateMachine: GKStateMachine = {
// exclude timeline middle fetcher state
let stateMachine = GKStateMachine(states: [
LoadOldestState.Initial(viewModel: self),
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
index 73650b6ea..e69d3bae2 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
@@ -388,7 +388,7 @@ extension HomeTimelineViewController: LoadMoreConfigurableTableViewContainer {
typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
typealias LoadingState = HomeTimelineViewModel.LoadOldestState.Loading
var loadMoreConfigurableTableView: UITableView { return tableView }
- var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadoldestStateMachine }
+ var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadLatestStateMachine }
}
// MARK: - UITableViewDelegate
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
index b2ea2035c..d25f30aee 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift
@@ -115,7 +115,7 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate {
let endSnapshot = CACurrentMediaTime()
DispatchQueue.main.async {
- if shouldAddBottomLoader, !(self.loadoldestStateMachine.currentState is LoadOldestState.NoMore) {
+ if shouldAddBottomLoader, !(self.loadLatestStateMachine.currentState is LoadOldestState.NoMore) {
newSnapshot.appendItems([.bottomLoader], toSection: .main)
}
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
index 9d8f6f709..611e95368 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
@@ -15,7 +15,6 @@ import CoreDataStack
import GameplayKit
import AlamofireImage
import DateToolsSwift
-import ActiveLabel
final class HomeTimelineViewModel: NSObject {
@@ -52,7 +51,7 @@ final class HomeTimelineViewModel: NSObject {
}()
lazy var loadLatestStateMachinePublisher = CurrentValueSubject(nil)
// bottom loader
- private(set) lazy var loadoldestStateMachine: GKStateMachine = {
+ private(set) lazy var loadOldestStateMachine: GKStateMachine = {
// exclude timeline middle fetcher state
let stateMachine = GKStateMachine(states: [
LoadOldestState.Initial(viewModel: self),
diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift
index 5528adf68..100cd3d82 100644
--- a/Mastodon/Scene/Notification/NotificationViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationViewController.swift
@@ -12,7 +12,6 @@ import GameplayKit
import MastodonSDK
import OSLog
import UIKit
-import ActiveLabel
import Meta
import MetaTextKit
@@ -272,7 +271,7 @@ extension NotificationViewController {
switch item {
case .bottomLoader:
if !tableView.isDragging, !tableView.isDecelerating {
- viewModel.loadoldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self)
+ viewModel.loadOldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self)
}
default:
break
@@ -305,7 +304,7 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
}
}
- func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel) {
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: MetaLabel) {
guard let diffableDataSource = viewModel.diffableDataSource else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
@@ -319,7 +318,6 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
}
}
-
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton) {
viewModel.acceptFollowRequest(notification: notification)
}
@@ -380,7 +378,7 @@ extension NotificationViewController: LoadMoreConfigurableTableViewContainer {
typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell
typealias LoadingState = NotificationViewModel.LoadOldestState.Loading
var loadMoreConfigurableTableView: UITableView { tableView }
- var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.loadoldestStateMachine }
+ var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.loadOldestStateMachine }
}
extension NotificationViewController {
diff --git a/Mastodon/Scene/Notification/NotificationViewModel.swift b/Mastodon/Scene/Notification/NotificationViewModel.swift
index 8102f7705..712380917 100644
--- a/Mastodon/Scene/Notification/NotificationViewModel.swift
+++ b/Mastodon/Scene/Notification/NotificationViewModel.swift
@@ -54,7 +54,7 @@ final class NotificationViewModel: NSObject {
lazy var loadLatestStateMachinePublisher = CurrentValueSubject(nil)
// bottom loader
- private(set) lazy var loadoldestStateMachine: GKStateMachine = {
+ private(set) lazy var loadOldestStateMachine: GKStateMachine = {
// exclude timeline middle fetcher state
let stateMachine = GKStateMachine(states: [
LoadOldestState.Initial(viewModel: self),
diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
index 6afc61e9a..65e4dbcdb 100644
--- a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
+++ b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
@@ -10,7 +10,6 @@ import Combine
import Foundation
import CoreDataStack
import UIKit
-import ActiveLabel
import MetaTextKit
import Meta
import FLAnimatedImage
@@ -20,7 +19,7 @@ protocol NotificationTableViewCellDelegate: AnyObject {
func parent() -> UIViewController
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, avatarImageViewDidPressed imageView: UIImageView)
- func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel)
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: MetaLabel)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
@@ -58,13 +57,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
return label
}()
- let nameLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusName)
- label.textColor = Asset.Colors.brandBlue.color
- label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20)
- label.lineBreakMode = .byTruncatingTail
- return label
- }()
+ let nameLabel = MetaLabel(style: .notificationName)
let buttonStackView = UIStackView()
@@ -318,10 +311,6 @@ extension NotificationStatusTableViewCell: StatusViewDelegate {
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton) {
// do nothing
}
-
- func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- // do nothing
- }
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
delegate?.notificationStatusTableViewCell(self, statusView: statusView, metaText: metaText, didSelectMeta: meta)
diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
index 3af4f884a..c9890c248 100644
--- a/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
+++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewController.swift
@@ -57,7 +57,7 @@ extension FavoriteViewController {
.store(in: &disposeBag)
navigationItem.titleView = titleView
- titleView.update(title: L10n.Scene.Favorite.title, subtitle: nil, emojiDict: [:])
+ titleView.update(title: L10n.Scene.Favorite.title, subtitle: nil)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
index a88d3e06c..f0bf72af1 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
@@ -9,16 +9,16 @@ import os.log
import UIKit
import Combine
import PhotosUI
-import ActiveLabel
import AlamofireImage
import CropViewController
import TwitterTextEditor
import MastodonMeta
+import MetaTextKit
protocol ProfileHeaderViewControllerDelegate: AnyObject {
func profileHeaderViewController(_ viewController: ProfileHeaderViewController, viewLayoutDidUpdate view: UIView)
func profileHeaderViewController(_ viewController: ProfileHeaderViewController, pageSegmentedControlValueChanged segmentedControl: UISegmentedControl, selectedSegmentIndex index: Int)
- func profileHeaderViewController(_ viewController: ProfileHeaderViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
+ func profileHeaderViewController(_ viewController: ProfileHeaderViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, metaLabel: MetaLabel, didSelectMeta meta: Meta)
}
final class ProfileHeaderViewController: UIViewController {
@@ -35,6 +35,7 @@ final class ProfileHeaderViewController: UIViewController {
let titleView: DoubleTitleLabelNavigationBarTitleView = {
let titleView = DoubleTitleLabelNavigationBarTitleView()
titleView.titleLabel.textColor = .white
+ titleView.titleLabel.textAttributes[.foregroundColor] = UIColor.white
titleView.titleLabel.alpha = 0
titleView.subtitleLabel.textColor = .white
titleView.subtitleLabel.alpha = 0
@@ -179,19 +180,14 @@ extension ProfileHeaderViewController {
viewModel.isEditing,
viewModel.displayProfileInfo.name.removeDuplicates(),
viewModel.editProfileInfo.name.removeDuplicates(),
- viewModel.emojiDict
+ viewModel.emojiMeta
)
.receive(on: DispatchQueue.main)
- .sink { [weak self] isEditing, name, editingName, emojiDict in
+ .sink { [weak self] isEditing, name, editingName, emojiMeta in
guard let self = self else { return }
do {
- var emojis = MastodonContent.Emojis()
- for (key, value) in emojiDict {
- emojis[key] = value.absoluteString
- }
- let metaContent = try MastodonMetaContent.convert(
- document: MastodonContent(content: name ?? " ", emojis: emojis)
- )
+ let mastodonContent = MastodonContent(content: name ?? " ", emojis: emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
self.profileHeaderView.nameMetaText.configure(content: metaContent)
} catch {
assertionFailure()
@@ -200,25 +196,37 @@ extension ProfileHeaderViewController {
}
.store(in: &disposeBag)
- Publishers.CombineLatest3(
- viewModel.isEditing.eraseToAnyPublisher(),
- viewModel.displayProfileInfo.note.removeDuplicates().eraseToAnyPublisher(),
- viewModel.editProfileInfo.note.removeDuplicates().eraseToAnyPublisher()
+ Publishers.CombineLatest4(
+ viewModel.isEditing.removeDuplicates(),
+ viewModel.displayProfileInfo.note.removeDuplicates(),
+ viewModel.editProfileInfo.note.removeDuplicates(),
+ viewModel.emojiMeta.removeDuplicates()
)
.receive(on: DispatchQueue.main)
- .sink { [weak self] isEditing, note, editingNote in
+ .sink { [weak self] isEditing, note, editingNote, emojiMeta in
guard let self = self else { return }
- self.profileHeaderView.bioActiveLabel.configure(note: note ?? "", emojiDict: [:]) // FIXME: custom emoji
- // prevent duplicate set
- let editingNote = editingNote ?? ""
- if self.profileHeaderView.bioTextEditorView.text != editingNote {
- self.profileHeaderView.bioTextEditorView.text = editingNote
+ self.profileHeaderView.bioMetaText.textView.isEditable = isEditing
+
+ if isEditing {
+ if self.profileHeaderView.bioMetaText.backedString != note {
+ let metaContent = PlaintextMetaContent(string: editingNote ?? "")
+ self.profileHeaderView.bioMetaText.configure(content: metaContent)
+ }
+ } else {
+ let mastodonContent = MastodonContent(content: note ?? "", emojis: emojiMeta)
+ do {
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ self.profileHeaderView.bioMetaText.configure(content: metaContent)
+ } catch {
+ assertionFailure()
+ self.profileHeaderView.bioMetaText.reset()
+ }
}
}
.store(in: &disposeBag)
-
- profileHeaderView.bioTextEditorView.changeObserver = self
+ profileHeaderView.bioMetaText.delegate = self
+
NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: profileHeaderView.nameTextField)
.receive(on: DispatchQueue.main)
.sink { [weak self] notification in
@@ -450,13 +458,16 @@ extension ProfileHeaderViewController {
}
-// MARK: - TextEditorViewChangeObserver
-extension ProfileHeaderViewController: TextEditorViewChangeObserver {
- func textEditorView(_ textEditorView: TextEditorView, didChangeWithChangeResult changeResult: TextEditorViewChangeResult) {
- os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: text: %s", ((#file as NSString).lastPathComponent), #line, #function, textEditorView.text)
- guard changeResult.isTextChanged else { return }
- assert(textEditorView === profileHeaderView.bioTextEditorView)
- viewModel.editProfileInfo.note.value = textEditorView.text
+// MARK: - MetaTextDelegate
+extension ProfileHeaderViewController: MetaTextDelegate {
+ func metaText(_ metaText: MetaText, processEditing textStorage: MetaTextStorage) -> MetaContent? {
+ os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: text: %s", ((#file as NSString).lastPathComponent), #line, #function, metaText.backedString)
+ assert(metaText.textView === profileHeaderView.bioMetaText.textView)
+ if metaText.textView === profileHeaderView.bioMetaText.textView {
+ viewModel.editProfileInfo.note.value = metaText.backedString
+ }
+
+ return nil
}
}
@@ -533,6 +544,7 @@ extension ProfileHeaderViewController: UICollectionViewDelegate {
// MARK: - ProfileFieldCollectionViewCellDelegate
extension ProfileHeaderViewController: ProfileFieldCollectionViewCellDelegate {
+
// should be remove style edit button
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, editButtonDidPressed button: UIButton) {
guard let diffableDataSource = viewModel.fieldDiffableDataSource else { return }
@@ -541,8 +553,8 @@ extension ProfileHeaderViewController: ProfileFieldCollectionViewCellDelegate {
viewModel.removeFieldItem(item: item)
}
- func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- delegate?.profileHeaderViewController(self, profileFieldCollectionViewCell: cell, activeLabel: activeLabel, didSelectActiveEntity: entity)
+ func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta) {
+ delegate?.profileHeaderViewController(self, profileFieldCollectionViewCell: cell, metaLabel: metaLebel, didSelectMeta: meta)
}
}
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
index 9a0145751..c98758581 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift
@@ -10,6 +10,7 @@ import UIKit
import Combine
import Kanna
import MastodonSDK
+import MastodonMeta
final class ProfileHeaderViewModel {
@@ -24,7 +25,7 @@ final class ProfileHeaderViewModel {
let needsSetupBottomShadow = CurrentValueSubject(true)
let needsFiledCollectionViewHidden = CurrentValueSubject(false)
let isTitleViewContentOffsetSet = CurrentValueSubject(false)
- let emojiDict = CurrentValueSubject([:])
+ let emojiMeta = CurrentValueSubject([:])
let accountForEdit = CurrentValueSubject(nil)
// output
@@ -58,10 +59,10 @@ final class ProfileHeaderViewModel {
isEditing.removeDuplicates(),
displayProfileInfo.fields.removeDuplicates(),
editProfileInfo.fields.removeDuplicates(),
- emojiDict.removeDuplicates()
+ emojiMeta.removeDuplicates()
)
.receive(on: RunLoop.main)
- .sink { [weak self] isEditing, displayFields, editingFields, emojiDict in
+ .sink { [weak self] isEditing, displayFields, editingFields, emojiMeta in
guard let self = self else { return }
guard let diffableDataSource = self.fieldDiffableDataSource else { return }
@@ -87,7 +88,7 @@ final class ProfileHeaderViewModel {
let attribute = oldFieldAttributeDict[field.id] ?? ProfileFieldItem.FieldItemAttribute()
attribute.isEditing = isEditing
- attribute.emojiDict.value = emojiDict
+ attribute.emojiMeta.value = emojiMeta
attribute.isLast = false
return ProfileFieldItem.field(field: field, attribute: attribute)
}
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileFieldAddEntryCollectionViewCell.swift b/Mastodon/Scene/Profile/Header/View/ProfileFieldAddEntryCollectionViewCell.swift
index d8ecb198d..cafe0eda9 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileFieldAddEntryCollectionViewCell.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileFieldAddEntryCollectionViewCell.swift
@@ -95,12 +95,12 @@ extension ProfileFieldAddEntryCollectionViewCell {
bottomSeparatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: self)).priority(.defaultHigh),
])
- fieldView.titleActiveLabel.isHidden = false
- fieldView.titleActiveLabel.configure(field: L10n.Scene.Profile.Fields.addRow, emojiDict: [:])
+ fieldView.titleMetaLabel.isHidden = false
+ fieldView.titleMetaLabel.configure(content: PlaintextMetaContent(string: L10n.Scene.Profile.Fields.addRow))
fieldView.titleTextField.isHidden = true
- fieldView.valueActiveLabel.isHidden = false
- fieldView.valueActiveLabel.configure(field: " ", emojiDict: [:])
+ fieldView.valueMetaLabel.isHidden = false
+ fieldView.valueMetaLabel.configure(content: PlaintextMetaContent(string: " "))
fieldView.valueTextField.isHidden = true
addGestureRecognizer(singleTagGestureRecognizer)
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/Header/View/ProfileFieldCollectionViewCell.swift
index 6efa92e18..9106b0e44 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileFieldCollectionViewCell.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileFieldCollectionViewCell.swift
@@ -8,11 +8,11 @@
import os.log
import UIKit
import Combine
-import ActiveLabel
+import MetaTextKit
protocol ProfileFieldCollectionViewCellDelegate: AnyObject {
func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, editButtonDidPressed button: UIButton)
- func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
+ func profileFieldCollectionViewCell(_ cell: ProfileFieldCollectionViewCell, metaLebel: MetaLabel, didSelectMeta meta: Meta)
}
final class ProfileFieldCollectionViewCell: UICollectionViewCell {
@@ -107,7 +107,7 @@ extension ProfileFieldCollectionViewCell {
editButton.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.editButtonDidPressed(_:)), for: .touchUpInside)
- fieldView.valueActiveLabel.delegate = self
+ fieldView.valueMetaLabel.linkDelegate = self
resetSeparatorLineLayout()
}
@@ -153,13 +153,11 @@ extension ProfileFieldCollectionViewCell {
}
}
-
-
-// MARK: - ActiveLabelDelegate
-extension ProfileFieldCollectionViewCell: ActiveLabelDelegate {
- func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
+// MARK: - MetaLabelDelegate
+extension ProfileFieldCollectionViewCell: MetaLabelDelegate {
+ func metaLabel(_ metaLabel: MetaLabel, didSelectMeta meta: Meta) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
- delegate?.profileFieldCollectionViewCell(self, activeLabel: activeLabel, didSelectActiveEntity: entity)
+ delegate?.profileFieldCollectionViewCell(self, metaLebel: metaLabel, didSelectMeta: meta)
}
}
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileFieldView.swift b/Mastodon/Scene/Profile/Header/View/ProfileFieldView.swift
index 956b8d6d9..ee17d7e4d 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileFieldView.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileFieldView.swift
@@ -7,7 +7,7 @@
import UIKit
import Combine
-import ActiveLabel
+import MetaTextKit
final class ProfileFieldView: UIView {
@@ -18,11 +18,7 @@ final class ProfileFieldView: UIView {
let value = PassthroughSubject()
// for custom emoji display
- let titleActiveLabel: ActiveLabel = {
- let label = ActiveLabel(style: .profileFieldName)
- label.configure(content: "title", emojiDict: [:])
- return label
- }()
+ let titleMetaLabel = MetaLabel(style: .profileFieldName)
// for editing
let titleTextField: UITextField = {
@@ -34,12 +30,7 @@ final class ProfileFieldView: UIView {
}()
// for custom emoji display
- let valueActiveLabel: ActiveLabel = {
- let label = ActiveLabel(style: .profileFieldValue)
- label.configure(content: "value", emojiDict: [:])
- label.textAlignment = .right
- return label
- }()
+ let valueMetaLabel = MetaLabel(style: .profileFieldValue)
// for editing
let valueTextField: UITextField = {
@@ -81,10 +72,10 @@ extension ProfileFieldView {
containerStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
containerStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
- titleActiveLabel.translatesAutoresizingMaskIntoConstraints = false
- containerStackView.addArrangedSubview(titleActiveLabel)
+ titleMetaLabel.translatesAutoresizingMaskIntoConstraints = false
+ containerStackView.addArrangedSubview(titleMetaLabel)
NSLayoutConstraint.activate([
- titleActiveLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
+ titleMetaLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
])
titleTextField.setContentHuggingPriority(.defaultLow - 1, for: .horizontal)
titleTextField.translatesAutoresizingMaskIntoConstraints = false
@@ -94,12 +85,12 @@ extension ProfileFieldView {
])
titleTextField.setContentHuggingPriority(.defaultLow - 1, for: .horizontal)
- valueActiveLabel.translatesAutoresizingMaskIntoConstraints = false
- containerStackView.addArrangedSubview(valueActiveLabel)
+ valueMetaLabel.translatesAutoresizingMaskIntoConstraints = false
+ containerStackView.addArrangedSubview(valueMetaLabel)
NSLayoutConstraint.activate([
- valueActiveLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
+ valueMetaLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
])
- valueActiveLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
+ valueMetaLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
valueTextField.translatesAutoresizingMaskIntoConstraints = false
containerStackView.addArrangedSubview(valueTextField)
NSLayoutConstraint.activate([
@@ -137,7 +128,8 @@ struct ProfileFieldView_Previews: PreviewProvider {
static var previews: some View {
UIViewPreview(width: 375) {
let filedView = ProfileFieldView()
- filedView.valueActiveLabel.configure(field: "https://mastodon.online", emojiDict: [:])
+ let content = PlaintextMetaContent(string: "https://mastodon.online")
+ filedView.valueMetaLabel.configure(content: content)
return filedView
}
.previewLayout(.fixed(width: 375, height: 100))
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
index 043e1b665..eb6e06a04 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
@@ -8,8 +8,6 @@
import os.log
import UIKit
import Combine
-import ActiveLabel
-import TwitterTextEditor
import FLAnimatedImage
import MetaTextKit
@@ -17,7 +15,7 @@ protocol ProfileHeaderViewDelegate: AnyObject {
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView)
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, bannerImageViewDidPressed imageView: UIImageView)
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, relationshipButtonDidPressed button: ProfileRelationshipActionButton)
- func profileHeaderView(_ profileHeaderView: ProfileHeaderView, activeLabel: ActiveLabel, entityDidPressed entity: ActiveEntity)
+ func profileHeaderView(_ profileHeaderView: ProfileHeaderView, metaTextView: MetaTextView, metaDidPressed meta: Meta)
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView)
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed followingDashboardMeterView: ProfileStatusDashboardMeterView)
@@ -166,28 +164,38 @@ final class ProfileHeaderView: UIView {
}()
let bioContainerView = UIView()
- let bioContainerStackView = UIStackView()
let fieldContainerStackView = UIStackView()
-
- let bioActiveLabelContainer: UIView = {
- // use to set margin for active label
- // the display/edit mode bio transition animation should without flicker with that
- let view = UIView()
- // note: comment out to see how it works
- view.layoutMargins = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 5) // magic from TextEditorView
- return view
- }()
- let bioActiveLabel = ActiveLabel(style: .default)
- let bioTextEditorView: TextEditorView = {
- let textEditorView = TextEditorView()
- textEditorView.scrollView.isScrollEnabled = false
- textEditorView.isScrollEnabled = false
- textEditorView.font = .preferredFont(forTextStyle: .body)
- textEditorView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
- textEditorView.layer.masksToBounds = true
- textEditorView.layer.cornerCurve = .continuous
- textEditorView.layer.cornerRadius = 10
- return textEditorView
+
+ let bioMetaText: MetaText = {
+ let metaText = MetaText()
+ metaText.textView.backgroundColor = .clear
+ metaText.textView.isEditable = false
+ metaText.textView.isSelectable = true
+ metaText.textView.isScrollEnabled = false
+ //metaText.textView.textContainer.lineFragmentPadding = 0
+ //metaText.textView.textContainerInset = .zero
+ metaText.textView.layer.masksToBounds = false
+ metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment
+
+ metaText.textView.layer.masksToBounds = true
+ metaText.textView.layer.cornerCurve = .continuous
+ metaText.textView.layer.cornerRadius = 10
+
+ metaText.paragraphStyle = {
+ let style = NSMutableParagraphStyle()
+ style.lineSpacing = 5
+ style.paragraphSpacing = 8
+ return style
+ }()
+ metaText.textAttributes = [
+ .font: UIFont.preferredFont(forTextStyle: .body),
+ .foregroundColor: Asset.Colors.Label.primary.color,
+ ]
+ metaText.linkAttributes = [
+ .font: UIFont.preferredFont(forTextStyle: .body),
+ .foregroundColor: Asset.Colors.brandBlue.color,
+ ]
+ return metaText
}()
static func createFieldCollectionViewLayout() -> UICollectionViewLayout {
@@ -405,28 +413,15 @@ extension ProfileHeaderView {
bioContainerView.preservesSuperviewLayoutMargins = true
metaContainerStackView.addArrangedSubview(bioContainerView)
- bioContainerStackView.translatesAutoresizingMaskIntoConstraints = false
- bioContainerView.addSubview(bioContainerStackView)
+ bioMetaText.textView.translatesAutoresizingMaskIntoConstraints = false
+ bioContainerView.addSubview(bioMetaText.textView)
NSLayoutConstraint.activate([
- bioContainerStackView.topAnchor.constraint(equalTo: bioContainerView.topAnchor),
- bioContainerStackView.leadingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.leadingAnchor),
- bioContainerStackView.trailingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.trailingAnchor),
- bioContainerStackView.bottomAnchor.constraint(equalTo: bioContainerView.bottomAnchor),
+ bioMetaText.textView.topAnchor.constraint(equalTo: bioContainerView.topAnchor),
+ bioMetaText.textView.leadingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.leadingAnchor),
+ bioMetaText.textView.trailingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.trailingAnchor),
+ bioMetaText.textView.bottomAnchor.constraint(equalTo: bioContainerView.bottomAnchor),
])
- bioActiveLabel.translatesAutoresizingMaskIntoConstraints = false
- bioActiveLabelContainer.addSubview(bioActiveLabel)
- NSLayoutConstraint.activate([
- bioActiveLabel.topAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.topAnchor),
- bioActiveLabel.leadingAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.leadingAnchor),
- bioActiveLabel.trailingAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.trailingAnchor),
- bioActiveLabel.bottomAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.bottomAnchor),
- ])
-
- bioContainerStackView.axis = .vertical
- bioContainerStackView.addArrangedSubview(bioActiveLabelContainer)
- bioContainerStackView.addArrangedSubview(bioTextEditorView)
-
fieldCollectionView.translatesAutoresizingMaskIntoConstraints = false
metaContainerStackView.addArrangedSubview(fieldCollectionView)
fieldCollectionViewHeightLayoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
@@ -445,7 +440,7 @@ extension ProfileHeaderView {
bringSubviewToFront(bannerContainerView)
bringSubviewToFront(nameContainerStackView)
- bioActiveLabel.delegate = self
+ bioMetaText.textView.linkDelegate = self
let avatarImageViewSingleTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
avatarImageView.addGestureRecognizer(avatarImageViewSingleTapGestureRecognizer)
@@ -479,9 +474,8 @@ extension ProfileHeaderView {
nameMetaText.textView.alpha = 1
nameTextField.alpha = 0
nameTextField.isEnabled = false
- bioActiveLabelContainer.isHidden = false
- bioTextEditorView.isHidden = true
-
+ bioMetaText.textView.backgroundColor = .clear
+
animator.addAnimations {
self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundNormalColor
self.nameTextFieldBackgroundView.backgroundColor = .clear
@@ -494,17 +488,15 @@ extension ProfileHeaderView {
nameMetaText.textView.alpha = 0
nameTextField.isEnabled = true
nameTextField.alpha = 1
- bioActiveLabelContainer.isHidden = true
- bioTextEditorView.isHidden = false
editAvatarBackgroundView.isHidden = false
editAvatarBackgroundView.alpha = 0
- bioTextEditorView.backgroundColor = .clear
+ bioMetaText.textView.backgroundColor = .clear
animator.addAnimations {
self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundEditingColor
self.nameTextFieldBackgroundView.backgroundColor = Asset.Scene.Profile.Banner.nameEditBackgroundGray.color
self.editAvatarBackgroundView.alpha = 1
- self.bioTextEditorView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
+ self.bioMetaText.textView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
}
}
@@ -530,11 +522,11 @@ extension ProfileHeaderView {
}
}
-// MARK: - ActiveLabelDelegate
-extension ProfileHeaderView: ActiveLabelDelegate {
- func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select entity: %s", ((#file as NSString).lastPathComponent), #line, #function, entity.primaryText)
- delegate?.profileHeaderView(self, activeLabel: activeLabel, entityDidPressed: entity)
+// MARK: - MetaTextViewDelegate
+extension ProfileHeaderView: MetaTextViewDelegate {
+ func metaTextView(_ metaTextView: MetaTextView, didSelectMeta meta: Meta) {
+ os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select entity", ((#file as NSString).lastPathComponent), #line, #function)
+ delegate?.profileHeaderView(self, metaTextView: metaTextView, metaDidPressed: meta)
}
}
diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift
index 1ac0c4a4e..fa54abf7b 100644
--- a/Mastodon/Scene/Profile/ProfileViewController.swift
+++ b/Mastodon/Scene/Profile/ProfileViewController.swift
@@ -8,7 +8,8 @@
import os.log
import UIKit
import Combine
-import ActiveLabel
+import MastodonMeta
+import MetaTextKit
final class ProfileViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
@@ -316,20 +317,26 @@ extension ProfileViewController {
// bind view model
Publishers.CombineLatest3(
viewModel.name,
- viewModel.emojiDict,
+ viewModel.emojiMeta,
viewModel.statusesCount
)
.receive(on: DispatchQueue.main)
- .sink { [weak self] name, emojiDict, statusesCount in
+ .sink { [weak self] name, emojiMeta, statusesCount in
guard let self = self else { return }
guard let title = name, let statusesCount = statusesCount,
let formattedStatusCount = MastodonMetricFormatter().string(from: statusesCount) else {
self.titleView.isHidden = true
return
}
- let subtitle = L10n.Plural.Count.MetricFormatted.post(formattedStatusCount, statusesCount)
- self.titleView.update(title: title, subtitle: subtitle, emojiDict: emojiDict)
self.titleView.isHidden = false
+ let subtitle = L10n.Plural.Count.MetricFormatted.post(formattedStatusCount, statusesCount)
+ let mastodonContent = MastodonContent(content: title, emojis: emojiMeta)
+ do {
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ self.titleView.update(titleMetaContent: metaContent, subtitle: subtitle)
+ } catch {
+
+ }
}
.store(in: &disposeBag)
viewModel.name
@@ -391,9 +398,9 @@ extension ProfileViewController {
viewModel.accountForEdit
.assign(to: \.value, on: profileHeaderViewController.viewModel.accountForEdit)
.store(in: &disposeBag)
- viewModel.emojiDict
+ viewModel.emojiMeta
.receive(on: DispatchQueue.main)
- .assign(to: \.value, on: profileHeaderViewController.viewModel.emojiDict)
+ .assign(to: \.value, on: profileHeaderViewController.viewModel.emojiMeta)
.store(in: &disposeBag)
viewModel.username
.map { username in username.flatMap { "@" + $0 } ?? " " }
@@ -695,7 +702,7 @@ extension ProfileViewController: UIScrollViewDelegate {
// MARK: - ProfileHeaderViewControllerDelegate
extension ProfileViewController: ProfileHeaderViewControllerDelegate {
-
+
func profileHeaderViewController(_ viewController: ProfileHeaderViewController, viewLayoutDidUpdate view: UIView) {
guard let scrollView = (profileSegmentedViewController.pagingViewController.currentViewController as? UserTimelineViewController)?.scrollView else {
// assertionFailure()
@@ -712,23 +719,24 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
)
}
- func profileHeaderViewController(_ viewController: ProfileHeaderViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- // handle profile fields interaction
- switch entity.type {
+ func profileHeaderViewController(_ viewController: ProfileHeaderViewController, profileFieldCollectionViewCell: ProfileFieldCollectionViewCell, metaLabel: MetaLabel, didSelectMeta meta: Meta) {
+ switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- case .hashtag(let hashtag, _):
+ case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag)
coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
- case .mention(_, let userInfo):
+ case .mention(_, _, let userInfo):
guard let href = userInfo?["href"] as? String else {
// currently we cannot present profile scene without userID
return
}
guard let url = URL(string: href) else { return }
coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- default:
+ case .email:
+ break
+ case .emoji:
break
}
}
@@ -758,7 +766,7 @@ extension ProfileViewController: ProfilePagingViewControllerDelegate {
// MARK: - ProfileHeaderViewDelegate
extension ProfileViewController: ProfileHeaderViewDelegate {
-
+
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView) {
guard let mastodonUser = viewModel.mastodonUser.value else { return }
guard let avatar = imageView.image else { return }
@@ -953,24 +961,24 @@ extension ProfileViewController: ProfileHeaderViewDelegate {
}
}
}
-
- func profileHeaderView(_ profileHeaderView: ProfileHeaderView, activeLabel: ActiveLabel, entityDidPressed entity: ActiveEntity) {
- switch entity.type {
+
+ func profileHeaderView(_ profileHeaderView: ProfileHeaderView, metaTextView: MetaTextView, metaDidPressed meta: Meta) {
+ switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- case .mention(_, let userInfo):
+ case .mention(_, _, let userInfo):
guard let href = userInfo?["href"] as? String,
- let url = URL(string: href) else { return }
+ let url = URL(string: href) else { return }
coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
- case .hashtag(let hashtag, _):
+ case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag)
coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
- default:
+ case .email, .emoji:
break
}
}
-
+
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) {
}
diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift
index 4b2809a3a..5efbaa684 100644
--- a/Mastodon/Scene/Profile/ProfileViewModel.swift
+++ b/Mastodon/Scene/Profile/ProfileViewModel.swift
@@ -10,6 +10,7 @@ import UIKit
import Combine
import CoreDataStack
import MastodonSDK
+import MastodonMeta
// please override this base class
class ProfileViewModel: NSObject {
@@ -40,7 +41,7 @@ class ProfileViewModel: NSObject {
let followingCount: CurrentValueSubject
let followersCount: CurrentValueSubject
let fields: CurrentValueSubject<[Mastodon.Entity.Field], Never>
- let emojiDict: CurrentValueSubject
+ let emojiMeta: CurrentValueSubject
// fulfill this before editing
let accountForEdit = CurrentValueSubject(nil)
@@ -83,7 +84,7 @@ class ProfileViewModel: NSObject {
self.protected = CurrentValueSubject(mastodonUser?.locked)
self.suspended = CurrentValueSubject(mastodonUser?.suspended ?? false)
self.fields = CurrentValueSubject(mastodonUser?.fields ?? [])
- self.emojiDict = CurrentValueSubject(mastodonUser?.emojiDict ?? [:])
+ self.emojiMeta = CurrentValueSubject(mastodonUser?.emojiMeta ?? [:])
super.init()
relationshipActionOptionSet
@@ -258,7 +259,7 @@ extension ProfileViewModel {
self.protected.value = mastodonUser?.locked
self.suspended.value = mastodonUser?.suspended ?? false
self.fields.value = mastodonUser?.fields ?? []
- self.emojiDict.value = mastodonUser?.emojiDict ?? [:]
+ self.emojiMeta.value = mastodonUser?.emojiMeta ?? [:]
}
private func update(mastodonUser: MastodonUser?, currentMastodonUser: MastodonUser?) {
diff --git a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
index 32d096a33..ff566a248 100644
--- a/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
+++ b/Mastodon/Scene/Report/ReportedStatusTableviewCell.swift
@@ -11,7 +11,6 @@ import AVKit
import Combine
import CoreData
import CoreDataStack
-import ActiveLabel
import Meta
import MetaTextKit
@@ -212,9 +211,6 @@ extension ReportedStatusTableViewCell: StatusViewDelegate {
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton) {
}
-
- func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- }
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
}
diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift
index b69914dbe..cd1d196e4 100644
--- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift
+++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendAccountsCollectionViewCell.swift
@@ -10,7 +10,8 @@ import CoreDataStack
import Foundation
import MastodonSDK
import UIKit
-import ActiveLabel
+import MetaTextKit
+import MastodonMeta
protocol SearchRecommendAccountsCollectionViewCellDelegate: NSObject {
func followButtonDidPressed(clickedUser: MastodonUser)
@@ -43,14 +44,7 @@ class SearchRecommendAccountsCollectionViewCell: UICollectionViewCell {
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
- let displayNameLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusName)
- label.textColor = .white
- label.textAlignment = .center
- label.font = .systemFont(ofSize: 18, weight: .semibold)
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
+ let displayNameLabel = MetaLabel(style: .recommendAccountName)
let acctLabel: UILabel = {
let label = UILabel()
@@ -165,7 +159,14 @@ extension SearchRecommendAccountsCollectionViewCell {
}
func config(with mastodonUser: MastodonUser) {
- displayNameLabel.configure(content: mastodonUser.displayNameWithFallback, emojiDict: mastodonUser.emojiDict)
+ do {
+ let mastodonContent = MastodonContent(content: mastodonUser.displayNameWithFallback, emojis: mastodonUser.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ displayNameLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: mastodonUser.displayNameWithFallback)
+ displayNameLabel.configure(content: metaContent)
+ }
acctLabel.text = "@" + mastodonUser.acct
avatarImageView.af.setImage(
withURL: URL(string: mastodonUser.avatar)!,
diff --git a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift
index 1b48d1d2d..4c1753ff0 100644
--- a/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift
+++ b/Mastodon/Scene/Search/SearchDetail/TableViewCell/SearchResultTableViewCell.swift
@@ -11,6 +11,8 @@ import Foundation
import MastodonSDK
import UIKit
import FLAnimatedImage
+import MetaTextKit
+import MastodonMeta
final class SearchResultTableViewCell: UITableViewCell {
@@ -22,13 +24,7 @@ final class SearchResultTableViewCell: UITableViewCell {
return imageView
}()
- let _titleLabel: UILabel = {
- let label = UILabel()
- label.textColor = Asset.Colors.brandBlue.color
- label.font = .systemFont(ofSize: 17, weight: .semibold)
- label.lineBreakMode = .byTruncatingTail
- return label
- }()
+ let _titleLabel = MetaLabel(style: .statusName)
let _subTitleLabel: UILabel = {
let label = UILabel()
@@ -155,13 +151,28 @@ extension SearchResultTableViewCell {
func config(with account: Mastodon.Entity.Account) {
configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: account.avatarImageURL()))
- _titleLabel.text = account.displayName.isEmpty ? account.username : account.displayName
+ let name = account.displayName.isEmpty ? account.username : account.displayName
+ do {
+ let mastodonContent = MastodonContent(content: name, emojis: account.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ _titleLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: name)
+ _titleLabel.configure(content: metaContent)
+ }
_subTitleLabel.text = account.acct
}
func config(with account: MastodonUser) {
configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: account.avatarImageURL()))
- _titleLabel.text = account.displayNameWithFallback
+ do {
+ let mastodonContent = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ _titleLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: account.displayNameWithFallback)
+ _titleLabel.configure(content: metaContent)
+ }
_subTitleLabel.text = account.acct
}
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index 744900bed..e8ff57844 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -8,10 +8,11 @@
import os.log
import UIKit
import Combine
-import ActiveLabel
import CoreData
import CoreDataStack
import MastodonSDK
+import MetaTextKit
+import MastodonMeta
import AuthenticationServices
class SettingsViewController: UIViewController, NeedsDependency {
@@ -103,12 +104,7 @@ class SettingsViewController: UIViewController, NeedsDependency {
return tableView
}()
- let tableFooterActiveLabel: ActiveLabel = {
- let label = ActiveLabel(style: .default)
- label.adjustsFontForContentSizeCategory = true
- label.textAlignment = .center
- return label
- }()
+ let tableFooterLabel = MetaLabel(style: .settingTableFooter)
lazy var tableFooterView: UIView = {
// init with a frame to fix a conflict ('UIView-Encapsulated-Layout-Height' UIStackView:0x7ffe41e47da0.height == 0)
let view = UIStackView(frame: CGRect(x: 0, y: 0, width: 320, height: 320))
@@ -117,8 +113,8 @@ class SettingsViewController: UIViewController, NeedsDependency {
view.axis = .vertical
view.alignment = .center
- tableFooterActiveLabel.delegate = self
- view.addArrangedSubview(tableFooterActiveLabel)
+ tableFooterLabel.linkDelegate = self
+ view.addArrangedSubview(tableFooterLabel)
return view
}()
@@ -199,7 +195,15 @@ class SettingsViewController: UIViewController, NeedsDependency {
let version = instance?.version ?? "-"
let link = #"mastodon/mastodon"#
let content = L10n.Scene.Settings.Footer.mastodonDescription(link, version)
- self.tableFooterActiveLabel.configure(content: content, emojiDict: [:])
+ let mastodonContent = MastodonContent(content: content, emojis: [:])
+ do {
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ self.tableFooterLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: "")
+ self.tableFooterLabel.configure(content: metaContent)
+ assertionFailure()
+ }
}
.store(in: &disposeBag)
}
@@ -510,13 +514,16 @@ extension SettingsViewController: SettingsToggleCellDelegate {
}
}
-extension SettingsViewController: ActiveLabelDelegate {
- func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- coordinator.present(
- scene: .safari(url: URL(string: "https://github.com/mastodon/mastodon")!),
- from: self,
- transition: .safariPresent(animated: true, completion: nil)
- )
+// MARK: - MetaLabelDelegate
+extension SettingsViewController: MetaLabelDelegate {
+ func metaLabel(_ metaLabel: MetaLabel, didSelectMeta meta: Meta) {
+ switch meta {
+ case .url(_, _, let url, _):
+ guard let url = URL(string: url) else { return }
+ coordinator.present(scene: .safari(url: url), from: self, transition: .safariPresent(animated: true, completion: nil))
+ default:
+ assertionFailure()
+ }
}
}
diff --git a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
index 33ef86dd0..d900307ab 100644
--- a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
+++ b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift
@@ -6,19 +6,14 @@
//
import UIKit
-import ActiveLabel
+import Meta
+import MetaTextKit
final class DoubleTitleLabelNavigationBarTitleView: UIView {
let containerView = UIStackView()
- let titleLabel: ActiveLabel = {
- let label = ActiveLabel(style: .default)
- label.font = .systemFont(ofSize: 17, weight: .semibold)
- label.textColor = Asset.Colors.Label.primary.color
- label.textAlignment = .center
- return label
- }()
+ let titleLabel = MetaLabel(style: .titleView)
let subtitleLabel: UILabel = {
let label = UILabel()
@@ -58,9 +53,18 @@ extension DoubleTitleLabelNavigationBarTitleView {
containerView.addArrangedSubview(titleLabel)
containerView.addArrangedSubview(subtitleLabel)
}
+
+ func update(title: String, subtitle: String?) {
+ titleLabel.configure(content: PlaintextMetaContent(string: title))
+ update(subtitle: subtitle)
+ }
- func update(title: String, subtitle: String?, emojiDict: MastodonStatusContent.EmojiDict) {
- titleLabel.configure(content: title, emojiDict: emojiDict)
+ func update(titleMetaContent: MetaContent, subtitle: String?) {
+ titleLabel.configure(content: titleMetaContent)
+ update(subtitle: subtitle)
+ }
+
+ func update(subtitle: String?) {
if let subtitle = subtitle {
subtitleLabel.text = subtitle
subtitleLabel.isHidden = false
diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift
index 0964ee3ba..c1294bff5 100644
--- a/Mastodon/Scene/Share/View/Content/StatusView.swift
+++ b/Mastodon/Scene/Share/View/Content/StatusView.swift
@@ -9,7 +9,6 @@ import os.log
import UIKit
import Combine
import AVKit
-import ActiveLabel
import AlamofireImage
import FLAnimatedImage
import MetaTextKit
@@ -26,7 +25,6 @@ protocol StatusViewDelegate: AnyObject {
func statusView(_ statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton)
- func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
}
@@ -215,7 +213,7 @@ final class StatusView: UIView {
metaText.textView.layer.masksToBounds = false
metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment
- let paragraphStyle: NSMutableParagraphStyle = {
+ metaText.paragraphStyle = {
let style = NSMutableParagraphStyle()
style.lineSpacing = 5
style.paragraphSpacing = 8
@@ -224,12 +222,10 @@ final class StatusView: UIView {
metaText.textAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)),
.foregroundColor: Asset.Colors.Label.primary.color,
- .paragraphStyle: paragraphStyle,
]
metaText.linkAttributes = [
.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)),
.foregroundColor: Asset.Colors.brandBlue.color,
- .paragraphStyle: paragraphStyle,
]
return metaText
}()
@@ -559,11 +555,10 @@ extension StatusView {
// MARK: - MetaTextViewDelegate
extension StatusView: MetaTextViewDelegate {
- func metaTextView(_ metaTextView: MetaTextView, didSelectLink link: URL) {
+ func metaTextView(_ metaTextView: MetaTextView, didSelectMeta meta: Meta) {
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
switch metaTextView {
case contentMetaText.textView:
- guard let meta = Meta(url: link) else { return }
delegate?.statusView(self, metaText: contentMetaText, didSelectMeta: meta)
default:
assertionFailure()
@@ -596,14 +591,6 @@ extension StatusView: UITextViewDelegate {
}
}
-// MARK: - ActiveLabelDelegate
-extension StatusView: ActiveLabelDelegate {
- func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select entity: %s", ((#file as NSString).lastPathComponent), #line, #function, entity.primaryText)
- delegate?.statusView(self, activeLabel: activeLabel, didSelectActiveEntity: entity)
- }
-}
-
// MARK: - ContentWarningOverlayViewDelegate
extension StatusView: ContentWarningOverlayViewDelegate {
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) {
diff --git a/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift b/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift
index 9e62fd74d..693540473 100644
--- a/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift
+++ b/Mastodon/Scene/Share/View/Node/Status/StatusNode.swift
@@ -11,11 +11,10 @@ import UIKit
import Combine
import AsyncDisplayKit
import CoreDataStack
-import ActiveLabel
import func AVFoundation.AVMakeRect
protocol StatusNodeDelegate: AnyObject {
- func statusNode(_ node: StatusNode, statusContentTextNode: ASMetaEditableTextNode, didSelectActiveEntityType type: ActiveEntityType)
+ //func statusNode(_ node: StatusNode, statusContentTextNode: ASMetaEditableTextNode, didSelectActiveEntityType type: ActiveEntityType)
}
final class StatusNode: ASCellNode {
@@ -29,21 +28,21 @@ final class StatusNode: ASCellNode {
static let avatarImageSize = CGSize(width: 42, height: 42)
static let avatarImageCornerRadius: CGFloat = 4
- static let statusContentAppearance: MastodonStatusContent.Appearance = {
- let linkAttributes: [NSAttributedString.Key: Any] = [
- .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)),
- .foregroundColor: Asset.Colors.brandBlue.color
- ]
- return MastodonStatusContent.Appearance(
- attributes: [
- .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)),
- .foregroundColor: Asset.Colors.Label.primary.color
- ],
- urlAttributes: linkAttributes,
- hashtagAttributes: linkAttributes,
- mentionAttributes: linkAttributes
- )
- }()
+// static let statusContentAppearance: MastodonStatusContent.Appearance = {
+// let linkAttributes: [NSAttributedString.Key: Any] = [
+// .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)),
+// .foregroundColor: Asset.Colors.brandBlue.color
+// ]
+// return MastodonStatusContent.Appearance(
+// attributes: [
+// .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)),
+// .foregroundColor: Asset.Colors.Label.primary.color
+// ],
+// urlAttributes: linkAttributes,
+// hashtagAttributes: linkAttributes,
+// mentionAttributes: linkAttributes
+// )
+// }()
let avatarImageNode: ASNetworkImageNode = {
let node = ASNetworkImageNode()
@@ -112,13 +111,14 @@ final class StatusNode: ASCellNode {
.font: UIFont.systemFont(ofSize: 15, weight: .regular)
])
- statusContentTextNode.metaEditableTextNodeDelegate = self
- if let parseResult = try? MastodonStatusContent.parse(
- content: (status.reblog ?? status).content,
- emojiDict: (status.reblog ?? status).emojiDict
- ) {
- statusContentTextNode.attributedText = parseResult.trimmedAttributedString(appearance: StatusNode.statusContentAppearance)
- }
+ // FIXME:
+ // statusContentTextNode.metaEditableTextNodeDelegate = self
+// if let parseResult = try? MastodonStatusContent.parse(
+// content: (status.reblog ?? status).content,
+// emojiDict: (status.reblog ?? status).emojiDict
+// ) {
+// statusContentTextNode.attributedText = parseResult.trimmedAttributedString(appearance: StatusNode.statusContentAppearance)
+// }
for imageNode in mediaMultiplexImageNodes {
imageNode.dataSource = self
@@ -200,29 +200,19 @@ final class StatusNode: ASCellNode {
}
-//extension StatusNode: ASImageDownloaderProtocol {
-// func downloadImage(with URL: URL, callbackQueue: DispatchQueue, downloadProgress: ASImageDownloaderProgress?, completion: @escaping ASImageDownloaderCompletion) -> Any? {
-//
-// }
-//
-// func cancelImageDownload(forIdentifier downloadIdentifier: Any) {
-//
+// MARK: - ASEditableTextNodeDelegate
+//extension StatusNode: ASMetaEditableTextNodeDelegate {
+// func metaEditableTextNode(_ textNode: ASMetaEditableTextNode, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
+// guard let activityEntityType = ActiveEntityType(url: URL) else {
+// return false
+// }
+// defer {
+// delegate?.statusNode(self, statusContentTextNode: textNode, didSelectActiveEntityType: activityEntityType)
+// }
+// return false
// }
//}
-// MARK: - ASEditableTextNodeDelegate
-extension StatusNode: ASMetaEditableTextNodeDelegate {
- func metaEditableTextNode(_ textNode: ASMetaEditableTextNode, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
- guard let activityEntityType = ActiveEntityType(url: URL) else {
- return false
- }
- defer {
- delegate?.statusNode(self, statusContentTextNode: textNode, didSelectActiveEntityType: activityEntityType)
- }
- return false
- }
-}
-
// MARK: - ASMultiplexImageNodeDataSource
extension StatusNode: ASMultiplexImageNodeDataSource {
func multiplexImageNode(_ imageNode: ASMultiplexImageNode, urlForImageIdentifier imageIdentifier: ASImageIdentifier) -> URL? {
diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
index 3a186f00b..8e9f4a641 100644
--- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
+++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
@@ -11,7 +11,6 @@ import AVKit
import Combine
import CoreData
import CoreDataStack
-import ActiveLabel
import Meta
import MetaTextKit
@@ -27,7 +26,6 @@ protocol StatusTableViewCellDelegate: AnyObject {
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
- func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity)
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
@@ -328,10 +326,6 @@ extension StatusTableViewCell: StatusViewDelegate {
func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton) {
delegate?.statusTableViewCell(self, statusView: statusView, pollVoteButtonPressed: button)
}
-
- func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
- delegate?.statusTableViewCell(self, statusView: statusView, activeLabel: activeLabel, didSelectActiveEntity: entity)
- }
func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) {
delegate?.statusTableViewCell(self, statusView: statusView, metaText: metaText, didSelectMeta: meta)
diff --git a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
index 30f7688a6..905e1db32 100644
--- a/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
+++ b/Mastodon/Scene/SuggestionAccount/TableViewCell/SuggestionAccountTableViewCell.swift
@@ -11,7 +11,8 @@ import CoreDataStack
import Foundation
import MastodonSDK
import UIKit
-import ActiveLabel
+import MetaTextKit
+import MastodonMeta
protocol SuggestionAccountTableViewCellDelegate: AnyObject {
func accountButtonPressed(objectID: NSManagedObjectID, cell: SuggestionAccountTableViewCell)
@@ -29,13 +30,7 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
return imageView
}()
- let titleLabel: ActiveLabel = {
- let label = ActiveLabel(style: .statusName)
- label.textColor = Asset.Colors.brandBlue.color
- label.font = .systemFont(ofSize: 17, weight: .semibold)
- label.lineBreakMode = .byTruncatingTail
- return label
- }()
+ let titleLabel = MetaLabel(style: .statusName)
let subTitleLabel: UILabel = {
let label = UILabel()
@@ -152,8 +147,15 @@ extension SuggestionAccountTableViewCell {
imageTransition: .crossDissolve(0.2)
)
}
- titleLabel.configure(content: account.displayNameWithFallback, emojiDict: account.emojiDict)
- subTitleLabel.text = account.acct
+ let mastodonContent = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojiMeta)
+ do {
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ titleLabel.configure(content: metaContent)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: account.displayNameWithFallback)
+ titleLabel.configure(content: metaContent)
+ }
+ subTitleLabel.text = "@" + account.acct
button.isSelected = isSelected
button.publisher(for: .touchUpInside)
.sink { [weak self] _ in
diff --git a/Mastodon/Scene/Thread/ThreadViewController.swift b/Mastodon/Scene/Thread/ThreadViewController.swift
index 71a7de9ee..c1d580a71 100644
--- a/Mastodon/Scene/Thread/ThreadViewController.swift
+++ b/Mastodon/Scene/Thread/ThreadViewController.swift
@@ -10,6 +10,7 @@ import UIKit
import Combine
import CoreData
import AVKit
+import MastodonMeta
final class ThreadViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
@@ -84,18 +85,27 @@ extension ThreadViewController {
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
-
- viewModel.navigationBarTitle
- .receive(on: DispatchQueue.main)
- .sink { [weak self] tuple in
- guard let self = self else { return }
- guard let (title, emojiDict) = tuple else {
- self.titleView.update(title: L10n.Scene.Thread.backTitle, subtitle: nil, emojiDict: [:])
- return
- }
- self.titleView.update(title: title, subtitle: nil, emojiDict: emojiDict)
+
+ Publishers.CombineLatest(
+ viewModel.navigationBarTitle,
+ viewModel.navigationBarTitleEmojiMeta
+ )
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] title, emojiMeta in
+ guard let self = self else { return }
+ guard let title = title else {
+ self.titleView.update(title: "", subtitle: nil)
+ return
}
- .store(in: &disposeBag)
+ let mastodonContent = MastodonContent(content: title, emojis: emojiMeta ?? [:])
+ do {
+ let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
+ self.titleView.update(titleMetaContent: metaContent, subtitle: nil)
+ } catch {
+ assertionFailure()
+ }
+ }
+ .store(in: &disposeBag)
}
override func viewWillAppear(_ animated: Bool) {
diff --git a/Mastodon/Scene/Thread/ThreadViewModel.swift b/Mastodon/Scene/Thread/ThreadViewModel.swift
index 26be56430..1c4a7071e 100644
--- a/Mastodon/Scene/Thread/ThreadViewModel.swift
+++ b/Mastodon/Scene/Thread/ThreadViewModel.swift
@@ -12,6 +12,7 @@ import CoreData
import CoreDataStack
import GameplayKit
import MastodonSDK
+import MastodonMeta
class ThreadViewModel {
@@ -45,7 +46,8 @@ class ThreadViewModel {
let ancestorItems = CurrentValueSubject<[Item], Never>([])
let descendantNodes = CurrentValueSubject<[LeafNode], Never>([])
let descendantItems = CurrentValueSubject<[Item], Never>([])
- let navigationBarTitle: CurrentValueSubject<(String, MastodonStatusContent.EmojiDict)?, Never>
+ let navigationBarTitle: CurrentValueSubject
+ let navigationBarTitleEmojiMeta: CurrentValueSubject
init(context: AppContext, optionalStatus: Status?) {
self.context = context
@@ -53,8 +55,8 @@ class ThreadViewModel {
self.rootItem = CurrentValueSubject(optionalStatus.flatMap { Item.root(statusObjectID: $0.objectID, attribute: Item.StatusAttribute()) })
self.existStatusFetchedResultsController = StatusFetchedResultsController(managedObjectContext: context.managedObjectContext, domain: nil, additionalTweetPredicate: nil)
self.navigationBarTitle = CurrentValueSubject(
- optionalStatus.flatMap { (L10n.Scene.Thread.title($0.author.displayNameWithFallback), $0.author.emojiDict) }
- )
+ optionalStatus.flatMap { L10n.Scene.Thread.title($0.author.displayNameWithFallback) })
+ self.navigationBarTitleEmojiMeta = CurrentValueSubject(optionalStatus.flatMap { $0.author.emojiMeta } ?? [:])
// bind fetcher domain
context.authenticationService.activeMastodonAuthenticationBox
@@ -85,7 +87,8 @@ class ThreadViewModel {
return
}
self.rootNode.value = RootNode(domain: status.domain, statusID: status.id, replyToID: status.inReplyToID)
- self.navigationBarTitle.value = (L10n.Scene.Thread.title(status.author.displayNameWithFallback), status.author.emojiDict)
+ self.navigationBarTitle.value = L10n.Scene.Thread.title(status.author.displayNameWithFallback)
+ self.navigationBarTitleEmojiMeta.value = status.author.emojiMeta ?? [:]
}
}
.store(in: &disposeBag)
diff --git a/Mastodon/Service/StatusContentCacheService.swift b/Mastodon/Service/StatusContentCacheService.swift
deleted file mode 100644
index ff17b0478..000000000
--- a/Mastodon/Service/StatusContentCacheService.swift
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// StatusContentCacheService.swift
-// Mastodon
-//
-// Created by MainasuK Cirno on 2021-6-17.
-//
-
-import UIKit
-import Combine
-
-final class StatusContentCacheService {
-
- var disposeBag = Set()
-
- let cache = NSCache()
-
- let workingQueue = DispatchQueue(label: "org.joinmastodon.app.BlurhashImageCacheService.working-queue", qos: .userInitiated, attributes: .concurrent)
-
- func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> MastodonStatusContent.ParseResult? {
- let key = Key(content: content, emojiDict: emojiDict)
- return cache.object(forKey: key)?.parseResult
- }
-
- func prefetch(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
- let key = Key(content: content, emojiDict: emojiDict)
- guard cache.object(forKey: key) == nil else { return }
- MastodonStatusContent.parseResult(content: content, emojiDict: emojiDict)
- .sink { [weak self] parseResult in
- guard let self = self else { return }
- guard let parseResult = parseResult else { return }
- let wrapper = ParseResultWrapper(parseResult: parseResult)
- self.cache.setObject(wrapper, forKey: key)
- }
- .store(in: &disposeBag)
- }
-
-}
-
-extension StatusContentCacheService {
- class Key: NSObject {
- let content: String
- let emojiDict: MastodonStatusContent.EmojiDict
-
- init(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
- self.content = content
- self.emojiDict = emojiDict
- }
-
- override func isEqual(_ object: Any?) -> Bool {
- guard let object = object as? Key else { return false }
- return object.content == content
- && object.emojiDict == emojiDict
- }
-
- override var hash: Int {
- return content.hashValue ^
- emojiDict.hashValue
- }
- }
-
- class ParseResultWrapper: NSObject {
- let parseResult: MastodonStatusContent.ParseResult
-
- init(parseResult: MastodonStatusContent.ParseResult) {
- self.parseResult = parseResult
- }
-
- override func isEqual(_ object: Any?) -> Bool {
- guard let object = object as? ParseResultWrapper else { return false }
- return object.parseResult == parseResult
- }
-
- override var hash: Int {
- return parseResult.hashValue
- }
- }
-}
diff --git a/Mastodon/State/AppContext.swift b/Mastodon/State/AppContext.swift
index 7db669e5e..d4682ed5e 100644
--- a/Mastodon/State/AppContext.swift
+++ b/Mastodon/State/AppContext.swift
@@ -38,7 +38,6 @@ class AppContext: ObservableObject {
let placeholderImageCacheService = PlaceholderImageCacheService()
let blurhashImageCacheService = BlurhashImageCacheService()
- let statusContentCacheService = StatusContentCacheService()
let documentStore: DocumentStore
private var documentStoreSubscription: AnyCancellable!
From fff4f0a2049cecc9658723a65a24883f96b8e5c5 Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 19:33:05 +0800
Subject: [PATCH 4/9] feat: add emoji animation preference
---
.../CoreData.xcdatamodel/contents | 5 +++--
CoreDataStack/Entity/Setting.swift | 7 +++++++
Localization/app.json | 7 +++----
Mastodon/Diffiable/Item/SettingsItem.swift | 6 ++++--
.../Section/Compose/CustomEmojiPickerSection.swift | 3 ++-
Mastodon/Diffiable/Section/SettingsSection.swift | 2 ++
Mastodon/Extension/CoreDataStack/Emojis.swift | 6 +++++-
.../MastodonSDK/Mastodon+Entity+Account.swift | 4 +++-
Mastodon/Generated/Strings.swift | 12 ++++++------
Mastodon/Preference/AppearancePreference.swift | 9 +++++++++
Mastodon/Resources/ar.lproj/Localizable.strings | 5 +++--
Mastodon/Resources/en.lproj/Localizable.strings | 5 +++--
Mastodon/Scene/Settings/SettingsViewController.swift | 4 ++++
Mastodon/Scene/Settings/SettingsViewModel.swift | 8 +++-----
Mastodon/Service/SettingService.swift | 6 ++++++
15 files changed, 63 insertions(+), 26 deletions(-)
diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
index 14c7dc2ec..51df98e36 100644
--- a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
+++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
@@ -1,5 +1,5 @@
-
+
@@ -195,6 +195,7 @@
+
@@ -290,7 +291,7 @@
-
+
diff --git a/CoreDataStack/Entity/Setting.swift b/CoreDataStack/Entity/Setting.swift
index 0be80f973..27971157f 100644
--- a/CoreDataStack/Entity/Setting.swift
+++ b/CoreDataStack/Entity/Setting.swift
@@ -16,6 +16,7 @@ public final class Setting: NSManagedObject {
@NSManaged public var appearanceRaw: String
@NSManaged public var preferredTrueBlackDarkMode: Bool
@NSManaged public var preferredStaticAvatar: Bool
+ @NSManaged public var preferredStaticEmoji: Bool
@NSManaged public var preferredUsingDefaultBrowser: Bool
@NSManaged public private(set) var createdAt: Date
@@ -64,6 +65,12 @@ extension Setting {
didUpdate(at: Date())
}
+ public func update(preferredStaticEmoji: Bool) {
+ guard preferredStaticEmoji != self.preferredStaticEmoji else { return }
+ self.preferredStaticEmoji = preferredStaticEmoji
+ didUpdate(at: Date())
+ }
+
public func update(preferredUsingDefaultBrowser: Bool) {
guard preferredUsingDefaultBrowser != self.preferredUsingDefaultBrowser else { return }
self.preferredUsingDefaultBrowser = preferredUsingDefaultBrowser
diff --git a/Localization/app.json b/Localization/app.json
index 049094d4f..21e91ca29 100644
--- a/Localization/app.json
+++ b/Localization/app.json
@@ -500,10 +500,6 @@
"light": "Always Light",
"dark": "Always Dark"
},
- "appearance_settings": {
- "true_black_dark_mode": "True black dark mode",
- "disable_avatar_animation": "Disable animated avatars"
- },
"notifications": {
"title": "Notifications",
"favorites": "Favorites my post",
@@ -520,6 +516,9 @@
},
"preference": {
"title": "Preferences",
+ "true_black_dark_mode": "True black dark mode",
+ "disable_avatar_animation": "Disable animated avatars",
+ "disable_emoji_animation": "Disable animated emojis",
"using_default_browser": "Use default browser to open links"
},
"boring_zone": {
diff --git a/Mastodon/Diffiable/Item/SettingsItem.swift b/Mastodon/Diffiable/Item/SettingsItem.swift
index 777df750d..e82d0e1f9 100644
--- a/Mastodon/Diffiable/Item/SettingsItem.swift
+++ b/Mastodon/Diffiable/Item/SettingsItem.swift
@@ -43,12 +43,14 @@ extension SettingsItem {
enum PreferenceType: CaseIterable {
case darkMode
case disableAvatarAnimation
+ case disableEmojiAnimation
case useDefaultBrowser
var title: String {
switch self {
- case .darkMode: return L10n.Scene.Settings.Section.AppearanceSettings.trueBlackDarkMode
- case .disableAvatarAnimation: return L10n.Scene.Settings.Section.AppearanceSettings.disableAvatarAnimation
+ case .darkMode: return L10n.Scene.Settings.Section.Preference.trueBlackDarkMode
+ case .disableAvatarAnimation: return L10n.Scene.Settings.Section.Preference.disableAvatarAnimation
+ case .disableEmojiAnimation: return L10n.Scene.Settings.Section.Preference.disableEmojiAnimation
case .useDefaultBrowser: return L10n.Scene.Settings.Section.Preference.usingDefaultBrowser
}
}
diff --git a/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift b/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
index 251b52f3a..e55e8849d 100644
--- a/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
+++ b/Mastodon/Diffiable/Section/Compose/CustomEmojiPickerSection.swift
@@ -24,7 +24,8 @@ extension CustomEmojiPickerSection {
let placeholder = UIImage.placeholder(size: CustomEmojiPickerItemCollectionViewCell.itemSize, color: .systemFill)
.af.imageRounded(withCornerRadius: 4)
- let url = URL(string: attribute.emoji.url)
+ let isAnimated = !UserDefaults.shared.preferredStaticEmoji
+ let url = URL(string: isAnimated ? attribute.emoji.url : attribute.emoji.staticURL)
cell.emojiImageView.sd_setImage(
with: url,
placeholderImage: placeholder,
diff --git a/Mastodon/Diffiable/Section/SettingsSection.swift b/Mastodon/Diffiable/Section/SettingsSection.swift
index e329bd120..939fd4315 100644
--- a/Mastodon/Diffiable/Section/SettingsSection.swift
+++ b/Mastodon/Diffiable/Section/SettingsSection.swift
@@ -125,6 +125,8 @@ extension SettingsSection {
cell.switchButton.isOn = setting.preferredTrueBlackDarkMode
case .disableAvatarAnimation:
cell.switchButton.isOn = setting.preferredStaticAvatar
+ case .disableEmojiAnimation:
+ cell.switchButton.isOn = setting.preferredStaticEmoji
case .useDefaultBrowser:
cell.switchButton.isOn = setting.preferredUsingDefaultBrowser
}
diff --git a/Mastodon/Extension/CoreDataStack/Emojis.swift b/Mastodon/Extension/CoreDataStack/Emojis.swift
index 2f45880bd..c318e8ed9 100644
--- a/Mastodon/Extension/CoreDataStack/Emojis.swift
+++ b/Mastodon/Extension/CoreDataStack/Emojis.swift
@@ -13,6 +13,8 @@ protocol EmojiContainer {
var emojisData: Data? { get }
}
+// FIXME: `Mastodon.Entity.Account` extension
+
extension EmojiContainer {
static func encode(emojis: [Mastodon.Entity.Emoji]) -> Data? {
@@ -25,9 +27,11 @@ extension EmojiContainer {
}
var emojiMeta: MastodonContent.Emojis {
+ let isAnimated = !UserDefaults.shared.preferredStaticEmoji
+
var dict = MastodonContent.Emojis()
for emoji in emojis ?? [] {
- dict[emoji.shortcode] = emoji.url
+ dict[emoji.shortcode] = isAnimated ? emoji.url : emoji.staticURL
}
return dict
}
diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
index de703fd16..6aad350c3 100644
--- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
+++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Account.swift
@@ -32,9 +32,11 @@ extension Mastodon.Entity.Account {
extension Mastodon.Entity.Account {
var emojiMeta: MastodonContent.Emojis {
+ let isAnimated = !UserDefaults.shared.preferredStaticEmoji
+
var dict = MastodonContent.Emojis()
for emoji in emojis ?? [] {
- dict[emoji.shortcode] = emoji.url
+ dict[emoji.shortcode] = isAnimated ? emoji.url : emoji.staticURL
}
return dict
}
diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift
index 8d5443abb..0e31e5da7 100644
--- a/Mastodon/Generated/Strings.swift
+++ b/Mastodon/Generated/Strings.swift
@@ -943,12 +943,6 @@ internal enum L10n {
/// Appearance
internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Appearance.Title")
}
- internal enum AppearanceSettings {
- /// Disable animated avatars
- internal static let disableAvatarAnimation = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation")
- /// True black dark mode
- internal static let trueBlackDarkMode = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode")
- }
internal enum BoringZone {
/// Account Settings
internal static let accountSettings = L10n.tr("Localizable", "Scene.Settings.Section.BoringZone.AccountSettings")
@@ -984,8 +978,14 @@ internal enum L10n {
}
}
internal enum Preference {
+ /// Disable animated avatars
+ internal static let disableAvatarAnimation = L10n.tr("Localizable", "Scene.Settings.Section.Preference.DisableAvatarAnimation")
+ /// Disable animated emojis
+ internal static let disableEmojiAnimation = L10n.tr("Localizable", "Scene.Settings.Section.Preference.DisableEmojiAnimation")
/// Preferences
internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Preference.Title")
+ /// True black dark mode
+ internal static let trueBlackDarkMode = L10n.tr("Localizable", "Scene.Settings.Section.Preference.TrueBlackDarkMode")
/// Use default browser to open links
internal static let usingDefaultBrowser = L10n.tr("Localizable", "Scene.Settings.Section.Preference.UsingDefaultBrowser")
}
diff --git a/Mastodon/Preference/AppearancePreference.swift b/Mastodon/Preference/AppearancePreference.swift
index 4630c1234..034bf9654 100644
--- a/Mastodon/Preference/AppearancePreference.swift
+++ b/Mastodon/Preference/AppearancePreference.swift
@@ -26,4 +26,13 @@ extension UserDefaults {
set { self[#function] = newValue }
}
+ @objc dynamic var preferredStaticEmoji: Bool {
+ get {
+ // default false
+ // without set register to profile timeline performance
+ return bool(forKey: #function)
+ }
+ set { self[#function] = newValue }
+ }
+
}
diff --git a/Mastodon/Resources/ar.lproj/Localizable.strings b/Mastodon/Resources/ar.lproj/Localizable.strings
index 99babb0bf..0d09e4594 100644
--- a/Mastodon/Resources/ar.lproj/Localizable.strings
+++ b/Mastodon/Resources/ar.lproj/Localizable.strings
@@ -321,8 +321,6 @@ any server.";
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
"Scene.Settings.Section.Appearance.Light" = "Always Light";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
-"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
-"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
@@ -337,7 +335,10 @@ any server.";
"Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower";
"Scene.Settings.Section.Notifications.Trigger.Noone" = "no one";
"Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when";
+"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars";
+"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis";
"Scene.Settings.Section.Preference.Title" = "Preferences";
+"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links";
"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache";
"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out";
diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings
index 99babb0bf..0d09e4594 100644
--- a/Mastodon/Resources/en.lproj/Localizable.strings
+++ b/Mastodon/Resources/en.lproj/Localizable.strings
@@ -321,8 +321,6 @@ any server.";
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
"Scene.Settings.Section.Appearance.Light" = "Always Light";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
-"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
-"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
@@ -337,7 +335,10 @@ any server.";
"Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower";
"Scene.Settings.Section.Notifications.Trigger.Noone" = "no one";
"Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when";
+"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars";
+"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis";
"Scene.Settings.Section.Preference.Title" = "Preferences";
+"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links";
"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache";
"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out";
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index e8ff57844..122a853ed 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -486,6 +486,8 @@ extension SettingsViewController: SettingsToggleCellDelegate {
setting.update(preferredTrueBlackDarkMode: isOn)
case .disableAvatarAnimation:
setting.update(preferredStaticAvatar: isOn)
+ case .disableEmojiAnimation:
+ setting.update(preferredStaticEmoji: isOn)
case .useDefaultBrowser:
setting.update(preferredUsingDefaultBrowser: isOn)
}
@@ -498,6 +500,8 @@ extension SettingsViewController: SettingsToggleCellDelegate {
ThemeService.shared.set(themeName: isOn ? .system : .mastodon)
case .disableAvatarAnimation:
UserDefaults.shared.preferredStaticAvatar = isOn
+ case .disableEmojiAnimation:
+ UserDefaults.shared.preferredStaticEmoji = isOn
case .useDefaultBrowser:
UserDefaults.shared.preferredUsingDefaultBrowser = isOn
}
diff --git a/Mastodon/Scene/Settings/SettingsViewModel.swift b/Mastodon/Scene/Settings/SettingsViewModel.swift
index b586195e6..9bc0adce2 100644
--- a/Mastodon/Scene/Settings/SettingsViewModel.swift
+++ b/Mastodon/Scene/Settings/SettingsViewModel.swift
@@ -121,11 +121,9 @@ extension SettingsViewModel {
// preference
snapshot.appendSections([.preference])
- let preferenceItems: [SettingsItem] = [
- .preference(settingObjectID: setting.objectID, preferenceType: .darkMode),
- .preference(settingObjectID: setting.objectID, preferenceType: .disableAvatarAnimation),
- .preference(settingObjectID: setting.objectID, preferenceType: .useDefaultBrowser),
- ]
+ let preferenceItems: [SettingsItem] = SettingsItem.PreferenceType.allCases.map { preferenceType in
+ SettingsItem.preference(settingObjectID: setting.objectID, preferenceType: preferenceType)
+ }
snapshot.appendItems(preferenceItems,toSection: .preference)
// boring zone
diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift
index 37246765f..5985f6fce 100644
--- a/Mastodon/Service/SettingService.swift
+++ b/Mastodon/Service/SettingService.swift
@@ -211,9 +211,15 @@ extension SettingService {
UserDefaults.shared.preferredStaticAvatar = setting.preferredStaticAvatar
}
+ // set emoji mode
+ if UserDefaults.shared.preferredStaticEmoji != setting.preferredStaticEmoji {
+ UserDefaults.shared.preferredStaticEmoji = setting.preferredStaticEmoji
+ }
+
// set browser
if UserDefaults.shared.preferredUsingDefaultBrowser != setting.preferredUsingDefaultBrowser {
UserDefaults.shared.preferredUsingDefaultBrowser = setting.preferredUsingDefaultBrowser
}
+
}
}
From ca930047d45f36c70da7e74d5602c514e8f6fa1a Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 19:40:41 +0800
Subject: [PATCH 5/9] feat: add some haptic feedbacks for setting scene
---
Mastodon/Scene/Settings/SettingsViewController.swift | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index 122a853ed..0685229c4 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -358,10 +358,11 @@ extension SettingsViewController: UITableViewDelegate {
guard let dataSource = viewModel.dataSource else { return }
guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
+ let feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
+
switch item {
case .appearance:
- // do nothing
- break
+ feedbackGenerator.impactOccurred()
case .notification:
// do nothing
break
@@ -369,6 +370,7 @@ extension SettingsViewController: UITableViewDelegate {
// do nothing
break
case .boringZone(let link), .spicyZone(let link):
+ feedbackGenerator.impactOccurred()
switch link {
case .accountSettings:
guard let box = context.authenticationService.activeMastodonAuthenticationBox.value,
@@ -399,6 +401,7 @@ extension SettingsViewController: UITableViewDelegate {
}
.store(in: &disposeBag)
case .signOut:
+ feedbackGenerator.impactOccurred()
alertToSignout()
}
}
From afb79fb870d9514dbd26763e7b3461066f10f24e Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 20:03:39 +0800
Subject: [PATCH 6/9] fix: status poll height not stable issue
---
.../Section/Status/StatusSection.swift | 1 +
.../Scene/Share/View/Content/StatusView.swift | 25 +++++++++++--------
.../PollOptionTableViewCell.swift | 2 ++
3 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/Mastodon/Diffiable/Section/Status/StatusSection.swift b/Mastodon/Diffiable/Section/Status/StatusSection.swift
index 9bb34466e..c6cde80f7 100644
--- a/Mastodon/Diffiable/Section/Status/StatusSection.swift
+++ b/Mastodon/Diffiable/Section/Status/StatusSection.swift
@@ -1035,6 +1035,7 @@ extension StatusSection {
}
snapshot.appendItems(pollItems, toSection: .main)
cell.statusView.pollTableViewDataSource?.apply(snapshot, animatingDifferences: false, completion: nil)
+ cell.statusView.pollTableViewHeightLayoutConstraint.constant = PollOptionTableViewCell.height * CGFloat(poll.options.count)
}
static func configureActionToolBar(
diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift
index c1294bff5..49452e1b4 100644
--- a/Mastodon/Scene/Share/View/Content/StatusView.swift
+++ b/Mastodon/Scene/Share/View/Content/StatusView.swift
@@ -287,6 +287,7 @@ extension StatusView {
headerContainerStackView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor),
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
])
+ headerContainerStackView.setContentCompressionResistancePriority(.required - 5, for: .vertical)
containerStackView.addArrangedSubview(headerContainerView)
defer {
containerStackView.bringSubviewToFront(headerContainerView)
@@ -418,17 +419,21 @@ extension StatusView {
NSLayoutConstraint.activate([
pollTableViewHeightLayoutConstraint,
])
-
- statusPollTableViewHeightObservation = pollTableView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
- guard let self = self else { return }
- guard self.pollTableView.contentSize.height != .zero else {
- self.pollTableViewHeightLayoutConstraint.constant = 44
- return
- }
- self.pollTableViewHeightLayoutConstraint.constant = self.pollTableView.contentSize.height
- })
-
+
+ // statusPollTableViewHeightObservation = pollTableView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
+ // guard let self = self else { return }
+ // guard self.pollTableView.contentSize.height != .zero else {
+ // self.pollTableViewHeightLayoutConstraint.constant = 44
+ // return
+ // }
+ // self.pollTableViewHeightLayoutConstraint.constant = self.pollTableView.contentSize.height
+ // })
+
+ pollStatusStackView.translatesAutoresizingMaskIntoConstraints = false
statusContainerStackView.addArrangedSubview(pollStatusStackView)
+ NSLayoutConstraint.activate([
+ pollStatusStackView.heightAnchor.constraint(equalToConstant: 30).priority(.required - 10)
+ ])
pollStatusStackView.axis = .horizontal
pollStatusStackView.addArrangedSubview(pollVoteCountLabel)
pollStatusStackView.addArrangedSubview(pollStatusDotLabel)
diff --git a/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
index fdcaa95f3..16b39feb5 100644
--- a/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
+++ b/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
@@ -10,6 +10,8 @@ import Combine
final class PollOptionTableViewCell: UITableViewCell {
+ static let height: CGFloat = PollOptionView.height
+
var disposeBag = Set()
let pollOptionView = PollOptionView()
From 581f0ba0601b0b9189fb8c69f9b0452c7b69a099 Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 20:03:54 +0800
Subject: [PATCH 7/9] feat: add haptic feedback for settings
---
Mastodon/Scene/Settings/SettingsViewController.swift | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index 0685229c4..475b93f57 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -358,11 +358,10 @@ extension SettingsViewController: UITableViewDelegate {
guard let dataSource = viewModel.dataSource else { return }
guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
- let feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
-
switch item {
case .appearance:
- feedbackGenerator.impactOccurred()
+ // do nothing
+ break
case .notification:
// do nothing
break
@@ -370,6 +369,7 @@ extension SettingsViewController: UITableViewDelegate {
// do nothing
break
case .boringZone(let link), .spicyZone(let link):
+ let feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
feedbackGenerator.impactOccurred()
switch link {
case .accountSettings:
@@ -447,7 +447,8 @@ extension SettingsViewController: SettingsAppearanceTableViewCellDelegate {
setting.update(appearanceRaw: appearanceMode.rawValue)
}
.sink { _ in
- // do nothing
+ let feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
+ feedbackGenerator.impactOccurred()
}.store(in: &disposeBag)
}
}
From d0263ffb615e4c17e32d81ddd343508ac04d3b2e Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 20:04:30 +0800
Subject: [PATCH 8/9] chore: update version to 0.9.3 (45)
---
Mastodon.xcodeproj/project.pbxproj | 24 +++++++++----------
.../xcschemes/xcschememanagement.plist | 6 ++---
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index d42733555..7f446ce9c 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -4282,7 +4282,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4309,7 +4309,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4574,7 +4574,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4598,7 +4598,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4622,7 +4622,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4646,7 +4646,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4736,7 +4736,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4851,7 +4851,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4970,7 +4970,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -5085,7 +5085,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5139,7 +5139,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5162,7 +5162,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 44;
+ CURRENT_PROJECT_VERSION = 45;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index d551bebb6..d28d5cdd8 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,7 +12,7 @@
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 25
+ 22
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -37,12 +37,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 23
+ 24
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 24
+ 23
SuppressBuildableAutocreation
From 356b5905fe250912784bf203163648e9e58a4651 Mon Sep 17 00:00:00 2001
From: CMK
Date: Fri, 23 Jul 2021 20:13:44 +0800
Subject: [PATCH 9/9] fix: add missing emoji animation for status report scene
---
Mastodon.xcodeproj/project.pbxproj | 9 --------
.../xcshareddata/swiftpm/Package.resolved | 9 --------
.../Compose/ComposeViewModel+DataSource.swift | 1 -
.../Header/ProfileHeaderViewController.swift | 1 -
.../Scene/Report/ReportViewController.swift | 21 ++++++++++++++-----
5 files changed, 16 insertions(+), 25 deletions(-)
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 7f446ce9c..f1351b859 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -3198,7 +3198,6 @@
DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */,
DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */,
DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */,
- DB6F5E30264E7410009108F4 /* XCRemoteSwiftPackageReference "TwitterTextEditor" */,
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */,
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */,
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */,
@@ -5348,14 +5347,6 @@
minimumVersion = 4.2.2;
};
};
- DB6F5E30264E7410009108F4 /* XCRemoteSwiftPackageReference "TwitterTextEditor" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/MainasuK/TwitterTextEditor.git";
- requirement = {
- branch = "feature/expose-layout";
- kind = branch;
- };
- };
DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/MainasuK/UITextView-Placeholder";
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 56f675a6d..dc848b695 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -190,15 +190,6 @@
"version": "2.6.0"
}
},
- {
- "package": "TwitterTextEditor",
- "repositoryURL": "https://github.com/MainasuK/TwitterTextEditor.git",
- "state": {
- "branch": "feature/expose-layout",
- "revision": "c208329b23dcb3c8c7192de34776440d625a26a4",
- "version": null
- }
- },
{
"package": "UITextView+Placeholder",
"repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder",
diff --git a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
index 79fe538d3..49406144b 100644
--- a/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
+++ b/Mastodon/Scene/Compose/ComposeViewModel+DataSource.swift
@@ -9,7 +9,6 @@ import os.log
import UIKit
import Combine
import CoreDataStack
-import TwitterTextEditor
import MastodonSDK
import MastodonMeta
import MetaTextKit
diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
index f0bf72af1..216c81685 100644
--- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
+++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift
@@ -11,7 +11,6 @@ import Combine
import PhotosUI
import AlamofireImage
import CropViewController
-import TwitterTextEditor
import MastodonMeta
import MetaTextKit
diff --git a/Mastodon/Scene/Report/ReportViewController.swift b/Mastodon/Scene/Report/ReportViewController.swift
index ebe1788f8..efaa533e1 100644
--- a/Mastodon/Scene/Report/ReportViewController.swift
+++ b/Mastodon/Scene/Report/ReportViewController.swift
@@ -11,8 +11,8 @@ import CoreData
import CoreDataStack
import os.log
import UIKit
-import TwitterTextEditor
import MastodonSDK
+import MastodonMeta
class ReportViewController: UIViewController, NeedsDependency {
static let kAnimationDuration: TimeInterval = 0.33
@@ -92,6 +92,8 @@ class ReportViewController: UIViewController, NeedsDependency {
}()
var bottomConstraint: NSLayoutConstraint!
+
+ let titleView = DoubleTitleLabelNavigationBarTitleView()
override func viewDidLoad() {
super.viewDidLoad()
@@ -267,10 +269,19 @@ class ReportViewController: UIViewController, NeedsDependency {
return nil
}
}()
-
- navigationItem.title = L10n.Scene.Report.title(
- beReportedUser?.displayNameWithFallback ?? ""
- )
+
+ navigationItem.titleView = titleView
+ if let user = beReportedUser {
+ do {
+ let mastodonConent = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojiMeta)
+ let metaContent = try MastodonMetaContent.convert(document: mastodonConent)
+ titleView.update(titleMetaContent: metaContent, subtitle: nil)
+ } catch {
+ let metaContent = PlaintextMetaContent(string: user.displayNameWithFallback)
+ titleView.update(titleMetaContent: metaContent, subtitle: nil)
+ }
+ }
+
}
private func switchToStep2Content() {