PR comments and a few missed use cases

Disabled the attachments and voice message buttons for the first message
Disabled the Disappearing Messages flag for the until the conversation is approved
Fixed a bug where the recipient of a message request could incorrectly get the 'pending approval' state
Refactored some standard auto layout code to use the custom extension code
pull/559/head
Morgan Pretty 3 years ago
parent 6009c30805
commit 051f03f4b4

@ -778,14 +778,16 @@
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */; };
FD659AC027A7649600F12C02 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */; };
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
FD705A8C278CDB5600F16121 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */; };
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8D278CE29800F16121 /* String+Localization.swift */; };
FD705A90278CEBBC00F16121 /* ShareAppExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */; };
FD705A92278D051200F16121 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A91278D051200F16121 /* ReusableView.swift */; };
FD705A94278D052B00F16121 /* UITableView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A93278D052B00F16121 /* UITableView+ReusableView.swift */; };
FD705A98278E9F4D00F16121 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */; };
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
FDC4389E27BA2B8A00C60D73 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; platformFilter = ios; };
FDC4389F27BA2B8A00C60D73 /* SessionUtilitiesKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -901,6 +903,13 @@
remoteGlobalIDString = C33FD9AA255A548A00E217F9;
remoteInfo = SignalUtilitiesKit;
};
FDC438A027BA2B8A00C60D73 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D221A080169C9E5E00537ABF /* Project object */;
proxyType = 1;
remoteGlobalIDString = C3C2A678255388CC00C340D1;
remoteInfo = SessionUtilitiesKit;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@ -931,6 +940,17 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
FDC438A227BA2B8A00C60D73 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
FDC4389F27BA2B8A00C60D73 /* SessionUtilitiesKit.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@ -1812,14 +1832,14 @@
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
FD705A8D278CE29800F16121 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
FD705A8F278CEBBC00F16121 /* ShareAppExtensionContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppExtensionContext.swift; sourceTree = "<group>"; };
FD705A91278D051200F16121 /* ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = "<group>"; };
FD705A93278D052B00F16121 /* UITableView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableView+ReusableView.swift"; sourceTree = "<group>"; };
FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
FD9039443F7CB729CF71350E /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
FEDBAE1B98C49BBE8C87F575 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
FF9BA33D021B115B1F5B4E46 /* Pods-SessionMessagingKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionMessagingKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionMessagingKit/Pods-SessionMessagingKit.app store release.xcconfig"; sourceTree = "<group>"; };
@ -1892,6 +1912,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FDC4389E27BA2B8A00C60D73 /* SessionUtilitiesKit.framework in Frameworks */,
C3C2A70B25539E1E00C340D1 /* SessionSnodeKit.framework in Frameworks */,
9B0A583E9B89FEF0916B793A /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit.framework in Frameworks */,
);
@ -3928,10 +3949,12 @@
C3C2A6EC25539DE700C340D1 /* Sources */,
C3C2A6ED25539DE700C340D1 /* Frameworks */,
C3C2A6EE25539DE700C340D1 /* Resources */,
FDC438A227BA2B8A00C60D73 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
FDC438A127BA2B8A00C60D73 /* PBXTargetDependency */,
);
name = SessionMessagingKit;
productName = SessionMessagingKit;
@ -5092,6 +5115,12 @@
target = C33FD9AA255A548A00E217F9 /* SignalUtilitiesKit */;
targetProxy = C3D90A7025773A44002C9DF5 /* PBXContainerItemProxy */;
};
FDC438A127BA2B8A00C60D73 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
target = C3C2A678255388CC00C340D1 /* SessionUtilitiesKit */;
targetProxy = FDC438A027BA2B8A00C60D73 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */

@ -317,8 +317,19 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
self.snInputView.text = ""
self.snInputView.quoteDraftInfo = nil
if let contactThread: TSContactThread = thread as? TSContactThread, let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()) {
self.snInputView.setEnabled(contact.didApproveMe, message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized())
// Update the input state if this is a contact thread
if let contactThread: TSContactThread = thread as? TSContactThread {
let contact: Contact? = Storage.shared.getContact(with: contactThread.contactSessionID())
// If the contact doesn't exist yet then it's a message request without the first message sent
// so only allow text-based messages
self.snInputView.setEnabledMessageTypes(
(thread.isNoteToSelf() || contact?.didApproveMe == true || thread.isMessageRequest() ?
.all :
(contact != nil ? .none : .textOnly)
),
message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized()
)
}
self.markAllAsRead()

@ -120,7 +120,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
return result
}()
lazy var snInputView = InputView(delegate: self)
lazy var snInputView: InputView = InputView(delegate: self)
lazy var unreadCountView: UIView = {
let result = UIView()
@ -303,7 +303,6 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
// Message requests view & scroll to bottom
view.addSubview(footerControlsStackView)
scrollButton.translatesAutoresizingMaskIntoConstraints = false
footerControlsStackView.addArrangedSubview(scrollButton)
footerControlsStackView.addArrangedSubview(messageRequestView)
@ -311,34 +310,33 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
messageRequestView.addSubview(messageRequestAcceptButton)
messageRequestView.addSubview(messageRequestDeleteButton)
let footerControlsStackViewBottomConstraint: NSLayoutConstraint = footerControlsStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16)
self.footerControlsStackViewBottomConstraint = footerControlsStackViewBottomConstraint
NSLayoutConstraint.activate([
footerControlsStackView.leftAnchor.constraint(equalTo: view.leftAnchor),
footerControlsStackView.rightAnchor.constraint(equalTo: view.rightAnchor),
footerControlsStackViewBottomConstraint,
scrollButton.rightAnchor.constraint(equalTo: footerControlsStackView.rightAnchor, constant: -20),
messageRequestView.leftAnchor.constraint(equalTo: footerControlsStackView.leftAnchor),
messageRequestView.rightAnchor.constraint(equalTo: footerControlsStackView.rightAnchor),
messageRequestDescriptionLabel.topAnchor.constraint(equalTo: messageRequestView.topAnchor, constant: 10),
messageRequestDescriptionLabel.leftAnchor.constraint(equalTo: messageRequestView.leftAnchor, constant: 40),
messageRequestDescriptionLabel.rightAnchor.constraint(equalTo: messageRequestView.rightAnchor, constant: -40),
messageRequestAcceptButton.topAnchor.constraint(equalTo: messageRequestDescriptionLabel.bottomAnchor, constant: 20),
messageRequestAcceptButton.leftAnchor.constraint(equalTo: messageRequestView.leftAnchor, constant: 20),
messageRequestAcceptButton.bottomAnchor.constraint(equalTo: messageRequestView.bottomAnchor),
messageRequestAcceptButton.heightAnchor.constraint(equalToConstant: ConversationVC.messageRequestButtonHeight),
messageRequestDeleteButton.topAnchor.constraint(equalTo: messageRequestDescriptionLabel.bottomAnchor, constant: 20),
messageRequestDeleteButton.leftAnchor.constraint(equalTo: messageRequestAcceptButton.rightAnchor, constant: 20),
messageRequestDeleteButton.rightAnchor.constraint(equalTo: messageRequestView.rightAnchor, constant: -20),
messageRequestDeleteButton.bottomAnchor.constraint(equalTo: messageRequestView.bottomAnchor),
messageRequestDeleteButton.widthAnchor.constraint(equalTo: messageRequestAcceptButton.widthAnchor),
messageRequestDeleteButton.heightAnchor.constraint(equalToConstant: ConversationVC.messageRequestButtonHeight)
])
scrollButton.pin(.right, to: .right, of: footerControlsStackView, withInset: -20)
messageRequestView.pin(.left, to: .left, of: footerControlsStackView)
messageRequestView.pin(.right, to: .right, of: footerControlsStackView)
footerControlsStackView.pin(.left, to: .left, of: view)
footerControlsStackView.pin(.right, to: .right, of: view)
self.footerControlsStackViewBottomConstraint = footerControlsStackView.pin(.bottom, to: .bottom, of: view, withInset: -16)
messageRequestDescriptionLabel.pin(.top, to: .top, of: messageRequestView, withInset: 10)
messageRequestDescriptionLabel.pin(.left, to: .left, of: messageRequestView, withInset: 40)
messageRequestDescriptionLabel.pin(.right, to: .right, of: messageRequestView, withInset: -40)
messageRequestAcceptButton.pin(.top, to: .bottom, of: messageRequestDescriptionLabel, withInset: 20)
messageRequestAcceptButton.pin(.left, to: .left, of: messageRequestView, withInset: 20)
messageRequestAcceptButton.pin(.bottom, to: .bottom, of: messageRequestView)
messageRequestAcceptButton.set(.height, to: ConversationVC.messageRequestButtonHeight)
messageRequestAcceptButton.pin(.top, to: .bottom, of: messageRequestDescriptionLabel, withInset: 20)
messageRequestAcceptButton.pin(.left, to: .left, of: messageRequestView, withInset: 20)
messageRequestAcceptButton.pin(.bottom, to: .bottom, of: messageRequestView)
messageRequestAcceptButton.set(.height, to: ConversationVC.messageRequestButtonHeight)
messageRequestDeleteButton.pin(.top, to: .bottom, of: messageRequestDescriptionLabel, withInset: 20)
messageRequestDeleteButton.pin(.left, to: .right, of: messageRequestAcceptButton, withInset: 20)
messageRequestDeleteButton.pin(.right, to: .right, of: messageRequestView, withInset: -20)
messageRequestDeleteButton.pin(.bottom, to: .bottom, of: messageRequestView)
messageRequestDeleteButton.set(.width, to: .width, of: messageRequestAcceptButton)
messageRequestDeleteButton.set(.height, to: ConversationVC.messageRequestButtonHeight)
// Unread count view
view.addSubview(unreadCountView)
@ -372,8 +370,18 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
}
// Update the input state if this is a contact thread
if let contactThread: TSContactThread = thread as? TSContactThread, let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()) {
self.snInputView.setEnabled(contact.didApproveMe, message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized())
if let contactThread: TSContactThread = thread as? TSContactThread {
let contact: Contact? = Storage.shared.getContact(with: contactThread.contactSessionID())
// If the contact doesn't exist yet then it's a message request without the first message sent
// so only allow text-based messages
self.snInputView.setEnabledMessageTypes(
(thread.isNoteToSelf() || contact?.didApproveMe == true || thread.isMessageRequest() ?
.all :
(contact != nil ? .none : .textOnly)
),
message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized()
)
}
// Update member count if this is a V2 open group
@ -619,8 +627,18 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
}
// Update the input state if this is a contact thread
if let contactThread: TSContactThread = thread as? TSContactThread, let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()) {
self.snInputView.setEnabled(contact.didApproveMe, message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized())
if let contactThread: TSContactThread = thread as? TSContactThread {
let contact: Contact? = Storage.shared.getContact(with: contactThread.contactSessionID())
// If the contact doesn't exist yet then it's a message request without the first message sent
// so only allow text-based messages
self.snInputView.setEnabledMessageTypes(
(thread.isNoteToSelf() || contact?.didApproveMe == true || thread.isMessageRequest() ?
.all :
(contact != nil ? .none : .textOnly)
),
message: "MESSAGE_REQUESTS_DISABLED_INPUT".localized()
)
}
}

@ -3,6 +3,16 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate {
private weak var delegate: ExpandingAttachmentsButtonDelegate?
private var isExpanded = false { didSet { expandOrCollapse() } }
override var isUserInteractionEnabled: Bool {
didSet {
gifButton.isUserInteractionEnabled = isUserInteractionEnabled
documentButton.isUserInteractionEnabled = isUserInteractionEnabled
libraryButton.isUserInteractionEnabled = isUserInteractionEnabled
cameraButton.isUserInteractionEnabled = isUserInteractionEnabled
mainButton.isUserInteractionEnabled = isUserInteractionEnabled
}
}
// MARK: Constraints
private lazy var gifButtonContainerBottomConstraint = gifButtonContainer.pin(.bottom, to: .bottom, of: self)
private lazy var documentButtonContainerBottomConstraint = documentButtonContainer.pin(.bottom, to: .bottom, of: self)
@ -134,7 +144,8 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate {
}
// MARK: Delegate
protocol ExpandingAttachmentsButtonDelegate : class {
protocol ExpandingAttachmentsButtonDelegate: AnyObject {
func handleGIFButtonTapped()
func handleDocumentButtonTapped()

@ -1,6 +1,13 @@
import UIKit
import SessionUIKit
final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, QuoteViewDelegate, LinkPreviewViewDelegate, MentionSelectionViewDelegate {
enum MessageTypes {
case all
case textOnly
case none
}
private weak var delegate: InputViewDelegate?
var quoteDraftInfo: (model: OWSQuotedReplyModel, isOutgoing: Bool)? { didSet { handleQuoteDraftChanged() } }
var linkPreviewInfo: (url: String, draft: OWSLinkPreviewDraft?)?
@ -17,9 +24,9 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
set { inputTextView.text = newValue }
}
var isEnabled: Bool = true {
var enabledMessageTypes: MessageTypes = .all {
didSet {
setEnabled(isEnabled, message: nil)
setEnabledMessageTypes(enabledMessageTypes, message: nil)
}
}
@ -144,12 +151,10 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
addSubview(disabledInputLabel)
NSLayoutConstraint.activate([
disabledInputLabel.topAnchor.constraint(equalTo: mainStackView.topAnchor),
disabledInputLabel.leftAnchor.constraint(equalTo: mainStackView.leftAnchor),
disabledInputLabel.rightAnchor.constraint(equalTo: mainStackView.rightAnchor),
disabledInputLabel.heightAnchor.constraint(equalToConstant: InputViewButton.expandedSize)
])
disabledInputLabel.pin(.top, to: .top, of: mainStackView)
disabledInputLabel.pin(.left, to: .left, of: mainStackView)
disabledInputLabel.pin(.right, to: .right, of: mainStackView)
disabledInputLabel.set(.height, to: InputViewButton.expandedSize)
// Mentions
insertSubview(mentionsViewContainer, belowSubview: mainStackView)
@ -248,16 +253,26 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate,
}.retainUntilComplete()
}
func setEnabled(_ enabled: Bool, message: String?) {
guard isEnabled != enabled else { return }
func setEnabledMessageTypes(_ messageTypes: MessageTypes, message: String?) {
guard enabledMessageTypes != messageTypes else { return }
isEnabled = enabled
enabledMessageTypes = messageTypes
disabledInputLabel.text = (message ?? "")
attachmentsButton.isUserInteractionEnabled = (messageTypes == .all)
voiceMessageButton.isUserInteractionEnabled = (messageTypes == .all)
UIView.animate(withDuration: 0.3) { [weak self] in
self?.bottomStackView?.alpha = (enabled ? 1 : 0)
self?.voiceMessageButton.alpha = (enabled ? 1 : 0)
self?.disabledInputLabel.alpha = (enabled ? 0 : 1)
self?.bottomStackView?.alpha = (messageTypes != .none ? 1 : 0)
self?.attachmentsButton.alpha = (messageTypes == .all ?
1 :
(messageTypes == .textOnly ? 0.4 : 0)
)
self?.voiceMessageButton.alpha = (messageTypes == .all ?
1 :
(messageTypes == .textOnly ? 0.4 : 0)
)
self?.disabledInputLabel.alpha = (messageTypes != .none ? 0 : 1)
}
}

@ -98,6 +98,8 @@ final class InputViewButton : UIView {
// We want to detect both taps and long presses
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard isUserInteractionEnabled else { return }
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
expand()
invalidateLongPressIfNeeded()
@ -109,12 +111,16 @@ final class InputViewButton : UIView {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard isUserInteractionEnabled else { return }
if isLongPress {
delegate?.handleInputViewButtonLongPressMoved(self, with: touches.first!)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard isUserInteractionEnabled else { return }
collapse()
if !isLongPress {
delegate?.handleInputViewButtonTapped(self)

@ -359,6 +359,13 @@ CGFloat kIconViewLength = 24;
[switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:)
forControlEvents:UIControlEventValueChanged];
// Disable Disappearing Messages if the conversation hasn't been approved
if (!self.thread.isGroupThread) {
TSContactThread *thread = (TSContactThread *)self.thread;
SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID];
[switchView setEnabled:contact.didApproveMe];
}
UIStackView *topRow =
[[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]];
topRow.spacing = strongSelf.iconSpacing;

@ -10,10 +10,12 @@ NS_ASSUME_NONNULL_BEGIN
extern NSString *const TSInboxGroup;
extern NSString *const TSMessageRequestGroup;
extern NSString *const TSArchiveGroup;
extern NSString *const TSShareExtensionGroup;
extern NSString *const TSUnreadIncomingMessagesGroup;
extern NSString *const TSSecondaryDevicesGroup;
extern NSString *const TSThreadDatabaseViewExtensionName;
extern NSString *const TSThreadShareExtensionDatabaseViewExtensionName;
extern NSString *const TSMessageDatabaseViewExtensionName;
extern NSString *const TSMessageDatabaseViewExtensionName_Legacy;

@ -13,12 +13,16 @@
#import <YapDatabase/YapDatabaseAutoView.h>
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
#import <YapDatabase/YapDatabaseViewTypes.h>
#import <SessionUtilitiesKit/AppContext.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const TSInboxGroup = @"TSInboxGroup";
NSString *const TSMessageRequestGroup = @"TSMessageRequestGroup";
NSString *const TSArchiveGroup = @"TSArchiveGroup";
NSString *const TSShareExtensionGroup = @"TSShareExtensionGroup";
NSString *const TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
@ -27,6 +31,8 @@ NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
// -> TSThreadDatabaseViewExtensionName2 to work around https://github.com/yapstudios/YapDatabase/issues/324
NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName2";
NSString *const TSThreadShareExtensionDatabaseViewExtensionName = @"TSThreadShareExtensionDatabaseViewExtensionName";
// We sort interactions by a monotonically increasing counter.
//
// Previously we sorted the interactions database by local timestamp, which was problematic if the local clock changed.
@ -268,6 +274,53 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options];
[storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
YapDatabaseView *shareExtensionThreadView = [storage registeredExtension:TSThreadShareExtensionDatabaseViewExtensionName];
if (shareExtensionThreadView) {
return;
}
YapDatabaseViewGrouping *shareExtensionViewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSThread class]]) {
return nil;
}
TSThread *thread = (TSThread *)object;
if (thread.isMessageRequest) {
return nil;
}
else {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId];
if (threadMessageCount < 1) {
return nil;
}
if (!thread.isGroupThread) {
TSContactThread *contactThead = (TSContactThread *)thread;
SNContact *contact = [LKStorage.shared getContactWithSessionID:[contactThead contactSessionID]];
if (contact == nil || !contact.didApproveMe) {
return nil;
}
}
}
return TSShareExtensionGroup;
}];
YapDatabaseViewSorting *shareExtensionViewSorting = [self threadSorting];
YapDatabaseViewOptions *shareExtensionOptions = [[YapDatabaseViewOptions alloc] init];
shareExtensionOptions.isPersistent = YES;
shareExtensionOptions.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
YapDatabaseView *shareExtensionDatabaseView =
[[YapDatabaseAutoView alloc] initWithGrouping:shareExtensionViewGrouping sorting:shareExtensionViewSorting versionTag:@"1" options:shareExtensionOptions];
[storage asyncRegisterExtension:shareExtensionDatabaseView withName:TSThreadShareExtensionDatabaseViewExtensionName];
}
+ (YapDatabaseViewSorting *)threadSorting {

@ -11,7 +11,7 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
var shareVC: ShareVC?
private var threadCount: UInt {
threads.numberOfItems(inGroup: TSInboxGroup)
threads.numberOfItems(inGroup: TSShareExtensionGroup)
}
private lazy var dbConnection: YapDatabaseConnection = {
@ -65,8 +65,8 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
// Threads
dbConnection.beginLongLivedReadTransaction() // Freeze the connection for use on the main thread (this gives us a stable data source that doesn't change until we tell it to)
threads = YapDatabaseViewMappings(groups: [ TSInboxGroup ], view: TSThreadDatabaseViewExtensionName) // The extension should be registered at this point
threads.setIsReversed(true, forGroup: TSInboxGroup)
threads = YapDatabaseViewMappings(groups: [ TSShareExtensionGroup ], view: TSThreadShareExtensionDatabaseViewExtensionName) // The extension should be registered at this point
threads.setIsReversed(true, forGroup: TSShareExtensionGroup)
dbConnection.read { transaction in
self.threads.update(with: transaction) // Perform the initial update
}
@ -217,7 +217,7 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
private func thread(at index: Int) -> TSThread? {
var thread: TSThread? = nil
dbConnection.read { transaction in
let ext = transaction.ext(TSThreadDatabaseViewExtensionName) as! YapDatabaseViewTransaction
let ext = transaction.ext(TSThreadShareExtensionDatabaseViewExtensionName) as! YapDatabaseViewTransaction
thread = ext.object(atRow: UInt(index), inSection: 0, with: self.threads) as! TSThread?
}
return thread

@ -96,6 +96,25 @@ public extension UIView {
return constraint
}
@discardableResult
func set(_ dimension: Dimension, to otherDimension: Dimension, of view: UIView, withOffset offset: CGFloat = 0) -> NSLayoutConstraint {
translatesAutoresizingMaskIntoConstraints = false
let otherAnchor: NSLayoutAnchor<NSLayoutDimension> = {
switch otherDimension {
case .width: return view.widthAnchor
case .height: return view.heightAnchor
}
}()
let constraint: NSLayoutConstraint = {
switch dimension {
case .width: return widthAnchor.constraint(equalTo: otherAnchor, constant: offset)
case .height: return heightAnchor.constraint(equalTo: otherAnchor, constant: offset)
}
}()
constraint.isActive = true
return constraint
}
@discardableResult
func set(_ dimension: Dimension, greaterThanOrEqualTo size: CGFloat) -> NSLayoutConstraint {
translatesAutoresizingMaskIntoConstraints = false

Loading…
Cancel
Save