Switch to expanding attachment buttons
This commit is contained in:
parent
d30fd2fb07
commit
a6ae026541
|
@ -282,6 +282,7 @@
|
|||
B8D64FC725BA78520029CFC0 /* SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */; };
|
||||
B8D64FCB25BA78A90029CFC0 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; };
|
||||
B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D84EA225DF745A005A043E /* LinkPreviewState.swift */; };
|
||||
B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */; };
|
||||
B8FF8DAE25C0D00F004D1F22 /* SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */; };
|
||||
B8FF8DAF25C0D00F004D1F22 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; };
|
||||
B8FF8E6225C10DA5004D1F22 /* GeoLite2-Country-Blocks-IPv4 in Resources */ = {isa = PBXBuildFile; fileRef = B8FF8E6125C10DA5004D1F22 /* GeoLite2-Country-Blocks-IPv4 */; };
|
||||
|
@ -1272,6 +1273,7 @@
|
|||
B8CCF6422397711F0091D419 /* SettingsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVC.swift; sourceTree = "<group>"; };
|
||||
B8D84E9325DF72AF005A043E /* ConversationViewAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConversationViewAction.h; sourceTree = "<group>"; };
|
||||
B8D84EA225DF745A005A043E /* LinkPreviewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewState.swift; sourceTree = "<group>"; };
|
||||
B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandingAttachmentsButton.swift; sourceTree = "<group>"; };
|
||||
B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+ClosedGroups.swift"; sourceTree = "<group>"; };
|
||||
B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Jobs.swift"; sourceTree = "<group>"; };
|
||||
B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = "<group>"; };
|
||||
|
@ -2229,6 +2231,7 @@
|
|||
B8269D3C25C7B34D00488AB4 /* InputTextView.swift */,
|
||||
C374EEF325DB31D40073A857 /* VoiceMessageRecordingView.swift */,
|
||||
C302093D25DCBF07001F572D /* MentionSelectionView.swift */,
|
||||
B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */,
|
||||
);
|
||||
path = "Input View";
|
||||
sourceTree = "<group>";
|
||||
|
@ -4950,6 +4953,7 @@
|
|||
34ABC0E421DD20C500ED9469 /* ConversationMessageMapping.swift in Sources */,
|
||||
B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */,
|
||||
45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */,
|
||||
B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */,
|
||||
4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */,
|
||||
B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */,
|
||||
C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
// TODO
|
||||
// • Brendan no likey buttons above text field
|
||||
// • Slight paging glitch
|
||||
// • Image detail VC transition glitch
|
||||
// • Photo rounding
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate {
|
||||
private let delegate: ExpandingAttachmentsButtonDelegate
|
||||
private var isExpanded = false { didSet { expandOrCollapse() } }
|
||||
|
||||
// MARK: Constraints
|
||||
private lazy var gifButtonContainerBottomConstraint = gifButtonContainer.pin(.bottom, to: .bottom, of: self)
|
||||
private lazy var documentButtonContainerBottomConstraint = documentButtonContainer.pin(.bottom, to: .bottom, of: self)
|
||||
private lazy var libraryButtonContainerBottomConstraint = libraryButtonContainer.pin(.bottom, to: .bottom, of: self)
|
||||
private lazy var cameraButtonContainerBottomConstraint = cameraButtonContainer.pin(.bottom, to: .bottom, of: self)
|
||||
|
||||
// MARK: UI Components
|
||||
lazy var gifButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self, hasOpaqueBackground: true)
|
||||
lazy var gifButtonContainer = container(for: gifButton)
|
||||
lazy var documentButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true)
|
||||
lazy var documentButtonContainer = container(for: documentButton)
|
||||
lazy var libraryButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true)
|
||||
lazy var libraryButtonContainer = container(for: libraryButton)
|
||||
lazy var cameraButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true)
|
||||
lazy var cameraButtonContainer = container(for: cameraButton)
|
||||
lazy var mainButton = InputViewButton(icon: #imageLiteral(resourceName: "ic_plus_24"), delegate: self)
|
||||
lazy var mainButtonContainer = container(for: mainButton)
|
||||
|
||||
// MARK: Lifecycle
|
||||
init(delegate: ExpandingAttachmentsButtonDelegate) {
|
||||
self.delegate = delegate
|
||||
super.init(frame: CGRect.zero)
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
preconditionFailure("Use init(delegate:) instead.")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
preconditionFailure("Use init(delegate:) instead.")
|
||||
}
|
||||
|
||||
private func setUpViewHierarchy() {
|
||||
backgroundColor = .clear
|
||||
// GIF button
|
||||
addSubview(gifButtonContainer)
|
||||
gifButtonContainer.alpha = 0
|
||||
// Document button
|
||||
addSubview(documentButtonContainer)
|
||||
documentButtonContainer.alpha = 0
|
||||
// Library button
|
||||
addSubview(libraryButtonContainer)
|
||||
libraryButtonContainer.alpha = 0
|
||||
// Camera button
|
||||
addSubview(cameraButtonContainer)
|
||||
cameraButtonContainer.alpha = 0
|
||||
// Main button
|
||||
addSubview(mainButtonContainer)
|
||||
// Constraints
|
||||
mainButtonContainer.pin(to: self)
|
||||
gifButtonContainer.center(.horizontal, in: self)
|
||||
documentButtonContainer.center(.horizontal, in: self)
|
||||
libraryButtonContainer.center(.horizontal, in: self)
|
||||
cameraButtonContainer.center(.horizontal, in: self)
|
||||
[ gifButtonContainerBottomConstraint, documentButtonContainerBottomConstraint, libraryButtonContainerBottomConstraint, cameraButtonContainerBottomConstraint ].forEach {
|
||||
$0.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Animation
|
||||
private func expandOrCollapse() {
|
||||
if isExpanded {
|
||||
let expandedButtonSize = InputViewButton.expandedSize
|
||||
let spacing: CGFloat = 4
|
||||
cameraButtonContainerBottomConstraint.constant = -1 * (expandedButtonSize + spacing)
|
||||
libraryButtonContainerBottomConstraint.constant = -2 * (expandedButtonSize + spacing)
|
||||
documentButtonContainerBottomConstraint.constant = -3 * (expandedButtonSize + spacing)
|
||||
gifButtonContainerBottomConstraint.constant = -4 * (expandedButtonSize + spacing)
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
[ self.gifButtonContainer, self.documentButtonContainer, self.libraryButtonContainer, self.cameraButtonContainer ].forEach {
|
||||
$0.alpha = 1
|
||||
}
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
} else {
|
||||
[ gifButtonContainerBottomConstraint, documentButtonContainerBottomConstraint, libraryButtonContainerBottomConstraint, cameraButtonContainerBottomConstraint ].forEach {
|
||||
$0.constant = 0
|
||||
}
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
[ self.gifButtonContainer, self.documentButtonContainer, self.libraryButtonContainer, self.cameraButtonContainer ].forEach {
|
||||
$0.alpha = 0
|
||||
}
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interaction
|
||||
func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) {
|
||||
if inputViewButton == gifButton { delegate.handleGIFButtonTapped(); isExpanded = false }
|
||||
if inputViewButton == documentButton { delegate.handleDocumentButtonTapped(); isExpanded = false }
|
||||
if inputViewButton == libraryButton { delegate.handleLibraryButtonTapped(); isExpanded = false }
|
||||
if inputViewButton == cameraButton { delegate.handleCameraButtonTapped(); isExpanded = false }
|
||||
if inputViewButton == mainButton { isExpanded = !isExpanded }
|
||||
}
|
||||
|
||||
// MARK: Convenience
|
||||
private func container(for button: InputViewButton) -> UIView {
|
||||
let result = UIView()
|
||||
result.addSubview(button)
|
||||
result.set(.width, to: InputViewButton.expandedSize)
|
||||
result.set(.height, to: InputViewButton.expandedSize)
|
||||
button.center(in: result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Delegate
|
||||
protocol ExpandingAttachmentsButtonDelegate {
|
||||
|
||||
func handleGIFButtonTapped()
|
||||
func handleDocumentButtonTapped()
|
||||
func handleLibraryButtonTapped()
|
||||
func handleCameraButtonTapped()
|
||||
}
|
|
@ -20,11 +20,10 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
|
|||
var lastSearchedText: String? { nil }
|
||||
|
||||
// MARK: UI Components
|
||||
private lazy var cameraButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self)
|
||||
private lazy var libraryButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self)
|
||||
private lazy var gifButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self)
|
||||
private lazy var documentButton = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self)
|
||||
private lazy var attachmentsButton = ExpandingAttachmentsButton(delegate: delegate)
|
||||
|
||||
private lazy var voiceMessageButton = InputViewButton(icon: #imageLiteral(resourceName: "Microphone"), delegate: self)
|
||||
|
||||
private lazy var sendButton: InputViewButton = {
|
||||
let result = InputViewButton(icon: #imageLiteral(resourceName: "ArrowUp"), isSendButton: true, delegate: self)
|
||||
result.isHidden = true
|
||||
|
@ -94,18 +93,13 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
|
|||
separator.set(.height, to: 1 / UIScreen.main.scale)
|
||||
addSubview(separator)
|
||||
separator.pin([ UIView.HorizontalEdge.leading, UIView.VerticalEdge.top, UIView.HorizontalEdge.trailing ], to: self)
|
||||
// Buttons
|
||||
let (cameraButtonContainer, libraryButtonContainer, gifButtonContainer, documentButtonContainer) = (container(for: cameraButton), container(for: libraryButton), container(for: gifButton), container(for: documentButton))
|
||||
let buttonStackView = UIStackView(arrangedSubviews: [ cameraButtonContainer, libraryButtonContainer, gifButtonContainer, documentButtonContainer, UIView.hStretchingSpacer() ])
|
||||
buttonStackView.axis = .horizontal
|
||||
buttonStackView.spacing = Values.smallSpacing
|
||||
// Bottom stack view
|
||||
let bottomStackView = UIStackView(arrangedSubviews: [ inputTextView, container(for: sendButton) ])
|
||||
let bottomStackView = UIStackView(arrangedSubviews: [ attachmentsButton, inputTextView, container(for: sendButton) ])
|
||||
bottomStackView.axis = .horizontal
|
||||
bottomStackView.spacing = Values.smallSpacing
|
||||
bottomStackView.alignment = .center
|
||||
// Main stack view
|
||||
let mainStackView = UIStackView(arrangedSubviews: [ buttonStackView, additionalContentContainer, bottomStackView ])
|
||||
let mainStackView = UIStackView(arrangedSubviews: [ additionalContentContainer, bottomStackView ])
|
||||
mainStackView.axis = .vertical
|
||||
mainStackView.isLayoutMarginsRelativeArrangement = true
|
||||
let adjustment = (InputViewButton.expandedSize - InputViewButton.size) / 2
|
||||
|
@ -204,19 +198,31 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
|
|||
}
|
||||
|
||||
// MARK: Interaction
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let buttonContainers = [ attachmentsButton.mainButton, attachmentsButton.cameraButton,
|
||||
attachmentsButton.libraryButton, attachmentsButton.documentButton, attachmentsButton.gifButton ]
|
||||
let buttonContainer = buttonContainers.first { $0.superview!.convert($0.frame, to: self).contains(point) }
|
||||
if let buttonContainer = buttonContainer {
|
||||
return buttonContainer
|
||||
} else {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
if mentionsViewContainer.frame.contains(point) {
|
||||
let buttonContainers = [ attachmentsButton.gifButtonContainer, attachmentsButton.documentButtonContainer,
|
||||
attachmentsButton.libraryButtonContainer, attachmentsButton.cameraButtonContainer, attachmentsButton.mainButtonContainer ]
|
||||
let isPointInsideAttachmentsButton = buttonContainers.contains { $0.superview!.convert($0.frame, to: self).contains(point) }
|
||||
if isPointInsideAttachmentsButton {
|
||||
return true
|
||||
} else if mentionsViewContainer.frame.contains(point) {
|
||||
return true
|
||||
} else {
|
||||
return super.point(inside: point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) {
|
||||
if inputViewButton == cameraButton { delegate.handleCameraButtonTapped() }
|
||||
if inputViewButton == libraryButton { delegate.handleLibraryButtonTapped() }
|
||||
if inputViewButton == gifButton { delegate.handleGIFButtonTapped() }
|
||||
if inputViewButton == documentButton { delegate.handleDocumentButtonTapped() }
|
||||
if inputViewButton == sendButton { delegate.handleSendButtonTapped() }
|
||||
}
|
||||
|
||||
|
@ -264,14 +270,14 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
|
|||
voiceMessageRecordingView.pin(to: self)
|
||||
self.voiceMessageRecordingView = voiceMessageRecordingView
|
||||
voiceMessageRecordingView.animate()
|
||||
let allOtherViews = [ cameraButton, libraryButton, gifButton, documentButton, sendButton, inputTextView, additionalContentContainer ]
|
||||
let allOtherViews = [ attachmentsButton, sendButton, inputTextView, additionalContentContainer ]
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
allOtherViews.forEach { $0.alpha = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
func hideVoiceMessageUI() {
|
||||
let allOtherViews = [ cameraButton, libraryButton, gifButton, documentButton, sendButton, inputTextView, additionalContentContainer ]
|
||||
let allOtherViews = [ attachmentsButton, sendButton, inputTextView, additionalContentContainer ]
|
||||
UIView.animate(withDuration: 0.25, animations: {
|
||||
allOtherViews.forEach { $0.alpha = 1 }
|
||||
self.voiceMessageRecordingView?.alpha = 0
|
||||
|
@ -320,13 +326,9 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
|
|||
}
|
||||
|
||||
// MARK: Delegate
|
||||
protocol InputViewDelegate : VoiceMessageRecordingViewDelegate {
|
||||
protocol InputViewDelegate : ExpandingAttachmentsButtonDelegate, VoiceMessageRecordingViewDelegate {
|
||||
|
||||
func showLinkPreviewSuggestionModal()
|
||||
func handleCameraButtonTapped()
|
||||
func handleLibraryButtonTapped()
|
||||
func handleGIFButtonTapped()
|
||||
func handleDocumentButtonTapped()
|
||||
func handleSendButtonTapped()
|
||||
func handleQuoteViewCancelButtonTapped()
|
||||
func inputTextViewDidChangeContent(_ inputTextView: InputTextView)
|
||||
|
|
|
@ -3,21 +3,26 @@ final class InputViewButton : UIView {
|
|||
private let icon: UIImage
|
||||
private let isSendButton: Bool
|
||||
private let delegate: InputViewButtonDelegate
|
||||
private let hasOpaqueBackground: Bool
|
||||
private lazy var widthConstraint = set(.width, to: InputViewButton.size)
|
||||
private lazy var heightConstraint = set(.height, to: InputViewButton.size)
|
||||
private var longPressTimer: Timer?
|
||||
private var isLongPress = false
|
||||
|
||||
// MARK: UI Components
|
||||
private lazy var backgroundView = UIView()
|
||||
|
||||
// MARK: Settings
|
||||
static let size = CGFloat(40)
|
||||
static let expandedSize = CGFloat(48)
|
||||
static let iconSize: CGFloat = 20
|
||||
|
||||
// MARK: Lifecycle
|
||||
init(icon: UIImage, isSendButton: Bool = false, delegate: InputViewButtonDelegate) {
|
||||
init(icon: UIImage, isSendButton: Bool = false, delegate: InputViewButtonDelegate, hasOpaqueBackground: Bool = false) {
|
||||
self.icon = icon
|
||||
self.isSendButton = isSendButton
|
||||
self.delegate = delegate
|
||||
self.hasOpaqueBackground = hasOpaqueBackground
|
||||
super.init(frame: CGRect.zero)
|
||||
setUpViewHierarchy()
|
||||
}
|
||||
|
@ -31,7 +36,10 @@ final class InputViewButton : UIView {
|
|||
}
|
||||
|
||||
private func setUpViewHierarchy() {
|
||||
backgroundColor = isSendButton ? Colors.accent : Colors.text.withAlphaComponent(0.05)
|
||||
backgroundColor = .clear
|
||||
backgroundView.backgroundColor = isSendButton ? Colors.accent : Colors.text.withAlphaComponent(0.05)
|
||||
addSubview(backgroundView)
|
||||
backgroundView.pin(to: self)
|
||||
layer.cornerRadius = InputViewButton.size / 2
|
||||
layer.masksToBounds = true
|
||||
isUserInteractionEnabled = true
|
||||
|
@ -58,7 +66,7 @@ final class InputViewButton : UIView {
|
|||
self.layer.cornerRadius = size / 2
|
||||
let glowConfiguration = UIView.CircularGlowConfiguration(size: size, color: glowColor, isAnimated: true, radius: isLightMode ? 4 : 6)
|
||||
self.setCircularGlow(with: glowConfiguration)
|
||||
self.backgroundColor = backgroundColor
|
||||
self.backgroundView.backgroundColor = backgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,3 +126,10 @@ protocol InputViewButtonDelegate {
|
|||
func handleInputViewButtonLongPressMoved(_ inputViewButton: InputViewButton, with touch: UITouch)
|
||||
func handleInputViewButtonLongPressEnded(_ inputViewButton: InputViewButton, with touch: UITouch)
|
||||
}
|
||||
|
||||
extension InputViewButtonDelegate {
|
||||
|
||||
func handleInputViewButtonLongPressBegan(_ inputViewButton: InputViewButton) { }
|
||||
func handleInputViewButtonLongPressMoved(_ inputViewButton: InputViewButton, with touch: UITouch) { }
|
||||
func handleInputViewButtonLongPressEnded(_ inputViewButton: InputViewButton, with touch: UITouch) { }
|
||||
}
|
||||
|
|
|
@ -378,7 +378,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
|
|||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
unloadContent?()
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton ]
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton, timerView, messageStatusImageView ]
|
||||
viewsToMove.forEach { $0.transform = .identity }
|
||||
replyButton.alpha = 0
|
||||
timerView.prepareForReuse()
|
||||
|
@ -431,7 +431,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
|
|||
}
|
||||
|
||||
@objc private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton ]
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton, timerView, messageStatusImageView ]
|
||||
let translationX = gestureRecognizer.translation(in: self).x.clamp(-CGFloat.greatestFiniteMagnitude, 0)
|
||||
switch gestureRecognizer.state {
|
||||
case .changed:
|
||||
|
@ -460,7 +460,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
|
|||
}
|
||||
|
||||
private func resetReply() {
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton ]
|
||||
let viewsToMove = [ bubbleView, profilePictureView, replyButton, timerView, messageStatusImageView ]
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
viewsToMove.forEach { $0.transform = .identity }
|
||||
self.replyButton.alpha = 0
|
||||
|
|
Loading…
Reference in New Issue