Merge branch 'dev' into disappearing-message-redesign

pull/941/head
Ryan Zhao 1 year ago
commit 600637ec78

@ -6064,7 +6064,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6137,7 +6137,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6203,7 +6203,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6277,7 +6277,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -7205,7 +7205,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7277,7 +7277,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 393;
CURRENT_PROJECT_VERSION = 395;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",

@ -57,14 +57,17 @@ extension ContextMenuVC {
static func copy(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action {
return Action(
icon: UIImage(named: "ic_copy"),
title: "copy".localized()
title: "copy".localized(),
accessibilityLabel: "Copy text"
) { delegate?.copy(cellViewModel) }
}
static func copySessionID(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action {
return Action(
icon: UIImage(named: "ic_copy"),
title: "vc_conversation_settings_copy_session_id_button_title".localized()
title: "vc_conversation_settings_copy_session_id_button_title".localized(),
accessibilityLabel: "Copy Session ID"
) { delegate?.copySessionID(cellViewModel) }
}
@ -87,14 +90,16 @@ extension ContextMenuVC {
static func ban(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action {
return Action(
icon: UIImage(named: "ic_block"),
title: "context_menu_ban_user".localized()
title: "context_menu_ban_user".localized(),
accessibilityLabel: "Ban user"
) { delegate?.ban(cellViewModel) }
}
static func banAndDeleteAllMessages(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action {
return Action(
icon: UIImage(named: "ic_block"),
title: "context_menu_ban_and_delete_all".localized()
title: "context_menu_ban_and_delete_all".localized(),
accessibilityLabel: "Ban user and delete"
) { delegate?.banAndDeleteAllMessages(cellViewModel) }
}
@ -107,7 +112,8 @@ extension ContextMenuVC {
static func emojiPlusButton(_ cellViewModel: MessageViewModel, _ delegate: ContextMenuActionDelegate?) -> Action {
return Action(
isEmojiPlus: true
isEmojiPlus: true,
accessibilityLabel: "Add emoji"
) { delegate?.showFullEmojiKeyboard(cellViewModel) }
}

@ -1644,6 +1644,23 @@ extension ConversationVC:
let thread: SessionThread = try SessionThread.fetchOne(db, id: threadId)
else { return }
if
let quote = try? interaction.quote.fetchOne(db),
let quotedAttachment = try? quote.attachment.fetchOne(db),
quotedAttachment.isVisualMedia,
quotedAttachment.downloadUrl == Attachment.nonMediaQuoteFileId,
let quotedInteraction = try? quote.originalInteraction.fetchOne(db)
{
let attachment = try? quotedInteraction.attachments.fetchAll(db).first
try quote.with(
attachmentId: attachment?.cloneAsQuoteThumbnail()?.inserted(db).id
).update(db)
}
// Remove message sending jobs for the same interaction in database
// Prevent the same message being sent twice
try Job.filter(Job.Columns.interactionId == interaction.id).deleteAll(db)
try MessageSender.send(
db,
interaction: interaction,
@ -1902,7 +1919,11 @@ extension ConversationVC:
}
let actionSheet: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "delete_message_for_me".localized(), style: .destructive) { [weak self] _ in
actionSheet.addAction(UIAlertAction(
title: "delete_message_for_me".localized(),
accessibilityIdentifier: "Delete for me",
style: .destructive
) { [weak self] _ in
Storage.shared.writeAsync { db in
_ = try Interaction
.filter(id: cellViewModel.id)
@ -1931,6 +1952,7 @@ extension ConversationVC:
)
}
}(),
accessibilityIdentifier: "Delete for everyone",
style: .destructive
) { [weak self] _ in
deleteRemotely(

@ -26,28 +26,31 @@ final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate {
// MARK: UI Components
lazy var gifButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityLabel = "GIF button"
result.accessibilityIdentifier = "GIF button"
result.isAccessibilityElement = true
return result
}()
lazy var gifButtonContainer = container(for: gifButton)
lazy var documentButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityLabel = "Documents folder"
result.accessibilityIdentifier = "Documents folder"
result.isAccessibilityElement = true
return result
}()
lazy var documentButtonContainer = container(for: documentButton)
lazy var libraryButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityLabel = "Images folder"
result.accessibilityIdentifier = "Images folder"
result.isAccessibilityElement = true
return result
}()
lazy var libraryButtonContainer = container(for: libraryButton)
lazy var cameraButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityLabel = "Select camera button"
result.accessibilityIdentifier = "Select camera button"
result.isAccessibilityElement = true
return result
}()

@ -54,6 +54,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
private lazy var attachmentsButton: ExpandingAttachmentsButton = {
let result = ExpandingAttachmentsButton(delegate: delegate)
result.accessibilityLabel = "Attachments button"
result.accessibilityIdentifier = "Attachments button"
result.isAccessibilityElement = true
return result
@ -62,6 +63,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
private lazy var voiceMessageButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "Microphone"), delegate: self)
result.accessibilityLabel = "New voice message"
result.accessibilityIdentifier = "New voice message"
result.isAccessibilityElement = true
return result
@ -70,6 +72,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
private lazy var sendButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "ArrowUp"), isSendButton: true, delegate: self)
result.isHidden = true
result.accessibilityIdentifier = "Send message button"
result.accessibilityLabel = "Send message button"
result.isAccessibilityElement = true
@ -87,6 +90,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
private lazy var mentionsViewContainer: UIView = {
let result: UIView = UIView()
result.accessibilityLabel = "Mentions list"
result.accessibilityIdentifier = "Mentions list"
result.isAccessibilityElement = true
result.alpha = 0
@ -119,6 +123,7 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
let maxWidth = UIScreen.main.bounds.width - 2 * InputViewButton.expandedSize - 2 * Values.smallSpacing - 2 * (Values.mediumSpacing - adjustment)
let result = InputTextView(delegate: self, maxWidth: maxWidth)
result.accessibilityLabel = "Message input box"
result.accessibilityIdentifier = "Message input box"
result.isAccessibilityElement = true
return result

@ -13,7 +13,8 @@ final class DeletedMessageView: UIView {
init(textColor: ThemeValue) {
super.init(frame: CGRect.zero)
accessibilityIdentifier = "Deleted message"
isAccessibilityElement = true
setUpViewHierarchy(textColor: textColor)
}

@ -12,7 +12,8 @@ final class MediaPlaceholderView: UIView {
init(cellViewModel: MessageViewModel, textColor: ThemeValue) {
super.init(frame: CGRect.zero)
self.accessibilityLabel = "Untrusted attachment message"
self.accessibilityIdentifier = "Untrusted attachment message"
self.isAccessibilityElement = true
setUpViewHierarchy(cellViewModel: cellViewModel, textColor: textColor)
}

@ -144,7 +144,7 @@ final class QuoteView: UIView {
.messageBubble_outgoingText :
.messageBubble_incomingText
)
case .draft: return .messageBubble_outgoingText
case .draft: return .textPrimary
}
}()
imageView.contentMode = .center
@ -156,10 +156,7 @@ final class QuoteView: UIView {
mainStackView.addArrangedSubview(imageView)
if (body ?? "").isEmpty {
body = (attachment.isImage ?
"Image" :
(isAudio ? "Audio" : "Document")
)
body = attachment.shortDescription
}
// Generate the thumbnail if needed
@ -223,10 +220,10 @@ final class QuoteView: UIView {
}
.defaulting(
to: attachment.map {
NSAttributedString(string: MIMETypeUtil.isAudio($0.contentType) ? "Audio" : "Document")
NSAttributedString(string: $0.shortDescription, attributes: [ .foregroundColor: textColor ])
}
)
.defaulting(to: NSAttributedString(string: "Document"))
.defaulting(to: NSAttributedString(string: "QUOTED_MESSAGE_NOT_FOUND".localized(), attributes: [ .foregroundColor: textColor ]))
}
// Label stack view

@ -98,7 +98,8 @@ public final class VoiceMessageView: UIView {
init() {
super.init(frame: CGRect.zero)
self.accessibilityIdentifier = "Voice message"
self.isAccessibilityElement = true
setUpViewHierarchy()
}

@ -150,15 +150,17 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
internal lazy var messageStatusLabel: UILabel = {
let result = UILabel()
result.accessibilityIdentifier = "Message sent status"
result.accessibilityLabel = "Message sent status"
result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .messageBubble_deliveryStatus
result.themeTextColor = .messageBubble_deliveryStatus
return result
}()
internal lazy var messageStatusImageView: UIImageView = {
let result = UIImageView()
result.accessibilityIdentifier = "Message sent status tick"
result.accessibilityLabel = "Message sent status tick"
result.contentMode = .scaleAspectFit
result.themeTintColor = .messageBubble_deliveryStatus
@ -425,6 +427,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
messageStatusLabel.text = statusText
messageStatusLabel.themeTextColor = tintColor
messageStatusImageView.image = image
messageStatusLabel.accessibilityIdentifier = "Message sent status: \(statusText ?? "invalid")"
messageStatusImageView.themeTintColor = tintColor
messageStatusContainerView.isHidden = (
cellViewModel.variant != .standardOutgoing ||
@ -470,6 +473,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
subview.removeFromSuperview()
}
albumView = nil
albumView = nil
bodyTappableLabel = nil
// Handle the deleted state first (it's much simpler than the others)
@ -541,7 +545,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
let quoteView: QuoteView = QuoteView(
for: .regular,
authorId: quote.authorId,
quotedText: quote.body ?? "QUOTED_MESSAGE_NOT_FOUND".localized(),
quotedText: quote.body,
threadVariant: cellViewModel.threadVariant,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
@ -770,15 +774,15 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
// MARK: - Interaction
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if let bodyTappableLabel = bodyTappableLabel {
let btIngetBodyTappableLabelCoordinates = convert(point, to: bodyTappableLabel)
if bodyTappableLabel.bounds.contains(btIngetBodyTappableLabelCoordinates) {
return bodyTappableLabel
}
}
return super.hitTest(point, with: event)
}
// override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// if let bodyTappableLabel = bodyTappableLabel {
// let btIngetBodyTappableLabelCoordinates = convert(point, to: bodyTappableLabel)
// if bodyTappableLabel.bounds.contains(btIngetBodyTappableLabelCoordinates) {
// return bodyTappableLabel
// }
// }
// return super.hitTest(point, with: event)
// }
override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true // Needed for the pan gesture recognizer to work with the table view's pan gesture recognizer

@ -206,6 +206,10 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
threadVariant == .closedGroup &&
threadViewModel.currentUserIsClosedGroupMember == true
)
let currentUserIsClosedGroupAdmin: Bool = (
threadVariant == .closedGroup &&
threadViewModel.currentUserIsClosedGroupAdmin == true
)
return [
SectionModel(
@ -389,7 +393,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
accessibilityLabel: "Leave group",
confirmationInfo: ConfirmationModal.Info(
title: "CONFIRM_LEAVE_GROUP_TITLE".localized(),
explanation: (currentUserIsClosedGroupMember ?
explanation: (currentUserIsClosedGroupAdmin ?
"Because you are the creator of this group it will be deleted for everyone. This cannot be undone." :
"CONFIRM_LEAVE_GROUP_DESCRIPTION".localized()
),
@ -676,9 +680,9 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
nil
),
accessibilityLabel: oldBlockedState == false ? "User blocked" : "Confirm unblock",
accessibilityId: "OK",
accessibilityId: "Test_name",
cancelTitle: "BUTTON_OK".localized(),
cancelAccessibilityLabel: "OK",
cancelAccessibilityLabel: "OK_BUTTON",
cancelStyle: .alert_text
)
)

@ -218,6 +218,7 @@ class GifPickerCell: UICollectionViewCell {
return
}
imageView.image = image
imageView.accessibilityIdentifier = "gif cell"
self.themeBackgroundColor = nil
if self.isCellSelected {

@ -172,7 +172,7 @@ final class RegisterVC : BaseVC {
private func updatePublicKeyLabel() {
let hexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey
publicKeyLabel.accessibilityLabel = hexEncodedPublicKey
publicKeyLabel.accessibilityIdentifier = "Session ID generated"
publicKeyLabel.accessibilityIdentifier = "Session ID"
publicKeyLabel.isAccessibilityElement = true
let characterCount = hexEncodedPublicKey.count
var count = 0

@ -63,6 +63,7 @@ class SessionAvatarCell: UITableViewCell {
fileprivate let displayNameContainer: UIView = {
let view: UIView = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.accessibilityIdentifier = "Username"
view.accessibilityLabel = "Username"
view.isAccessibilityElement = true
@ -266,6 +267,7 @@ class SessionAvatarCell: UITableViewCell {
}
let completion: (Bool) -> Void = { [weak self] complete in
self?.displayNameTextField.text = self?.originalInputValue
self?.displayNameContainer.accessibilityLabel = self?.displayNameLabel.text
}
if animated {

@ -787,6 +787,13 @@ extension Attachment {
public var isText: Bool { MIMETypeUtil.isText(contentType) }
public var isMicrosoftDoc: Bool { MIMETypeUtil.isMicrosoftDoc(contentType) }
public var shortDescription: String {
if isImage { return "Image" }
if isAudio { return "Audio" }
if isVideo { return "Video" }
return "Document"
}
public func readDataFromFile() throws -> Data? {
guard let filePath: String = self.originalFilePath else {
return nil

@ -76,6 +76,26 @@ public struct Quote: Codable, Equatable, Hashable, FetchableRecord, PersistableR
}
}
// MARK: - Mutation
public extension Quote {
func with(
interactionId: Int64? = nil,
authorId: String? = nil,
timestampMs: Int64? = nil,
body: String? = nil,
attachmentId: String? = nil
) -> Quote {
return Quote(
interactionId: interactionId ?? self.interactionId,
authorId: authorId ?? self.authorId,
timestampMs: timestampMs ?? self.timestampMs,
body: body ?? self.body,
attachmentId: attachmentId ?? self.attachmentId
)
}
}
// MARK: - Protobuf
public extension Quote {

@ -420,7 +420,7 @@ extension MessageReceiver {
// Delete the members to remove
try GroupMember
.filter(GroupMember.Columns.groupId == id)
.filter(updatedMemberIds.contains(GroupMember.Columns.profileId))
.filter(membersToRemove.map{ $0.profileId }.contains(GroupMember.Columns.profileId))
.deleteAll(db)
if didAdminLeave || sender == userPublicKey {

@ -904,7 +904,7 @@ public extension SessionThreadViewModel {
LEFT JOIN \(OpenGroup.self) ON \(openGroup[.threadId]) = \(thread[.id])
LEFT JOIN \(ClosedGroup.self) ON \(closedGroup[.threadId]) = \(thread[.id])
LEFT JOIN \(GroupMember.self) AS \(ViewModel.currentUserIsClosedGroupMemberKey) ON (
\(SQL("\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberRoleColumnLiteral) = \(GroupMember.Role.standard)")) AND
\(SQL("\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberRoleColumnLiteral) != \(GroupMember.Role.zombie)")) AND
\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberGroupIdColumnLiteral) = \(closedGroup[.threadId]) AND
\(SQL("\(ViewModel.currentUserIsClosedGroupMemberKey).\(groupMemberProfileIdColumnLiteral) = \(userPublicKey)"))
)

@ -22,7 +22,7 @@ public class ConfirmationModal: Modal {
let explanation: String?
let attributedExplanation: NSAttributedString?
let accessibilityLabel: String?
let accessibilityId: String?
let accessibilityIdentifier: String?
public let stateToShow: State
let confirmTitle: String?
let confirmAccessibilityLabel: String?
@ -57,7 +57,7 @@ public class ConfirmationModal: Modal {
self.explanation = explanation
self.attributedExplanation = attributedExplanation
self.accessibilityLabel = accessibilityLabel
self.accessibilityId = accessibilityId
self.accessibilityIdentifier = accessibilityId
self.stateToShow = stateToShow
self.confirmTitle = confirmTitle
self.confirmAccessibilityLabel = confirmAccessibilityLabel
@ -241,8 +241,8 @@ public class ConfirmationModal: Modal {
cancelButton.setTitle(info.cancelTitle, for: .normal)
cancelButton.setThemeTitleColor(info.cancelStyle, for: .normal)
self.accessibilityLabel = info.accessibilityLabel
self.contentView.accessibilityIdentifier = info.accessibilityId
self.contentView.accessibilityLabel = info.accessibilityLabel
self.contentView.accessibilityIdentifier = info.accessibilityIdentifier
}
required init?(coder: NSCoder) {

@ -58,6 +58,8 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
self.themeBackgroundColor = .clear
textView.delegate = self
textView.accessibilityIdentifier = "Text input box"
textView.isAccessibilityElement = true
let sendTitle = NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", comment: "Label for 'send' button in the 'attachment approval' dialog.")
sendButton.setTitle(sendTitle, for: .normal)
@ -66,6 +68,8 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
sendButton.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize)
sendButton.titleLabel?.textAlignment = .center
sendButton.themeTintColor = .textPrimary
sendButton.accessibilityIdentifier = "Send button"
sendButton.isAccessibilityElement = true
// Increase hit area of send button
sendButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 8, bottom: 6, right: 8)

@ -40,6 +40,8 @@ public class ModalActivityIndicatorViewController: OWSViewController {
result.set(.width, to: 64)
result.set(.height, to: 64)
result.accessibilityIdentifier = "Loading animation"
ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in
guard let textPrimary: UIColor = theme.color(for: .textPrimary) else { return }

Loading…
Cancel
Save