Compare commits
No commits in common. "68c3affacfbc6dbebeae5b65eec28671f1cb6649" and "b38c24b3474821a0de050dfa4945c39e774147b2" have entirely different histories.
68c3affacf
...
b38c24b347
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,20 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2022.1 (44)
|
|
||||||
Features/Improvements:
|
|
||||||
- Dynamic Type support
|
|
||||||
- Improve performance when displaying statuses with large numbers of custom emojis
|
|
||||||
- Add preference for default reply visibility
|
|
||||||
- Add preference to turn off blurring media in posts with content warnings
|
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
- Fix drawing background flashing between black/white in dark mode
|
|
||||||
- Fix undo scroll-to-top not working in release builds
|
|
||||||
- Fix favorite and reblog menu actions not working
|
|
||||||
- Fix avatar in compose being wrongly aligned on short statuses
|
|
||||||
- Fix posts that are tall but have few characters not getting collapsed
|
|
||||||
- Fix crash when profile screen is closed for the profile loads
|
|
||||||
|
|
||||||
## 2022.1 (43)
|
## 2022.1 (43)
|
||||||
Features/Improvements:
|
Features/Improvements:
|
||||||
- Re-add undo scroll-to-top by tapping the status bar a second time
|
- Re-add undo scroll-to-top by tapping the status bar a second time
|
||||||
|
|
|
@ -125,7 +125,6 @@
|
||||||
D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AAC2128D88B005A6F37 /* LocalData.swift */; };
|
D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AAC2128D88B005A6F37 /* LocalData.swift */; };
|
||||||
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
|
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; };
|
||||||
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
|
D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; };
|
||||||
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */; };
|
|
||||||
D65234E12561AA68001AF9CF /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */; };
|
D65234E12561AA68001AF9CF /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */; };
|
||||||
D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */; };
|
D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */; };
|
||||||
D6531DF0246B867E000F9538 /* GifvAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DEF246B867E000F9538 /* GifvAttachmentViewController.swift */; };
|
D6531DF0246B867E000F9538 /* GifvAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DEF246B867E000F9538 /* GifvAttachmentViewController.swift */; };
|
||||||
|
@ -282,6 +281,8 @@
|
||||||
D6DD2A45273D6C5700386A6C /* GIFImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD2A44273D6C5700386A6C /* GIFImageView.swift */; };
|
D6DD2A45273D6C5700386A6C /* GIFImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD2A44273D6C5700386A6C /* GIFImageView.swift */; };
|
||||||
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
||||||
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
||||||
|
D6DEA0DE268400C300FE896A /* ConfirmLoadMoreTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DEA0DC268400C300FE896A /* ConfirmLoadMoreTableViewCell.swift */; };
|
||||||
|
D6DEA0DF268400C300FE896A /* ConfirmLoadMoreTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6DEA0DD268400C300FE896A /* ConfirmLoadMoreTableViewCell.xib */; };
|
||||||
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */; };
|
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */; };
|
||||||
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
||||||
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
||||||
|
@ -478,7 +479,6 @@
|
||||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = "<group>"; };
|
D64D0AAC2128D88B005A6F37 /* LocalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalData.swift; sourceTree = "<group>"; };
|
||||||
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
|
D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = "<group>"; };
|
||||||
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
|
D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = "<group>"; };
|
||||||
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldsView.swift; sourceTree = "<group>"; };
|
|
||||||
D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = "<group>"; };
|
D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = "<group>"; };
|
||||||
D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvAttachmentView.swift; sourceTree = "<group>"; };
|
D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvAttachmentView.swift; sourceTree = "<group>"; };
|
||||||
D6531DEF246B867E000F9538 /* GifvAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvAttachmentViewController.swift; sourceTree = "<group>"; };
|
D6531DEF246B867E000F9538 /* GifvAttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvAttachmentViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -643,6 +643,8 @@
|
||||||
D6DD2A44273D6C5700386A6C /* GIFImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GIFImageView.swift; sourceTree = "<group>"; };
|
D6DD2A44273D6C5700386A6C /* GIFImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GIFImageView.swift; sourceTree = "<group>"; };
|
||||||
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
||||||
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
||||||
|
D6DEA0DC268400C300FE896A /* ConfirmLoadMoreTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmLoadMoreTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
|
D6DEA0DD268400C300FE896A /* ConfirmLoadMoreTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfirmLoadMoreTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipMO.swift; sourceTree = "<group>"; };
|
D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipMO.swift; sourceTree = "<group>"; };
|
||||||
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1059,7 +1061,6 @@
|
||||||
children = (
|
children = (
|
||||||
D6412B0A24B0D4C600F5412E /* ProfileHeaderView.xib */,
|
D6412B0A24B0D4C600F5412E /* ProfileHeaderView.xib */,
|
||||||
D6412B0C24B0D4CF00F5412E /* ProfileHeaderView.swift */,
|
D6412B0C24B0D4CF00F5412E /* ProfileHeaderView.swift */,
|
||||||
D651C5B32915B00400236EF6 /* ProfileFieldsView.swift */,
|
|
||||||
);
|
);
|
||||||
path = "Profile Header";
|
path = "Profile Header";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1447,6 +1448,8 @@
|
||||||
D6DEA0DB268400AF00FE896A /* Confirm Load More Cell */ = {
|
D6DEA0DB268400AF00FE896A /* Confirm Load More Cell */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D6DEA0DC268400C300FE896A /* ConfirmLoadMoreTableViewCell.swift */,
|
||||||
|
D6DEA0DD268400C300FE896A /* ConfirmLoadMoreTableViewCell.xib */,
|
||||||
D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */,
|
D61A45E528DC0F2F002BE511 /* ConfirmLoadMoreCollectionViewCell.swift */,
|
||||||
);
|
);
|
||||||
path = "Confirm Load More Cell";
|
path = "Confirm Load More Cell";
|
||||||
|
@ -1680,6 +1683,7 @@
|
||||||
D6F2E966249E8BFD005846BB /* IssueReporterViewController.xib in Resources */,
|
D6F2E966249E8BFD005846BB /* IssueReporterViewController.xib in Resources */,
|
||||||
D662AEF0263A3B880082A153 /* PollFinishedTableViewCell.xib in Resources */,
|
D662AEF0263A3B880082A153 /* PollFinishedTableViewCell.xib in Resources */,
|
||||||
D6A4DCCD2553667800D9DE31 /* FastAccountSwitcherViewController.xib in Resources */,
|
D6A4DCCD2553667800D9DE31 /* FastAccountSwitcherViewController.xib in Resources */,
|
||||||
|
D6DEA0DF268400C300FE896A /* ConfirmLoadMoreTableViewCell.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1770,6 +1774,7 @@
|
||||||
D60E2F292442372B005F8713 /* AccountMO.swift in Sources */,
|
D60E2F292442372B005F8713 /* AccountMO.swift in Sources */,
|
||||||
D6412B0324AFF6A600F5412E /* TabBarScrollableViewController.swift in Sources */,
|
D6412B0324AFF6A600F5412E /* TabBarScrollableViewController.swift in Sources */,
|
||||||
D6093FB725BE0CF3004811E6 /* TrendHistoryView.swift in Sources */,
|
D6093FB725BE0CF3004811E6 /* TrendHistoryView.swift in Sources */,
|
||||||
|
D6DEA0DE268400C300FE896A /* ConfirmLoadMoreTableViewCell.swift in Sources */,
|
||||||
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */,
|
D6EBF01723C55E0D00AE061B /* UISceneSession+MastodonController.swift in Sources */,
|
||||||
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */,
|
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */,
|
||||||
D68E525D24A3E8F00054355A /* SearchViewController.swift in Sources */,
|
D68E525D24A3E8F00054355A /* SearchViewController.swift in Sources */,
|
||||||
|
@ -1811,7 +1816,6 @@
|
||||||
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */,
|
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */,
|
||||||
D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */,
|
D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */,
|
||||||
D620483623D38075008A63EF /* ContentTextView.swift in Sources */,
|
D620483623D38075008A63EF /* ContentTextView.swift in Sources */,
|
||||||
D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */,
|
|
||||||
D6F2E965249E8BFD005846BB /* IssueReporterViewController.swift in Sources */,
|
D6F2E965249E8BFD005846BB /* IssueReporterViewController.swift in Sources */,
|
||||||
D6A57408255C53EC00674551 /* ComposeTextViewCaretScrolling.swift in Sources */,
|
D6A57408255C53EC00674551 /* ComposeTextViewCaretScrolling.swift in Sources */,
|
||||||
D6CA6A94249FADE700AD45C1 /* GalleryPlayerViewController.swift in Sources */,
|
D6CA6A94249FADE700AD45C1 /* GalleryPlayerViewController.swift in Sources */,
|
||||||
|
@ -2166,7 +2170,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2234,7 +2238,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
@ -2384,7 +2388,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2413,7 +2417,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
@ -2523,7 +2527,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
@ -2550,7 +2554,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 44;
|
CURRENT_PROJECT_VERSION = 43;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||||
|
|
|
@ -26,7 +26,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
||||||
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
||||||
context.automaticallyMergesChangesFromParent = true
|
context.automaticallyMergesChangesFromParent = true
|
||||||
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
|
||||||
return context
|
return context
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -34,7 +33,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
||||||
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
context.persistentStoreCoordinator = self.persistentStoreCoordinator
|
||||||
context.automaticallyMergesChangesFromParent = true
|
context.automaticallyMergesChangesFromParent = true
|
||||||
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
|
||||||
return context
|
return context
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -64,7 +62,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewContext.automaticallyMergesChangesFromParent = true
|
viewContext.automaticallyMergesChangesFromParent = true
|
||||||
viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: viewContext)
|
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: viewContext)
|
||||||
}
|
}
|
||||||
|
@ -75,27 +72,12 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
try context.save()
|
try context.save()
|
||||||
} catch let error as NSError {
|
} catch {
|
||||||
logger.error("Unable to save managed object context: \(String(describing: error), privacy: .public)")
|
logger.error("Unable to save managed object context: \(String(describing: error), privacy: .public)")
|
||||||
let crumb = Breadcrumb(level: .fatal, category: "PersistentStore")
|
let crumb = Breadcrumb(level: .fatal, category: "PersistentStore")
|
||||||
// note: NSDetailedErrorsKey == "NSDetailedErrorsKey" != "NSDetailedErrors"
|
crumb.message = String(describing: error)
|
||||||
if let detailed = error.userInfo["NSDetailedErrors"] as? [NSError] {
|
|
||||||
crumb.data = [
|
|
||||||
"errors": detailed.compactMap { error -> [String: Any?]? in
|
|
||||||
guard let object = error.userInfo[NSValidationObjectErrorKey] as? NSManagedObject else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
"entity": object.entity.name,
|
|
||||||
"key": error.userInfo[NSValidationKeyErrorKey],
|
|
||||||
"value": error.userInfo[NSValidationValueErrorKey],
|
|
||||||
"message": error.localizedDescription,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
fatalError("Unable to save managed object context: \(String(describing: error))")
|
fatalError("Unable to save managed object context")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ extension NSTextAttachment {
|
||||||
image.draw(in: CGRect(origin: .zero, size: imageSizeMatchingFontSize))
|
image.draw(in: CGRect(origin: .zero, size: imageSizeMatchingFontSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.init(image: attachmentImage)
|
self.init()
|
||||||
|
self.image = attachmentImage
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(emojiPlaceholderIn font: UIFont) {
|
convenience init(emojiPlaceholderIn font: UIFont) {
|
||||||
|
@ -30,6 +31,7 @@ extension NSTextAttachment {
|
||||||
// assumes emoji are mostly square
|
// assumes emoji are mostly square
|
||||||
let size = CGSize(width: adjustedCapHeight, height: adjustedCapHeight)
|
let size = CGSize(width: adjustedCapHeight, height: adjustedCapHeight)
|
||||||
let image = UIGraphicsImageRenderer(size: size).image { (_) in }
|
let image = UIGraphicsImageRenderer(size: size).image { (_) in }
|
||||||
self.init(image: image)
|
self.init()
|
||||||
|
self.image = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,11 @@ import Pachyderm
|
||||||
|
|
||||||
extension StatusState {
|
extension StatusState {
|
||||||
|
|
||||||
func resolveFor(status: StatusMO, height: CGFloat) {
|
func resolveFor(status: StatusMO, text: String?) {
|
||||||
let longEnoughToCollapse: Bool
|
let longEnoughToCollapse: Bool
|
||||||
if Preferences.shared.collapseLongPosts,
|
if Preferences.shared.collapseLongPosts,
|
||||||
height > 500 {
|
let text = text,
|
||||||
|
text.count > 500 {
|
||||||
longEnoughToCollapse = true
|
longEnoughToCollapse = true
|
||||||
} else {
|
} else {
|
||||||
longEnoughToCollapse = false
|
longEnoughToCollapse = false
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
private let prevScrollOffsetBeforeScrollToTopKey = UnsafeMutableRawPointer.allocate(byteCount: 0, alignment: 0)
|
private var prevScrollOffsetBeforeScrollToTopKey: Void = ()
|
||||||
|
|
||||||
extension UIScrollView {
|
extension UIScrollView {
|
||||||
private var prevScrollOffsetBeforeScrollToTop: CGFloat? {
|
private var prevScrollOffsetBeforeScrollToTop: CGFloat? {
|
||||||
get {
|
get {
|
||||||
if let v = (objc_getAssociatedObject(self, prevScrollOffsetBeforeScrollToTopKey) as? NSNumber)?.doubleValue {
|
if let v = (objc_getAssociatedObject(self, &prevScrollOffsetBeforeScrollToTopKey) as? NSNumber)?.doubleValue {
|
||||||
return CGFloat(v)
|
return CGFloat(v)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -21,9 +21,9 @@ extension UIScrollView {
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if let newValue {
|
if let newValue {
|
||||||
objc_setAssociatedObject(self, prevScrollOffsetBeforeScrollToTopKey, NSNumber(value: newValue), .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
objc_setAssociatedObject(self, &prevScrollOffsetBeforeScrollToTopKey, NSNumber(value: newValue), .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||||
} else {
|
} else {
|
||||||
objc_setAssociatedObject(self, prevScrollOffsetBeforeScrollToTopKey, nil, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
objc_setAssociatedObject(self, &prevScrollOffsetBeforeScrollToTopKey, nil, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,18 +64,3 @@ extension Status.Visibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Status.Visibility: Comparable {
|
|
||||||
public static func < (lhs: Pachyderm.Status.Visibility, rhs: Pachyderm.Status.Visibility) -> Bool {
|
|
||||||
switch (lhs, rhs) {
|
|
||||||
case (.direct, .public), (.private, .public), (.unlisted, .public):
|
|
||||||
return true
|
|
||||||
case (.direct, .unlisted), (.private, .unlisted):
|
|
||||||
return true
|
|
||||||
case (.direct, .private):
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -187,14 +187,14 @@ extension MastodonController {
|
||||||
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil) -> Draft {
|
func createDraft(inReplyToID: String? = nil, mentioningAcct: String? = nil) -> Draft {
|
||||||
var acctsToMention = [String]()
|
var acctsToMention = [String]()
|
||||||
|
|
||||||
var visibility = inReplyToID != nil ? Preferences.shared.defaultReplyVisibility.resolved : Preferences.shared.defaultPostVisibility
|
var visibility = Preferences.shared.defaultPostVisibility
|
||||||
var contentWarning = ""
|
var contentWarning = ""
|
||||||
|
|
||||||
if let inReplyToID = inReplyToID,
|
if let inReplyToID = inReplyToID,
|
||||||
let inReplyTo = persistentContainer.status(for: inReplyToID) {
|
let inReplyTo = persistentContainer.status(for: inReplyToID) {
|
||||||
acctsToMention.append(inReplyTo.account.acct)
|
acctsToMention.append(inReplyTo.account.acct)
|
||||||
acctsToMention.append(contentsOf: inReplyTo.mentions.map(\.acct))
|
acctsToMention.append(contentsOf: inReplyTo.mentions.map(\.acct))
|
||||||
visibility = min(visibility, inReplyTo.visibility)
|
visibility = inReplyTo.visibility
|
||||||
|
|
||||||
if !inReplyTo.spoilerText.isEmpty {
|
if !inReplyTo.spoilerText.isEmpty {
|
||||||
switch Preferences.shared.contentWarningCopyMode {
|
switch Preferences.shared.contentWarningCopyMode {
|
||||||
|
|
|
@ -45,14 +45,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
self.hideActionsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .hideActionsInTimeline) ?? false
|
self.hideActionsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .hideActionsInTimeline) ?? false
|
||||||
|
|
||||||
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
|
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
|
||||||
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
|
|
||||||
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
|
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
|
||||||
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
||||||
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
||||||
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
|
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
|
||||||
|
|
||||||
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
|
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
|
||||||
self.blurMediaBehindContentWarning = try container.decodeIfPresent(Bool.self, forKey: .blurMediaBehindContentWarning) ?? true
|
|
||||||
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
||||||
|
|
||||||
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
||||||
|
@ -86,14 +84,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
try container.encode(hideActionsInTimeline, forKey: .hideActionsInTimeline)
|
try container.encode(hideActionsInTimeline, forKey: .hideActionsInTimeline)
|
||||||
|
|
||||||
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
|
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
|
||||||
try container.encode(defaultReplyVisibility, forKey: .defaultReplyVisibility)
|
|
||||||
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
|
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
|
||||||
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
|
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
|
||||||
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
|
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
|
||||||
try container.encode(mentionReblogger, forKey: .mentionReblogger)
|
try container.encode(mentionReblogger, forKey: .mentionReblogger)
|
||||||
|
|
||||||
try container.encode(blurAllMedia, forKey: .blurAllMedia)
|
try container.encode(blurAllMedia, forKey: .blurAllMedia)
|
||||||
try container.encode(blurMediaBehindContentWarning, forKey: .blurMediaBehindContentWarning)
|
|
||||||
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
||||||
|
|
||||||
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
||||||
|
@ -126,21 +122,13 @@ class Preferences: Codable, ObservableObject {
|
||||||
|
|
||||||
// MARK: Composing
|
// MARK: Composing
|
||||||
@Published var defaultPostVisibility = Status.Visibility.public
|
@Published var defaultPostVisibility = Status.Visibility.public
|
||||||
@Published var defaultReplyVisibility = ReplyVisibility.sameAsPost
|
|
||||||
@Published var automaticallySaveDrafts = true
|
@Published var automaticallySaveDrafts = true
|
||||||
@Published var requireAttachmentDescriptions = false
|
@Published var requireAttachmentDescriptions = false
|
||||||
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
||||||
@Published var mentionReblogger = false
|
@Published var mentionReblogger = false
|
||||||
|
|
||||||
// MARK: Media
|
// MARK: Media
|
||||||
@Published var blurAllMedia = false {
|
@Published var blurAllMedia = false
|
||||||
didSet {
|
|
||||||
if blurAllMedia {
|
|
||||||
blurMediaBehindContentWarning = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Published var blurMediaBehindContentWarning = true
|
|
||||||
@Published var automaticallyPlayGifs = true
|
@Published var automaticallyPlayGifs = true
|
||||||
|
|
||||||
// MARK: Behavior
|
// MARK: Behavior
|
||||||
|
@ -176,14 +164,12 @@ class Preferences: Codable, ObservableObject {
|
||||||
case hideActionsInTimeline
|
case hideActionsInTimeline
|
||||||
|
|
||||||
case defaultPostVisibility
|
case defaultPostVisibility
|
||||||
case defaultReplyVisibility
|
|
||||||
case automaticallySaveDrafts
|
case automaticallySaveDrafts
|
||||||
case requireAttachmentDescriptions
|
case requireAttachmentDescriptions
|
||||||
case contentWarningCopyMode
|
case contentWarningCopyMode
|
||||||
case mentionReblogger
|
case mentionReblogger
|
||||||
|
|
||||||
case blurAllMedia
|
case blurAllMedia
|
||||||
case blurMediaBehindContentWarning
|
|
||||||
case automaticallyPlayGifs
|
case automaticallyPlayGifs
|
||||||
|
|
||||||
case openLinksInApps
|
case openLinksInApps
|
||||||
|
@ -208,40 +194,4 @@ class Preferences: Codable, ObservableObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Preferences {
|
|
||||||
enum ReplyVisibility: Codable, Hashable, CaseIterable {
|
|
||||||
case sameAsPost
|
|
||||||
case visibility(Status.Visibility)
|
|
||||||
|
|
||||||
static var allCases: [Preferences.ReplyVisibility] = [.sameAsPost] + Status.Visibility.allCases.map { .visibility($0) }
|
|
||||||
|
|
||||||
var resolved: Status.Visibility {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return Preferences.shared.defaultPostVisibility
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var displayName: String {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return "Same as Default"
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.displayName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageName: String? {
|
|
||||||
switch self {
|
|
||||||
case .sameAsPost:
|
|
||||||
return nil
|
|
||||||
case .visibility(let vis):
|
|
||||||
return vis.imageName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UIUserInterfaceStyle: Codable {}
|
extension UIUserInterfaceStyle: Codable {}
|
||||||
|
|
|
@ -49,6 +49,7 @@ struct ComposeAttachmentRow: View {
|
||||||
ComposeTextView(text: $attachment.attachmentDescription, placeholder: Text("Describe for the visually impaired…"), minHeight: 80)
|
ComposeTextView(text: $attachment.attachmentDescription, placeholder: Text("Describe for the visually impaired…"), minHeight: 80)
|
||||||
.heightDidChange(self.heightChanged)
|
.heightDidChange(self.heightChanged)
|
||||||
.backgroundColor(.clear)
|
.backgroundColor(.clear)
|
||||||
|
.fontSize(17)
|
||||||
|
|
||||||
case .recognizingText:
|
case .recognizingText:
|
||||||
ProgressView()
|
ProgressView()
|
||||||
|
|
|
@ -66,11 +66,11 @@ struct ComposeAutocompleteMentionsView: View {
|
||||||
.cornerRadius(preferences.avatarStyle.cornerRadiusFraction * 30)
|
.cornerRadius(preferences.avatarStyle.cornerRadiusFraction * 30)
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
AccountDisplayNameLabel(account: account.value, textStyle: .subheadline, emojiSize: 14)
|
AccountDisplayNameLabel(account: account.value, fontSize: 14)
|
||||||
.foregroundColor(Color(UIColor.label))
|
.foregroundColor(Color(UIColor.label))
|
||||||
|
|
||||||
Text(verbatim: "@\(account.value.acct)")
|
Text(verbatim: "@\(account.value.acct)")
|
||||||
.font(.caption)
|
.font(.system(size: 12))
|
||||||
.foregroundColor(Color(UIColor.label))
|
.foregroundColor(Color(UIColor.label))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,6 @@ struct ComposeAutocompleteEmojisView: View {
|
||||||
|
|
||||||
@State var expanded = false
|
@State var expanded = false
|
||||||
@State private var emojis: [Emoji] = []
|
@State private var emojis: [Emoji] = []
|
||||||
@ScaledMetric private var emojiSize = 30
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
// When exapnded, the toggle button should be at the top. When collapsed, it should be centered.
|
// When exapnded, the toggle button should be at the top. When collapsed, it should be centered.
|
||||||
|
@ -213,13 +212,13 @@ struct ComposeAutocompleteEmojisView: View {
|
||||||
|
|
||||||
private var verticalGrid: some View {
|
private var verticalGrid: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: emojiSize), spacing: 4)]) {
|
LazyVGrid(columns: [GridItem(.adaptive(minimum: 30), spacing: 4)]) {
|
||||||
ForEach(emojis, id: \.shortcode) { (emoji) in
|
ForEach(emojis, id: \.shortcode) { (emoji) in
|
||||||
Button {
|
Button {
|
||||||
uiState.currentInput?.autocomplete(with: ":\(emoji.shortcode):")
|
uiState.currentInput?.autocomplete(with: ":\(emoji.shortcode):")
|
||||||
} label: {
|
} label: {
|
||||||
CustomEmojiImageView(emoji: emoji)
|
CustomEmojiImageView(emoji: emoji)
|
||||||
.frame(height: emojiSize)
|
.frame(height: 30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,19 +236,19 @@ struct ComposeAutocompleteEmojisView: View {
|
||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
CustomEmojiImageView(emoji: emoji)
|
CustomEmojiImageView(emoji: emoji)
|
||||||
.frame(height: emojiSize)
|
.frame(height: 30)
|
||||||
Text(verbatim: ":\(emoji.shortcode):")
|
Text(verbatim: ":\(emoji.shortcode):")
|
||||||
.foregroundColor(Color(UIColor.label))
|
.foregroundColor(Color(UIColor.label))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(height: emojiSize)
|
.frame(height: 30)
|
||||||
}
|
}
|
||||||
.animation(.linear(duration: 0.2), value: emojis)
|
.animation(.linear(duration: 0.2), value: emojis)
|
||||||
|
|
||||||
Spacer(minLength: emojiSize)
|
Spacer(minLength: 30)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
.frame(height: emojiSize + 16)
|
.frame(height: 46)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ struct ComposeCurrentAccount: View {
|
||||||
if let id = account?.id,
|
if let id = account?.id,
|
||||||
let account = mastodonController.persistentContainer.account(for: id) {
|
let account = mastodonController.persistentContainer.account(for: id) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
AccountDisplayNameLabel(account: account, textStyle: .title2, emojiSize: 24)
|
AccountDisplayNameLabel(account: account, fontSize: 20)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
|
|
||||||
Text(verbatim: "@\(account.acct)")
|
Text(verbatim: "@\(account.acct)")
|
||||||
.font(.body.weight(.light))
|
.font(.system(size: 17, weight: .light))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,30 +14,6 @@ protocol ComposeDrawingViewControllerDelegate: AnyObject {
|
||||||
func composeDrawingViewController(_ drawingController: ComposeDrawingViewController, saveDrawing drawing: PKDrawing)
|
func composeDrawingViewController(_ drawingController: ComposeDrawingViewController, saveDrawing drawing: PKDrawing)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComposeDrawingNavigationController: UINavigationController {
|
|
||||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
|
||||||
.darkContent
|
|
||||||
}
|
|
||||||
|
|
||||||
init(editing initialDrawing: PKDrawing, delegate: ComposeDrawingViewControllerDelegate) {
|
|
||||||
let vc = ComposeDrawingViewController(editing: initialDrawing)
|
|
||||||
vc.delegate = delegate
|
|
||||||
super.init(rootViewController: vc)
|
|
||||||
|
|
||||||
modalPresentationStyle = .fullScreen
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
overrideUserInterfaceStyle = .light
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComposeDrawingViewController: UIViewController {
|
class ComposeDrawingViewController: UIViewController {
|
||||||
|
|
||||||
weak var delegate: ComposeDrawingViewControllerDelegate?
|
weak var delegate: ComposeDrawingViewControllerDelegate?
|
||||||
|
@ -87,8 +63,7 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
canvasView.drawingPolicy = .anyInput
|
canvasView.drawingPolicy = .anyInput
|
||||||
canvasView.minimumZoomScale = 0.5
|
canvasView.minimumZoomScale = 0.5
|
||||||
canvasView.maximumZoomScale = 2
|
canvasView.maximumZoomScale = 2
|
||||||
canvasView.backgroundColor = .white
|
canvasView.backgroundColor = .systemBackground
|
||||||
canvasView.overrideUserInterfaceStyle = .light
|
|
||||||
canvasView.translatesAutoresizingMaskIntoConstraints = false
|
canvasView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(canvasView)
|
view.addSubview(canvasView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
|
@ -99,7 +74,6 @@ class ComposeDrawingViewController: UIViewController {
|
||||||
])
|
])
|
||||||
|
|
||||||
toolPicker = PKToolPicker()
|
toolPicker = PKToolPicker()
|
||||||
toolPicker.overrideUserInterfaceStyle = .light
|
|
||||||
toolPicker.setVisible(true, forFirstResponder: canvasView)
|
toolPicker.setVisible(true, forFirstResponder: canvasView)
|
||||||
toolPicker.addObserver(canvasView)
|
toolPicker.addObserver(canvasView)
|
||||||
toolPicker.addObserver(self)
|
toolPicker.addObserver(self)
|
||||||
|
|
|
@ -46,13 +46,12 @@ struct ComposeEmojiTextField: UIViewRepresentable {
|
||||||
|
|
||||||
view.placeholder = placeholder
|
view.placeholder = placeholder
|
||||||
view.borderStyle = .roundedRect
|
view.borderStyle = .roundedRect
|
||||||
view.font = .preferredFont(forTextStyle: .body)
|
|
||||||
view.adjustsFontForContentSizeCategory = true
|
|
||||||
view.backgroundColor = backgroundColor
|
|
||||||
|
|
||||||
view.delegate = context.coordinator
|
view.delegate = context.coordinator
|
||||||
view.addTarget(context.coordinator, action: #selector(Coordinator.didChange(_:)), for: .editingChanged)
|
view.addTarget(context.coordinator, action: #selector(Coordinator.didChange(_:)), for: .editingChanged)
|
||||||
|
|
||||||
|
view.backgroundColor = backgroundColor
|
||||||
|
|
||||||
// otherwise when the text gets too wide it starts expanding the ComposeView
|
// otherwise when the text gets too wide it starts expanding the ComposeView
|
||||||
view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
|
||||||
|
|
|
@ -360,7 +360,11 @@ extension ComposeHostingController: ComposeUIStateDelegate {
|
||||||
drawing = PKDrawing()
|
drawing = PKDrawing()
|
||||||
}
|
}
|
||||||
|
|
||||||
present(ComposeDrawingNavigationController(editing: drawing, delegate: self), animated: true)
|
let drawingVC = ComposeDrawingViewController(editing: drawing)
|
||||||
|
drawingVC.delegate = self
|
||||||
|
let nav = UINavigationController(rootViewController: drawingVC)
|
||||||
|
nav.modalPresentationStyle = .fullScreen
|
||||||
|
present(nav, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct ComposeReplyView: View {
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
HStack {
|
HStack {
|
||||||
AccountDisplayNameLabel(account: status.account, textStyle: .body, emojiSize: 17)
|
AccountDisplayNameLabel(account: status.account, fontSize: 17)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.layoutPriority(1)
|
.layoutPriority(1)
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ struct ComposeReplyView: View {
|
||||||
.frame(height: contentHeight ?? 0)
|
.frame(height: contentHeight ?? 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(minHeight: 50, alignment: .top)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func replyAvatarImage(geometry: GeometryProxy) -> some View {
|
private func replyAvatarImage(geometry: GeometryProxy) -> some View {
|
||||||
|
@ -64,7 +63,7 @@ struct ComposeReplyView: View {
|
||||||
offset = max(offset, 0)
|
offset = max(offset, 0)
|
||||||
|
|
||||||
// subtract 50, because we care about where the bottom of the view is but the offset is relative to the top of the view
|
// subtract 50, because we care about where the bottom of the view is but the offset is relative to the top of the view
|
||||||
let maxOffset = max((contentHeight ?? 0) + (displayNameHeight ?? 0) - 50, 0)
|
let maxOffset = (contentHeight ?? 0) + (displayNameHeight ?? 0) - 50
|
||||||
|
|
||||||
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
|
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
|
||||||
offset = min(offset, maxOffset)
|
offset = min(offset, maxOffset)
|
||||||
|
|
|
@ -15,6 +15,7 @@ struct ComposeTextView: View {
|
||||||
|
|
||||||
private var heightDidChange: ((CGFloat) -> Void)?
|
private var heightDidChange: ((CGFloat) -> Void)?
|
||||||
private var backgroundColor = UIColor.secondarySystemBackground
|
private var backgroundColor = UIColor.secondarySystemBackground
|
||||||
|
private var fontSize: CGFloat = 20
|
||||||
|
|
||||||
@State private var height: CGFloat?
|
@State private var height: CGFloat?
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ struct ComposeTextView: View {
|
||||||
|
|
||||||
if text.isEmpty, let placeholder = placeholder {
|
if text.isEmpty, let placeholder = placeholder {
|
||||||
placeholder
|
placeholder
|
||||||
.font(.body)
|
.font(.system(size: fontSize))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.offset(x: 4, y: 8)
|
.offset(x: 4, y: 8)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +39,7 @@ struct ComposeTextView: View {
|
||||||
WrappedTextView(
|
WrappedTextView(
|
||||||
text: $text,
|
text: $text,
|
||||||
textDidChange: self.textDidChange,
|
textDidChange: self.textDidChange,
|
||||||
font: .preferredFont(forTextStyle: .body)
|
font: .systemFont(ofSize: fontSize)
|
||||||
)
|
)
|
||||||
.frame(height: height ?? minHeight)
|
.frame(height: height ?? minHeight)
|
||||||
}
|
}
|
||||||
|
@ -60,6 +61,12 @@ struct ComposeTextView: View {
|
||||||
copy.backgroundColor = color
|
copy.backgroundColor = color
|
||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fontSize(_ size: CGFloat) -> Self {
|
||||||
|
var copy = self
|
||||||
|
copy.fontSize = size
|
||||||
|
return copy
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WrappedTextView: UIViewRepresentable {
|
struct WrappedTextView: UIViewRepresentable {
|
||||||
|
@ -75,7 +82,6 @@ struct WrappedTextView: UIViewRepresentable {
|
||||||
textView.isEditable = true
|
textView.isEditable = true
|
||||||
textView.backgroundColor = .clear
|
textView.backgroundColor = .clear
|
||||||
textView.font = font
|
textView.font = font
|
||||||
textView.adjustsFontForContentSizeCategory = true
|
|
||||||
textView.textContainer.lineBreakMode = .byWordWrapping
|
textView.textContainer.lineBreakMode = .byWordWrapping
|
||||||
return textView
|
return textView
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ struct MainComposeTextView: View {
|
||||||
@State private var height: CGFloat?
|
@State private var height: CGFloat?
|
||||||
@State private var becomeFirstResponder: Bool = false
|
@State private var becomeFirstResponder: Bool = false
|
||||||
@State private var hasFirstAppeared = false
|
@State private var hasFirstAppeared = false
|
||||||
@ScaledMetric private var fontSize = 20
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .topLeading) {
|
||||||
|
@ -41,7 +40,7 @@ struct MainComposeTextView: View {
|
||||||
|
|
||||||
if draft.text.isEmpty {
|
if draft.text.isEmpty {
|
||||||
placeholder
|
placeholder
|
||||||
.font(.system(size: fontSize))
|
.font(.system(size: 20))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.offset(x: 4, y: 8)
|
.offset(x: 4, y: 8)
|
||||||
}
|
}
|
||||||
|
@ -80,8 +79,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
|
||||||
textView.delegate = context.coordinator
|
textView.delegate = context.coordinator
|
||||||
textView.isEditable = true
|
textView.isEditable = true
|
||||||
textView.backgroundColor = .clear
|
textView.backgroundColor = .clear
|
||||||
textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 20))
|
textView.font = .systemFont(ofSize: 20)
|
||||||
textView.adjustsFontForContentSizeCategory = true
|
|
||||||
textView.textContainer.lineBreakMode = .byWordWrapping
|
textView.textContainer.lineBreakMode = .byWordWrapping
|
||||||
context.coordinator.textView = textView
|
context.coordinator.textView = textView
|
||||||
return textView
|
return textView
|
||||||
|
|
|
@ -29,11 +29,7 @@ class FeaturedProfileCollectionViewCell: UICollectionViewCell {
|
||||||
avatarContainerView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarContainerView)
|
avatarContainerView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarContainerView)
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||||
|
|
||||||
displayNameLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold))
|
noteTextView.defaultFont = .systemFont(ofSize: 16)
|
||||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
noteTextView.defaultFont = .preferredFont(forTextStyle: .body)
|
|
||||||
noteTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
noteTextView.textContainer.lineBreakMode = .byTruncatingTail
|
noteTextView.textContainer.lineBreakMode = .byTruncatingTail
|
||||||
noteTextView.textContainerInset = UIEdgeInsets(top: 16, left: 4, bottom: 16, right: 4)
|
noteTextView.textContainerInset = UIEdgeInsets(top: 16, left: 4, bottom: 16, right: 4)
|
||||||
|
|
||||||
|
|
|
@ -9,164 +9,78 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
|
||||||
class TrendingStatusesViewController: UIViewController {
|
class TrendingStatusesViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
weak var mastodonController: MastodonController!
|
weak var mastodonController: MastodonController!
|
||||||
|
|
||||||
private var collectionView: UICollectionView {
|
private var dataSource: UITableViewDiffableDataSource<Section, Item>!
|
||||||
view as! UICollectionView
|
|
||||||
}
|
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
|
||||||
|
|
||||||
init(mastodonController: MastodonController) {
|
init(mastodonController: MastodonController) {
|
||||||
self.mastodonController = mastodonController
|
self.mastodonController = mastodonController
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(style: .grouped)
|
||||||
|
|
||||||
title = NSLocalizedString("Trending Posts", comment: "trending posts screen title")
|
dragEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadView() {
|
override func viewDidLoad() {
|
||||||
var config = UICollectionLayoutListConfiguration(appearance: .plain)
|
super.viewDidLoad()
|
||||||
config.leadingSwipeActionsConfigurationProvider = { [unowned self] in
|
|
||||||
(collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.leadingSwipeActions()
|
|
||||||
}
|
|
||||||
config.trailingSwipeActionsConfigurationProvider = { [unowned self] in
|
|
||||||
(collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.trailingSwipeActions()
|
|
||||||
}
|
|
||||||
config.itemSeparatorHandler = { [unowned self] indexPath, sectionSeparatorConfiguration in
|
|
||||||
guard let item = self.dataSource.itemIdentifier(for: indexPath) else {
|
|
||||||
return sectionSeparatorConfiguration
|
|
||||||
}
|
|
||||||
var config = sectionSeparatorConfiguration
|
|
||||||
if item.hideSeparators {
|
|
||||||
config.topSeparatorVisibility = .hidden
|
|
||||||
config.bottomSeparatorVisibility = .hidden
|
|
||||||
}
|
|
||||||
if case .status(_, _) = item {
|
|
||||||
config.topSeparatorInsets = TimelineStatusCollectionViewCell.separatorInsets
|
|
||||||
config.bottomSeparatorInsets = TimelineStatusCollectionViewCell.separatorInsets
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
let layout = UICollectionViewCompositionalLayout.list(using: config)
|
|
||||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
|
||||||
collectionView.delegate = self
|
|
||||||
collectionView.dragDelegate = self
|
|
||||||
|
|
||||||
dataSource = createDataSource()
|
title = NSLocalizedString("Trending Posts", comment: "trending posts screen title")
|
||||||
}
|
|
||||||
|
|
||||||
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: "statusCell")
|
||||||
let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, (String, StatusState)> { [unowned self] cell, indexPath, item in
|
tableView.estimatedRowHeight = 144
|
||||||
|
|
||||||
|
dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as! TimelineStatusTableViewCell
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
cell.updateUI(statusID: item.0, state: item.1)
|
cell.updateUI(statusID: item.id, state: item.state)
|
||||||
}
|
return cell
|
||||||
let loadingCell = UICollectionView.CellRegistration<LoadingCollectionViewCell, Void> { cell, _, _ in
|
})
|
||||||
cell.indicator.startAnimating()
|
|
||||||
}
|
|
||||||
return UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
|
|
||||||
switch itemIdentifier {
|
|
||||||
case .status(id: let id, state: let state):
|
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: (id, state))
|
|
||||||
case .loadingIndicator:
|
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: loadingCell, for: indexPath, item: ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
let request = Client.getTrendingStatuses()
|
||||||
snapshot.appendSections([.statuses])
|
|
||||||
snapshot.appendItems([.loadingIndicator])
|
|
||||||
dataSource.apply(snapshot, animatingDifferences: false)
|
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
await loadTrendingStatuses()
|
guard let (statuses, _) = try? await mastodonController.run(request) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mastodonController.persistentContainer.addAll(statuses: statuses) {
|
||||||
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
|
snapshot.appendSections([.statuses])
|
||||||
|
snapshot.appendItems(statuses.map { Item(id: $0.id, state: .unknown) })
|
||||||
|
self.dataSource.apply(snapshot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadTrendingStatuses() async {
|
// MARK: - Table View Delegate
|
||||||
let statuses: [Status]
|
|
||||||
do {
|
|
||||||
statuses = try await mastodonController.run(Client.getTrendingStatuses()).0
|
|
||||||
} catch {
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
|
||||||
await dataSource.apply(snapshot)
|
|
||||||
let config = ToastConfiguration(from: error, with: "Loading Trending Posts", in: self) { toast in
|
|
||||||
toast.dismissToast(animated: true)
|
|
||||||
await self.loadTrendingStatuses()
|
|
||||||
}
|
|
||||||
showToast(configuration: config, animated: true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses)
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
|
||||||
snapshot.appendSections([.statuses])
|
|
||||||
snapshot.appendItems(statuses.map { .status(id: $0.id, state: .unknown) })
|
|
||||||
await dataSource.apply(snapshot)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrendingStatusesViewController {
|
extension TrendingStatusesViewController {
|
||||||
enum Section {
|
enum Section {
|
||||||
case statuses
|
case statuses
|
||||||
}
|
}
|
||||||
enum Item: Hashable {
|
struct Item: Hashable {
|
||||||
case status(id: String, state: StatusState)
|
let id: String
|
||||||
case loadingIndicator
|
let state: StatusState
|
||||||
|
|
||||||
var hideSeparators: Bool {
|
static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
if case .loadingIndicator = self {
|
return lhs.id == rhs.id
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSelectable: Bool {
|
func hash(into hasher: inout Hasher) {
|
||||||
if case .status(id: _, state: _) = self {
|
hasher.combine(id)
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrendingStatusesViewController: UICollectionViewDelegate {
|
|
||||||
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
|
||||||
return dataSource.itemIdentifier(for: indexPath)?.isSelectable ?? false
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
||||||
guard case .status(id: let id, state: let state) = dataSource.itemIdentifier(for: indexPath) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
selected(status: id, state: state.copy())
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
|
||||||
return (collectionView.cellForItem(at: indexPath) as? TimelineStatusCollectionViewCell)?.contextMenuConfiguration()
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
|
||||||
MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrendingStatusesViewController: UICollectionViewDragDelegate {
|
|
||||||
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
|
||||||
(collectionView.cellForItem(at: indexPath) as? TimelineStatusCollectionViewCell)?.dragItemsForBeginning(session: session) ?? []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrendingStatusesViewController: TuskerNavigationDelegate {
|
extension TrendingStatusesViewController: TuskerNavigationDelegate {
|
||||||
var apiController: MastodonController! { mastodonController }
|
var apiController: MastodonController! { mastodonController }
|
||||||
}
|
}
|
||||||
|
@ -177,19 +91,9 @@ extension TrendingStatusesViewController: ToastableViewController {
|
||||||
extension TrendingStatusesViewController: MenuActionProvider {
|
extension TrendingStatusesViewController: MenuActionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TrendingStatusesViewController: StatusCollectionViewCellDelegate {
|
extension TrendingStatusesViewController: StatusTableViewCellDelegate {
|
||||||
func statusCellNeedsReconfigure(_ cell: StatusCollectionViewCell, animated: Bool, completion: (() -> Void)?) {
|
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
|
||||||
if let indexPath = collectionView.indexPath(for: cell) {
|
tableView.beginUpdates()
|
||||||
var snapshot = dataSource.snapshot()
|
tableView.endUpdates()
|
||||||
snapshot.reconfigureItems([dataSource.itemIdentifier(for: indexPath)!])
|
|
||||||
dataSource.apply(snapshot, animatingDifferences: animated, completion: completion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TrendingStatusesViewController: StatusBarTappableViewController {
|
|
||||||
func handleStatusBarTapped(xPosition: CGFloat) -> StatusBarTapActionResult {
|
|
||||||
collectionView.scrollToTop()
|
|
||||||
return .stop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -42,7 +42,6 @@
|
||||||
<constraint firstAttribute="height" constant="20" id="4tF-oL-qXT"/>
|
<constraint firstAttribute="height" constant="20" id="4tF-oL-qXT"/>
|
||||||
<constraint firstAttribute="width" constant="20" id="zWx-jJ-dBj"/>
|
<constraint firstAttribute="width" constant="20" id="zWx-jJ-dBj"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
|
||||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<state key="normal" image="square.and.arrow.up" catalog="system"/>
|
<state key="normal" image="square.and.arrow.up" catalog="system"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -55,7 +54,7 @@
|
||||||
<constraint firstAttribute="width" constant="20" id="eg0-hN-rda"/>
|
<constraint firstAttribute="width" constant="20" id="eg0-hN-rda"/>
|
||||||
<constraint firstAttribute="height" constant="20" id="fmA-pI-8WB"/>
|
<constraint firstAttribute="height" constant="20" id="fmA-pI-8WB"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<state key="normal" image="xmark" catalog="system"/>
|
<state key="normal" image="xmark" catalog="system"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -76,9 +75,9 @@
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rPa-Zu-T6g">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rPa-Zu-T6g">
|
||||||
<rect key="frame" x="0.0" y="622.5" width="375" height="44.5"/>
|
<rect key="frame" x="0.0" y="622.5" width="375" height="44.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eo5-fc-RV8">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eo5-fc-RV8">
|
||||||
<rect key="frame" x="16" y="8" width="343" height="20.5"/>
|
<rect key="frame" x="16" y="8" width="343" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -14,7 +14,6 @@ struct ComposingPrefsView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
visibilitySection
|
|
||||||
composingSection
|
composingSection
|
||||||
replyingSection
|
replyingSection
|
||||||
}
|
}
|
||||||
|
@ -22,9 +21,9 @@ struct ComposingPrefsView: View {
|
||||||
.navigationBarTitle("Composing")
|
.navigationBarTitle("Composing")
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibilitySection: some View {
|
var composingSection: some View {
|
||||||
Section {
|
Section(header: Text("Composing")) {
|
||||||
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Visibility")) {
|
Picker(selection: $preferences.defaultPostVisibility, label: Text("Default Post Visibility")) {
|
||||||
ForEach(Status.Visibility.allCases, id: \.self) { visibility in
|
ForEach(Status.Visibility.allCases, id: \.self) { visibility in
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: visibility.imageName)
|
Image(systemName: visibility.imageName)
|
||||||
|
@ -34,26 +33,6 @@ struct ComposingPrefsView: View {
|
||||||
}//.navigationBarTitle("Default Post Visibility")
|
}//.navigationBarTitle("Default Post Visibility")
|
||||||
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
// navbar title on the ForEach is currently incorrectly applied when the picker is not expanded, see FB6838291
|
||||||
}
|
}
|
||||||
Picker(selection: $preferences.defaultReplyVisibility, label: Text("Reply Visibility")) {
|
|
||||||
ForEach(Preferences.ReplyVisibility.allCases, id: \.self) { visibility in
|
|
||||||
HStack {
|
|
||||||
if let imageName = visibility.imageName {
|
|
||||||
Image(systemName: imageName)
|
|
||||||
}
|
|
||||||
Text(visibility.displayName)
|
|
||||||
}
|
|
||||||
.tag(visibility)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} header: {
|
|
||||||
Text("Visibility")
|
|
||||||
} footer: {
|
|
||||||
Text("When starting a reply, Tusker will use your preferred visibility or the visibility of the post to which you're replying, whichever is narrower.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var composingSection: some View {
|
|
||||||
Section(header: Text("Composing")) {
|
|
||||||
Toggle(isOn: $preferences.automaticallySaveDrafts) {
|
Toggle(isOn: $preferences.automaticallySaveDrafts) {
|
||||||
Text("Automatically Save Drafts")
|
Text("Automatically Save Drafts")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,6 @@ struct MediaPrefsView: View {
|
||||||
Toggle(isOn: $preferences.blurAllMedia) {
|
Toggle(isOn: $preferences.blurAllMedia) {
|
||||||
Text("Blur All Media")
|
Text("Blur All Media")
|
||||||
}
|
}
|
||||||
|
|
||||||
Toggle(isOn: $preferences.blurMediaBehindContentWarning) {
|
|
||||||
Text("Blur Media Behind Content Warning")
|
|
||||||
}
|
|
||||||
.disabled(preferences.blurAllMedia)
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
||||||
Text("Automatically Play GIFs")
|
Text("Automatically Play GIFs")
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,17 +222,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
||||||
}
|
}
|
||||||
|
|
||||||
var snapshot = dataSource.snapshot()
|
var snapshot = dataSource.snapshot()
|
||||||
let existingPinned = snapshot.itemIdentifiers(inSection: .pinned)
|
let items = statuses.map { Item.status(id: $0.id, state: .unknown, pinned: true) }
|
||||||
let items = statuses.map {
|
|
||||||
let item = Item.status(id: $0.id, state: .unknown, pinned: true)
|
|
||||||
// try to keep the existing status state
|
|
||||||
if let existing = existingPinned.first(where: { $0 == item }) {
|
|
||||||
return existing
|
|
||||||
} else {
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .pinned))
|
|
||||||
snapshot.appendItems(items, toSection: .pinned)
|
snapshot.appendItems(items, toSection: .pinned)
|
||||||
await apply(snapshot, animatingDifferences: true)
|
await apply(snapshot, animatingDifferences: true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,11 +185,21 @@ extension MenuActionProvider {
|
||||||
favImage = favImage.withTintColor(UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1), renderingMode: .alwaysOriginal)
|
favImage = favImage.withTintColor(UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1), renderingMode: .alwaysOriginal)
|
||||||
}
|
}
|
||||||
toggleableSection.insert(createAction(identifier: "favorite", title: favorited ? "Unfavorite" : "Favorite", image: favImage, handler: { [weak self] _ in
|
toggleableSection.insert(createAction(identifier: "favorite", title: favorited ? "Unfavorite" : "Favorite", image: favImage, handler: { [weak self] _ in
|
||||||
guard let self,
|
guard let self = self else { return }
|
||||||
let navigationDelegate = self.navigationDelegate else { return }
|
let request = (favorited ? Status.favourite : Status.unfavourite)(status.id)
|
||||||
Task { @MainActor in
|
self.mastodonController?.run(request, completion: { response in
|
||||||
await FavoriteService(status: status, mastodonController: mastodonController, presenter: navigationDelegate).toggleFavorite()
|
switch response {
|
||||||
}
|
case .success(let status, _):
|
||||||
|
self.mastodonController?.persistentContainer.addOrUpdate(status: status)
|
||||||
|
case .failure(let error):
|
||||||
|
if let toastable = self.toastableViewController {
|
||||||
|
let config = ToastConfiguration(from: error, with: "Error \(favorited ? "Unf" : "F")avoriting", in: toastable, retryAction: nil)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
toastable.showToast(configuration: config, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}), at: 0)
|
}), at: 0)
|
||||||
|
|
||||||
let reblogged = status.reblogged
|
let reblogged = status.reblogged
|
||||||
|
@ -198,11 +208,26 @@ extension MenuActionProvider {
|
||||||
reblogImage = reblogImage.withTintColor(UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1), renderingMode: .alwaysOriginal)
|
reblogImage = reblogImage.withTintColor(UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1), renderingMode: .alwaysOriginal)
|
||||||
}
|
}
|
||||||
toggleableSection.insert(createAction(identifier: "reblog", title: reblogged ? "Unreblog" : "Reblog", image: reblogImage, handler: { [weak self] _ in
|
toggleableSection.insert(createAction(identifier: "reblog", title: reblogged ? "Unreblog" : "Reblog", image: reblogImage, handler: { [weak self] _ in
|
||||||
guard let self,
|
guard let self = self else { return }
|
||||||
let navigationDelegate = self.navigationDelegate else { return }
|
let request: Request<Status>
|
||||||
Task { @MainActor in
|
if reblogged {
|
||||||
await ReblogService(status: status, mastodonController: mastodonController, presenter: navigationDelegate).toggleReblog()
|
request = Status.reblog(status.id)
|
||||||
|
} else {
|
||||||
|
request = Status.unreblog(status.id)
|
||||||
}
|
}
|
||||||
|
self.mastodonController?.run(request, completion: { response in
|
||||||
|
switch response {
|
||||||
|
case .success(let status, _):
|
||||||
|
self.mastodonController?.persistentContainer.addOrUpdate(status: status)
|
||||||
|
case .failure(let error):
|
||||||
|
if let toastable = self.toastableViewController {
|
||||||
|
let config = ToastConfiguration(from: error, with: "Error \(reblogged ? "Unr" : "R")eblogging", in: toastable, retryAction: nil)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
toastable.showToast(configuration: config, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}), at: 1)
|
}), at: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +362,7 @@ extension MenuActionProvider {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createAction(identifier: String, title: String, systemImageName: String?, handler: @escaping (UIAction) -> Void) -> UIAction {
|
private func createAction(identifier: String, title: String, systemImageName: String?, handler: @escaping UIActionHandler) -> UIAction {
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
if let name = systemImageName {
|
if let name = systemImageName {
|
||||||
image = UIImage(systemName: name)
|
image = UIImage(systemName: name)
|
||||||
|
|
|
@ -29,12 +29,6 @@ class AccountTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
avatarImageView.layer.masksToBounds = true
|
avatarImageView.layer.masksToBounds = true
|
||||||
|
|
||||||
usernameLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .light))
|
|
||||||
usernameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
noteLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15))
|
|
||||||
noteLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPrefrences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPrefrences), name: .preferencesChanged, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16092.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16082.1"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
@ -28,16 +26,16 @@
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Iif-9m-vM5">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="Iif-9m-vM5">
|
||||||
<rect key="frame" x="74" y="11" width="230" height="78"/>
|
<rect key="frame" x="74" y="11" width="230" height="78"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fhc-bZ-lkB" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fhc-bZ-lkB" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="230" height="20.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="230" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JMo-QH-1is">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JMo-QH-1is">
|
||||||
<rect key="frame" x="0.0" y="20.5" width="230" height="18"/>
|
<rect key="frame" x="0.0" y="20.5" width="230" height="18"/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
|
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Note" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bNO-qR-YEe" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Note" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bNO-qR-YEe" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
|
@ -68,9 +66,4 @@
|
||||||
<point key="canvasLocation" x="173.91304347826087" y="35.491071428571423"/>
|
<point key="canvasLocation" x="173.91304347826087" y="35.491071428571423"/>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
|
||||||
<systemColor name="secondaryLabelColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -14,22 +14,20 @@ private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options:
|
||||||
|
|
||||||
struct AccountDisplayNameLabel: View {
|
struct AccountDisplayNameLabel: View {
|
||||||
let account: any AccountProtocol
|
let account: any AccountProtocol
|
||||||
let textStyle: Font.TextStyle
|
let fontSize: Int
|
||||||
@ScaledMetric var emojiSize: CGFloat
|
|
||||||
@State var text: Text
|
@State var text: Text
|
||||||
@State var emojiRequests = [ImageCache.Request]()
|
@State var emojiRequests = [ImageCache.Request]()
|
||||||
|
|
||||||
init(account: any AccountProtocol, textStyle: Font.TextStyle, emojiSize: CGFloat) {
|
init(account: any AccountProtocol, fontSize: Int) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.textStyle = textStyle
|
self.fontSize = fontSize
|
||||||
self._emojiSize = ScaledMetric(wrappedValue: emojiSize, relativeTo: textStyle)
|
|
||||||
let name = account.displayName.isEmpty ? account.username : account.displayName
|
let name = account.displayName.isEmpty ? account.username : account.displayName
|
||||||
self._text = State(initialValue: Text(verbatim: name))
|
self._text = State(initialValue: Text(verbatim: name))
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
text
|
text
|
||||||
.font(.system(textStyle).weight(.semibold))
|
.font(.system(size: CGFloat(fontSize), weight: .semibold))
|
||||||
.onAppear(perform: self.loadEmojis)
|
.onAppear(perform: self.loadEmojis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +53,7 @@ struct AccountDisplayNameLabel: View {
|
||||||
defer { group.leave() }
|
defer { group.leave() }
|
||||||
guard let image = image else { return }
|
guard let image = image else { return }
|
||||||
|
|
||||||
let size = CGSize(width: emojiSize, height: emojiSize)
|
let size = CGSize(width: fontSize, height: fontSize)
|
||||||
let renderer = UIGraphicsImageRenderer(size: size)
|
let renderer = UIGraphicsImageRenderer(size: size)
|
||||||
let resized = renderer.image { (ctx) in
|
let resized = renderer.image { (ctx) in
|
||||||
image.draw(in: CGRect(origin: .zero, size: size))
|
image.draw(in: CGRect(origin: .zero, size: size))
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -24,9 +23,9 @@
|
||||||
<constraint firstAttribute="height" constant="64" id="ZhL-aE-TCF"/>
|
<constraint firstAttribute="height" constant="64" id="ZhL-aE-TCF"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Album Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fK1-aD-yvs">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Album Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fK1-aD-yvs">
|
||||||
<rect key="frame" x="96" y="30" width="216" height="20.5"/>
|
<rect key="frame" x="96" y="30" width="216" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -24,9 +23,9 @@
|
||||||
<constraint firstAttribute="width" constant="64" id="P7K-i4-Id7"/>
|
<constraint firstAttribute="width" constant="64" id="P7K-i4-Id7"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="All Photos" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pcI-Ow-ilI">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="All Photos" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pcI-Ow-ilI">
|
||||||
<rect key="frame" x="96" y="30" width="216" height="20.5"/>
|
<rect key="frame" x="96" y="30" width="216" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -236,9 +236,27 @@ class AttachmentsContainerView: UIView {
|
||||||
// Make sure accessibilityElements is set every time the UI is updated, otherwise it holds
|
// Make sure accessibilityElements is set every time the UI is updated, otherwise it holds
|
||||||
// on to strong references to the old set of attachment views
|
// on to strong references to the old set of attachment views
|
||||||
self.accessibilityElements = accessibilityElements
|
self.accessibilityElements = accessibilityElements
|
||||||
|
|
||||||
|
contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createAttachmentView(index: Int, hSize: RelativeSize, vSize: RelativeSize) -> AttachmentView {
|
private func createAttachmentView(index: Int, hSize: RelativeSize, vSize: RelativeSize) -> AttachmentView {
|
||||||
|
let width: CGFloat
|
||||||
|
switch hSize {
|
||||||
|
case .full:
|
||||||
|
width = bounds.width
|
||||||
|
case .half:
|
||||||
|
width = (bounds.width - 4) / 2
|
||||||
|
}
|
||||||
|
let height: CGFloat
|
||||||
|
switch vSize {
|
||||||
|
case .full:
|
||||||
|
height = bounds.height
|
||||||
|
case .half:
|
||||||
|
height = (bounds.height - 4) / 2
|
||||||
|
}
|
||||||
|
let size = CGSize(width: width, height: height)
|
||||||
|
|
||||||
let attachmentView = AttachmentView(attachment: attachments[index], index: index)
|
let attachmentView = AttachmentView(attachment: attachments[index], index: index)
|
||||||
attachmentView.delegate = delegate
|
attachmentView.delegate = delegate
|
||||||
attachmentView.translatesAutoresizingMaskIntoConstraints = false
|
attachmentView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -274,8 +292,6 @@ class AttachmentsContainerView: UIView {
|
||||||
let imageView = UIImageView(image: image)
|
let imageView = UIImageView(image: image)
|
||||||
imageView.translatesAutoresizingMaskIntoConstraints = false
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .preferredFont(forTextStyle: .body)
|
|
||||||
label.adjustsFontForContentSizeCategory = true
|
|
||||||
label.text = "Sensitive Content"
|
label.text = "Sensitive Content"
|
||||||
let stack = UIStackView(arrangedSubviews: [
|
let stack = UIStackView(arrangedSubviews: [
|
||||||
imageView,
|
imageView,
|
||||||
|
|
|
@ -86,30 +86,27 @@ extension BaseEmojiLabel {
|
||||||
func buildStringWithEmojisReplaced(usePlaceholders: Bool) -> NSAttributedString {
|
func buildStringWithEmojisReplaced(usePlaceholders: Bool) -> NSAttributedString {
|
||||||
let mutAttrString = NSMutableAttributedString(attributedString: attributedString)
|
let mutAttrString = NSMutableAttributedString(attributedString: attributedString)
|
||||||
|
|
||||||
|
// lock once for the entire loop, rather than lock/unlocking for each iteration to do the lookup
|
||||||
// OSAllocatedUnfairLock.withLock expects a @Sendable closure, so this warns about captures of non-sendable types (attribute dstrings, text checking results)
|
// OSAllocatedUnfairLock.withLock expects a @Sendable closure, so this warns about captures of non-sendable types (attribute dstrings, text checking results)
|
||||||
// even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878)
|
// even though the closures is invoked on the same thread that withLock is called, so it's unclear why it needs to be @Sendable (FB11494878)
|
||||||
// so, just ignore the warnings
|
// so, just ignore the warnings
|
||||||
let emojiAttachments = emojiImages.withLock {
|
emojiImages.withLock { emojiImages in
|
||||||
$0.mapValues { image in
|
// replaces the emojis starting from the end of the string as to not alter the indices of preceeding emojis
|
||||||
NSTextAttachment(emojiImage: image, in: self.emojiFont, with: self.emojiTextColor)
|
for match in matches.reversed() {
|
||||||
}
|
let shortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
||||||
}
|
let attachment: NSTextAttachment
|
||||||
let placeholder = usePlaceholders ? NSTextAttachment(emojiPlaceholderIn: self.emojiFont) : nil
|
|
||||||
|
|
||||||
// replaces the emojis starting from the end of the string as to not alter the indices of preceeding emojis
|
if let emojiImage = emojiImages[shortcode] {
|
||||||
for match in matches.reversed() {
|
attachment = NSTextAttachment(emojiImage: emojiImage, in: self.emojiFont, with: self.emojiTextColor)
|
||||||
let shortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
} else if usePlaceholders {
|
||||||
let attachment: NSTextAttachment
|
attachment = NSTextAttachment(emojiPlaceholderIn: self.emojiFont)
|
||||||
if let emoji = emojiAttachments[shortcode] {
|
} else {
|
||||||
attachment = emoji
|
continue
|
||||||
} else if usePlaceholders {
|
}
|
||||||
attachment = placeholder!
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachmentStr = NSAttributedString(attachment: attachment)
|
let attachmentStr = NSAttributedString(attachment: attachment)
|
||||||
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mutAttrString
|
return mutAttrString
|
||||||
|
|
|
@ -32,8 +32,6 @@ class ConfirmLoadMoreCollectionViewCell: UICollectionViewCell {
|
||||||
|
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.text = "Infinite scrolling is off. Do you want to keep going?"
|
label.text = "Infinite scrolling is off. Do you want to keep going?"
|
||||||
label.font = .preferredFont(forTextStyle: .body)
|
|
||||||
label.adjustsFontForContentSizeCategory = true
|
|
||||||
label.textColor = .secondaryLabel
|
label.textColor = .secondaryLabel
|
||||||
label.textAlignment = .natural
|
label.textAlignment = .natural
|
||||||
label.numberOfLines = 0
|
label.numberOfLines = 0
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// ConfirmLoadMoreTableViewCell.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/23/21.
|
||||||
|
// Copyright © 2021 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
protocol ConfirmLoadOlderTableViewCellDelegate: AnyObject {
|
||||||
|
func confirmLoadMore()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfirmLoadMoreTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
|
var confirmLoadMore: (() -> Void)?
|
||||||
|
|
||||||
|
@IBOutlet weak var confirmButton: UIButton!
|
||||||
|
|
||||||
|
private var isLoading = false
|
||||||
|
|
||||||
|
override func awakeFromNib() {
|
||||||
|
super.awakeFromNib()
|
||||||
|
|
||||||
|
var config = UIButton.Configuration.tinted()
|
||||||
|
config.title = "Load More"
|
||||||
|
config.showsActivityIndicator = false
|
||||||
|
config.imagePadding = 4
|
||||||
|
confirmButton.configuration = config
|
||||||
|
confirmButton.configurationUpdateHandler = { [unowned self] button in
|
||||||
|
button.configuration?.showsActivityIndicator = self.isLoading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
|
||||||
|
isLoading = false
|
||||||
|
confirmButton.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func loadMorePressed(_ sender: Any) {
|
||||||
|
confirmLoadMore?()
|
||||||
|
isLoading = true
|
||||||
|
confirmButton.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19115.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19107.5"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="105" id="KGk-i7-Jjw" customClass="ConfirmLoadMoreTableViewCell" customModule="Tusker" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="320" height="105"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="320" height="105"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="Rpx-45-c2n">
|
||||||
|
<rect key="frame" x="16" y="11" width="288" height="86"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Infinite scrolling is off. Do you want to keep going?" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9nv-Re-5sL">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="288" height="41"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NT9-ly-efr">
|
||||||
|
<rect key="frame" x="0.0" y="45" width="288" height="41"/>
|
||||||
|
<state key="normal" title="Button"/>
|
||||||
|
<buttonConfiguration key="configuration" style="tinted" title="Load More"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="loadMorePressed:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="Pgz-MB-icB"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="Rpx-45-c2n" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="YfZ-rr-Omf"/>
|
||||||
|
<constraint firstItem="Rpx-45-c2n" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="hhi-yX-Wa4"/>
|
||||||
|
<constraint firstAttribute="trailingMargin" secondItem="Rpx-45-c2n" secondAttribute="trailing" id="jI8-St-34M"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="Rpx-45-c2n" secondAttribute="bottom" constant="8" id="mQh-0l-Eo2"/>
|
||||||
|
</constraints>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="confirmButton" destination="NT9-ly-efr" id="Lja-th-LeH"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="131.8840579710145" y="150.33482142857142"/>
|
||||||
|
</tableViewCell>
|
||||||
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<systemColor name="secondaryLabelColor">
|
||||||
|
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</systemColor>
|
||||||
|
<systemColor name="secondarySystemBackgroundColor">
|
||||||
|
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</systemColor>
|
||||||
|
</resources>
|
||||||
|
</document>
|
|
@ -17,13 +17,6 @@ class DraftTableViewCell: UITableViewCell {
|
||||||
@IBOutlet weak var attachmentsStackViewContainer: UIView!
|
@IBOutlet weak var attachmentsStackViewContainer: UIView!
|
||||||
@IBOutlet weak var attachmentsStackView: UIStackView!
|
@IBOutlet weak var attachmentsStackView: UIStackView!
|
||||||
|
|
||||||
override func awakeFromNib() {
|
|
||||||
super.awakeFromNib()
|
|
||||||
|
|
||||||
contentWarningLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))
|
|
||||||
contentWarningLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(for draft: Draft) {
|
func updateUI(for draft: Draft) {
|
||||||
contentWarningLabel.text = draft.contentWarning
|
contentWarningLabel.text = draft.contentWarning
|
||||||
contentWarningLabel.isHidden = !draft.contentWarningEnabled
|
contentWarningLabel.isHidden = !draft.contentWarningEnabled
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
@ -18,27 +16,27 @@
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="gaD-3B-qO1">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="gaD-3B-qO1">
|
||||||
<rect key="frame" x="16" y="11" width="351" height="124"/>
|
<rect key="frame" x="15" y="11" width="352" height="124"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Content Warning" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VhS-ig-6Fu">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Content Warning" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VhS-ig-6Fu">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="351" height="18"/>
|
<rect key="frame" x="0.0" y="0.0" width="352" height="18"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zMS-88-DcM">
|
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zMS-88-DcM">
|
||||||
<rect key="frame" x="0.0" y="26" width="351" height="40"/>
|
<rect key="frame" x="0.0" y="26" width="352" height="40"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" ambiguous="YES" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eA-yd-rBp">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" ambiguous="YES" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eA-yd-rBp">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="310.5" height="32"/>
|
<rect key="frame" x="0.0" y="0.0" width="311.5" height="32"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D2X-9O-iQw">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D2X-9O-iQw">
|
||||||
<rect key="frame" x="326.5" y="0.0" width="24.5" height="20.5"/>
|
<rect key="frame" x="327.5" y="0.0" width="24.5" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
@ -52,7 +50,7 @@
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="csc-gx-KVg">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="csc-gx-KVg">
|
||||||
<rect key="frame" x="0.0" y="74" width="351" height="50"/>
|
<rect key="frame" x="0.0" y="74" width="352" height="50"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="htC-hf-vJ4">
|
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="htC-hf-vJ4">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="352" height="50"/>
|
<rect key="frame" x="0.0" y="0.0" width="352" height="50"/>
|
||||||
|
@ -90,9 +88,4 @@
|
||||||
<point key="canvasLocation" x="-388" y="184.85757121439281"/>
|
<point key="canvasLocation" x="-388" y="184.85757121439281"/>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
|
||||||
<systemColor name="secondaryLabelColor">
|
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -28,14 +28,8 @@ class InstanceTableViewCell: UITableViewCell {
|
||||||
thumbnailImageView.layer.masksToBounds = true
|
thumbnailImageView.layer.masksToBounds = true
|
||||||
thumbnailImageView.layer.cornerRadius = 5
|
thumbnailImageView.layer.cornerRadius = 5
|
||||||
|
|
||||||
domainLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 22, weight: .bold))
|
|
||||||
domainLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
adultLabel.layer.masksToBounds = true
|
adultLabel.layer.masksToBounds = true
|
||||||
adultLabel.layer.cornerRadius = 0.5 * adultLabel.bounds.height
|
adultLabel.layer.cornerRadius = 0.5 * adultLabel.bounds.height
|
||||||
|
|
||||||
descriptionTextView.defaultFont = .preferredFont(forTextStyle: .body)
|
|
||||||
descriptionTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUI(instance: InstanceSelector.Instance) {
|
func updateUI(instance: InstanceSelector.Instance) {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
@ -29,34 +27,34 @@
|
||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="QG1-xB-nmt">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="QG1-xB-nmt">
|
||||||
<rect key="frame" x="88" y="0.0" width="200" height="64.5"/>
|
<rect key="frame" x="88" y="0.0" width="200" height="63"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="XtJ-BL-iHb">
|
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="XtJ-BL-iHb">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="200" height="26.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="200" height="26.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="domain.tld" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="17" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SjP-Nk-sSH">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="domain.tld" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SjP-Nk-sSH">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="164" height="26.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="164" height="26.5"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="18+" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ekk-aL-7Pq">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="18+" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ekk-aL-7Pq">
|
||||||
<rect key="frame" x="164" y="1.5" width="36" height="24"/>
|
<rect key="frame" x="164" y="1.5" width="36" height="24"/>
|
||||||
<color key="backgroundColor" systemColor="systemBlueColor"/>
|
<color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="24" id="CNa-UL-LJh"/>
|
<constraint firstAttribute="height" constant="24" id="CNa-UL-LJh"/>
|
||||||
<constraint firstAttribute="width" constant="36" id="tzn-KZ-r2f"/>
|
<constraint firstAttribute="width" constant="36" id="tzn-KZ-r2f"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Instance Description" textAlignment="natural" adjustsFontForContentSizeCategory="YES" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z5t-Zl-040" customClass="ContentTextView" customModule="Tusker" customModuleProvider="target">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Instance Description" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z5t-Zl-040" customClass="ContentTextView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="26.5" width="200" height="38"/>
|
<rect key="frame" x="0.0" y="26.5" width="200" height="36.5"/>
|
||||||
<color key="textColor" systemColor="labelColor"/>
|
<color key="textColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
</textView>
|
</textView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
@ -81,12 +79,4 @@
|
||||||
<point key="canvasLocation" x="131.8840579710145" y="178.79464285714286"/>
|
<point key="canvasLocation" x="131.8840579710145" y="178.79464285714286"/>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
|
||||||
<systemColor name="labelColor">
|
|
||||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
<systemColor name="systemBlueColor">
|
|
||||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</systemColor>
|
|
||||||
</resources>
|
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -10,17 +10,9 @@ import UIKit
|
||||||
|
|
||||||
class LinkTextView: UITextView {
|
class LinkTextView: UITextView {
|
||||||
|
|
||||||
override init(frame: CGRect, textContainer: NSTextContainer?) {
|
override func awakeFromNib() {
|
||||||
super.init(frame: frame, textContainer: textContainer)
|
super.awakeFromNib()
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
delaysContentTouches = false
|
delaysContentTouches = false
|
||||||
isScrollEnabled = false
|
isScrollEnabled = false
|
||||||
isEditable = false
|
isEditable = false
|
||||||
|
|
|
@ -35,13 +35,6 @@ class ActionNotificationGroupTableViewCell: UITableViewCell {
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
timestampLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
timestampLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
actionLabel.combiner = self.updateActionLabel
|
actionLabel.combiner = self.updateActionLabel
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -41,15 +40,15 @@
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Actioned by Person 1, Person 2, and Person 3" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fkn-Gk-ngr" customClass="MultiSourceEmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Actioned by Person 1, Person 2, and Person 3" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fkn-Gk-ngr" customClass="MultiSourceEmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="34" width="230" height="42.5"/>
|
<rect key="frame" x="0.0" y="34" width="230" height="41"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lc7-zZ-HrZ">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lc7-zZ-HrZ">
|
||||||
<rect key="frame" x="0.0" y="80.5" width="230" height="72.5"/>
|
<rect key="frame" x="0.0" y="79" width="230" height="74"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -31,13 +31,6 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
timestampLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
timestampLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
actionLabel.combiner = self.updateActionLabel
|
actionLabel.combiner = self.updateActionLabel
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18121" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18091"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -41,9 +40,9 @@
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Followed by Person 1 and Person 2" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bHA-9x-pcO" customClass="MultiSourceEmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Followed by Person 1 and Person 2" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bHA-9x-pcO" customClass="MultiSourceEmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="30" width="230" height="46"/>
|
<rect key="frame" x="0.0" y="30" width="230" height="46"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -76,7 +75,7 @@
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="person.fill.badge.plus" catalog="system" width="128" height="125"/>
|
<image name="person.fill.badge.plus" catalog="system" width="128" height="124"/>
|
||||||
<systemColor name="secondaryLabelColor">
|
<systemColor name="secondaryLabelColor">
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
|
|
|
@ -36,13 +36,6 @@ class FollowRequestNotificationTableViewCell: UITableViewCell {
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
timestampLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
timestampLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
avatarImageView.layer.masksToBounds = true
|
avatarImageView.layer.masksToBounds = true
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -42,9 +41,9 @@
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Request to follow by Person 1" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aM6-C6-9QH" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Request to follow by Person 1" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aM6-C6-9QH" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="34" width="230" height="20.5"/>
|
<rect key="frame" x="0.0" y="34" width="230" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -105,9 +104,9 @@
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="checkmark.circle.fill" catalog="system" width="128" height="123"/>
|
<image name="checkmark.circle.fill" catalog="system" width="128" height="121"/>
|
||||||
<image name="person.fill" catalog="system" width="128" height="120"/>
|
<image name="person.fill" catalog="system" width="128" height="120"/>
|
||||||
<image name="xmark.circle.fill" catalog="system" width="128" height="123"/>
|
<image name="xmark.circle.fill" catalog="system" width="128" height="121"/>
|
||||||
<systemColor name="secondaryLabelColor">
|
<systemColor name="secondaryLabelColor">
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
|
|
|
@ -24,20 +24,6 @@ class PollFinishedTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
private var updateTimestampWorkItem: DispatchWorkItem?
|
private var updateTimestampWorkItem: DispatchWorkItem?
|
||||||
|
|
||||||
override func awakeFromNib() {
|
|
||||||
super.awakeFromNib()
|
|
||||||
|
|
||||||
timestampLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
timestampLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
displayNameLabel.font = .preferredFont(forTextStyle: .body).withTraits(.traitBold)!
|
|
||||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(notification: Pachyderm.Notification) {
|
func updateUI(notification: Pachyderm.Notification) {
|
||||||
guard let statusID = notification.status?.id,
|
guard let statusID = notification.status?.id,
|
||||||
let status = delegate?.apiController.persistentContainer.status(for: statusID),
|
let status = delegate?.apiController.persistentContainer.status(for: statusID),
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -24,9 +23,9 @@
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="69j-GL-yd7">
|
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="69j-GL-yd7">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="232" height="20.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="232" height="20.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="A poll has finished" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9He-JX-i6Z">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="A poll has finished" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9He-JX-i6Z">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="208" height="20.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="208" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -44,9 +43,9 @@
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bLL-8K-VWn">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bLL-8K-VWn">
|
||||||
<rect key="frame" x="0.0" y="49" width="232" height="20.5"/>
|
<rect key="frame" x="0.0" y="49" width="232" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -57,7 +56,7 @@
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="checkmark.square.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="cqi-cV-ejs">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="checkmark.square.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="cqi-cV-ejs">
|
||||||
<rect key="frame" x="34" y="9" width="30" height="34"/>
|
<rect key="frame" x="34" y="10" width="30" height="32"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="30" id="E9e-iF-rqo"/>
|
<constraint firstAttribute="height" constant="30" id="E9e-iF-rqo"/>
|
||||||
<constraint firstAttribute="width" constant="30" id="Efu-VP-pjH"/>
|
<constraint firstAttribute="width" constant="30" id="Efu-VP-pjH"/>
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
//
|
|
||||||
// ProfileFieldsView.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 11/4/22.
|
|
||||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class ProfileFieldsView: UIView {
|
|
||||||
|
|
||||||
weak var delegate: ProfileHeaderViewDelegate?
|
|
||||||
|
|
||||||
private let stack = UIStackView()
|
|
||||||
private var fieldViews: [(EmojiLabel, ContentTextView)] = []
|
|
||||||
private var fieldConstraints: [NSLayoutConstraint] = []
|
|
||||||
|
|
||||||
private var isUsingSingleColumn: Bool = false
|
|
||||||
private var needsSingleColumn: Bool {
|
|
||||||
traitCollection.preferredContentSizeCategory > .large
|
|
||||||
}
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
stack.axis = .vertical
|
|
||||||
stack.alignment = .fill
|
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(stack)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
stack.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
||||||
stack.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
||||||
stack.topAnchor.constraint(equalTo: topAnchor),
|
|
||||||
stack.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
|
||||||
if isUsingSingleColumn != needsSingleColumn {
|
|
||||||
configureFields()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(account: AccountMO) {
|
|
||||||
isHidden = account.fields.isEmpty
|
|
||||||
guard !account.fields.isEmpty else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name, value) in fieldViews {
|
|
||||||
name.removeFromSuperview()
|
|
||||||
value.removeFromSuperview()
|
|
||||||
}
|
|
||||||
fieldViews = []
|
|
||||||
|
|
||||||
for field in account.fields {
|
|
||||||
let nameLabel = EmojiLabel()
|
|
||||||
nameLabel.text = field.name
|
|
||||||
nameLabel.font = .preferredFont(forTextStyle: .body).withTraits(.traitBold)!
|
|
||||||
nameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
nameLabel.numberOfLines = 0
|
|
||||||
nameLabel.lineBreakMode = .byWordWrapping
|
|
||||||
nameLabel.setEmojis(account.emojis, identifier: account.id)
|
|
||||||
nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
||||||
|
|
||||||
let valueTextView = ContentTextView()
|
|
||||||
valueTextView.isSelectable = false
|
|
||||||
valueTextView.defaultFont = .preferredFont(forTextStyle: .body)
|
|
||||||
valueTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
valueTextView.setTextFromHtml(field.value)
|
|
||||||
valueTextView.setEmojis(account.emojis, identifier: account.id)
|
|
||||||
valueTextView.navigationDelegate = delegate
|
|
||||||
valueTextView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
||||||
|
|
||||||
fieldViews.append((nameLabel, valueTextView))
|
|
||||||
}
|
|
||||||
|
|
||||||
configureFields()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func configureFields() {
|
|
||||||
guard !isHidden else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isUsingSingleColumn = needsSingleColumn
|
|
||||||
|
|
||||||
NSLayoutConstraint.deactivate(fieldConstraints)
|
|
||||||
fieldConstraints = []
|
|
||||||
|
|
||||||
stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
|
||||||
|
|
||||||
if needsSingleColumn {
|
|
||||||
stack.spacing = 4
|
|
||||||
var isFirst = true
|
|
||||||
for (name, value) in fieldViews {
|
|
||||||
if isFirst {
|
|
||||||
isFirst = false
|
|
||||||
} else {
|
|
||||||
let spacer = UIView()
|
|
||||||
// don't need any height, since there's 4pts of padding on either side
|
|
||||||
spacer.heightAnchor.constraint(equalToConstant: 0).isActive = true
|
|
||||||
stack.addArrangedSubview(spacer)
|
|
||||||
}
|
|
||||||
name.textAlignment = .natural
|
|
||||||
stack.addArrangedSubview(name)
|
|
||||||
value.textAlignment = .natural
|
|
||||||
stack.addArrangedSubview(value)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stack.spacing = 8
|
|
||||||
|
|
||||||
let dividerLayoutGuide = UILayoutGuide()
|
|
||||||
addLayoutGuide(dividerLayoutGuide)
|
|
||||||
fieldConstraints.append(contentsOf: [
|
|
||||||
dividerLayoutGuide.widthAnchor.constraint(equalToConstant: 8),
|
|
||||||
])
|
|
||||||
|
|
||||||
for (name, value) in fieldViews {
|
|
||||||
name.textAlignment = .right
|
|
||||||
name.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
|
||||||
value.textAlignment = .left
|
|
||||||
value.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
|
||||||
let fieldContainer = UIView()
|
|
||||||
fieldContainer.addSubview(name)
|
|
||||||
fieldContainer.addSubview(value)
|
|
||||||
stack.addArrangedSubview(fieldContainer)
|
|
||||||
fieldConstraints.append(contentsOf: [
|
|
||||||
name.leadingAnchor.constraint(equalTo: fieldContainer.leadingAnchor),
|
|
||||||
name.trailingAnchor.constraint(equalTo: dividerLayoutGuide.leadingAnchor),
|
|
||||||
name.topAnchor.constraint(equalTo: fieldContainer.topAnchor),
|
|
||||||
name.bottomAnchor.constraint(equalTo: fieldContainer.bottomAnchor),
|
|
||||||
|
|
||||||
value.leadingAnchor.constraint(equalTo: dividerLayoutGuide.trailingAnchor),
|
|
||||||
value.trailingAnchor.constraint(equalTo: fieldContainer.trailingAnchor),
|
|
||||||
value.topAnchor.constraint(equalTo: fieldContainer.topAnchor),
|
|
||||||
value.bottomAnchor.constraint(equalTo: fieldContainer.bottomAnchor),
|
|
||||||
|
|
||||||
name.widthAnchor.constraint(greaterThanOrEqualTo: value.widthAnchor, multiplier: 0.5),
|
|
||||||
name.widthAnchor.constraint(lessThanOrEqualTo: value.widthAnchor, multiplier: 2),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate(fieldConstraints)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -36,7 +36,9 @@ class ProfileHeaderView: UIView {
|
||||||
@IBOutlet weak var usernameLabel: UILabel!
|
@IBOutlet weak var usernameLabel: UILabel!
|
||||||
@IBOutlet weak var followsYouLabel: UILabel!
|
@IBOutlet weak var followsYouLabel: UILabel!
|
||||||
@IBOutlet weak var noteTextView: StatusContentTextView!
|
@IBOutlet weak var noteTextView: StatusContentTextView!
|
||||||
@IBOutlet weak var fieldsView: ProfileFieldsView!
|
@IBOutlet weak var fieldsStackView: UIStackView!
|
||||||
|
@IBOutlet weak var fieldNamesStackView: UIStackView!
|
||||||
|
@IBOutlet weak var fieldValuesStackView: UIStackView!
|
||||||
@IBOutlet weak var pagesSegmentedControl: UISegmentedControl!
|
@IBOutlet weak var pagesSegmentedControl: UISegmentedControl!
|
||||||
|
|
||||||
var accountID: String!
|
var accountID: String!
|
||||||
|
@ -66,31 +68,15 @@ class ProfileHeaderView: UIView {
|
||||||
|
|
||||||
moreButton.layer.cornerRadius = 16
|
moreButton.layer.cornerRadius = 16
|
||||||
moreButton.layer.masksToBounds = true
|
moreButton.layer.masksToBounds = true
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
||||||
moreButton.addInteraction(UIPointerInteraction(delegate: self))
|
moreButton.addInteraction(UIPointerInteraction(delegate: self))
|
||||||
moreButton.showsMenuAsPrimaryAction = true
|
moreButton.showsMenuAsPrimaryAction = true
|
||||||
moreButton.isContextMenuInteractionEnabled = true
|
moreButton.isContextMenuInteractionEnabled = true
|
||||||
|
|
||||||
displayNameLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold))
|
|
||||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
usernameLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .light))
|
|
||||||
usernameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
followsYouLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 14))
|
|
||||||
followsYouLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
noteTextView.defaultFont = .preferredFont(forTextStyle: .body)
|
|
||||||
noteTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createObservers() {
|
private func createObservers() {
|
||||||
// mastodonController may be nil if the ProfileViewController is deinit'd before the header is even created
|
|
||||||
guard let mastodonController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cancellables = []
|
cancellables = []
|
||||||
|
|
||||||
mastodonController.persistentContainer.accountSubject
|
mastodonController.persistentContainer.accountSubject
|
||||||
|
@ -142,14 +128,43 @@ class ProfileHeaderView: UIView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsView.updateUI(account: account)
|
fieldsStackView.isHidden = account.fields.isEmpty
|
||||||
|
|
||||||
|
fieldNamesStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
|
fieldValuesStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
|
var fieldAccessibilityElements = [Any]()
|
||||||
|
for field in account.fields {
|
||||||
|
let nameLabel = EmojiLabel()
|
||||||
|
nameLabel.text = field.name
|
||||||
|
nameLabel.font = .boldSystemFont(ofSize: 17)
|
||||||
|
nameLabel.textAlignment = .right
|
||||||
|
nameLabel.numberOfLines = 0
|
||||||
|
nameLabel.lineBreakMode = .byWordWrapping
|
||||||
|
nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
nameLabel.setEmojis(account.emojis, identifier: "")
|
||||||
|
fieldNamesStackView.addArrangedSubview(nameLabel)
|
||||||
|
|
||||||
|
let valueTextView = ContentTextView()
|
||||||
|
valueTextView.isSelectable = false
|
||||||
|
valueTextView.font = .systemFont(ofSize: 17)
|
||||||
|
valueTextView.setTextFromHtml(field.value)
|
||||||
|
valueTextView.setEmojis(account.emojis, identifier: account.id)
|
||||||
|
valueTextView.textAlignment = .left
|
||||||
|
valueTextView.awakeFromNib()
|
||||||
|
valueTextView.navigationDelegate = delegate
|
||||||
|
valueTextView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
fieldValuesStackView.addArrangedSubview(valueTextView)
|
||||||
|
|
||||||
|
nameLabel.heightAnchor.constraint(equalTo: valueTextView.heightAnchor).isActive = true
|
||||||
|
fieldAccessibilityElements.append(nameLabel)
|
||||||
|
fieldAccessibilityElements.append(valueTextView)
|
||||||
|
}
|
||||||
|
|
||||||
accessibilityElements = [
|
accessibilityElements = [
|
||||||
displayNameLabel!,
|
displayNameLabel!,
|
||||||
usernameLabel!,
|
usernameLabel!,
|
||||||
noteTextView!,
|
noteTextView!,
|
||||||
// TODO: voiceover for fieldsview
|
] + fieldAccessibilityElements + [
|
||||||
// fieldsView!,
|
|
||||||
moreButton!,
|
moreButton!,
|
||||||
pagesSegmentedControl!,
|
pagesSegmentedControl!,
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18121" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18091"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -15,13 +14,13 @@
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dgG-dR-lSv">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dgG-dR-lSv">
|
||||||
<rect key="frame" x="0.0" y="48" width="414" height="150"/>
|
<rect key="frame" x="0.0" y="44" width="414" height="150"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="150" id="aCE-CA-XWm"/>
|
<constraint firstAttribute="height" constant="150" id="aCE-CA-XWm"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wT9-2J-uSY">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wT9-2J-uSY">
|
||||||
<rect key="frame" x="16" y="138" width="120" height="120"/>
|
<rect key="frame" x="16" y="134" width="120" height="120"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TkY-oK-if4">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TkY-oK-if4">
|
||||||
<rect key="frame" x="2" y="2" width="116" height="116"/>
|
<rect key="frame" x="2" y="2" width="116" height="116"/>
|
||||||
|
@ -39,14 +38,14 @@
|
||||||
<constraint firstItem="TkY-oK-if4" firstAttribute="centerX" secondItem="wT9-2J-uSY" secondAttribute="centerX" id="ozz-sa-gSc"/>
|
<constraint firstItem="TkY-oK-if4" firstAttribute="centerX" secondItem="wT9-2J-uSY" secondAttribute="centerX" id="ozz-sa-gSc"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vcl-Gl-kXl" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vcl-Gl-kXl" customClass="EmojiLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="144" y="206" width="254" height="32"/>
|
<rect key="frame" x="144" y="202" width="254" height="24"/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="24"/>
|
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="20"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bRJ-Xf-kc9" customClass="VisualEffectImageButton" customModule="Tusker" customModuleProvider="target">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bRJ-Xf-kc9" customClass="VisualEffectImageButton" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="374" y="158" width="32" height="32"/>
|
<rect key="frame" x="374" y="154" width="32" height="32"/>
|
||||||
<viewLayoutGuide key="safeArea" id="kQa-ou-pQz"/>
|
<viewLayoutGuide key="safeArea" id="kQa-ou-pQz"/>
|
||||||
<accessibility key="accessibilityConfiguration" label="More Actions">
|
<accessibility key="accessibilityConfiguration" label="More Actions">
|
||||||
<accessibilityTraits key="traits" button="YES"/>
|
<accessibilityTraits key="traits" button="YES"/>
|
||||||
|
@ -60,7 +59,7 @@
|
||||||
</userDefinedRuntimeAttributes>
|
</userDefinedRuntimeAttributes>
|
||||||
</view>
|
</view>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="u4P-3i-gEq">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="u4P-3i-gEq">
|
||||||
<rect key="frame" x="16" y="419" width="398" height="443"/>
|
<rect key="frame" x="16" y="262" width="398" height="600"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Follows you" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UF8-nI-KVj">
|
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Follows you" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UF8-nI-KVj">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="75.5" height="0.0"/>
|
<rect key="frame" x="0.0" y="0.0" width="75.5" height="0.0"/>
|
||||||
|
@ -69,21 +68,29 @@
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" scrollEnabled="NO" delaysContentTouches="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1O8-2P-Gbf" customClass="StatusContentTextView" customModule="Tusker" customModuleProvider="target">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" scrollEnabled="NO" delaysContentTouches="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1O8-2P-Gbf" customClass="StatusContentTextView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="382" height="259.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="382" height="186.5"/>
|
||||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
|
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
|
||||||
<color key="textColor" systemColor="labelColor"/>
|
<color key="textColor" systemColor="labelColor"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
</textView>
|
</textView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vKC-m1-Sbs" customClass="ProfileFieldsView" customModule="Tusker" customModuleProvider="target">
|
<stackView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="251" distribution="fillProportionally" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="sp4-Zb-00B">
|
||||||
<rect key="frame" x="0.0" y="267.5" width="398" height="128"/>
|
<rect key="frame" x="0.0" y="194.5" width="382" height="358"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
<subviews>
|
||||||
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="aqG-FA-so5">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="186.5" height="358"/>
|
||||||
|
</stackView>
|
||||||
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="EfH-Dj-Jmn">
|
||||||
|
<rect key="frame" x="194.5" y="0.0" width="187.5" height="358"/>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="128" placeholder="YES" id="xbR-M6-H0I"/>
|
<constraint firstItem="EfH-Dj-Jmn" firstAttribute="width" relation="greaterThanOrEqual" secondItem="aqG-FA-so5" secondAttribute="width" multiplier="0.5" id="2hZ-pF-C9b"/>
|
||||||
|
<constraint firstItem="EfH-Dj-Jmn" firstAttribute="width" relation="lessThanOrEqual" secondItem="aqG-FA-so5" secondAttribute="width" multiplier="2" id="Lir-Ff-z0m"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</stackView>
|
||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="n1M-vM-Cj0">
|
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="n1M-vM-Cj0">
|
||||||
<rect key="frame" x="0.0" y="403.5" width="382" height="32"/>
|
<rect key="frame" x="0.0" y="560.5" width="382" height="32"/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="Posts"/>
|
<segment title="Posts"/>
|
||||||
<segment title="Posts and Replies"/>
|
<segment title="Posts and Replies"/>
|
||||||
|
@ -94,7 +101,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</segmentedControl>
|
</segmentedControl>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5ja-fK-Fqz">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5ja-fK-Fqz">
|
||||||
<rect key="frame" x="0.0" y="442.5" width="398" height="0.5"/>
|
<rect key="frame" x="0.0" y="599.5" width="398" height="0.5"/>
|
||||||
<color key="backgroundColor" systemColor="separatorColor"/>
|
<color key="backgroundColor" systemColor="separatorColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="0.5" id="VwS-gV-q8M"/>
|
<constraint firstAttribute="height" constant="0.5" id="VwS-gV-q8M"/>
|
||||||
|
@ -102,14 +109,14 @@
|
||||||
</view>
|
</view>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="vKC-m1-Sbs" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" id="0dI-ax-7eI"/>
|
|
||||||
<constraint firstItem="n1M-vM-Cj0" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" constant="-16" id="9Ds-zl-acc"/>
|
<constraint firstItem="n1M-vM-Cj0" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" constant="-16" id="9Ds-zl-acc"/>
|
||||||
|
<constraint firstItem="sp4-Zb-00B" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" constant="-16" id="Qum-qT-goH"/>
|
||||||
<constraint firstItem="5ja-fK-Fqz" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" id="azv-le-93y"/>
|
<constraint firstItem="5ja-fK-Fqz" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" id="azv-le-93y"/>
|
||||||
<constraint firstItem="1O8-2P-Gbf" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" constant="-16" id="hnA-3G-B9B"/>
|
<constraint firstItem="1O8-2P-Gbf" firstAttribute="width" secondItem="u4P-3i-gEq" secondAttribute="width" constant="-16" id="hnA-3G-B9B"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</stackView>
|
</stackView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1C3-Pd-QiL">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1C3-Pd-QiL">
|
||||||
<rect key="frame" x="144" y="238" width="254" height="18"/>
|
<rect key="frame" x="144" y="234" width="254" height="18"/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
|
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
|
@ -125,24 +132,25 @@
|
||||||
<constraint firstItem="vcl-Gl-kXl" firstAttribute="leading" secondItem="wT9-2J-uSY" secondAttribute="trailing" constant="8" id="8ho-WU-MxW"/>
|
<constraint firstItem="vcl-Gl-kXl" firstAttribute="leading" secondItem="wT9-2J-uSY" secondAttribute="trailing" constant="8" id="8ho-WU-MxW"/>
|
||||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="u4P-3i-gEq" secondAttribute="bottom" id="9zc-N2-mfI"/>
|
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="u4P-3i-gEq" secondAttribute="bottom" id="9zc-N2-mfI"/>
|
||||||
<constraint firstItem="bRJ-Xf-kc9" firstAttribute="bottom" secondItem="dgG-dR-lSv" secondAttribute="bottom" constant="-8" id="AXS-bG-20Q"/>
|
<constraint firstItem="bRJ-Xf-kc9" firstAttribute="bottom" secondItem="dgG-dR-lSv" secondAttribute="bottom" constant="-8" id="AXS-bG-20Q"/>
|
||||||
<constraint firstItem="1C3-Pd-QiL" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="TkY-oK-if4" secondAttribute="bottom" id="OpB-YM-gyu"/>
|
<constraint firstItem="1C3-Pd-QiL" firstAttribute="bottom" secondItem="TkY-oK-if4" secondAttribute="bottom" id="OpB-YM-gyu"/>
|
||||||
<constraint firstItem="dgG-dR-lSv" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="VD1-yc-KSa"/>
|
<constraint firstItem="dgG-dR-lSv" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="VD1-yc-KSa"/>
|
||||||
<constraint firstItem="wT9-2J-uSY" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="WNS-AR-ff2"/>
|
<constraint firstItem="wT9-2J-uSY" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="WNS-AR-ff2"/>
|
||||||
<constraint firstItem="bRJ-Xf-kc9" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" constant="-8" id="ZB4-ys-9zP"/>
|
<constraint firstItem="bRJ-Xf-kc9" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" constant="-8" id="ZB4-ys-9zP"/>
|
||||||
<constraint firstItem="1C3-Pd-QiL" firstAttribute="top" secondItem="vcl-Gl-kXl" secondAttribute="bottom" id="d0z-X6-Sig"/>
|
<constraint firstItem="1C3-Pd-QiL" firstAttribute="top" relation="greaterThanOrEqual" secondItem="vcl-Gl-kXl" secondAttribute="bottom" id="d0z-X6-Sig"/>
|
||||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="vcl-Gl-kXl" secondAttribute="trailing" constant="16" id="e38-Od-kPg"/>
|
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="vcl-Gl-kXl" secondAttribute="trailing" constant="16" id="e38-Od-kPg"/>
|
||||||
<constraint firstItem="u4P-3i-gEq" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="hgl-UR-o3W"/>
|
<constraint firstItem="u4P-3i-gEq" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="hgl-UR-o3W"/>
|
||||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="dgG-dR-lSv" secondAttribute="trailing" id="j0d-hY-815"/>
|
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="dgG-dR-lSv" secondAttribute="trailing" id="j0d-hY-815"/>
|
||||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="1C3-Pd-QiL" secondAttribute="trailing" constant="16" id="pcH-vi-2zH"/>
|
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="1C3-Pd-QiL" secondAttribute="trailing" constant="16" id="pcH-vi-2zH"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="u4P-3i-gEq" secondAttribute="trailing" id="ph6-NT-A02"/>
|
<constraint firstAttribute="trailing" secondItem="u4P-3i-gEq" secondAttribute="trailing" id="ph6-NT-A02"/>
|
||||||
<constraint firstItem="u4P-3i-gEq" firstAttribute="top" relation="greaterThanOrEqual" secondItem="wT9-2J-uSY" secondAttribute="bottom" constant="8" id="tKQ-6d-Z55"/>
|
<constraint firstItem="u4P-3i-gEq" firstAttribute="top" secondItem="wT9-2J-uSY" secondAttribute="bottom" constant="8" id="tKQ-6d-Z55"/>
|
||||||
<constraint firstItem="u4P-3i-gEq" firstAttribute="top" relation="greaterThanOrEqual" secondItem="vcl-Gl-kXl" secondAttribute="bottom" constant="8" id="xDD-rx-gC0"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="avatarContainerView" destination="wT9-2J-uSY" id="yEm-h7-tfq"/>
|
<outlet property="avatarContainerView" destination="wT9-2J-uSY" id="yEm-h7-tfq"/>
|
||||||
<outlet property="avatarImageView" destination="TkY-oK-if4" id="bSJ-7z-j4w"/>
|
<outlet property="avatarImageView" destination="TkY-oK-if4" id="bSJ-7z-j4w"/>
|
||||||
<outlet property="displayNameLabel" destination="vcl-Gl-kXl" id="64n-a9-my0"/>
|
<outlet property="displayNameLabel" destination="vcl-Gl-kXl" id="64n-a9-my0"/>
|
||||||
<outlet property="fieldsView" destination="vKC-m1-Sbs" id="FeE-jh-lYH"/>
|
<outlet property="fieldNamesStackView" destination="aqG-FA-so5" id="prA-n7-blZ"/>
|
||||||
|
<outlet property="fieldValuesStackView" destination="EfH-Dj-Jmn" id="LMk-Hn-EkY"/>
|
||||||
|
<outlet property="fieldsStackView" destination="sp4-Zb-00B" id="eyx-GF-2Wf"/>
|
||||||
<outlet property="followsYouLabel" destination="UF8-nI-KVj" id="dTe-DQ-eJV"/>
|
<outlet property="followsYouLabel" destination="UF8-nI-KVj" id="dTe-DQ-eJV"/>
|
||||||
<outlet property="headerImageView" destination="dgG-dR-lSv" id="HXT-v4-2iX"/>
|
<outlet property="headerImageView" destination="dgG-dR-lSv" id="HXT-v4-2iX"/>
|
||||||
<outlet property="moreButton" destination="bRJ-Xf-kc9" id="zIN-pz-L7y"/>
|
<outlet property="moreButton" destination="bRJ-Xf-kc9" id="zIN-pz-L7y"/>
|
||||||
|
@ -156,7 +164,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
||||||
<systemColor name="labelColor">
|
<systemColor name="labelColor">
|
||||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
<systemColor name="secondaryLabelColor">
|
<systemColor name="secondaryLabelColor">
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
|
@ -182,8 +182,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
updateStatusIconsForPreferences(status)
|
updateStatusIconsForPreferences(status)
|
||||||
|
|
||||||
if state.unknown {
|
if state.unknown {
|
||||||
layoutIfNeeded()
|
state.resolveFor(status: status, text: contentTextView.text)
|
||||||
state.resolveFor(status: status, height: contentTextView.bounds.height)
|
|
||||||
if state.collapsible! && showStatusAutomatically {
|
if state.collapsible! && showStatusAutomatically {
|
||||||
state.collapsed = false
|
state.collapsed = false
|
||||||
}
|
}
|
||||||
|
@ -231,17 +230,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
func updateUIForPreferences(account: AccountMO, status: StatusMO) {
|
func updateUIForPreferences(account: AccountMO, status: StatusMO) {
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||||
if Preferences.shared.blurAllMedia {
|
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
attachmentsView.contentHidden = true
|
|
||||||
} else if status.sensitive {
|
|
||||||
if !Preferences.shared.blurMediaBehindContentWarning && !status.spoilerText.isEmpty {
|
|
||||||
attachmentsView.contentHidden = false
|
|
||||||
} else {
|
|
||||||
attachmentsView.contentHidden = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
attachmentsView.contentHidden = false
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatusIconsForPreferences(status)
|
updateStatusIconsForPreferences(status)
|
||||||
|
|
||||||
|
|
|
@ -49,35 +49,16 @@ class ConversationMainStatusTableViewCell: BaseStatusTableViewCell {
|
||||||
moreButton!,
|
moreButton!,
|
||||||
]
|
]
|
||||||
|
|
||||||
profileDetailContainerView.addInteraction(UIContextMenuInteraction(delegate: self))
|
contentTextView.defaultFont = .systemFont(ofSize: 18)
|
||||||
|
|
||||||
displayNameLabel.font = UIFontMetrics(forTextStyle: .title1).scaledFont(for: .systemFont(ofSize: 24, weight: .semibold))
|
|
||||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
usernameLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 17, weight: .light))
|
|
||||||
usernameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
metaIndicatorsView.allowedIndicators = [.visibility, .localOnly]
|
|
||||||
metaIndicatorsView.squeezeHorizontal = true
|
|
||||||
metaIndicatorsView.primaryAxis = .horizontal
|
|
||||||
|
|
||||||
contentWarningLabel.font = .preferredFont(forTextStyle: .body).withTraits(.traitBold)!
|
|
||||||
contentWarningLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
contentTextView.defaultFont = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 18))
|
|
||||||
contentTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
contentTextView.dataDetectorTypes = [.flightNumber, .address, .shipmentTrackingNumber, .phoneNumber]
|
contentTextView.dataDetectorTypes = [.flightNumber, .address, .shipmentTrackingNumber, .phoneNumber]
|
||||||
if #available(iOS 16.0, *) {
|
if #available(iOS 16.0, *) {
|
||||||
contentTextView.dataDetectorTypes.formUnion([.money, .physicalValue])
|
contentTextView.dataDetectorTypes.formUnion([.money, .physicalValue])
|
||||||
}
|
}
|
||||||
|
|
||||||
let metaFont = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 15))
|
profileDetailContainerView.addInteraction(UIContextMenuInteraction(delegate: self))
|
||||||
totalFavoritesButton.titleLabel!.font = metaFont
|
|
||||||
totalFavoritesButton.titleLabel!.adjustsFontForContentSizeCategory = true
|
metaIndicatorsView.allowedIndicators = [.visibility, .localOnly]
|
||||||
totalReblogsButton.titleLabel!.font = metaFont
|
metaIndicatorsView.squeezeHorizontal = true
|
||||||
totalReblogsButton.titleLabel!.adjustsFontForContentSizeCategory = true
|
|
||||||
timestampAndClientLabel.font = metaFont
|
|
||||||
timestampAndClientLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func doUpdateUI(status: StatusMO, state: StatusState) {
|
override func doUpdateUI(status: StatusMO, state: StatusState) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||||
<capability name="Image references" minToolsVersion="12.0"/>
|
<capability name="Image references" minToolsVersion="12.0"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
|
@ -261,13 +261,13 @@
|
||||||
</view>
|
</view>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="arrowshape.turn.up.left.fill" catalog="system" width="128" height="104"/>
|
<image name="arrowshape.turn.up.left.fill" catalog="system" width="128" height="106"/>
|
||||||
<image name="chevron.down" catalog="system" width="128" height="70"/>
|
<image name="chevron.down" catalog="system" width="128" height="72"/>
|
||||||
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
<image name="ellipsis" catalog="system" width="128" height="37"/>
|
||||||
<image name="repeat" catalog="system" width="128" height="98"/>
|
<image name="repeat" catalog="system" width="128" height="98"/>
|
||||||
<image name="star.fill" catalog="system" width="128" height="116"/>
|
<image name="star.fill" catalog="system" width="128" height="116"/>
|
||||||
<systemColor name="labelColor">
|
<systemColor name="labelColor">
|
||||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
<systemColor name="opaqueSeparatorColor">
|
<systemColor name="opaqueSeparatorColor">
|
||||||
<color red="0.77647058823529413" green="0.77647058823529413" blue="0.78431372549019607" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.77647058823529413" green="0.77647058823529413" blue="0.78431372549019607" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
|
|
@ -51,12 +51,10 @@ class StatusCardView: UIView {
|
||||||
|
|
||||||
titleLabel = UILabel()
|
titleLabel = UILabel()
|
||||||
titleLabel.font = UIFont(descriptor: UIFontDescriptor.preferredFontDescriptor(withTextStyle: .subheadline).withSymbolicTraits(.traitBold)!, size: 0)
|
titleLabel.font = UIFont(descriptor: UIFontDescriptor.preferredFontDescriptor(withTextStyle: .subheadline).withSymbolicTraits(.traitBold)!, size: 0)
|
||||||
titleLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
titleLabel.numberOfLines = 2
|
titleLabel.numberOfLines = 2
|
||||||
|
|
||||||
descriptionLabel = UILabel()
|
descriptionLabel = UILabel()
|
||||||
descriptionLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .caption1), size: 0)
|
descriptionLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .caption1), size: 0)
|
||||||
descriptionLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
descriptionLabel.numberOfLines = 2
|
descriptionLabel.numberOfLines = 2
|
||||||
descriptionLabel.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
descriptionLabel.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
||||||
|
|
||||||
|
|
|
@ -104,9 +104,7 @@ extension StatusCollectionViewCell {
|
||||||
favoriteButton.isEnabled = mastodonController.loggedIn
|
favoriteButton.isEnabled = mastodonController.loggedIn
|
||||||
|
|
||||||
if statusState.unknown {
|
if statusState.unknown {
|
||||||
// layout so that we can take the content height into consideration when deciding whether to collapse
|
statusState.resolveFor(status: status, text: contentContainer.contentTextView.text)
|
||||||
layoutIfNeeded()
|
|
||||||
statusState.resolveFor(status: status, height: contentContainer.contentTextView.bounds.height)
|
|
||||||
if statusState.collapsible! && showStatusAutomatically {
|
if statusState.collapsible! && showStatusAutomatically {
|
||||||
statusState.collapsed = false
|
statusState.collapsed = false
|
||||||
}
|
}
|
||||||
|
@ -147,17 +145,7 @@ extension StatusCollectionViewCell {
|
||||||
|
|
||||||
func baseUpdateUIForPreferences(status: StatusMO) {
|
func baseUpdateUIForPreferences(status: StatusMO) {
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.avatarImageViewSize
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * Self.avatarImageViewSize
|
||||||
if Preferences.shared.blurAllMedia {
|
contentContainer.attachmentsView.contentHidden = Preferences.shared.blurAllMedia || status.sensitive
|
||||||
contentContainer.attachmentsView.contentHidden = true
|
|
||||||
} else if status.sensitive {
|
|
||||||
if !Preferences.shared.blurMediaBehindContentWarning && !status.spoilerText.isEmpty {
|
|
||||||
contentContainer.attachmentsView.contentHidden = false
|
|
||||||
} else {
|
|
||||||
contentContainer.attachmentsView.contentHidden = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contentContainer.attachmentsView.contentHidden = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let reblogButtonImage: UIImage
|
let reblogButtonImage: UIImage
|
||||||
if Preferences.shared.alwaysShowStatusVisibilityIcon || reblogEnabled(status: status) {
|
if Preferences.shared.alwaysShowStatusVisibilityIcon || reblogEnabled(status: status) {
|
||||||
|
|
|
@ -11,8 +11,7 @@ import UIKit
|
||||||
class StatusContentContainer: UIView {
|
class StatusContentContainer: UIView {
|
||||||
|
|
||||||
let contentTextView = StatusContentTextView().configure {
|
let contentTextView = StatusContentTextView().configure {
|
||||||
$0.defaultFont = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 16))
|
$0.defaultFont = .systemFont(ofSize: 16)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
$0.isScrollEnabled = false
|
$0.isScrollEnabled = false
|
||||||
$0.backgroundColor = nil
|
$0.backgroundColor = nil
|
||||||
$0.isEditable = false
|
$0.isEditable = false
|
||||||
|
|
|
@ -13,54 +13,11 @@ class StatusMetaIndicatorsView: UIView {
|
||||||
|
|
||||||
var allowedIndicators: Indicator = .all
|
var allowedIndicators: Indicator = .all
|
||||||
var squeezeHorizontal = false
|
var squeezeHorizontal = false
|
||||||
// The axis in which the indicators grow
|
|
||||||
var primaryAxis: NSLayoutConstraint.Axis = .vertical
|
|
||||||
// Only used when using single axis mode
|
|
||||||
var secondaryAxisAlignment: Alignment = .leading
|
|
||||||
private var images: [UIImageView] = []
|
private var images: [UIImageView] = []
|
||||||
private var isUsingSingleAxis = false
|
|
||||||
|
|
||||||
private var needsSingleAxis: Bool {
|
|
||||||
traitCollection.preferredContentSizeCategory > .extraLarge
|
|
||||||
}
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(configureImageViews), name: UIAccessibility.boldTextStatusDidChangeNotification, object: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
|
||||||
if isUsingSingleAxis != needsSingleAxis {
|
|
||||||
for image in images {
|
|
||||||
configureImageView(image)
|
|
||||||
}
|
|
||||||
placeImageViews(images)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func configureImageViews() {
|
|
||||||
for image in images {
|
|
||||||
configureImageView(image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func configureImageView(_ imageView: UIImageView) {
|
|
||||||
let weight: UIImage.SymbolWeight = UIAccessibility.isBoldTextEnabled ? .regular : traitCollection.preferredContentSizeCategory > .large ? .light : .thin
|
|
||||||
let scale: UIImage.SymbolScale = traitCollection.preferredContentSizeCategory > .extraLarge ? .large : .default
|
|
||||||
imageView.preferredSymbolConfiguration = .init(pointSize: 0, weight: weight, scale: scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(status: StatusMO) {
|
func updateUI(status: StatusMO) {
|
||||||
|
images.forEach { $0.removeFromSuperview() }
|
||||||
|
|
||||||
var images: [UIImage] = []
|
var images: [UIImage] = []
|
||||||
|
|
||||||
if allowedIndicators.contains(.reply) && Preferences.shared.showIsStatusReplyIcon && status.inReplyToID != nil {
|
if allowedIndicators.contains(.reply) && Preferences.shared.showIsStatusReplyIcon && status.inReplyToID != nil {
|
||||||
|
@ -75,66 +32,13 @@ class StatusMetaIndicatorsView: UIView {
|
||||||
images.append(UIImage(named: "link.broken")!)
|
images.append(UIImage(named: "link.broken")!)
|
||||||
}
|
}
|
||||||
|
|
||||||
let views = images.map {
|
self.images = []
|
||||||
let v = UIImageView(image: $0)
|
for (index, image) in images.enumerated() {
|
||||||
|
let v = UIImageView(image: image)
|
||||||
v.translatesAutoresizingMaskIntoConstraints = false
|
v.translatesAutoresizingMaskIntoConstraints = false
|
||||||
v.contentMode = .scaleAspectFit
|
v.contentMode = .scaleAspectFit
|
||||||
v.tintColor = .secondaryLabel
|
v.tintColor = .secondaryLabel
|
||||||
configureImageView(v)
|
v.preferredSymbolConfiguration = .init(weight: .thin)
|
||||||
return v
|
|
||||||
}
|
|
||||||
placeImageViews(views)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func placeImageViews(_ imageViews: [UIImageView]) {
|
|
||||||
images.forEach { $0.removeFromSuperview() }
|
|
||||||
images = imageViews
|
|
||||||
|
|
||||||
guard !images.isEmpty else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isUsingSingleAxis = needsSingleAxis
|
|
||||||
|
|
||||||
if needsSingleAxis {
|
|
||||||
for v in images {
|
|
||||||
addSubview(v)
|
|
||||||
|
|
||||||
switch (primaryAxis, secondaryAxisAlignment) {
|
|
||||||
case (.horizontal, .leading):
|
|
||||||
v.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
|
||||||
case (.horizontal, .trailing):
|
|
||||||
v.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
|
||||||
case (.vertical, .leading):
|
|
||||||
v.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
|
||||||
case (.vertical, .trailing):
|
|
||||||
v.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
|
||||||
case (_, _):
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if primaryAxis == .vertical {
|
|
||||||
images.first!.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
|
||||||
images.last!.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
|
||||||
} else {
|
|
||||||
images.first!.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
|
||||||
images.last!.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
|
||||||
}
|
|
||||||
for (a, b) in zip(images, images.dropFirst()) {
|
|
||||||
if primaryAxis == .vertical {
|
|
||||||
b.topAnchor.constraint(equalTo: a.bottomAnchor, constant: 4).isActive = true
|
|
||||||
} else {
|
|
||||||
b.leadingAnchor.constraint(equalTo: a.trailingAnchor, constant: 4).isActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard primaryAxis == .vertical || imageViews.count <= 2 else {
|
|
||||||
fatalError("StatusMetaIndicatorsView does not support horizontal primary axis with more than 2 views yet")
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index, v) in images.enumerated() {
|
|
||||||
addSubview(v)
|
addSubview(v)
|
||||||
|
|
||||||
if index % 2 == 0 {
|
if index % 2 == 0 {
|
||||||
|
@ -160,9 +64,14 @@ class StatusMetaIndicatorsView: UIView {
|
||||||
v.topAnchor.constraint(equalTo: self.images[index - 1].bottomAnchor, constant: 4).isActive = true
|
v.topAnchor.constraint(equalTo: self.images[index - 1].bottomAnchor, constant: 4).isActive = true
|
||||||
}
|
}
|
||||||
v.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor).isActive = true
|
v.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
self.images.append(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StatusMetaIndicatorsView {
|
||||||
struct Indicator: OptionSet {
|
struct Indicator: OptionSet {
|
||||||
let rawValue: Int
|
let rawValue: Int
|
||||||
|
|
||||||
|
@ -172,8 +81,4 @@ class StatusMetaIndicatorsView: UIView {
|
||||||
|
|
||||||
static let all: Indicator = [.reply, .visibility, .localOnly]
|
static let all: Indicator = [.reply, .visibility, .localOnly]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Alignment {
|
|
||||||
case leading, trailing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
|
|
||||||
private lazy var reblogLabel = EmojiLabel().configure {
|
private lazy var reblogLabel = EmojiLabel().configure {
|
||||||
$0.textColor = .secondaryLabel
|
$0.textColor = .secondaryLabel
|
||||||
$0.font = .preferredFont(forTextStyle: .body)
|
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
// this needs to have a higher priorty than the content container's zero height constraint
|
// this needs to have a higher priorty than the content container's zero height constraint
|
||||||
$0.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
$0.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
$0.isUserInteractionEnabled = true
|
$0.isUserInteractionEnabled = true
|
||||||
|
@ -60,10 +58,7 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
$0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
|
$0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(accountPressed)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private let metaIndicatorsView = StatusMetaIndicatorsView().configure {
|
private let metaIndicatorsView = StatusMetaIndicatorsView()
|
||||||
$0.primaryAxis = .vertical
|
|
||||||
$0.secondaryAxisAlignment = .trailing
|
|
||||||
}
|
|
||||||
|
|
||||||
private lazy var contentVStack = UIStackView(arrangedSubviews: [
|
private lazy var contentVStack = UIStackView(arrangedSubviews: [
|
||||||
nameHStack,
|
nameHStack,
|
||||||
|
@ -92,7 +87,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
|
||||||
]
|
]
|
||||||
]), size: 0)
|
]), size: 0)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
$0.setContentHuggingPriority(.init(251), for: .horizontal)
|
$0.setContentHuggingPriority(.init(251), for: .horizontal)
|
||||||
$0.setContentCompressionResistancePriority(.init(749), for: .horizontal)
|
$0.setContentCompressionResistancePriority(.init(749), for: .horizontal)
|
||||||
}
|
}
|
||||||
|
@ -104,7 +98,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
||||||
]
|
]
|
||||||
]), size: 0)
|
]), size: 0)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
$0.setContentHuggingPriority(.init(249), for: .horizontal)
|
$0.setContentHuggingPriority(.init(249), for: .horizontal)
|
||||||
$0.setContentCompressionResistancePriority(.init(748), for: .horizontal)
|
$0.setContentCompressionResistancePriority(.init(748), for: .horizontal)
|
||||||
}
|
}
|
||||||
|
@ -121,7 +114,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
||||||
]
|
]
|
||||||
]), size: 0)
|
]), size: 0)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private(set) lazy var contentWarningLabel = EmojiLabel().configure {
|
private(set) lazy var contentWarningLabel = EmojiLabel().configure {
|
||||||
|
@ -132,7 +124,6 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold.rawValue,
|
UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold.rawValue,
|
||||||
]
|
]
|
||||||
]), size: 0)
|
]), size: 0)
|
||||||
$0.adjustsFontForContentSizeCategory = true
|
|
||||||
// this needs to have a higher priorty than the content container's zero height constraint
|
// this needs to have a higher priorty than the content container's zero height constraint
|
||||||
$0.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
$0.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
$0.isUserInteractionEnabled = true
|
$0.isUserInteractionEnabled = true
|
||||||
|
|
|
@ -46,51 +46,17 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell {
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
isAccessibilityElement = true
|
|
||||||
|
|
||||||
reblogLabel.font = .preferredFont(forTextStyle: .body)
|
|
||||||
reblogLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
reblogLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reblogLabelPressed)))
|
reblogLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reblogLabelPressed)))
|
||||||
|
|
||||||
avatarImageView.addInteraction(UIContextMenuInteraction(delegate: self))
|
isAccessibilityElement = true
|
||||||
|
|
||||||
displayNameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
displayNameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
usernameLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
usernameLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
timestampLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
timestampLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
metaIndicatorsView.primaryAxis = .vertical
|
|
||||||
metaIndicatorsView.secondaryAxisAlignment = .trailing
|
|
||||||
|
|
||||||
contentWarningLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
|
|
||||||
.traits: [
|
|
||||||
UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold.rawValue,
|
|
||||||
]
|
|
||||||
]), size: 0)
|
|
||||||
contentWarningLabel.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
contentTextView.defaultFont = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 16))
|
|
||||||
contentTextView.adjustsFontForContentSizeCategory = true
|
|
||||||
|
|
||||||
// todo: double check this on RTL layouts
|
// todo: double check this on RTL layouts
|
||||||
replyButton.imageView!.leadingAnchor.constraint(equalTo: contentTextView.leadingAnchor).isActive = true
|
replyButton.imageView!.leadingAnchor.constraint(equalTo: contentTextView.leadingAnchor).isActive = true
|
||||||
|
|
||||||
|
contentTextView.defaultFont = .systemFont(ofSize: 16)
|
||||||
|
|
||||||
|
avatarImageView.addInteraction(UIContextMenuInteraction(delegate: self))
|
||||||
|
|
||||||
updateActionsVisibility()
|
updateActionsVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,20 @@ protocol ToastableViewController: UIViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private let currentToastKey = UnsafeMutableRawPointer.allocate(byteCount: 0, alignment: 0)
|
private var currentToastKey = "Tusker_currentToast"
|
||||||
|
|
||||||
extension ToastableViewController {
|
extension ToastableViewController {
|
||||||
|
|
||||||
private(set) var currentToast: ToastView? {
|
private(set) var currentToast: ToastView? {
|
||||||
get {
|
get {
|
||||||
let holder = objc_getAssociatedObject(self, currentToastKey) as? WeakHolder<ToastView>
|
let holder = objc_getAssociatedObject(self, ¤tToastKey) as? WeakHolder<ToastView>
|
||||||
return holder?.object
|
return holder?.object
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if let newValue = newValue {
|
if let newValue = newValue {
|
||||||
objc_setAssociatedObject(self, currentToastKey, WeakHolder(object: newValue), .OBJC_ASSOCIATION_RETAIN)
|
objc_setAssociatedObject(self, ¤tToastKey, WeakHolder(object: newValue), .OBJC_ASSOCIATION_RETAIN)
|
||||||
} else {
|
} else {
|
||||||
objc_setAssociatedObject(self, currentToastKey, nil, .OBJC_ASSOCIATION_RETAIN)
|
objc_setAssociatedObject(self, ¤tToastKey, nil, .OBJC_ASSOCIATION_RETAIN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue