mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Copy tweak Added a toast when copying the sessionId or group URL (fixes to the toast UI as well) Fixed the new conversation screen styling Fixed the styling of the various attachment screens Updated the buttons on the attachment screen to behave like the input view buttons Removed the old OWSNavigationBar and OWSNavigationController (logic was buggy and not actually needed in most cases)
216 lines
7.9 KiB
Swift
216 lines
7.9 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import SessionUIKit
|
|
|
|
protocol AttachmentApprovalInputAccessoryViewDelegate: AnyObject {
|
|
func attachmentApprovalInputUpdateMediaRail()
|
|
func attachmentApprovalInputStartEditingCaptions()
|
|
func attachmentApprovalInputStopEditingCaptions()
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
class AttachmentApprovalInputAccessoryView: UIView {
|
|
|
|
weak var delegate: AttachmentApprovalInputAccessoryViewDelegate?
|
|
|
|
let attachmentTextToolbar: AttachmentTextToolbar
|
|
let attachmentCaptionToolbar: AttachmentCaptionToolbar
|
|
let galleryRailView: GalleryRailView
|
|
let currentCaptionLabel = UILabel()
|
|
let currentCaptionWrapper = UIView()
|
|
|
|
var isEditingMediaMessage: Bool {
|
|
return attachmentTextToolbar.textView.isFirstResponder
|
|
}
|
|
|
|
private var isEditingCaptions: Bool = false
|
|
private var currentAttachmentItem: SignalAttachmentItem?
|
|
|
|
let kGalleryRailViewHeight: CGFloat = 72
|
|
|
|
required init() {
|
|
attachmentTextToolbar = AttachmentTextToolbar()
|
|
attachmentCaptionToolbar = AttachmentCaptionToolbar()
|
|
|
|
galleryRailView = GalleryRailView()
|
|
galleryRailView.scrollFocusMode = .keepWithinBounds
|
|
galleryRailView.autoSetDimension(.height, toSize: kGalleryRailViewHeight)
|
|
|
|
super.init(frame: .zero)
|
|
|
|
createContents()
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
private func createContents() {
|
|
// Specifying auto-resizing mask and an intrinsic content size allows proper
|
|
// sizing when used as an input accessory view.
|
|
self.autoresizingMask = .flexibleHeight
|
|
self.translatesAutoresizingMaskIntoConstraints = false
|
|
self.themeBackgroundColor = .clear
|
|
|
|
preservesSuperviewLayoutMargins = true
|
|
|
|
// Use a background view that extends below the keyboard to avoid animation glitches.
|
|
let backgroundView = UIView()
|
|
backgroundView.themeBackgroundColor = .backgroundPrimary
|
|
addSubview(backgroundView)
|
|
backgroundView.pin(to: self)
|
|
|
|
// Separator
|
|
let separator = UIView.separator()
|
|
addSubview(separator)
|
|
separator.pin(.top, to: .top, of: self)
|
|
separator.pin(.leading, to: .leading, of: self)
|
|
separator.pin(.trailing, to: .trailing, of: self)
|
|
|
|
currentCaptionLabel.themeTextColor = .white
|
|
currentCaptionLabel.font = .systemFont(ofSize: Values.mediumFontSize)
|
|
currentCaptionLabel.numberOfLines = 5
|
|
currentCaptionLabel.lineBreakMode = .byWordWrapping
|
|
|
|
currentCaptionWrapper.isUserInteractionEnabled = true
|
|
currentCaptionWrapper.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(captionTapped)))
|
|
currentCaptionWrapper.addSubview(currentCaptionLabel)
|
|
currentCaptionLabel.autoPinEdgesToSuperviewMargins()
|
|
|
|
attachmentCaptionToolbar.attachmentCaptionToolbarDelegate = self
|
|
|
|
let stackView = UIStackView(arrangedSubviews: [currentCaptionWrapper, attachmentCaptionToolbar, galleryRailView, attachmentTextToolbar])
|
|
stackView.axis = .vertical
|
|
|
|
addSubview(stackView)
|
|
stackView.autoPinEdge(toSuperviewEdge: .top)
|
|
stackView.autoPinEdge(toSuperviewEdge: .leading)
|
|
stackView.autoPinEdge(toSuperviewEdge: .trailing)
|
|
// We pin to the superview's _margin_. Otherwise the notch breaks
|
|
// the layout if you hide the keyboard in the simulator (or if the
|
|
// user uses an external keyboard).
|
|
stackView.autoPinEdge(toSuperviewMargin: .bottom)
|
|
|
|
let galleryRailBlockingView: UIView = UIView()
|
|
galleryRailBlockingView.themeBackgroundColor = .backgroundPrimary
|
|
stackView.addSubview(galleryRailBlockingView)
|
|
galleryRailBlockingView.pin(.top, to: .bottom, of: attachmentTextToolbar)
|
|
galleryRailBlockingView.pin(.left, to: .left, of: stackView)
|
|
galleryRailBlockingView.pin(.right, to: .right, of: stackView)
|
|
galleryRailBlockingView.pin(.bottom, to: .bottom, of: stackView)
|
|
}
|
|
|
|
// MARK: - Events
|
|
|
|
@objc func captionTapped(sender: UIGestureRecognizer) {
|
|
guard sender.state == .recognized else { return }
|
|
|
|
delegate?.attachmentApprovalInputStartEditingCaptions()
|
|
}
|
|
|
|
// MARK:
|
|
|
|
private var shouldHideControls = false
|
|
|
|
private func updateContents() {
|
|
var hasCurrentCaption = false
|
|
if let currentAttachmentItem = currentAttachmentItem,
|
|
let captionText = currentAttachmentItem.captionText {
|
|
hasCurrentCaption = captionText.count > 0
|
|
|
|
attachmentCaptionToolbar.textView.text = captionText
|
|
currentCaptionLabel.text = captionText
|
|
} else {
|
|
attachmentCaptionToolbar.textView.text = nil
|
|
currentCaptionLabel.text = nil
|
|
}
|
|
|
|
attachmentCaptionToolbar.isHidden = !isEditingCaptions
|
|
currentCaptionWrapper.isHidden = isEditingCaptions || !hasCurrentCaption
|
|
attachmentTextToolbar.isHidden = isEditingCaptions
|
|
|
|
updateFirstResponder()
|
|
|
|
layoutSubviews()
|
|
}
|
|
|
|
private func updateFirstResponder() {
|
|
if (shouldHideControls) {
|
|
if attachmentCaptionToolbar.textView.isFirstResponder {
|
|
attachmentCaptionToolbar.textView.resignFirstResponder()
|
|
} else if attachmentTextToolbar.textView.isFirstResponder {
|
|
attachmentTextToolbar.textView.resignFirstResponder()
|
|
}
|
|
} else if (isEditingCaptions) {
|
|
// While editing captions, the keyboard should always remain visible.
|
|
if !attachmentCaptionToolbar.textView.isFirstResponder {
|
|
attachmentCaptionToolbar.textView.becomeFirstResponder()
|
|
}
|
|
} else {
|
|
if attachmentCaptionToolbar.textView.isFirstResponder {
|
|
attachmentCaptionToolbar.textView.resignFirstResponder()
|
|
}
|
|
}
|
|
// NOTE: We don't automatically make attachmentTextToolbar.textView
|
|
// first responder;
|
|
}
|
|
|
|
public func update(isEditingCaptions: Bool,
|
|
currentAttachmentItem: SignalAttachmentItem?,
|
|
shouldHideControls: Bool) {
|
|
// De-bounce
|
|
guard self.isEditingCaptions != isEditingCaptions ||
|
|
self.currentAttachmentItem != currentAttachmentItem ||
|
|
self.shouldHideControls != shouldHideControls else {
|
|
|
|
updateFirstResponder()
|
|
return
|
|
}
|
|
|
|
self.isEditingCaptions = isEditingCaptions
|
|
self.currentAttachmentItem = currentAttachmentItem
|
|
self.shouldHideControls = shouldHideControls
|
|
|
|
updateContents()
|
|
}
|
|
|
|
// MARK:
|
|
|
|
override var intrinsicContentSize: CGSize {
|
|
get {
|
|
// Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, we must specify
|
|
// an intrinsicContentSize. Specifying CGSize.zero causes the height to be determined by autolayout.
|
|
return CGSize.zero
|
|
}
|
|
}
|
|
|
|
public var hasFirstResponder: Bool {
|
|
return (isFirstResponder ||
|
|
attachmentCaptionToolbar.textView.isFirstResponder ||
|
|
attachmentTextToolbar.textView.isFirstResponder)
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
extension AttachmentApprovalInputAccessoryView: AttachmentCaptionToolbarDelegate {
|
|
public func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar) {
|
|
guard let currentAttachmentItem = currentAttachmentItem else {
|
|
owsFailDebug("Missing currentAttachmentItem.")
|
|
return
|
|
}
|
|
|
|
// TODO: Look at refactoring this behaviour to consolidate attachment mutations
|
|
currentAttachmentItem.attachment.captionText = attachmentCaptionToolbar.textView.text
|
|
|
|
delegate?.attachmentApprovalInputUpdateMediaRail()
|
|
}
|
|
|
|
public func attachmentCaptionToolbarDidComplete() {
|
|
delegate?.attachmentApprovalInputStopEditingCaptions()
|
|
}
|
|
}
|