diff --git a/AppShared/Info.plist b/AppShared/Info.plist
index 222a7a1db..1958eb540 100644
--- a/AppShared/Info.plist
+++ b/AppShared/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
diff --git a/CoreDataStack/Info.plist b/CoreDataStack/Info.plist
index 222a7a1db..1958eb540 100644
--- a/CoreDataStack/Info.plist
+++ b/CoreDataStack/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
diff --git a/CoreDataStackTests/Info.plist b/CoreDataStackTests/Info.plist
index 222a7a1db..1958eb540 100644
--- a/CoreDataStackTests/Info.plist
+++ b/CoreDataStackTests/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index 4337bdc7d..600d1f4bb 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -347,6 +347,8 @@
DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F9626367249008423CD /* SettingsViewController.swift */; };
DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */; };
DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */; };
+ DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CA271D5A0300BE3819 /* LineChartView.swift */; };
+ DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */; };
DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */; };
DB71FD3625F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */; };
DB71FD3C25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */; };
@@ -1141,6 +1143,8 @@
DB6D9F9626367249008423CD /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewController.swift; sourceTree = ""; };
DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTopChevronView.swift; sourceTree = ""; };
+ DB71C7CA271D5A0300BE3819 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = ""; };
+ DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurveAlgorithm.swift; sourceTree = ""; };
DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStackContainerButton.swift; sourceTree = ""; };
DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistMemo.swift"; sourceTree = ""; };
DB71FD3B25F8A1C500512AE1 /* APIService+Persist+PersistCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistCache.swift"; sourceTree = ""; };
@@ -1750,6 +1754,7 @@
2D5A3D0125CF8640002347D6 /* Vender */ = {
isa = PBXGroup;
children = (
+ DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */,
2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */,
DB51D170262832380062B7A1 /* BlurHashDecode.swift */,
DB51D171262832380062B7A1 /* BlurHashEncode.swift */,
@@ -1954,6 +1959,7 @@
isa = PBXGroup;
children = (
2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */,
+ DB71C7CA271D5A0300BE3819 /* LineChartView.swift */,
);
path = View;
sourceTree = "";
@@ -4162,6 +4168,7 @@
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */,
2D34D9CB261489930081BFC0 /* SearchViewController+Recommend.swift in Sources */,
+ DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */,
DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */,
DB482A45261335BA008AE74C /* UserTimelineViewController+Provider.swift in Sources */,
2D206B8625F5FB0900143C56 /* Double.swift in Sources */,
@@ -4230,6 +4237,7 @@
DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */,
DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */,
2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */,
+ DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
DBAC6499267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift in Sources */,
@@ -4784,7 +4792,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4813,7 +4821,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4921,11 +4929,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AppShared/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -4952,11 +4960,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AppShared/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -4981,11 +4989,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = CoreDataStack/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5011,11 +5019,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = CoreDataStack/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5078,7 +5086,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5103,7 +5111,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5128,7 +5136,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5153,7 +5161,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = MastodonIntent/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5178,7 +5186,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5203,7 +5211,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5228,7 +5236,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5253,7 +5261,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5344,7 +5352,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -5411,11 +5419,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = CoreDataStack/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5460,7 +5468,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5485,11 +5493,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AppShared/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5581,7 +5589,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -5648,11 +5656,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = CoreDataStack/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5697,7 +5705,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5722,11 +5730,11 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 74;
+ DYLIB_CURRENT_VERSION = 78;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = AppShared/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -5752,7 +5760,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5776,7 +5784,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 74;
+ CURRENT_PROJECT_VERSION = 78;
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 beafe8c8e..424b6b090 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,12 +7,12 @@
AppShared.xcscheme_^#shared#^_
orderHint
- 43
+ 44
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 44
+ 43
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -37,7 +37,7 @@
Mastodon - ca.xcscheme_^#shared#^_
orderHint
- 18
+ 16
Mastodon - de.xcscheme_^#shared#^_
@@ -67,7 +67,7 @@
Mastodon - jp.xcscheme_^#shared#^_
orderHint
- 15
+ 14
Mastodon - nl.xcscheme_^#shared#^_
@@ -87,7 +87,7 @@
Mastodon - zh_Hans.xcscheme_^#shared#^_
orderHint
- 16
+ 15
Mastodon.xcscheme_^#shared#^_
diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 43a0036bd..26ba58d55 100644
--- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -141,8 +141,8 @@
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
"state": {
"branch": null,
- "revision": "d6367439527663d2038ca445a3c3c4e4bac40d60",
- "version": "5.12.0"
+ "revision": "a72df4849408da7e5d3c1b586797b7c601c41d1b",
+ "version": "5.12.1"
}
},
{
@@ -216,6 +216,15 @@
"revision": "dad97167bf1be16aeecd109130900995dd01c515",
"version": "2.6.0"
}
+ },
+ {
+ "package": "UITextView+Placeholder",
+ "repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder",
+ "state": {
+ "branch": null,
+ "revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
+ "version": "1.4.1"
+ }
}
]
},
diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist
index dd63aea2b..f8987fab7 100644
--- a/Mastodon/Info.plist
+++ b/Mastodon/Info.plist
@@ -30,7 +30,7 @@
CFBundleVersion
- 74
+ 78
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift
index 16dcbbeb6..23630741f 100644
--- a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift
+++ b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift
@@ -21,6 +21,19 @@ final class ProfilePagingViewController: TabmanViewController {
// MARK: - PageboyViewControllerDelegate
+ override func pageboyViewController(_ pageboyViewController: PageboyViewController, didCancelScrollToPageAt index: PageboyViewController.PageIndex, returnToPageAt previousIndex: PageboyViewController.PageIndex) {
+ super.pageboyViewController(pageboyViewController, didCancelScrollToPageAt: index, returnToPageAt: previousIndex)
+
+ // Fix the SDK bug for table view get row selected during swipe but cancel paging
+ guard previousIndex < viewModel.viewControllers.count else { return }
+ let viewController = viewModel.viewControllers[previousIndex]
+
+ if let tableView = viewController.scrollView as? UITableView {
+ for cell in tableView.visibleCells {
+ cell.setHighlighted(false, animated: false)
+ }
+ }
+ }
override func pageboyViewController(_ pageboyViewController: PageboyViewController, didScrollToPageAt index: TabmanViewController.PageIndex, direction: PageboyViewController.NavigationDirection, animated: Bool) {
super.pageboyViewController(pageboyViewController, didScrollToPageAt: index, direction: direction, animated: animated)
diff --git a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift
index e555e1fac..a538d30bf 100644
--- a/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift
+++ b/Mastodon/Scene/Search/Search/CollectionViewCell/SearchRecommendTagsCollectionViewCell.swift
@@ -17,7 +17,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell {
let hashtagTitleLabel: UILabel = {
let label = UILabel()
- label.textColor = .white
+ label.textColor = .label
label.font = .systemFont(ofSize: 20, weight: .semibold)
label.lineBreakMode = .byTruncatingTail
return label
@@ -25,18 +25,12 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell {
let peopleLabel: UILabel = {
let label = UILabel()
- label.textColor = .white
+ label.textColor = .label
label.font = .preferredFont(forTextStyle: .body)
return label
}()
- let flameIconView: UIImageView = {
- let imageView = UIImageView()
- let image = UIImage(systemName: "flame.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .semibold))!.withRenderingMode(.alwaysTemplate)
- imageView.image = image
- imageView.tintColor = .white
- return imageView
- }()
+ let lineChartView = LineChartView()
override func prepareForReuse() {
super.prepareForReuse()
@@ -54,7 +48,7 @@ class SearchRecommendTagsCollectionViewCell: UICollectionViewCell {
override var isHighlighted: Bool {
didSet {
- backgroundColor = isHighlighted ? Asset.Colors.brandBlueDarken20.color : Asset.Colors.brandBlue.color
+ backgroundColor = isHighlighted ? .systemBackground.withAlphaComponent(0.8) : .systemBackground
}
}
}
@@ -68,7 +62,7 @@ extension SearchRecommendTagsCollectionViewCell {
}
private func configure() {
- backgroundColor = Asset.Colors.brandBlue.color
+ backgroundColor = .systemBackground
layer.cornerRadius = 10
layer.cornerCurve = .continuous
clipsToBounds = false
@@ -98,41 +92,40 @@ extension SearchRecommendTagsCollectionViewCell {
containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
])
-
-
- let horizontalStackView = UIStackView()
- horizontalStackView.axis = .horizontal
- horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
- horizontalStackView.distribution = .fill
- hashtagTitleLabel.translatesAutoresizingMaskIntoConstraints = false
- hashtagTitleLabel.setContentHuggingPriority(.defaultLow - 1, for: .horizontal)
- horizontalStackView.addArrangedSubview(hashtagTitleLabel)
- horizontalStackView.setContentHuggingPriority(.required - 1, for: .vertical)
-
- flameIconView.translatesAutoresizingMaskIntoConstraints = false
- horizontalStackView.addArrangedSubview(flameIconView)
- flameIconView.setContentHuggingPriority(.required - 1, for: .horizontal)
-
- containerStackView.addArrangedSubview(horizontalStackView)
- peopleLabel.translatesAutoresizingMaskIntoConstraints = false
- peopleLabel.setContentHuggingPriority(.defaultLow - 1, for: .vertical)
+ containerStackView.addArrangedSubview(hashtagTitleLabel)
containerStackView.addArrangedSubview(peopleLabel)
- containerStackView.setCustomSpacing(SearchViewController.hashtagPeopleTalkingLabelTop, after: horizontalStackView)
+
+ lineChartView.translatesAutoresizingMaskIntoConstraints = false
+ contentView.addSubview(lineChartView)
+ NSLayoutConstraint.activate([
+ lineChartView.topAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 8),
+ lineChartView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
+ contentView.trailingAnchor.constraint(equalTo: lineChartView.trailingAnchor, constant: 16),
+ contentView.bottomAnchor.constraint(equalTo: lineChartView.bottomAnchor, constant: 16),
+ ])
}
func config(with tag: Mastodon.Entity.Tag) {
hashtagTitleLabel.text = "# " + tag.name
- guard let historys = tag.history else {
+ guard let history = tag.history else {
peopleLabel.text = ""
return
}
- let recentHistory = historys.prefix(2)
+ let recentHistory = history.prefix(2)
let peopleAreTalking = recentHistory.compactMap({ Int($0.accounts) }).reduce(0, +)
let string = L10n.Scene.Search.Recommend.HashTag.peopleTalking(String(peopleAreTalking))
peopleLabel.text = string
-
+
+ lineChartView.data = history
+ .sorted(by: { $0.day < $1.day }) // latest last
+ .map { entry in
+ guard let point = Int(entry.accounts) else {
+ return .zero
+ }
+ return CGFloat(point)
+ }
}
}
diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift
index 8dcf9cd3b..c72945927 100644
--- a/Mastodon/Scene/Search/Search/SearchViewController.swift
+++ b/Mastodon/Scene/Search/Search/SearchViewController.swift
@@ -23,9 +23,6 @@ final class SearchViewController: UIViewController, NeedsDependency {
public static var hashtagCardHeight: CGFloat {
get {
- if UIScreen.main.bounds.size.height > 736 {
- return 186
- }
return 130
}
}
diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/Mastodon/Scene/Search/Search/View/LineChartView.swift
new file mode 100644
index 000000000..2fb8ac733
--- /dev/null
+++ b/Mastodon/Scene/Search/Search/View/LineChartView.swift
@@ -0,0 +1,120 @@
+//
+// LineChartView.swift
+// Mastodon
+//
+// Created by Cirno MainasuK on 2021-10-18.
+//
+
+import UIKit
+import Accelerate
+import simd
+
+final class LineChartView: UIView {
+
+ var data: [CGFloat] = [] {
+ didSet {
+ setNeedsLayout()
+ }
+ }
+
+ let lineShapeLayer = CAShapeLayer()
+ let gradientLayer = CAGradientLayer()
+ let dotShapeLayer = CAShapeLayer()
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ _init()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ _init()
+ }
+
+}
+
+extension LineChartView {
+ private func _init() {
+ lineShapeLayer.frame = bounds
+ gradientLayer.frame = bounds
+ dotShapeLayer.frame = bounds
+ layer.addSublayer(lineShapeLayer)
+ layer.addSublayer(gradientLayer)
+ layer.addSublayer(dotShapeLayer)
+
+ gradientLayer.colors = [
+ Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor,
+ Asset.Colors.brandBlue.color.withAlphaComponent(0).cgColor,
+ ]
+ gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
+ gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
+ }
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+
+ lineShapeLayer.frame = bounds
+ gradientLayer.frame = bounds
+ dotShapeLayer.frame = bounds
+
+ guard data.count > 1 else {
+ lineShapeLayer.path = nil
+ dotShapeLayer.path = nil
+ gradientLayer.isHidden = true
+ return
+ }
+ gradientLayer.isHidden = false
+
+ // Draw smooth chart
+ guard let maxDataPoint = data.max() else {
+ return
+ }
+ func calculateY(for point: CGFloat, in frame: CGRect) -> CGFloat {
+ guard maxDataPoint > 0 else { return .zero }
+ return (1 - point / maxDataPoint) * frame.height
+ }
+
+ let segmentCount = data.count - 1
+ let segmentWidth = bounds.width / CGFloat(segmentCount)
+
+ let points: [CGPoint] = {
+ var points: [CGPoint] = []
+ var x: CGFloat = 0
+ for value in data {
+ let point = CGPoint(x: x, y: calculateY(for: value, in: bounds))
+ points.append(point)
+ x += segmentWidth
+ }
+ return points
+ }()
+
+ guard let linePath = CurveAlgorithm.shared.createCurvedPath(points) else { return }
+ let dotPath = UIBezierPath()
+
+ if let last = points.last {
+ dotPath.addArc(withCenter: last, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
+ }
+
+ lineShapeLayer.lineWidth = 3
+ lineShapeLayer.strokeColor = Asset.Colors.brandBlue.color.cgColor
+ lineShapeLayer.fillColor = UIColor.clear.cgColor
+ lineShapeLayer.lineJoin = .round
+ lineShapeLayer.lineCap = .round
+ lineShapeLayer.path = linePath.cgPath
+
+ let maskPath = UIBezierPath(cgPath: linePath.cgPath)
+ maskPath.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
+ maskPath.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
+ maskPath.close()
+ let maskLayer = CAShapeLayer()
+ maskLayer.path = maskPath.cgPath
+ maskLayer.fillColor = UIColor.red.cgColor
+ maskLayer.strokeColor = UIColor.clear.cgColor
+ maskLayer.lineWidth = 0.0
+ gradientLayer.mask = maskLayer
+
+ dotShapeLayer.lineWidth = 3
+ dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor
+ dotShapeLayer.path = dotPath.cgPath
+ }
+}
diff --git a/Mastodon/Vender/CurveAlgorithm.swift b/Mastodon/Vender/CurveAlgorithm.swift
new file mode 100644
index 000000000..0ca4c8734
--- /dev/null
+++ b/Mastodon/Vender/CurveAlgorithm.swift
@@ -0,0 +1,47 @@
+//
+// CurveAlgorithm.swift
+//
+// Ref: https://github.com/nhatminh12369/LineChart/blob/master/LineChart/CurveAlgorithm.swift
+
+import UIKit
+
+struct CurvedSegment {
+ var controlPoint1: CGPoint
+ var controlPoint2: CGPoint
+}
+
+class CurveAlgorithm {
+ static let shared = CurveAlgorithm()
+
+ private func controlPointsFrom(points: [CGPoint]) -> [CurvedSegment] {
+ var result: [CurvedSegment] = []
+
+ let delta: CGFloat = 0.2
+
+ // only use horizontal control point
+ for i in 1.. UIBezierPath? {
+ let path = UIBezierPath()
+ path.move(to: dataPoints[0])
+
+ var curveSegments: [CurvedSegment] = []
+ curveSegments = controlPointsFrom(points: dataPoints)
+
+ for i in 1..CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
NSExtension
NSExtensionAttributes
diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift
index e7f095eb3..740001572 100644
--- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift
+++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift
@@ -22,6 +22,7 @@ extension Mastodon.Entity {
public let url: String
public let history: [History]?
+
enum CodingKeys: String, CodingKey {
case name
case url
diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist
index 222a7a1db..1958eb540 100644
--- a/MastodonTests/Info.plist
+++ b/MastodonTests/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist
index 222a7a1db..1958eb540 100644
--- a/MastodonUITests/Info.plist
+++ b/MastodonUITests/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist
index e0a35aca8..f1f14ae01 100644
--- a/NotificationService/Info.plist
+++ b/NotificationService/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
NSExtension
NSExtensionPointIdentifier
diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist
index 3cc7eaedd..9edd32f6a 100644
--- a/ShareActionExtension/Info.plist
+++ b/ShareActionExtension/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.2.0
CFBundleVersion
- 74
+ 78
NSExtension
NSExtensionAttributes