Compare commits
8 Commits
17f15db32d
...
4ce8de280e
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 4ce8de280e | |
Shadowfacts | 4018d39312 | |
Shadowfacts | ae416bb604 | |
Shadowfacts | 5e9caf9179 | |
Shadowfacts | 3bbbb05083 | |
Shadowfacts | bd3e74c611 | |
Shadowfacts | 2e8c416e04 | |
Shadowfacts | 955f9e5916 |
|
@ -7,14 +7,11 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0411610022B442870030A9B7 /* AttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041160FE22B442870030A9B7 /* AttachmentViewController.swift */; };
|
0411610022B442870030A9B7 /* LoadingLargeImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041160FE22B442870030A9B7 /* LoadingLargeImageViewController.swift */; };
|
||||||
0411610122B442870030A9B7 /* AttachmentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 041160FF22B442870030A9B7 /* AttachmentViewController.xib */; };
|
|
||||||
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */; };
|
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */; };
|
||||||
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; };
|
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; };
|
||||||
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; };
|
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; };
|
||||||
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; };
|
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; };
|
||||||
0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */; };
|
|
||||||
0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */; };
|
|
||||||
04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; };
|
04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; };
|
||||||
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; };
|
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; };
|
||||||
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; };
|
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; };
|
||||||
|
@ -291,14 +288,11 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
041160FE22B442870030A9B7 /* AttachmentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentViewController.swift; sourceTree = "<group>"; };
|
041160FE22B442870030A9B7 /* LoadingLargeImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingLargeImageViewController.swift; sourceTree = "<group>"; };
|
||||||
041160FF22B442870030A9B7 /* AttachmentViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AttachmentViewController.xib; sourceTree = "<group>"; };
|
|
||||||
0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BehaviorPrefsView.swift; sourceTree = "<group>"; };
|
0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BehaviorPrefsView.swift; sourceTree = "<group>"; };
|
||||||
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = "<group>"; };
|
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = "<group>"; };
|
||||||
0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = "<group>"; };
|
0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = "<group>"; };
|
||||||
0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = "<group>"; };
|
0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = "<group>"; };
|
||||||
0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryExpandAnimationController.swift; sourceTree = "<group>"; };
|
|
||||||
0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryShrinkAnimationController.swift; sourceTree = "<group>"; };
|
|
||||||
04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||||
04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = "<group>"; };
|
04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = "<group>"; };
|
||||||
0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -572,31 +566,12 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
0411610422B4571E0030A9B7 /* Attachment */ = {
|
0411610522B457290030A9B7 /* Attachment Gallery */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
041160FE22B442870030A9B7 /* AttachmentViewController.swift */,
|
|
||||||
041160FF22B442870030A9B7 /* AttachmentViewController.xib */,
|
|
||||||
);
|
|
||||||
path = Attachment;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
0411610522B457290030A9B7 /* Gallery */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0411610622B457360030A9B7 /* Transitions */,
|
|
||||||
04D14BAE22B34A2800642648 /* GalleryViewController.swift */,
|
04D14BAE22B34A2800642648 /* GalleryViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Gallery;
|
path = "Attachment Gallery";
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
0411610622B457360030A9B7 /* Transitions */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */,
|
|
||||||
0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */,
|
|
||||||
);
|
|
||||||
path = Transitions;
|
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
D61099AC2144B0CC00432DC2 /* Pachyderm */ = {
|
D61099AC2144B0CC00432DC2 /* Pachyderm */ = {
|
||||||
|
@ -824,8 +799,7 @@
|
||||||
D6BC9DD8232D8BCA002CA326 /* Search */,
|
D6BC9DD8232D8BCA002CA326 /* Search */,
|
||||||
D627944B23A9A02400D38C68 /* Lists */,
|
D627944B23A9A02400D38C68 /* Lists */,
|
||||||
D641C788213DD86D004B4513 /* Large Image */,
|
D641C788213DD86D004B4513 /* Large Image */,
|
||||||
0411610422B4571E0030A9B7 /* Attachment */,
|
0411610522B457290030A9B7 /* Attachment Gallery */,
|
||||||
0411610522B457290030A9B7 /* Gallery */,
|
|
||||||
D6A3BC822321F69400FD64D5 /* Account List */,
|
D6A3BC822321F69400FD64D5 /* Account List */,
|
||||||
D6A3BC8C2321FF9B00FD64D5 /* Status Action Account List */,
|
D6A3BC8C2321FF9B00FD64D5 /* Status Action Account List */,
|
||||||
D627944823A6AD5100D38C68 /* Bookmarks */,
|
D627944823A6AD5100D38C68 /* Bookmarks */,
|
||||||
|
@ -904,6 +878,7 @@
|
||||||
D646C954213B364600269FB5 /* Transitions */,
|
D646C954213B364600269FB5 /* Transitions */,
|
||||||
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */,
|
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */,
|
||||||
D6C94D862139E62700CB5196 /* LargeImageViewController.swift */,
|
D6C94D862139E62700CB5196 /* LargeImageViewController.swift */,
|
||||||
|
041160FE22B442870030A9B7 /* LoadingLargeImageViewController.swift */,
|
||||||
);
|
);
|
||||||
path = "Large Image";
|
path = "Large Image";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1507,7 +1482,6 @@
|
||||||
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */,
|
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */,
|
||||||
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */,
|
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */,
|
||||||
D67C57B221E28FAD00C3118B /* ComposeStatusReplyView.xib in Resources */,
|
D67C57B221E28FAD00C3118B /* ComposeStatusReplyView.xib in Resources */,
|
||||||
0411610122B442870030A9B7 /* AttachmentViewController.xib in Resources */,
|
|
||||||
D63F9C6C241C50B9004C03CF /* ComposeAttachmentTableViewCell.xib in Resources */,
|
D63F9C6C241C50B9004C03CF /* ComposeAttachmentTableViewCell.xib in Resources */,
|
||||||
D6A3BC812321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib in Resources */,
|
D6A3BC812321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.xib in Resources */,
|
||||||
D63F9C66241C4CC3004C03CF /* AddAttachmentTableViewCell.xib in Resources */,
|
D63F9C66241C4CC3004C03CF /* AddAttachmentTableViewCell.xib in Resources */,
|
||||||
|
@ -1630,7 +1604,6 @@
|
||||||
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
||||||
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
||||||
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
|
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
|
||||||
0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */,
|
|
||||||
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
||||||
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
||||||
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
||||||
|
@ -1641,7 +1614,7 @@
|
||||||
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */,
|
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */,
|
||||||
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */,
|
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */,
|
||||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
||||||
0411610022B442870030A9B7 /* AttachmentViewController.swift in Sources */,
|
0411610022B442870030A9B7 /* LoadingLargeImageViewController.swift in Sources */,
|
||||||
D611C2CF232DC61100C86A49 /* HashtagTableViewCell.swift in Sources */,
|
D611C2CF232DC61100C86A49 /* HashtagTableViewCell.swift in Sources */,
|
||||||
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */,
|
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */,
|
||||||
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */,
|
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */,
|
||||||
|
@ -1664,7 +1637,6 @@
|
||||||
D64BC18823C1640A000D0238 /* PinStatusActivity.swift in Sources */,
|
D64BC18823C1640A000D0238 /* PinStatusActivity.swift in Sources */,
|
||||||
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */,
|
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */,
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */,
|
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
||||||
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
||||||
|
@ -2046,7 +2018,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
CURRENT_PROJECT_VERSION = 4;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
@ -2071,7 +2043,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
CURRENT_PROJECT_VERSION = 4;
|
||||||
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
DEVELOPMENT_TEAM = V4WK9KR9U2;
|
||||||
INFOPLIST_FILE = Tusker/Info.plist;
|
INFOPLIST_FILE = Tusker/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
|
|
@ -10,23 +10,17 @@ import UIKit
|
||||||
|
|
||||||
extension UIViewController: UIViewControllerTransitioningDelegate {
|
extension UIViewController: UIViewControllerTransitioningDelegate {
|
||||||
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
if let presented = presented as? LargeImageViewController,
|
if let presented = presented as? LargeImageAnimatableViewController,
|
||||||
presented.sourceInfo?.image != nil {
|
presented.animationImage != nil {
|
||||||
return LargeImageExpandAnimationController()
|
return LargeImageExpandAnimationController()
|
||||||
} else if let presented = presented as? GalleryViewController,
|
|
||||||
presented.sourcesInfo[presented.startIndex]?.image != nil {
|
|
||||||
return GalleryExpandAnimationController()
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
if let dismissed = dismissed as? LargeImageViewController,
|
if let dismissed = dismissed as? LargeImageAnimatableViewController,
|
||||||
dismissed.imageForDismissalAnimation() != nil {
|
dismissed.animationImage != nil {
|
||||||
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
||||||
} else if let dismissed = dismissed as? GalleryViewController,
|
|
||||||
dismissed.imageForDismissalAnimation() != nil {
|
|
||||||
return GalleryShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -36,10 +30,6 @@ extension UIViewController: UIViewControllerTransitioningDelegate {
|
||||||
let interactionController = animator.interactionController,
|
let interactionController = animator.interactionController,
|
||||||
interactionController.inProgress {
|
interactionController.inProgress {
|
||||||
return interactionController
|
return interactionController
|
||||||
} else if let animator = animator as? GalleryShrinkAnimationController,
|
|
||||||
let interactionController = animator.interactionController,
|
|
||||||
interactionController.inProgress {
|
|
||||||
return interactionController
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,6 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>UTExportedTypeDeclarations</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>UTTypeConformsTo</key>
|
|
||||||
<array/>
|
|
||||||
<key>UTTypeIdentifier</key>
|
|
||||||
<string>space.vaccor.Tusker.composition-attachment</string>
|
|
||||||
<key>UTTypeTagSpecification</key>
|
|
||||||
<dict/>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
@ -60,7 +49,7 @@
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Post videos from the camera.</string>
|
<string>Post videos from the camera.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Save photos directly from other people's posts.</string>
|
<string>Save photos directly from other people's posts.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Post photos from the photo library.</string>
|
<string>Post photos from the photo library.</string>
|
||||||
<key>NSUserActivityTypes</key>
|
<key>NSUserActivityTypes</key>
|
||||||
|
@ -109,5 +98,16 @@
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UTExportedTypeDeclarations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>space.vaccor.Tusker.composition-attachment</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -8,14 +8,16 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
|
||||||
class AttachmentViewController: UIViewController {
|
class PendingLargeImageViewController: UIViewController {
|
||||||
|
|
||||||
let attachment: Attachment
|
let url: URL
|
||||||
|
let cache: ImageCache
|
||||||
|
let imageDescription: String?
|
||||||
|
|
||||||
var largeImageVC: LargeImageViewController?
|
var largeImageVC: LargeImageViewController?
|
||||||
var loadingVC: LoadingViewController?
|
var loadingVC: LoadingViewController?
|
||||||
|
|
||||||
var attachmentRequest: ImageCache.Request?
|
var imageRequest: ImageCache.Request?
|
||||||
|
|
||||||
private var initialControlsVisible: Bool = true
|
private var initialControlsVisible: Bool = true
|
||||||
var controlsVisible: Bool {
|
var controlsVisible: Bool {
|
||||||
|
@ -35,10 +37,16 @@ class AttachmentViewController: UIViewController {
|
||||||
return largeImageVC
|
return largeImageVC
|
||||||
}
|
}
|
||||||
|
|
||||||
init(attachment: Attachment) {
|
init(url: URL, cache: ImageCache, imageDescription: String?) {
|
||||||
self.attachment = attachment
|
self.url = url
|
||||||
|
self.cache = cache
|
||||||
|
self.imageDescription = imageDescription
|
||||||
|
|
||||||
super.init(nibName: "AttachmentViewController", bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(attachment: Attachment) {
|
||||||
|
self.init(url: attachment.url, cache: .attachments, imageDescription: attachment.description)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
|
@ -51,14 +59,14 @@ class AttachmentViewController: UIViewController {
|
||||||
overrideUserInterfaceStyle = .dark
|
overrideUserInterfaceStyle = .dark
|
||||||
view.backgroundColor = .black
|
view.backgroundColor = .black
|
||||||
|
|
||||||
if let data = ImageCache.attachments.get(attachment.url) {
|
if let data = cache.get(url) {
|
||||||
createLargeImage(data: data)
|
createLargeImage(data: data)
|
||||||
} else {
|
} else {
|
||||||
loadingVC = LoadingViewController()
|
loadingVC = LoadingViewController()
|
||||||
embedChild(loadingVC!)
|
embedChild(loadingVC!)
|
||||||
attachmentRequest = ImageCache.attachments.get(attachment.url) { [weak self] (data) in
|
imageRequest = cache.get(url) { [weak self] (data) in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.attachmentRequest = nil
|
self.imageRequest = nil
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.loadingVC?.removeViewAndController()
|
self.loadingVC?.removeViewAndController()
|
||||||
self.createLargeImage(data: data!)
|
self.createLargeImage(data: data!)
|
||||||
|
@ -71,16 +79,16 @@ class AttachmentViewController: UIViewController {
|
||||||
super.didMove(toParent: parent)
|
super.didMove(toParent: parent)
|
||||||
|
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
attachmentRequest?.cancel()
|
imageRequest?.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createLargeImage(data: Data) {
|
func createLargeImage(data: Data) {
|
||||||
guard let image = UIImage(data: data) else { return }
|
guard let image = UIImage(data: data) else { return }
|
||||||
largeImageVC = LargeImageViewController(image: image, description: attachment.description, sourceInfo: nil)
|
largeImageVC = LargeImageViewController(image: image, description: imageDescription, sourceInfo: nil)
|
||||||
largeImageVC!.initialControlsVisible = initialControlsVisible
|
largeImageVC!.initialControlsVisible = initialControlsVisible
|
||||||
largeImageVC!.shrinkGestureEnabled = false
|
largeImageVC!.shrinkGestureEnabled = false
|
||||||
if attachment.url.pathExtension == "gif" {
|
if url.pathExtension == "gif" {
|
||||||
largeImageVC!.gifData = data
|
largeImageVC!.gifData = data
|
||||||
}
|
}
|
||||||
embedChild(largeImageVC!)
|
embedChild(largeImageVC!)
|
|
@ -10,9 +10,7 @@ import Pachyderm
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
import AVKit
|
import AVKit
|
||||||
|
|
||||||
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
|
||||||
|
|
||||||
let attachments: [Attachment]
|
let attachments: [Attachment]
|
||||||
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
||||||
|
@ -28,6 +26,24 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var animationSourceInfo: LargeImageViewController.SourceInfo? { sourcesInfo[currentIndex] }
|
||||||
|
var animationImage: UIImage? {
|
||||||
|
if let sourceImage = sourcesInfo[currentIndex]?.image {
|
||||||
|
return sourceImage
|
||||||
|
} else {
|
||||||
|
return (pages[currentIndex] as? LoadingLargeImageViewController)?.largeImageVC?.image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var animationGifData: Data? {
|
||||||
|
let attachment = attachments[currentIndex]
|
||||||
|
if attachment.url.pathExtension == "gif" {
|
||||||
|
return ImageCache.attachments.get(attachment.url)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
override var prefersStatusBarHidden: Bool {
|
override var prefersStatusBarHidden: Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -51,7 +67,9 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
self.pages = attachments.map {
|
self.pages = attachments.map {
|
||||||
switch $0.kind {
|
switch $0.kind {
|
||||||
case .image:
|
case .image:
|
||||||
return AttachmentViewController(attachment: $0)
|
let vc = LoadingLargeImageViewController(attachment: $0)
|
||||||
|
vc.shrinkGestureEnabled = false
|
||||||
|
return vc
|
||||||
case .video, .audio:
|
case .video, .audio:
|
||||||
let vc = AVPlayerViewController()
|
let vc = AVPlayerViewController()
|
||||||
vc.player = AVPlayer(url: $0.url)
|
vc.player = AVPlayer(url: $0.url)
|
||||||
|
@ -97,14 +115,6 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageForDismissalAnimation() -> UIImage? {
|
|
||||||
if let sourceImage = sourcesInfo[currentIndex]?.image {
|
|
||||||
return sourceImage
|
|
||||||
} else {
|
|
||||||
return (pages[currentIndex] as? AttachmentViewController)?.largeImageVC?.image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Page View Controller Data Source
|
// MARK: - Page View Controller Data Source
|
||||||
|
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
||||||
|
@ -125,8 +135,8 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
|
|
||||||
// MARK: - Page View Controller Delegate
|
// MARK: - Page View Controller Delegate
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
||||||
if let pending = pendingViewControllers.first as? AttachmentViewController,
|
if let pending = pendingViewControllers.first as? LoadingLargeImageViewController,
|
||||||
let current = viewControllers!.first as? AttachmentViewController {
|
let current = viewControllers!.first as? LoadingLargeImageViewController {
|
||||||
pending.controlsVisible = current.controlsVisible
|
pending.controlsVisible = current.controlsVisible
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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="retina6_1" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
|
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
|
||||||
<objects>
|
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AttachmentViewController" customModule="Tusker" customModuleProvider="target">
|
|
||||||
<connections>
|
|
||||||
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
|
|
||||||
</connections>
|
|
||||||
</placeholder>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
|
||||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
|
|
||||||
<point key="canvasLocation" x="139" y="3"/>
|
|
||||||
</view>
|
|
||||||
</objects>
|
|
||||||
</document>
|
|
|
@ -154,7 +154,7 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
stepProgress()
|
stepProgress()
|
||||||
|
|
||||||
let formAttachment = FormAttachment(mimeType: mimeType, data: data, fileName: "file")
|
let formAttachment = FormAttachment(mimeType: mimeType, data: data, fileName: "file")
|
||||||
let request = Client.upload(attachment: formAttachment, description: compAttachment.description)
|
let request = Client.upload(attachment: formAttachment, description: compAttachment.attachmentDescription)
|
||||||
self.mastodonController.run(request) { (response) in
|
self.mastodonController.run(request) { (response) in
|
||||||
switch response {
|
switch response {
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// GalleryExpandAnimationController.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 6/14/19.
|
|
||||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Gifu
|
|
||||||
|
|
||||||
class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
||||||
return 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from),
|
|
||||||
let toVC = transitionContext.viewController(forKey: .to) as? GalleryViewController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
|
||||||
guard let sourceInfo = toVC.sourcesInfo[toVC.startIndex],
|
|
||||||
let image = sourceInfo.image else {
|
|
||||||
toVC.view.frame = finalVCFrame
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachment = toVC.attachments[toVC.startIndex]
|
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
|
||||||
var width = finalVCFrame.width
|
|
||||||
var height = width / ratio
|
|
||||||
let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom
|
|
||||||
if height > maxHeight {
|
|
||||||
let scaleFactor = maxHeight / height
|
|
||||||
width *= scaleFactor
|
|
||||||
height = maxHeight
|
|
||||||
}
|
|
||||||
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceInfo.frame)
|
|
||||||
imageView.image = image
|
|
||||||
if attachment.url.pathExtension == "gif",
|
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
|
||||||
}
|
|
||||||
imageView.contentMode = .scaleAspectFill
|
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
|
||||||
imageView.layer.masksToBounds = true
|
|
||||||
|
|
||||||
let blackView = UIView(frame: finalVCFrame)
|
|
||||||
blackView.backgroundColor = .black
|
|
||||||
blackView.alpha = 0
|
|
||||||
|
|
||||||
containerView.addSubview(blackView)
|
|
||||||
containerView.addSubview(imageView)
|
|
||||||
|
|
||||||
toVC.view.isHidden = true
|
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
|
||||||
UIView.animate(withDuration: duration, animations: {
|
|
||||||
imageView.frame = finalFrame
|
|
||||||
imageView.layer.cornerRadius = 0
|
|
||||||
blackView.alpha = 1
|
|
||||||
}, completion: { _ in
|
|
||||||
toVC.view.frame = finalVCFrame
|
|
||||||
|
|
||||||
toVC.view.isHidden = false
|
|
||||||
fromVC.view.isHidden = false
|
|
||||||
blackView.removeFromSuperview()
|
|
||||||
imageView.removeFromSuperview()
|
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
// GalleryShrinkAnimationController.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 6/14/19.
|
|
||||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Gifu
|
|
||||||
|
|
||||||
class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
|
||||||
|
|
||||||
let interactionController: LargeImageInteractionController?
|
|
||||||
|
|
||||||
init(interactionController: LargeImageInteractionController?) {
|
|
||||||
self.interactionController = interactionController
|
|
||||||
}
|
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
||||||
return 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from) as? GalleryViewController,
|
|
||||||
let toVC = transitionContext.viewController(forKey: .to) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let sourceInfo = fromVC.sourcesInfo[fromVC.currentIndex],
|
|
||||||
let image = fromVC.imageForDismissalAnimation() else {
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let originalVCFrame = fromVC.view.frame
|
|
||||||
|
|
||||||
let attachment = fromVC.attachments[fromVC.currentIndex]
|
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
|
||||||
var width = originalVCFrame.width
|
|
||||||
var height = width / ratio
|
|
||||||
let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom
|
|
||||||
if height > maxHeight {
|
|
||||||
let scaleFactor = maxHeight / height
|
|
||||||
width *= scaleFactor
|
|
||||||
height = maxHeight
|
|
||||||
}
|
|
||||||
let originalFrame = CGRect(x: originalVCFrame.midX - width / 2, y: originalVCFrame.midY - height / 2, width: width, height: height)
|
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
|
||||||
imageView.image = image
|
|
||||||
if attachment.url.pathExtension == "gif",
|
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
|
||||||
}
|
|
||||||
imageView.contentMode = .scaleAspectFill
|
|
||||||
imageView.layer.cornerRadius = 0
|
|
||||||
imageView.layer.masksToBounds = true
|
|
||||||
|
|
||||||
let blackView = UIView(frame: originalVCFrame)
|
|
||||||
blackView.backgroundColor = .black
|
|
||||||
blackView.alpha = 1
|
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
containerView.addSubview(blackView)
|
|
||||||
containerView.addSubview(imageView)
|
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
|
||||||
UIView.animate(withDuration: duration, animations: {
|
|
||||||
imageView.frame = sourceInfo.frame
|
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
|
||||||
blackView.alpha = 0
|
|
||||||
}, completion: { _ in
|
|
||||||
blackView.removeFromSuperview()
|
|
||||||
imageView.removeFromSuperview()
|
|
||||||
|
|
||||||
if transitionContext.transitionWasCancelled {
|
|
||||||
toVC.view.removeFromSuperview()
|
|
||||||
}
|
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,15 +7,15 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
|
||||||
import Photos
|
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
||||||
|
|
||||||
var sourceInfo: SourceInfo?
|
var animationSourceInfo: SourceInfo?
|
||||||
|
var animationImage: UIImage? { animationSourceInfo?.image ?? image }
|
||||||
|
var animationGifData: Data? { gifData }
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
@IBOutlet weak var scrollView: UIScrollView!
|
@IBOutlet weak var scrollView: UIScrollView!
|
||||||
|
@ -62,7 +62,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
init(image: UIImage, description: String?, sourceInfo: SourceInfo?) {
|
init(image: UIImage, description: String?, sourceInfo: SourceInfo?) {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.imageDescription = description
|
self.imageDescription = description
|
||||||
self.sourceInfo = sourceInfo
|
self.animationSourceInfo = sourceInfo
|
||||||
|
|
||||||
super.init(nibName: "LargeImageViewController", bundle: nil)
|
super.init(nibName: "LargeImageViewController", bundle: nil)
|
||||||
|
|
||||||
|
@ -128,10 +128,6 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageForDismissalAnimation() -> UIImage? {
|
|
||||||
return sourceInfo?.image ?? image
|
|
||||||
}
|
|
||||||
|
|
||||||
func setControlsVisible(_ controlsVisible: Bool, animated: Bool) {
|
func setControlsVisible(_ controlsVisible: Bool, animated: Bool) {
|
||||||
self.controlsVisible = controlsVisible
|
self.controlsVisible = controlsVisible
|
||||||
if animated {
|
if animated {
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
// LoadingLargeImageViewController.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/14/19.
|
||||||
|
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
|
class LoadingLargeImageViewController: UIViewController, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
|
let url: URL
|
||||||
|
let cache: ImageCache
|
||||||
|
let imageDescription: String?
|
||||||
|
|
||||||
|
var largeImageVC: LargeImageViewController?
|
||||||
|
var loadingVC: LoadingViewController?
|
||||||
|
|
||||||
|
var imageRequest: ImageCache.Request?
|
||||||
|
|
||||||
|
private var initialControlsVisible: Bool = true
|
||||||
|
var controlsVisible: Bool {
|
||||||
|
get {
|
||||||
|
return largeImageVC?.controlsVisible ?? initialControlsVisible
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if let largeImageVC = largeImageVC {
|
||||||
|
largeImageVC.setControlsVisible(newValue, animated: false)
|
||||||
|
} else {
|
||||||
|
initialControlsVisible = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var shrinkGestureEnabled = true
|
||||||
|
|
||||||
|
var animationSourceInfo: LargeImageViewController.SourceInfo?
|
||||||
|
var animationImage: UIImage? { animationSourceInfo?.image ?? largeImageVC?.image }
|
||||||
|
var animationGifData: Data? { largeImageVC?.gifData }
|
||||||
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
|
override var prefersStatusBarHidden: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
override var childForHomeIndicatorAutoHidden: UIViewController? {
|
||||||
|
return largeImageVC
|
||||||
|
}
|
||||||
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||||
|
return .allButUpsideDown
|
||||||
|
} else {
|
||||||
|
return .all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(url: URL, cache: ImageCache, imageDescription: String?) {
|
||||||
|
self.url = url
|
||||||
|
self.cache = cache
|
||||||
|
self.imageDescription = imageDescription
|
||||||
|
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
|
modalPresentationStyle = .fullScreen
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(attachment: Attachment) {
|
||||||
|
self.init(url: attachment.url, cache: .attachments, imageDescription: attachment.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
overrideUserInterfaceStyle = .dark
|
||||||
|
view.backgroundColor = .black
|
||||||
|
|
||||||
|
if let data = cache.get(url) {
|
||||||
|
createLargeImage(data: data)
|
||||||
|
} else {
|
||||||
|
loadingVC = LoadingViewController()
|
||||||
|
embedChild(loadingVC!)
|
||||||
|
imageRequest = cache.get(url) { [weak self] (data) in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.imageRequest = nil
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.loadingVC?.removeViewAndController()
|
||||||
|
self.createLargeImage(data: data!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if shrinkGestureEnabled {
|
||||||
|
dismissInteractionController = LargeImageInteractionController(viewController: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func didMove(toParent parent: UIViewController?) {
|
||||||
|
super.didMove(toParent: parent)
|
||||||
|
|
||||||
|
if parent == nil {
|
||||||
|
imageRequest?.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLargeImage(data: Data) {
|
||||||
|
guard let image = UIImage(data: data) else { return }
|
||||||
|
largeImageVC = LargeImageViewController(image: image, description: imageDescription, sourceInfo: nil)
|
||||||
|
largeImageVC!.initialControlsVisible = initialControlsVisible
|
||||||
|
largeImageVC!.shrinkGestureEnabled = false
|
||||||
|
if url.pathExtension == "gif" {
|
||||||
|
largeImageVC!.gifData = data
|
||||||
|
}
|
||||||
|
embedChild(largeImageVC!)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,13 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
|
protocol LargeImageAnimatableViewController: UIViewController {
|
||||||
|
var animationSourceInfo: LargeImageViewController.SourceInfo? { get }
|
||||||
|
var animationImage: UIImage? { get }
|
||||||
|
var animationGifData: Data? { get }
|
||||||
|
var dismissInteractionController: LargeImageInteractionController? { get }
|
||||||
|
}
|
||||||
|
|
||||||
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||||
|
@ -17,7 +24,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from),
|
guard let fromVC = transitionContext.viewController(forKey: .from),
|
||||||
let toVC = transitionContext.viewController(forKey: .to) as? LargeImageViewController else {
|
let toVC = transitionContext.viewController(forKey: .to) as? LargeImageAnimatableViewController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +32,8 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
containerView.addSubview(toVC.view)
|
containerView.addSubview(toVC.view)
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let sourceInfo = toVC.sourceInfo,
|
guard let sourceInfo = toVC.animationSourceInfo,
|
||||||
let image = sourceInfo.image else {
|
let image = toVC.animationImage else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
|
@ -39,7 +46,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceInfo.frame)
|
let imageView = GIFImageView(frame: sourceInfo.frame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if let gifData = toVC.gifData {
|
if let gifData = toVC.animationGifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
|
@ -22,13 +22,13 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageViewController,
|
guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageAnimatableViewController,
|
||||||
let toVC = transitionContext.viewController(forKey: .to) else {
|
let toVC = transitionContext.viewController(forKey: .to) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let sourceInfo = fromVC.sourceInfo,
|
guard let sourceInfo = fromVC.animationSourceInfo,
|
||||||
let image = fromVC.imageForDismissalAnimation() else {
|
let image = fromVC.animationImage else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
let imageView = GIFImageView(frame: originalFrame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if let gifData = fromVC.gifData {
|
if let gifData = fromVC.animationGifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
|
@ -44,6 +44,10 @@ protocol TuskerNavigationDelegate: class {
|
||||||
|
|
||||||
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView)
|
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView)
|
||||||
|
|
||||||
|
func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController
|
||||||
|
|
||||||
|
func showLoadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView)
|
||||||
|
|
||||||
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController
|
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController
|
||||||
|
|
||||||
func showGallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int)
|
func showGallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int)
|
||||||
|
@ -183,6 +187,17 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
present(largeImage(gifData: gifData, description: description, sourceView: sourceView), animated: true)
|
present(largeImage(gifData: gifData, description: description, sourceView: sourceView), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController {
|
||||||
|
let vc = LoadingLargeImageViewController(url: url, cache: cache, imageDescription: description)
|
||||||
|
vc.animationSourceInfo = sourceViewInfo(sourceView)
|
||||||
|
vc.transitioningDelegate = self
|
||||||
|
return vc
|
||||||
|
}
|
||||||
|
|
||||||
|
func showLoadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) {
|
||||||
|
present(loadingLargeImage(url: url, cache: cache, description: description, animatingFrom: sourceView), animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController {
|
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController {
|
||||||
let sourcesInfo = sourceViews.map(sourceViewInfo)
|
let sourcesInfo = sourceViews.map(sourceViewInfo)
|
||||||
let vc = GalleryViewController(attachments: attachments, sourcesInfo: sourcesInfo, startIndex: startIndex)
|
let vc = GalleryViewController(attachments: attachments, sourcesInfo: sourcesInfo, startIndex: startIndex)
|
||||||
|
|
|
@ -149,11 +149,13 @@ class ProfileHeaderTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func avatarPressed() {
|
@objc func avatarPressed() {
|
||||||
delegate?.showLargeImage(avatarImageView.image!, description: nil, animatingFrom: avatarImageView)
|
guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") }
|
||||||
|
delegate?.showLoadingLargeImage(url: account.avatar, cache: .avatars, description: nil, animatingFrom: avatarImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func headerPressed() {
|
@objc func headerPressed() {
|
||||||
delegate?.showLargeImage(headerImageView.image!, description: nil, animatingFrom: headerImageView)
|
guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") }
|
||||||
|
delegate?.showLoadingLargeImage(url: account.header, cache: .headers, description: nil, animatingFrom: headerImageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ class BaseStatusTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateUIForPreferences() {
|
@objc func updateUIForPreferences() {
|
||||||
guard let account = mastodonController.cache.account(for: accountID) else { return }
|
guard let mastodonController = mastodonController, let account = mastodonController.cache.account(for: accountID) else { return }
|
||||||
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView)
|
||||||
displayNameLabel.updateForAccountDisplayName(account: account)
|
displayNameLabel.updateForAccountDisplayName(account: account)
|
||||||
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || (mastodonController.cache.status(for: statusID)?.sensitive ?? false)
|
attachmentsView.contentHidden = Preferences.shared.blurAllMedia || (mastodonController.cache.status(for: statusID)?.sensitive ?? false)
|
||||||
|
|
Loading…
Reference in New Issue