Compare commits
No commits in common. "6d692c273069113f2419d0aa211fdf4bdd6d19a5" and "01124b76a3e40d41e22e6e4a6f57475627e12a64" have entirely different histories.
6d692c2730
...
01124b76a3
|
@ -76,6 +76,10 @@
|
||||||
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */; };
|
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */; };
|
||||||
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944E23A9C99800D38C68 /* EditListAccountsViewController.swift */; };
|
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627944E23A9C99800D38C68 /* EditListAccountsViewController.swift */; };
|
||||||
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF75217E923E00CC0648 /* DraftsManager.swift */; };
|
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF75217E923E00CC0648 /* DraftsManager.swift */; };
|
||||||
|
D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF78217E950100CC0648 /* DraftsTableViewController.xib */; };
|
||||||
|
D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */; };
|
||||||
|
D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */; };
|
||||||
|
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */; };
|
||||||
D6285B5321EA708700FE4B39 /* StatusFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6285B5221EA708700FE4B39 /* StatusFormat.swift */; };
|
D6285B5321EA708700FE4B39 /* StatusFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6285B5221EA708700FE4B39 /* StatusFormat.swift */; };
|
||||||
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */; };
|
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */; };
|
||||||
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
|
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
|
||||||
|
@ -253,8 +257,6 @@
|
||||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */; };
|
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */; };
|
||||||
D6BEA245291A0EDE002F4D01 /* Duckable in Frameworks */ = {isa = PBXBuildFile; productRef = D6BEA244291A0EDE002F4D01 /* Duckable */; };
|
D6BEA245291A0EDE002F4D01 /* Duckable in Frameworks */ = {isa = PBXBuildFile; productRef = D6BEA244291A0EDE002F4D01 /* Duckable */; };
|
||||||
D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */; };
|
D6BEA247291A0F2D002F4D01 /* Duckable+Root.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */; };
|
||||||
D6BEA249291C6118002F4D01 /* DraftsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BEA248291C6118002F4D01 /* DraftsView.swift */; };
|
|
||||||
D6BEA24B291C6A2B002F4D01 /* AlertWithData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BEA24A291C6A2B002F4D01 /* AlertWithData.swift */; };
|
|
||||||
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */; };
|
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */; };
|
||||||
D6C143DA253510F4007DC240 /* ComposeEmojiTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */; };
|
D6C143DA253510F4007DC240 /* ComposeEmojiTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */; };
|
||||||
D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1B2072545D1EC00DAAA66 /* StatusCardView.swift */; };
|
D6C1B2082545D1EC00DAAA66 /* StatusCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1B2072545D1EC00DAAA66 /* StatusCardView.swift */; };
|
||||||
|
@ -430,6 +432,10 @@
|
||||||
D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTimelineViewController.swift; sourceTree = "<group>"; };
|
D627944C23A9A03D00D38C68 /* ListTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTimelineViewController.swift; sourceTree = "<group>"; };
|
||||||
D627944E23A9C99800D38C68 /* EditListAccountsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditListAccountsViewController.swift; sourceTree = "<group>"; };
|
D627944E23A9C99800D38C68 /* EditListAccountsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditListAccountsViewController.swift; sourceTree = "<group>"; };
|
||||||
D627FF75217E923E00CC0648 /* DraftsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsManager.swift; sourceTree = "<group>"; };
|
D627FF75217E923E00CC0648 /* DraftsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsManager.swift; sourceTree = "<group>"; };
|
||||||
|
D627FF78217E950100CC0648 /* DraftsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftsTableViewController.xib; sourceTree = "<group>"; };
|
||||||
|
D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsTableViewController.swift; sourceTree = "<group>"; };
|
||||||
|
D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
|
D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D6285B5221EA708700FE4B39 /* StatusFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFormat.swift; sourceTree = "<group>"; };
|
D6285B5221EA708700FE4B39 /* StatusFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFormat.swift; sourceTree = "<group>"; };
|
||||||
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LargeImageViewController.xib; sourceTree = "<group>"; };
|
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LargeImageViewController.xib; sourceTree = "<group>"; };
|
||||||
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
|
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
|
||||||
|
@ -609,8 +615,6 @@
|
||||||
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = "<group>"; };
|
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = "<group>"; };
|
||||||
D6BEA243291A0C83002F4D01 /* Duckable */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Duckable; path = Packages/Duckable; sourceTree = "<group>"; };
|
D6BEA243291A0C83002F4D01 /* Duckable */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Duckable; path = Packages/Duckable; sourceTree = "<group>"; };
|
||||||
D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Duckable+Root.swift"; sourceTree = "<group>"; };
|
D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Duckable+Root.swift"; sourceTree = "<group>"; };
|
||||||
D6BEA248291C6118002F4D01 /* DraftsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsView.swift; sourceTree = "<group>"; };
|
|
||||||
D6BEA24A291C6A2B002F4D01 /* AlertWithData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertWithData.swift; sourceTree = "<group>"; };
|
|
||||||
D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusTableViewCell.swift; sourceTree = "<group>"; };
|
D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeEmojiTextField.swift; sourceTree = "<group>"; };
|
D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeEmojiTextField.swift; sourceTree = "<group>"; };
|
||||||
D6C1B2072545D1EC00DAAA66 /* StatusCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCardView.swift; sourceTree = "<group>"; };
|
D6C1B2072545D1EC00DAAA66 /* StatusCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCardView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -739,6 +743,15 @@
|
||||||
path = "Hashtag Cell";
|
path = "Hashtag Cell";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D61959D0241E842400A37B8E /* Draft Cell */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */,
|
||||||
|
D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */,
|
||||||
|
);
|
||||||
|
path = "Draft Cell";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D61959D2241E846D00A37B8E /* Models */ = {
|
D61959D2241E846D00A37B8E /* Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -837,6 +850,15 @@
|
||||||
path = Lists;
|
path = Lists;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D627FF77217E94F200CC0648 /* Drafts */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D627FF78217E950100CC0648 /* DraftsTableViewController.xib */,
|
||||||
|
D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */,
|
||||||
|
);
|
||||||
|
path = Drafts;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D62D241E217AA46B005076CC /* Shortcuts */ = {
|
D62D241E217AA46B005076CC /* Shortcuts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -884,6 +906,7 @@
|
||||||
D641C787213DD862004B4513 /* Compose */,
|
D641C787213DD862004B4513 /* Compose */,
|
||||||
D641C785213DD83B004B4513 /* Conversation */,
|
D641C785213DD83B004B4513 /* Conversation */,
|
||||||
D6F2E960249E772F005846BB /* Crash Reporter */,
|
D6F2E960249E772F005846BB /* Crash Reporter */,
|
||||||
|
D627FF77217E94F200CC0648 /* Drafts */,
|
||||||
D627943C23A5635D00D38C68 /* Explore */,
|
D627943C23A5635D00D38C68 /* Explore */,
|
||||||
D6A4DCC92553666600D9DE31 /* Fast Account Switcher */,
|
D6A4DCC92553666600D9DE31 /* Fast Account Switcher */,
|
||||||
D641C788213DD86D004B4513 /* Large Image */,
|
D641C788213DD86D004B4513 /* Large Image */,
|
||||||
|
@ -988,7 +1011,6 @@
|
||||||
D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */,
|
D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */,
|
||||||
D6E4267625327FB400C02E1C /* ComposeAutocompleteView.swift */,
|
D6E4267625327FB400C02E1C /* ComposeAutocompleteView.swift */,
|
||||||
D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */,
|
D6C143D9253510F4007DC240 /* ComposeEmojiTextField.swift */,
|
||||||
D6BEA248291C6118002F4D01 /* DraftsView.swift */,
|
|
||||||
);
|
);
|
||||||
path = Compose;
|
path = Compose;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1262,7 +1284,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */,
|
D6B4A4FE2506B81A000C81C1 /* AccountDisplayNameLabel.swift */,
|
||||||
D6BEA24A291C6A2B002F4D01 /* AlertWithData.swift */,
|
|
||||||
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
|
D68E6F5E253C9B2D001A1B4C /* BaseEmojiLabel.swift */,
|
||||||
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
|
D6ADB6EF28ED1F25009924AB /* CachedImageView.swift */,
|
||||||
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
|
D6895DC328D65342006341DA /* ConfirmReblogStatusPreviewView.swift */,
|
||||||
|
@ -1291,6 +1312,7 @@
|
||||||
D626494023C122C800612E6E /* Asset Picker */,
|
D626494023C122C800612E6E /* Asset Picker */,
|
||||||
D6C7D27B22B6EBE200071952 /* Attachments */,
|
D6C7D27B22B6EBE200071952 /* Attachments */,
|
||||||
D6DEA0DB268400AF00FE896A /* Confirm Load More Cell */,
|
D6DEA0DB268400AF00FE896A /* Confirm Load More Cell */,
|
||||||
|
D61959D0241E842400A37B8E /* Draft Cell */,
|
||||||
D611C2CC232DC5FC00C86A49 /* Hashtag Cell */,
|
D611C2CC232DC5FC00C86A49 /* Hashtag Cell */,
|
||||||
D61AC1DA232EA43100C54D2D /* Instance Cell */,
|
D61AC1DA232EA43100C54D2D /* Instance Cell */,
|
||||||
D641C78C213DD937004B4513 /* Notifications */,
|
D641C78C213DD937004B4513 /* Notifications */,
|
||||||
|
@ -1648,6 +1670,7 @@
|
||||||
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */,
|
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */,
|
||||||
D626493923C0FD0000612E6E /* AllPhotosTableViewCell.xib in Resources */,
|
D626493923C0FD0000612E6E /* AllPhotosTableViewCell.xib in Resources */,
|
||||||
D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */,
|
D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */,
|
||||||
|
D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */,
|
||||||
D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */,
|
D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */,
|
||||||
D6412B0B24B0D4C600F5412E /* ProfileHeaderView.xib in Resources */,
|
D6412B0B24B0D4C600F5412E /* ProfileHeaderView.xib in Resources */,
|
||||||
D6C82B5725C5F3F20017F1E6 /* ExpandThreadTableViewCell.xib in Resources */,
|
D6C82B5725C5F3F20017F1E6 /* ExpandThreadTableViewCell.xib in Resources */,
|
||||||
|
@ -1659,6 +1682,7 @@
|
||||||
D663625D2135C74800C9CBA2 /* ConversationMainStatusTableViewCell.xib in Resources */,
|
D663625D2135C74800C9CBA2 /* ConversationMainStatusTableViewCell.xib in Resources */,
|
||||||
D640D76922BAF5E6004FBE69 /* DomainBlocks.plist in Resources */,
|
D640D76922BAF5E6004FBE69 /* DomainBlocks.plist in Resources */,
|
||||||
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */,
|
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */,
|
||||||
|
D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */,
|
||||||
D626493D23C1000300612E6E /* AlbumTableViewCell.xib in Resources */,
|
D626493D23C1000300612E6E /* AlbumTableViewCell.xib in Resources */,
|
||||||
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */,
|
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */,
|
||||||
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */,
|
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */,
|
||||||
|
@ -1837,7 +1861,7 @@
|
||||||
D67B506D250B291200FAECFB /* BlurHashDecode.swift in Sources */,
|
D67B506D250B291200FAECFB /* BlurHashDecode.swift in Sources */,
|
||||||
D62275A024F1677200B82A16 /* ComposeHostingController.swift in Sources */,
|
D62275A024F1677200B82A16 /* ComposeHostingController.swift in Sources */,
|
||||||
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */,
|
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */,
|
||||||
D6BEA249291C6118002F4D01 /* DraftsView.swift in Sources */,
|
D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */,
|
||||||
D6403CC224A6B72D00E81C55 /* VisualEffectImageButton.swift in Sources */,
|
D6403CC224A6B72D00E81C55 /* VisualEffectImageButton.swift in Sources */,
|
||||||
D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */,
|
D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */,
|
||||||
D673ACCE2919E74200D6F8B0 /* MenuPicker.swift in Sources */,
|
D673ACCE2919E74200D6F8B0 /* MenuPicker.swift in Sources */,
|
||||||
|
@ -1851,6 +1875,7 @@
|
||||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
||||||
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
|
D61ABEF628EE74D400B29151 /* StatusCollectionViewCell.swift in Sources */,
|
||||||
D61DC84628F498F200B82C6E /* Logging.swift in Sources */,
|
D61DC84628F498F200B82C6E /* Logging.swift in Sources */,
|
||||||
|
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
|
||||||
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */,
|
D6B17255254F88B800128392 /* OppositeCollapseKeywordsView.swift in Sources */,
|
||||||
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */,
|
D6A00B1D26379FC900316AD4 /* PollOptionsView.swift in Sources */,
|
||||||
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */,
|
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */,
|
||||||
|
@ -1908,7 +1933,6 @@
|
||||||
D681E4D3246E2AFF0053414F /* MuteConversationActivity.swift in Sources */,
|
D681E4D3246E2AFF0053414F /* MuteConversationActivity.swift in Sources */,
|
||||||
D6969EA0240C8384002843CE /* EmojiLabel.swift in Sources */,
|
D6969EA0240C8384002843CE /* EmojiLabel.swift in Sources */,
|
||||||
D64BC18623C1253A000D0238 /* AssetPreviewViewController.swift in Sources */,
|
D64BC18623C1253A000D0238 /* AssetPreviewViewController.swift in Sources */,
|
||||||
D6BEA24B291C6A2B002F4D01 /* AlertWithData.swift in Sources */,
|
|
||||||
D61ABEFE28F1C92600B29151 /* FavoriteService.swift in Sources */,
|
D61ABEFE28F1C92600B29151 /* FavoriteService.swift in Sources */,
|
||||||
D663626221360B1900C9CBA2 /* Preferences.swift in Sources */,
|
D663626221360B1900C9CBA2 /* Preferences.swift in Sources */,
|
||||||
D626493823C0FD0000612E6E /* AllPhotosTableViewCell.swift in Sources */,
|
D626493823C0FD0000612E6E /* AllPhotosTableViewCell.swift in Sources */,
|
||||||
|
|
|
@ -107,8 +107,6 @@ extension Draft: Equatable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Draft: Identifiable {}
|
|
||||||
|
|
||||||
extension Draft {
|
extension Draft {
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class DraftsManager: Codable, ObservableObject {
|
class DraftsManager: Codable {
|
||||||
|
|
||||||
private(set) static var shared: DraftsManager = load()
|
private(set) static var shared: DraftsManager = load()
|
||||||
|
|
||||||
|
@ -48,12 +48,7 @@ class DraftsManager: Codable, ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(to encoder: Encoder) throws {
|
private var drafts: [UUID: Draft] = [:]
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
||||||
try container.encode(drafts, forKey: .drafts)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Published private var drafts: [UUID: Draft] = [:]
|
|
||||||
var sorted: [Draft] {
|
var sorted: [Draft] {
|
||||||
return drafts.values.sorted(by: { $0.lastModified > $1.lastModified })
|
return drafts.values.sorted(by: { $0.lastModified > $1.lastModified })
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,7 +335,9 @@ class ComposeHostingController: UIHostingController<ComposeContainerView>, Ducka
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func draftsButtonPresed() {
|
@objc func draftsButtonPresed() {
|
||||||
uiState.isShowingDraftsList = true
|
let draftsVC = DraftsTableViewController(account: mastodonController.accountInfo!, exclude: draft)
|
||||||
|
draftsVC.delegate = self
|
||||||
|
present(UINavigationController(rootViewController: draftsVC), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -375,16 +377,6 @@ extension ComposeHostingController: ComposeUIStateDelegate {
|
||||||
|
|
||||||
present(ComposeDrawingNavigationController(editing: drawing, delegate: self), animated: true)
|
present(ComposeDrawingNavigationController(editing: drawing, delegate: self), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectDraft(_ draft: Draft) {
|
|
||||||
if self.draft.hasContent {
|
|
||||||
DraftsManager.save()
|
|
||||||
} else {
|
|
||||||
DraftsManager.shared.remove(self.draft)
|
|
||||||
}
|
|
||||||
uiState.draft = draft
|
|
||||||
uiState.isShowingDraftsList = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ComposeHostingController: AssetPickerViewControllerDelegate {
|
extension ComposeHostingController: AssetPickerViewControllerDelegate {
|
||||||
|
@ -411,6 +403,42 @@ extension ComposeHostingController: AssetPickerViewControllerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ComposeHostingController: DraftsTableViewControllerDelegate {
|
||||||
|
func draftSelectionCanceled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldSelectDraft(_ draft: Draft, completion: @escaping (Bool) -> Void) {
|
||||||
|
if draft.inReplyToID != self.draft.inReplyToID,
|
||||||
|
self.draft.hasContent {
|
||||||
|
let alertController = UIAlertController(title: "Different Reply", message: "The selected draft is a reply to a different status, do you wish to use it?", preferredStyle: .alert)
|
||||||
|
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
|
||||||
|
completion(false)
|
||||||
|
}))
|
||||||
|
alertController.addAction(UIAlertAction(title: "Restore Draft", style: .default, handler: { (_) in
|
||||||
|
completion(true)
|
||||||
|
}))
|
||||||
|
// we can't present the laert ourselves since the compose VC is already presenting the draft selector
|
||||||
|
// but presenting on the presented view controller seems hacky, is there a better way to do this?
|
||||||
|
presentedViewController!.present(alertController, animated: true)
|
||||||
|
} else {
|
||||||
|
completion(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func draftSelected(_ draft: Draft) {
|
||||||
|
if self.draft.hasContent {
|
||||||
|
DraftsManager.save()
|
||||||
|
} else {
|
||||||
|
DraftsManager.shared.remove(self.draft)
|
||||||
|
}
|
||||||
|
|
||||||
|
uiState.draft = draft
|
||||||
|
}
|
||||||
|
|
||||||
|
func draftSelectionCompleted() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// superseded by duckable stuff
|
// superseded by duckable stuff
|
||||||
@available(iOS, obsoleted: 16.0)
|
@available(iOS, obsoleted: 16.0)
|
||||||
extension ComposeHostingController: UIAdaptivePresentationControllerDelegate {
|
extension ComposeHostingController: UIAdaptivePresentationControllerDelegate {
|
||||||
|
|
|
@ -82,7 +82,6 @@ struct WrappedTextView: UIViewRepresentable {
|
||||||
|
|
||||||
func updateUIView(_ uiView: UITextView, context: Context) {
|
func updateUIView(_ uiView: UITextView, context: Context) {
|
||||||
uiView.text = text
|
uiView.text = text
|
||||||
context.coordinator.textView = uiView
|
|
||||||
context.coordinator.text = $text
|
context.coordinator.text = $text
|
||||||
context.coordinator.didChange = textDidChange
|
context.coordinator.didChange = textDidChange
|
||||||
// wait until the next runloop iteration so that SwiftUI view updates have finished and
|
// wait until the next runloop iteration so that SwiftUI view updates have finished and
|
||||||
|
@ -97,7 +96,6 @@ struct WrappedTextView: UIViewRepresentable {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Coordinator: NSObject, UITextViewDelegate, ComposeTextViewCaretScrolling {
|
class Coordinator: NSObject, UITextViewDelegate, ComposeTextViewCaretScrolling {
|
||||||
weak var textView: UITextView?
|
|
||||||
var text: Binding<String>
|
var text: Binding<String>
|
||||||
var didChange: ((UITextView) -> Void)?
|
var didChange: ((UITextView) -> Void)?
|
||||||
var caretScrollPositionAnimator: UIViewPropertyAnimator?
|
var caretScrollPositionAnimator: UIViewPropertyAnimator?
|
||||||
|
@ -105,16 +103,6 @@ struct WrappedTextView: UIViewRepresentable {
|
||||||
init(text: Binding<String>, didChange: ((UITextView) -> Void)?) {
|
init(text: Binding<String>, didChange: ((UITextView) -> Void)?) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.didChange = didChange
|
self.didChange = didChange
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func keyboardDidShow() {
|
|
||||||
guard let textView,
|
|
||||||
textView.isFirstResponder else { return }
|
|
||||||
ensureCursorVisible(textView: textView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func textViewDidChange(_ textView: UITextView) {
|
func textViewDidChange(_ textView: UITextView) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ extension ComposeTextViewCaretScrolling {
|
||||||
rectToMakeVisible.origin.y -= cursorRect.height
|
rectToMakeVisible.origin.y -= cursorRect.height
|
||||||
rectToMakeVisible.size.height *= 3
|
rectToMakeVisible.size.height *= 3
|
||||||
|
|
||||||
let animator = UIViewPropertyAnimator(duration: 0.2, curve: .easeInOut) {
|
let animator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
|
||||||
scrollView.scrollRectToVisible(rectToMakeVisible, animated: false)
|
scrollView.scrollRectToVisible(rectToMakeVisible, animated: false)
|
||||||
}
|
}
|
||||||
self.caretScrollPositionAnimator = animator
|
self.caretScrollPositionAnimator = animator
|
||||||
|
|
|
@ -15,7 +15,6 @@ protocol ComposeUIStateDelegate: AnyObject {
|
||||||
// @available(iOS, obsoleted: 16.0)
|
// @available(iOS, obsoleted: 16.0)
|
||||||
func presentAssetPickerSheet()
|
func presentAssetPickerSheet()
|
||||||
func presentComposeDrawing()
|
func presentComposeDrawing()
|
||||||
func selectDraft(_ draft: Draft)
|
|
||||||
|
|
||||||
func keyboardWillShow(accessoryView: UIView, notification: Notification)
|
func keyboardWillShow(accessoryView: UIView, notification: Notification)
|
||||||
func keyboardWillHide(accessoryView: UIView, notification: Notification)
|
func keyboardWillHide(accessoryView: UIView, notification: Notification)
|
||||||
|
@ -28,7 +27,6 @@ class ComposeUIState: ObservableObject {
|
||||||
|
|
||||||
@Published var draft: Draft
|
@Published var draft: Draft
|
||||||
@Published var isShowingSaveDraftSheet = false
|
@Published var isShowingSaveDraftSheet = false
|
||||||
@Published var isShowingDraftsList = false
|
|
||||||
@Published var attachmentsMissingDescriptions = Set<UUID>()
|
@Published var attachmentsMissingDescriptions = Set<UUID>()
|
||||||
@Published var autocompleteState: AutocompleteState? = nil
|
@Published var autocompleteState: AutocompleteState? = nil
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,6 @@ struct ComposeView: View {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.navigationTitle(navTitle)
|
.navigationTitle(navTitle)
|
||||||
.sheet(isPresented: $uiState.isShowingDraftsList) {
|
|
||||||
DraftsView(currentDraft: draft)
|
|
||||||
}
|
|
||||||
.actionSheet(isPresented: $uiState.isShowingSaveDraftSheet, content: self.saveAndCloseSheet)
|
.actionSheet(isPresented: $uiState.isShowingSaveDraftSheet, content: self.saveAndCloseSheet)
|
||||||
.alert(isPresented: $isShowingPostErrorAlert) {
|
.alert(isPresented: $isShowingPostErrorAlert) {
|
||||||
Alert(
|
Alert(
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
//
|
|
||||||
// DraftsView.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 11/9/22.
|
|
||||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct DraftsView: View {
|
|
||||||
let currentDraft: Draft
|
|
||||||
@EnvironmentObject var uiState: ComposeUIState
|
|
||||||
@EnvironmentObject var mastodonController: MastodonController
|
|
||||||
@StateObject private var draftsManager = DraftsManager.shared
|
|
||||||
@State private var draftForDifferentReply: Draft?
|
|
||||||
|
|
||||||
private var visibleDrafts: [Draft] {
|
|
||||||
draftsManager.sorted.filter {
|
|
||||||
$0.accountID == mastodonController.accountInfo!.id && $0.id != currentDraft.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
NavigationView {
|
|
||||||
List {
|
|
||||||
ForEach(visibleDrafts) { draft in
|
|
||||||
Button {
|
|
||||||
maybeSelectDraft(draft)
|
|
||||||
} label: {
|
|
||||||
DraftView(draft: draft)
|
|
||||||
}
|
|
||||||
.onDrag {
|
|
||||||
let activity = UserActivityManager.editDraftActivity(id: draft.id, accountID: mastodonController.accountInfo!.id)
|
|
||||||
activity.displaysAuxiliaryScene = true
|
|
||||||
return NSItemProvider(object: activity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onDelete { indices in
|
|
||||||
indices
|
|
||||||
.map { visibleDrafts[$0] }
|
|
||||||
.forEach { draftsManager.remove($0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.listStyle(.plain)
|
|
||||||
.navigationTitle(Text("Drafts"))
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
|
||||||
Button("Cancel") {
|
|
||||||
uiState.isShowingDraftsList = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.alertWithData("Different Reply", data: $draftForDifferentReply) { draft in
|
|
||||||
Button("Cancel", role: .cancel) {
|
|
||||||
draftForDifferentReply = nil
|
|
||||||
}
|
|
||||||
Button("Restore Draft") {
|
|
||||||
uiState.delegate?.selectDraft(draft)
|
|
||||||
}
|
|
||||||
} message: { draft in
|
|
||||||
Text("The selected draft is a reply to a different post, do you wish to use it?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func maybeSelectDraft(_ draft: Draft) {
|
|
||||||
if draft.inReplyToID != currentDraft.inReplyToID,
|
|
||||||
currentDraft.hasContent {
|
|
||||||
draftForDifferentReply = draft
|
|
||||||
} else {
|
|
||||||
uiState.delegate?.selectDraft(draft)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DraftView: View {
|
|
||||||
@ObservedObject private var draft: Draft
|
|
||||||
|
|
||||||
init(draft: Draft) {
|
|
||||||
self._draft = ObservedObject(wrappedValue: draft)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if draft.contentWarningEnabled {
|
|
||||||
Text(draft.contentWarning)
|
|
||||||
.font(.body.bold())
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(draft.text)
|
|
||||||
.font(.body)
|
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
|
||||||
ForEach(draft.attachments) { attachment in
|
|
||||||
ComposeAttachmentImage(attachment: attachment, fullSize: false)
|
|
||||||
.frame(width: 50, height: 50)
|
|
||||||
.cornerRadius(5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Text(draft.lastModified.timeAgoString())
|
|
||||||
.font(.body)
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DraftsView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
DraftsView(currentDraft: Draft(accountID: ""))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -168,16 +168,6 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.didChange = didChange
|
self.didChange = didChange
|
||||||
self.uiState = uiState
|
self.uiState = uiState
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: UIResponder.keyboardDidShowNotification, object: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func keyboardDidShow() {
|
|
||||||
guard let textView,
|
|
||||||
textView.isFirstResponder else { return }
|
|
||||||
ensureCursorVisible(textView: textView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func textViewDidChange(_ textView: UITextView) {
|
func textViewDidChange(_ textView: UITextView) {
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
//
|
||||||
|
// DraftsTableViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 10/22/18.
|
||||||
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
protocol DraftsTableViewControllerDelegate: AnyObject {
|
||||||
|
func draftSelectionCanceled()
|
||||||
|
func shouldSelectDraft(_ draft: Draft, completion: @escaping (Bool) -> Void)
|
||||||
|
func draftSelected(_ draft: Draft)
|
||||||
|
func draftSelectionCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
class DraftsTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
let account: LocalData.UserAccountInfo
|
||||||
|
let excludedDraft: Draft?
|
||||||
|
weak var delegate: DraftsTableViewControllerDelegate?
|
||||||
|
|
||||||
|
var drafts = [Draft]()
|
||||||
|
|
||||||
|
init(account: LocalData.UserAccountInfo, exclude: Draft? = nil) {
|
||||||
|
self.account = account
|
||||||
|
self.excludedDraft = exclude
|
||||||
|
|
||||||
|
super.init(nibName: "DraftsTableViewController", bundle: nil)
|
||||||
|
|
||||||
|
title = "Drafts"
|
||||||
|
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
|
tableView.estimatedRowHeight = 140
|
||||||
|
|
||||||
|
tableView.register(UINib(nibName: "DraftTableViewCell", bundle: nil), forCellReuseIdentifier: "draftCell")
|
||||||
|
|
||||||
|
tableView.dragDelegate = self
|
||||||
|
|
||||||
|
drafts = DraftsManager.shared.sorted.filter { (draft) in
|
||||||
|
draft.accountID == account.id && draft != excludedDraft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func draft(for indexPath: IndexPath) -> Draft {
|
||||||
|
return drafts[indexPath.row]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Table View Data Source
|
||||||
|
|
||||||
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return drafts.count
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "draftCell", for: indexPath) as? DraftTableViewCell else { fatalError() }
|
||||||
|
|
||||||
|
cell.updateUI(for: draft(for: indexPath))
|
||||||
|
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
let draft = self.draft(for: indexPath)
|
||||||
|
func select() {
|
||||||
|
delegate?.draftSelected(draft)
|
||||||
|
dismiss(animated: true) {
|
||||||
|
self.delegate?.draftSelectionCompleted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let delegate = delegate {
|
||||||
|
delegate.shouldSelectDraft(draft) { (shouldSelect) in
|
||||||
|
if shouldSelect {
|
||||||
|
select()
|
||||||
|
} else {
|
||||||
|
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||||
|
return .delete
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||||
|
guard editingStyle == .delete else { return }
|
||||||
|
DraftsManager.shared.remove(draft(for: indexPath))
|
||||||
|
drafts.remove(at: indexPath.row)
|
||||||
|
tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||||
|
return UIContextMenuConfiguration(actionProvider: { _ in
|
||||||
|
return UIMenu(children: [
|
||||||
|
UIAction(title: "Delete Draft", image: UIImage(systemName: "trash"), attributes: .destructive, handler: { [unowned self] _ in
|
||||||
|
DraftsManager.shared.remove(self.draft(for: indexPath))
|
||||||
|
drafts.remove(at: indexPath.row)
|
||||||
|
tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||||
|
})
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Interaction
|
||||||
|
|
||||||
|
@objc func cancelPressed() {
|
||||||
|
delegate?.draftSelectionCanceled()
|
||||||
|
dismiss(animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DraftsTableViewController: UITableViewDragDelegate {
|
||||||
|
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
||||||
|
let draft = self.draft(for: indexPath)
|
||||||
|
let activity = UserActivityManager.editDraftActivity(id: draft.id, accountID: account.id)
|
||||||
|
activity.displaysAuxiliaryScene = true
|
||||||
|
let provider = NSItemProvider(object: activity)
|
||||||
|
return [UIDragItem(itemProvider: provider)]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="DraftsTableViewController" customModule="Tusker" customModuleProvider="target">
|
||||||
|
<connections>
|
||||||
|
<outlet property="view" destination="O5v-ea-iTS" id="sft-3K-LZf"/>
|
||||||
|
</connections>
|
||||||
|
</placeholder>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="O5v-ea-iTS">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
|
<point key="canvasLocation" x="-302" y="87"/>
|
||||||
|
</tableView>
|
||||||
|
</objects>
|
||||||
|
</document>
|
|
@ -1,45 +0,0 @@
|
||||||
//
|
|
||||||
// AlertWithData.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 11/9/22.
|
|
||||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct AlertWithData<Data, A: View, M: View>: ViewModifier {
|
|
||||||
let title: LocalizedStringKey
|
|
||||||
@Binding var data: Data?
|
|
||||||
let actions: (Data) -> A
|
|
||||||
let message: (Data) -> M
|
|
||||||
|
|
||||||
private var isPresented: Binding<Bool> {
|
|
||||||
Binding(get: {
|
|
||||||
data != nil
|
|
||||||
}, set: { newValue in
|
|
||||||
guard !newValue else {
|
|
||||||
fatalError("Cannot set isPresented to true without data")
|
|
||||||
}
|
|
||||||
data = nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
init(title: LocalizedStringKey, data: Binding<Data?>, @ViewBuilder actions: @escaping (Data) -> A, @ViewBuilder message: @escaping (Data) -> M) {
|
|
||||||
self.title = title
|
|
||||||
self._data = data
|
|
||||||
self.actions = actions
|
|
||||||
self.message = message
|
|
||||||
}
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
content
|
|
||||||
.alert(title, isPresented: isPresented, presenting: data, actions: actions, message: message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
func alertWithData<Data, A: View, M: View>(_ title: LocalizedStringKey, data: Binding<Data?>, @ViewBuilder actions: @escaping (Data) -> A, @ViewBuilder message: @escaping (Data) -> M) -> some View {
|
|
||||||
modifier(AlertWithData(title: title, data: data, actions: actions, message: message))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
//
|
||||||
|
// DraftsTableViewCell.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 10/22/18.
|
||||||
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
class DraftTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
|
@IBOutlet weak var contentWarningLabel: UILabel!
|
||||||
|
@IBOutlet weak var contentLabel: UILabel!
|
||||||
|
@IBOutlet weak var lastModifiedLabel: UILabel!
|
||||||
|
@IBOutlet weak var attachmentsStackViewContainer: UIView!
|
||||||
|
@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) {
|
||||||
|
contentWarningLabel.text = draft.contentWarning
|
||||||
|
contentWarningLabel.isHidden = !draft.contentWarningEnabled
|
||||||
|
contentLabel.text = draft.text
|
||||||
|
lastModifiedLabel.text = draft.lastModified.timeAgoString()
|
||||||
|
|
||||||
|
attachmentsStackViewContainer.isHidden = draft.attachments.count == 0
|
||||||
|
|
||||||
|
for attachment in draft.attachments {
|
||||||
|
let size = CGSize(width: 50, height: 50)
|
||||||
|
let imageView = UIImageView(frame: CGRect(origin: .zero, size: size))
|
||||||
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
imageView.layer.masksToBounds = true
|
||||||
|
imageView.layer.cornerRadius = 5
|
||||||
|
attachmentsStackView.addArrangedSubview(imageView)
|
||||||
|
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
|
||||||
|
|
||||||
|
imageView.backgroundColor = .secondarySystemBackground
|
||||||
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
||||||
|
switch attachment.data {
|
||||||
|
case let .asset(asset):
|
||||||
|
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: nil) { (image, _) in
|
||||||
|
imageView.image = image
|
||||||
|
}
|
||||||
|
case let .image(image):
|
||||||
|
imageView.image = image
|
||||||
|
case .video(_):
|
||||||
|
// videos aren't saved to drafts, so this is unreachable
|
||||||
|
return
|
||||||
|
case let .drawing(drawing):
|
||||||
|
imageView.image = drawing.imageInLightMode(from: drawing.bounds)
|
||||||
|
imageView.backgroundColor = .white
|
||||||
|
imageView.contentMode = .scaleAspectFit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
|
||||||
|
attachmentsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?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">
|
||||||
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<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"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="143" id="Q7N-Mt-RPF" customClass="DraftTableViewCell" customModule="Tusker" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="143"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Q7N-Mt-RPF" id="KVi-jA-AET">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="143"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<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"/>
|
||||||
|
<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">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="351" height="18"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zMS-88-DcM">
|
||||||
|
<rect key="frame" x="0.0" y="26" width="351" height="40"/>
|
||||||
|
<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">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="310.5" height="32"/>
|
||||||
|
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||||
|
<nil key="textColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</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">
|
||||||
|
<rect key="frame" x="326.5" y="0.0" width="24.5" height="20.5"/>
|
||||||
|
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||||
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="D2X-9O-iQw" firstAttribute="leading" secondItem="8eA-yd-rBp" secondAttribute="trailing" constant="16" id="6Ux-ee-J5h"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="D2X-9O-iQw" secondAttribute="trailing" id="IRH-mM-HSs"/>
|
||||||
|
<constraint firstItem="8eA-yd-rBp" firstAttribute="leading" secondItem="zMS-88-DcM" secondAttribute="leading" id="StS-F9-9B3"/>
|
||||||
|
<constraint firstItem="8eA-yd-rBp" firstAttribute="top" secondItem="zMS-88-DcM" secondAttribute="top" id="Uuq-g5-n0A"/>
|
||||||
|
<constraint firstItem="D2X-9O-iQw" firstAttribute="top" secondItem="zMS-88-DcM" secondAttribute="top" id="lWB-6Z-nbG"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="8eA-yd-rBp" secondAttribute="bottom" id="zCK-s5-4Zo"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="csc-gx-KVg">
|
||||||
|
<rect key="frame" x="0.0" y="74" width="351" height="50"/>
|
||||||
|
<subviews>
|
||||||
|
<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"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="height" constant="50" id="lxT-O2-afE"/>
|
||||||
|
</constraints>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="htC-hf-vJ4" firstAttribute="leading" secondItem="csc-gx-KVg" secondAttribute="leading" id="c0s-O9-XKa"/>
|
||||||
|
<constraint firstItem="htC-hf-vJ4" firstAttribute="top" secondItem="csc-gx-KVg" secondAttribute="top" id="lcl-RN-qHw"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="htC-hf-vJ4" secondAttribute="bottom" id="oHX-Qh-bmI"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="csc-gx-KVg" secondAttribute="trailing" id="AcZ-yc-8Zh"/>
|
||||||
|
</constraints>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="gaD-3B-qO1" secondAttribute="bottomMargin" constant="8" id="4Hz-ax-JI6"/>
|
||||||
|
<constraint firstItem="gaD-3B-qO1" firstAttribute="leading" secondItem="KVi-jA-AET" secondAttribute="leadingMargin" id="KRA-Q8-klX"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="gaD-3B-qO1" secondAttribute="trailingMargin" constant="8" id="iGc-c4-n9y"/>
|
||||||
|
<constraint firstItem="gaD-3B-qO1" firstAttribute="top" secondItem="KVi-jA-AET" secondAttribute="topMargin" id="rVE-Jo-6zG"/>
|
||||||
|
</constraints>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
<connections>
|
||||||
|
<outlet property="attachmentsStackView" destination="htC-hf-vJ4" id="kEX-m7-LuE"/>
|
||||||
|
<outlet property="attachmentsStackViewContainer" destination="csc-gx-KVg" id="rIM-pj-TFX"/>
|
||||||
|
<outlet property="contentLabel" destination="8eA-yd-rBp" id="Uy0-8G-WbU"/>
|
||||||
|
<outlet property="contentWarningLabel" destination="VhS-ig-6Fu" id="jIU-vr-OsY"/>
|
||||||
|
<outlet property="lastModifiedLabel" destination="D2X-9O-iQw" id="dx7-0E-RuM"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="-388" y="184.85757121439281"/>
|
||||||
|
</tableViewCell>
|
||||||
|
</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>
|
Loading…
Reference in New Issue