Skip to content

Commit

Permalink
Boscojwho/improve comment show hide animations (#426)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Andrews <[email protected]>
  • Loading branch information
boscojwho and EricBAndrews authored Aug 9, 2023
1 parent 5204022 commit c561efa
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 44 deletions.
16 changes: 16 additions & 0 deletions Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@
CDF842682A49FB9000723DA0 /* Inbox View Logic.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF842672A49FB9000723DA0 /* Inbox View Logic.swift */; };
CDF8426B2A4A2AB600723DA0 /* Inbox Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF8426A2A4A2AB600723DA0 /* Inbox Item.swift */; };
CDF8426F2A4A385A00723DA0 /* Inbox Item Type.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF8426E2A4A385A00723DA0 /* Inbox Item Type.swift */; };
E4D4DBA02A7C7B9D00C4F3DE /* Comments.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D4DB9F2A7C7B9D00C4F3DE /* Comments.swift */; };
E4DDB4322A81819300B3A7E0 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4DDB4312A81819300B3A7E0 /* Double.swift */; };
E453A1D02A81C2140004BB8A /* QuickLookPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E453A1CF2A81C2140004BB8A /* QuickLookPreviewController.swift */; };
E4DDB4342A819C8000B3A7E0 /* QuickLookView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4DDB4332A819C8000B3A7E0 /* QuickLookView.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -743,6 +745,8 @@
CDF842672A49FB9000723DA0 /* Inbox View Logic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Inbox View Logic.swift"; sourceTree = "<group>"; };
CDF8426A2A4A2AB600723DA0 /* Inbox Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Inbox Item.swift"; sourceTree = "<group>"; };
CDF8426E2A4A385A00723DA0 /* Inbox Item Type.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Inbox Item Type.swift"; sourceTree = "<group>"; };
E4D4DB9F2A7C7B9D00C4F3DE /* Comments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comments.swift; sourceTree = "<group>"; };
E4DDB4312A81819300B3A7E0 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
E453A1CF2A81C2140004BB8A /* QuickLookPreviewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickLookPreviewController.swift; sourceTree = "<group>"; };
E4DDB4332A819C8000B3A7E0 /* QuickLookView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickLookView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -1076,6 +1080,7 @@
isa = PBXGroup;
children = (
6D8003782A45FD1300363206 /* Bundle.swift */,
E4DDB4312A81819300B3A7E0 /* Double.swift */,
6332FDC227EFCB5F0009A98A /* Color.swift */,
6386E0392A0455BC006B3C1D /* String - Contains Elements From Array.swift */,
63F0C7BA2A058CB700A18C5D /* URLSessionWebSocketTask - Send Ping.swift */,
Expand Down Expand Up @@ -1197,6 +1202,7 @@
6363D5C327EE196700E34822 /* Mlem */ = {
isa = PBXGroup;
children = (
E4D4DB9E2A7C7A5800C4F3DE /* Animations */,
CDE9CE4A2A7B07F6002B97DD /* Haptics */,
CDC6A8C82A6F1C8000CC11AC /* Protocols */,
CDDCF6412A662444003DA3AC /* Custom Tab Bar */,
Expand Down Expand Up @@ -1926,6 +1932,14 @@
path = Messages;
sourceTree = "<group>";
};
E4D4DB9E2A7C7A5800C4F3DE /* Animations */ = {
isa = PBXGroup;
children = (
E4D4DB9F2A7C7B9D00C4F3DE /* Comments.swift */,
);
path = Animations;
sourceTree = "<group>";
};
E453A1CE2A81C1F20004BB8A /* Quick Look */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2171,6 +2185,7 @@
B1DD00BD2A62DDEC002A7B39 /* RecognizedLemmyInstances.swift in Sources */,
6DA61F892A575DF1001EA633 /* URL - Lemmy Image Parameters.swift in Sources */,
ADDC9E3C2A5CF02A00383D58 /* BlockPersonLogic.swift in Sources */,
E4DDB4322A81819300B3A7E0 /* Double.swift in Sources */,
CD3FBCD92A4A6BD100B2063F /* Replies Tracker.swift in Sources */,
5016A2B32A67EC0700B257E8 /* NotificationDisplayer.swift in Sources */,
CD1446212A5B328E00610EF1 /* Privacy Policy.swift in Sources */,
Expand Down Expand Up @@ -2369,6 +2384,7 @@
6386E0402A045723006B3C1D /* Website Icon Complex.swift in Sources */,
5064D0412A6E63E000B22EE3 /* Task+Notifiable.swift in Sources */,
63F0C7BD2A058CD200A18C5D /* Check if Endpoint Exists.swift in Sources */,
E4D4DBA02A7C7B9D00C4F3DE /* Comments.swift in Sources */,
6363D5C727EE196700E34822 /* ContentView.swift in Sources */,
6D8F08FF2A4029AE003EB4FD /* Community List View.swift in Sources */,
5016A2B12A67EB8600B257E8 /* UIViewController.swift in Sources */,
Expand Down
32 changes: 32 additions & 0 deletions Mlem/Animations/Comments.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Comments.swift
// Mlem
//
// Created by Bosco Ho on 2023-08-03.
//

import SwiftUI

internal extension Animation {

/// Animation for expanding or collapsing a comment and its child comments.
static func showHideComment(_ collapse: Bool) -> Animation {
let standard = (0.4, 1.0, collapse ? 0.25 : 0.3)
let animationValues = standard
return .interactiveSpring(
response: animationValues.0,
dampingFraction: animationValues.1,
blendDuration: animationValues.2)
}
}

internal extension AnyTransition {

static func markdownView() -> AnyTransition {
.opacity
}

static func commentView() -> AnyTransition {
.move(edge: .top).combined(with: .opacity)
}
}
20 changes: 20 additions & 0 deletions Mlem/Extensions/Double.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Double.swift
// Mlem
//
// Created by Bosco Ho on 2023-08-07.
//

import Foundation

// MARK: - SwiftUI
extension Double {

/// Use this value in SwiftUI to modify a view to be the top-most layer.
///
/// This sentinel value exists because using `Int.max` doesn't work.
static var maxZIndex: Double {
/// [2023.08] `Int.max` doesn't work, which is why this is set to just some big value.
return 99999
}
}
84 changes: 40 additions & 44 deletions Mlem/Views/Shared/Comments/Comment Item.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,65 +95,62 @@ struct CommentItem: View {
}

// MARK: Body

// swiftlint:disable line_length
var body: some View {
if hierarchicalComment.isParentCollapsed, hierarchicalComment.isCollapsed, hierarchicalComment.commentView.comment.parentId != nil {
EmptyView()
} else if hierarchicalComment.isParentCollapsed, !hierarchicalComment.isCollapsed, hierarchicalComment.commentView.comment.parentId != nil {
EmptyView()
} else {
Group {
VStack(spacing: 0) {
commentBody(hierarchicalComment: self.hierarchicalComment)
Divider()
if hierarchicalComment.isParentCollapsed, hierarchicalComment.isCollapsed, hierarchicalComment.commentView.comment.parentId != nil {
EmptyView()
} else if hierarchicalComment.isParentCollapsed, !hierarchicalComment.isCollapsed, hierarchicalComment.commentView.comment.parentId != nil {
EmptyView()
} else {
Group {
commentBody(hierarchicalComment: self.hierarchicalComment)
Divider()
}
/// Clips any transitions to this view, otherwise comments will animate over other ones.
.clipped()
.padding(.leading, indentValue)
.transition(.commentView())
}
}
.clipped()
.padding(.leading, indentValue)
}
}
// swiftlint:enable line_length

// MARK: Subviews

// swiftlint:disable function_body_length
@ViewBuilder
private func commentBody(hierarchicalComment: HierarchicalComment) -> some View {
Group {
VStack(alignment: .leading, spacing: 0) {
CommentBodyView(commentView: hierarchicalComment.commentView,
isParentCollapsed: $hierarchicalComment.isParentCollapsed,
isCollapsed: $hierarchicalComment.isCollapsed,
showPostContext: showPostContext,
menuFunctions: genMenuFunctions())
// top and bottom spacing uses default even when compact--it's *too* compact otherwise
.padding(.top, AppConstants.postAndCommentSpacing)
.padding(.horizontal, AppConstants.postAndCommentSpacing)

if !hierarchicalComment.isCollapsed && !compactComments {
CommentInteractionBar(commentView: hierarchicalComment.commentView,
displayedScore: displayedScore,
displayedVote: displayedVote,
displayedSaved: displayedSaved,
upvote: upvote,
downvote: downvote,
saveComment: saveComment,
deleteComment: deleteComment,
replyToComment: replyToComment)
} else {
Spacer()
.frame(height: AppConstants.postAndCommentSpacing)
}
VStack(alignment: .leading, spacing: 0) {
CommentBodyView(commentView: hierarchicalComment.commentView,
isParentCollapsed: $hierarchicalComment.isParentCollapsed,
isCollapsed: $hierarchicalComment.isCollapsed,
showPostContext: showPostContext,
menuFunctions: genMenuFunctions())
// top and bottom spacing uses default even when compact--it's *too* compact otherwise
.padding(.top, AppConstants.postAndCommentSpacing)
.padding(.horizontal, AppConstants.postAndCommentSpacing)

if !hierarchicalComment.isCollapsed && !compactComments {
CommentInteractionBar(commentView: hierarchicalComment.commentView,
displayedScore: displayedScore,
displayedVote: displayedVote,
displayedSaved: displayedSaved,
upvote: upvote,
downvote: downvote,
saveComment: saveComment,
deleteComment: deleteComment,
replyToComment: replyToComment)
} else {
Spacer()
.frame(height: AppConstants.postAndCommentSpacing)
}
.transition(
.asymmetric(
insertion: .move(edge: .bottom).combined(with: .opacity),
removal: .move(edge: .top).combined(with: .opacity)
)
)
}
.contentShape(Rectangle()) // allow taps in blank space to register
.onTapGesture {
withAnimation(.interactiveSpring(response: 0.4, dampingFraction: 1, blendDuration: 0.4)) {
withAnimation(.showHideComment(!hierarchicalComment.isCollapsed)) {
// Perhaps we want an explict flag for this in the future?
if !showPostContext {
commentTracker.setCollapsed(!hierarchicalComment.isCollapsed, comment: hierarchicalComment)
Expand Down Expand Up @@ -182,7 +179,6 @@ struct CommentItem: View {
// report: true))
// }
}
// swiftlint:enable function_body_length
}

// MARK: - Swipe Actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct CommentBodyView: View {
} else if !isCollapsed {
MarkdownView(text: commentView.comment.content, isNsfw: commentView.post.nsfw)
.frame(maxWidth: .infinity, alignment: .topLeading)
.transition(.markdownView())
}
}

Expand Down
2 changes: 2 additions & 0 deletions Mlem/Views/Shared/Posts/Expanded Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ struct ExpandedPost: View {
showPostContext: false,
showCommentCreator: true
)
/// [2023.08] Manually set zIndex so child comments don't overlap parent comments on collapse/expand animations. `Int.max` doesn't work, which is why this is set to just some big value.
.zIndex(.maxZIndex - Double(comment.depth))
}
}
}
Expand Down

0 comments on commit c561efa

Please sign in to comment.