Merge remote-tracking branch 'origin/release/2.30.2'
This commit is contained in:
commit
f0f25aa413
2
Podfile
2
Podfile
|
@ -9,7 +9,7 @@ def shared_pods
|
|||
pod 'SQLCipher', :git => 'https://github.com/sqlcipher/sqlcipher.git', :commit => 'd5c2bec'
|
||||
# pod 'YapDatabase/SQLCipher', path: '../YapDatabase'
|
||||
pod 'YapDatabase/SQLCipher', :git => 'https://github.com/signalapp/YapDatabase.git', branch: 'signal-release'
|
||||
pod 'AxolotlKit', git: 'https://github.com/signalapp/SignalProtocolKit.git'
|
||||
pod 'AxolotlKit', git: 'https://github.com/signalapp/SignalProtocolKit.git', branch: 'release/2.30.2'
|
||||
# pod 'AxolotlKit', path: '../SignalProtocolKit'
|
||||
pod 'SignalServiceKit', path: '.', testspecs: ["Tests"]
|
||||
pod 'HKDFKit', git: 'https://github.com/signalapp/HKDFKit.git'
|
||||
|
|
|
@ -152,7 +152,7 @@ PODS:
|
|||
|
||||
DEPENDENCIES:
|
||||
- AFNetworking
|
||||
- AxolotlKit (from `https://github.com/signalapp/SignalProtocolKit.git`)
|
||||
- AxolotlKit (from `https://github.com/signalapp/SignalProtocolKit.git`, branch `release/2.30.2`)
|
||||
- Curve25519Kit (from `https://github.com/signalapp/Curve25519Kit`)
|
||||
- GRKOpenSSLFramework (from `https://github.com/signalapp/GRKOpenSSLFramework`)
|
||||
- HKDFKit (from `https://github.com/signalapp/HKDFKit.git`)
|
||||
|
@ -183,6 +183,7 @@ SPEC REPOS:
|
|||
|
||||
EXTERNAL SOURCES:
|
||||
AxolotlKit:
|
||||
:branch: release/2.30.2
|
||||
:git: https://github.com/signalapp/SignalProtocolKit.git
|
||||
Curve25519Kit:
|
||||
:git: https://github.com/signalapp/Curve25519Kit
|
||||
|
@ -204,7 +205,7 @@ EXTERNAL SOURCES:
|
|||
|
||||
CHECKOUT OPTIONS:
|
||||
AxolotlKit:
|
||||
:commit: 7b2af262204af6f5dcdc2986571c5a72400f7e04
|
||||
:commit: 446fbdaa5760cf1b1337441340d4d885beb27beb
|
||||
:git: https://github.com/signalapp/SignalProtocolKit.git
|
||||
Curve25519Kit:
|
||||
:commit: a4f46bd621bb2bcbf1a44b360e8ac4209e410ee9
|
||||
|
@ -246,6 +247,6 @@ SPEC CHECKSUMS:
|
|||
YapDatabase: b418a4baa6906e8028748938f9159807fd039af4
|
||||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
|
||||
PODFILE CHECKSUM: 40c4fc7dfb6066c4fdb80bc08600096e172dd4d7
|
||||
PODFILE CHECKSUM: 99cf978c46911aa96f569649e7113245f4ed30b7
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
|
2
Pods
2
Pods
|
@ -1 +1 @@
|
|||
Subproject commit e90476016714371cc689f6fae35fe853a0ad16ae
|
||||
Subproject commit 4c450a8a1702d3b00eaa476dbddff487d3a91c53
|
|
@ -438,7 +438,6 @@
|
|||
4C63CC00210A620B003AE45C /* SignalTSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C63CBFF210A620B003AE45C /* SignalTSan.supp */; };
|
||||
4C6F527C20FFE8400097DEEE /* SignalUBSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */; };
|
||||
4C858A52212DC5E1001B45D3 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */; };
|
||||
4C858A562130CBEC001B45D3 /* OWS110SortIdMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */; };
|
||||
4C948FF72146EB4800349F0D /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C948FF62146EB4800349F0D /* BlockListCache.swift */; };
|
||||
4CA5F793211E1F06008C2708 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA5F792211E1F06008C2708 /* Toast.swift */; };
|
||||
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF4C0920F55BBA005DA313 /* MenuActionsViewController.swift */; };
|
||||
|
@ -1125,7 +1124,6 @@
|
|||
4C63CBFF210A620B003AE45C /* SignalTSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalTSan.supp; sourceTree = "<group>"; };
|
||||
4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalUBSan.supp; sourceTree = "<group>"; };
|
||||
4C858A51212DC5E1001B45D3 /* UIImage+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+OWS.swift"; sourceTree = "<group>"; };
|
||||
4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWS110SortIdMigration.swift; sourceTree = "<group>"; };
|
||||
4C948FF62146EB4800349F0D /* BlockListCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListCache.swift; sourceTree = "<group>"; };
|
||||
4CA5F792211E1F06008C2708 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
|
||||
4CB5F26820F7D060004D1B42 /* MessageActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageActions.swift; sourceTree = "<group>"; };
|
||||
|
@ -1634,7 +1632,6 @@
|
|||
346129E41FD5C0C600532771 /* OWSDatabaseMigrationRunner.m */,
|
||||
34ABB2C32090C59700C727A6 /* OWSResaveCollectionDBMigration.h */,
|
||||
34ABB2C22090C59600C727A6 /* OWSResaveCollectionDBMigration.m */,
|
||||
4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */,
|
||||
);
|
||||
path = migrations;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3182,7 +3179,6 @@
|
|||
34AC09E6211B39B100997B47 /* SelectRecipientViewController.m in Sources */,
|
||||
4C858A52212DC5E1001B45D3 /* UIImage+OWS.swift in Sources */,
|
||||
34480B671FD0AA9400BC14EF /* UIFont+OWS.m in Sources */,
|
||||
4C858A562130CBEC001B45D3 /* OWS110SortIdMigration.swift in Sources */,
|
||||
346129E61FD5C0C600532771 /* OWSDatabaseMigrationRunner.m in Sources */,
|
||||
34AC0A11211B39EA00997B47 /* OWSLayerView.swift in Sources */,
|
||||
34AC0A1B211B39EA00997B47 /* GradientView.swift in Sources */,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.30.1</string>
|
||||
<string>2.30.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -38,7 +38,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.30.1.1</string>
|
||||
<string>2.30.2.4</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LOGS_EMAIL</key>
|
||||
|
|
|
@ -30,7 +30,6 @@ public class SessionResetJob: NSObject {
|
|||
self.primaryStorage.deleteAllSessions(forContact: self.recipientId, protocolContext: transaction)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.thread)
|
||||
|
||||
self.messageSender.enqueue(endSessionMessage, success: {
|
||||
|
@ -41,7 +40,6 @@ public class SessionResetJob: NSObject {
|
|||
self.primaryStorage.archiveAllSessions(forContact: self.recipientId, protocolContext: transaction)
|
||||
}
|
||||
Logger.info("successfully sent EndSessionMessage.")
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
let message = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
in: self.thread,
|
||||
messageType: TSInfoMessageType.typeSessionDidEnd)
|
||||
|
|
|
@ -67,66 +67,67 @@ struct MessageActionBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
extension ConversationViewItem {
|
||||
@objc
|
||||
class ConversationViewItemActions: NSObject {
|
||||
|
||||
@objc
|
||||
func textActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
class func textActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
var actions: [MenuAction] = []
|
||||
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(replyAction)
|
||||
|
||||
if self.hasBodyTextActionContent {
|
||||
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.hasBodyTextActionContent {
|
||||
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(copyTextAction)
|
||||
}
|
||||
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(deleteAction)
|
||||
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(showDetailsAction)
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
@objc
|
||||
func mediaActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
class func mediaActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
var actions: [MenuAction] = []
|
||||
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(replyAction)
|
||||
|
||||
if self.hasMediaActionContent {
|
||||
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.hasMediaActionContent {
|
||||
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(copyMediaAction)
|
||||
if self.canSaveMedia() {
|
||||
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.canSaveMedia() {
|
||||
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(saveMediaAction)
|
||||
}
|
||||
}
|
||||
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(deleteAction)
|
||||
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(showDetailsAction)
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
@objc
|
||||
func quotedMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
class func quotedMessageActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
|
||||
return [replyAction, deleteAction, showDetailsAction]
|
||||
}
|
||||
|
||||
@objc
|
||||
func infoMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
class func infoMessageActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
|
||||
return [deleteAction]
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import "AppSettingsViewController.h"
|
||||
#import "ContactCellView.h"
|
||||
#import "ContactTableViewCell.h"
|
||||
#import "ConversationViewCell.h"
|
||||
#import "ConversationViewItem.h"
|
||||
#import "DateUtil.h"
|
||||
#import "DebugUIPage.h"
|
||||
|
@ -21,6 +22,7 @@
|
|||
#import "NotificationsManager.h"
|
||||
#import "OWSAddToContactViewController.h"
|
||||
#import "OWSAnyTouchGestureRecognizer.h"
|
||||
#import "OWSAudioMessageView.h"
|
||||
#import "OWSAudioPlayer.h"
|
||||
#import "OWSBackup.h"
|
||||
#import "OWSBackupIO.h"
|
||||
|
|
|
@ -75,18 +75,18 @@ class ColorPicker: NSObject, ColorPickerViewDelegate {
|
|||
@objc
|
||||
let sheetViewController: SheetViewController
|
||||
|
||||
private let currentConversationColor: OWSConversationColor
|
||||
|
||||
@objc
|
||||
init(currentConversationColor: OWSConversationColor) {
|
||||
self.currentConversationColor = currentConversationColor
|
||||
init(thread: TSThread) {
|
||||
let colorName = thread.conversationColorName
|
||||
let currentConversationColor = OWSConversationColor.conversationColorOrDefault(colorName: colorName)
|
||||
sheetViewController = SheetViewController()
|
||||
|
||||
super.init()
|
||||
|
||||
let colorPickerView = ColorPickerView()
|
||||
let colorPickerView = ColorPickerView(thread: thread)
|
||||
colorPickerView.delegate = self
|
||||
colorPickerView.select(conversationColor: currentConversationColor)
|
||||
|
||||
sheetViewController.contentView.addSubview(colorPickerView)
|
||||
colorPickerView.autoPinEdgesToSuperviewEdges()
|
||||
}
|
||||
|
@ -105,21 +105,42 @@ protocol ColorPickerViewDelegate: class {
|
|||
class ColorPickerView: UIView, ColorViewDelegate {
|
||||
|
||||
private let colorViews: [ColorView]
|
||||
let conversationStyle: ConversationStyle
|
||||
var outgoingMessageView = OWSMessageBubbleView(forAutoLayout: ())
|
||||
var incomingMessageView = OWSMessageBubbleView(forAutoLayout: ())
|
||||
weak var delegate: ColorPickerViewDelegate?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
// This is mostly a developer convenience - OWSMessageCell asserts at some point
|
||||
// that the available method width is greater than 0.
|
||||
// We ultimately use the width of the picker view which will be larger.
|
||||
let kMinimumConversationWidth: CGFloat = 300
|
||||
override var bounds: CGRect {
|
||||
didSet {
|
||||
updateMockConversationView()
|
||||
}
|
||||
}
|
||||
|
||||
let mockConversationView: UIView = UIView()
|
||||
|
||||
init(thread: TSThread) {
|
||||
let allConversationColors = OWSConversationColor.conversationColorNames.map { OWSConversationColor.conversationColorOrDefault(colorName: $0) }
|
||||
|
||||
self.colorViews = allConversationColors.map { ColorView(conversationColor: $0) }
|
||||
|
||||
super.init(frame: frame)
|
||||
self.conversationStyle = ConversationStyle(thread: thread)
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
colorViews.forEach { $0.delegate = self }
|
||||
|
||||
let headerView = self.buildHeaderView()
|
||||
mockConversationView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
|
||||
mockConversationView.backgroundColor = Theme.backgroundColor
|
||||
self.updateMockConversationView()
|
||||
|
||||
let paletteView = self.buildPaletteView(colorViews: colorViews)
|
||||
|
||||
let rowsStackView = UIStackView(arrangedSubviews: [headerView, paletteView])
|
||||
let rowsStackView = UIStackView(arrangedSubviews: [headerView, mockConversationView, paletteView])
|
||||
rowsStackView.axis = .vertical
|
||||
addSubview(rowsStackView)
|
||||
rowsStackView.autoPinEdgesToSuperviewEdges()
|
||||
|
@ -134,6 +155,7 @@ class ColorPickerView: UIView, ColorViewDelegate {
|
|||
func colorViewWasTapped(_ colorView: ColorView) {
|
||||
self.select(conversationColor: colorView.conversationColor)
|
||||
self.delegate?.colorPickerView(self, didPickConversationColor: colorView.conversationColor)
|
||||
updateMockConversationView()
|
||||
}
|
||||
|
||||
fileprivate func select(conversationColor selectedConversationColor: OWSConversationColor) {
|
||||
|
@ -166,9 +188,59 @@ class ColorPickerView: UIView, ColorViewDelegate {
|
|||
return headerView
|
||||
}
|
||||
|
||||
private func updateMockConversationView() {
|
||||
conversationStyle.viewWidth = max(bounds.size.width, kMinimumConversationWidth)
|
||||
mockConversationView.subviews.forEach { $0.removeFromSuperview() }
|
||||
|
||||
// outgoing
|
||||
outgoingMessageView = OWSMessageBubbleView(forAutoLayout: ())
|
||||
let outgoingItem = MockConversationViewItem()
|
||||
let outgoingText = NSLocalizedString("COLOR_PICKER_DEMO_MESSAGE_1", comment: "The first of two messages demonstrating the chosen conversation color, by rendering this message in an outgoing message bubble.")
|
||||
outgoingItem.interaction = MockOutgoingMessage(messageBody: outgoingText)
|
||||
outgoingItem.displayableBodyText = DisplayableText.displayableText(outgoingText)
|
||||
outgoingItem.interactionType = .outgoingMessage
|
||||
|
||||
outgoingMessageView.viewItem = outgoingItem
|
||||
outgoingMessageView.cellMediaCache = NSCache()
|
||||
outgoingMessageView.conversationStyle = conversationStyle
|
||||
outgoingMessageView.configureViews()
|
||||
outgoingMessageView.loadContent()
|
||||
let outgoingCell = UIView()
|
||||
outgoingCell.addSubview(outgoingMessageView)
|
||||
outgoingMessageView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .leading)
|
||||
let outgoingSize = outgoingMessageView.measureSize()
|
||||
outgoingMessageView.autoSetDimensions(to: outgoingSize)
|
||||
|
||||
// incoming
|
||||
incomingMessageView = OWSMessageBubbleView(forAutoLayout: ())
|
||||
let incomingItem = MockConversationViewItem()
|
||||
let incomingText = NSLocalizedString("COLOR_PICKER_DEMO_MESSAGE_2", comment: "The second of two messages demonstrating the chosen conversation color, by rendering this message in an incoming message bubble.")
|
||||
incomingItem.interaction = MockIncomingMessage(messageBody: incomingText)
|
||||
incomingItem.displayableBodyText = DisplayableText.displayableText(incomingText)
|
||||
incomingItem.interactionType = .incomingMessage
|
||||
|
||||
incomingMessageView.viewItem = incomingItem
|
||||
incomingMessageView.cellMediaCache = NSCache()
|
||||
incomingMessageView.conversationStyle = conversationStyle
|
||||
incomingMessageView.configureViews()
|
||||
incomingMessageView.loadContent()
|
||||
let incomingCell = UIView()
|
||||
incomingCell.addSubview(incomingMessageView)
|
||||
incomingMessageView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .trailing)
|
||||
let incomingSize = incomingMessageView.measureSize()
|
||||
incomingMessageView.autoSetDimensions(to: incomingSize)
|
||||
|
||||
let messagesStackView = UIStackView(arrangedSubviews: [outgoingCell, incomingCell])
|
||||
messagesStackView.axis = .vertical
|
||||
messagesStackView.spacing = 12
|
||||
|
||||
mockConversationView.addSubview(messagesStackView)
|
||||
messagesStackView.autoPinEdgesToSuperviewMargins()
|
||||
}
|
||||
|
||||
private func buildPaletteView(colorViews: [ColorView]) -> UIView {
|
||||
let paletteView = UIView()
|
||||
paletteView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
|
||||
paletteView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 0, right: 16)
|
||||
|
||||
let kRowLength = 4
|
||||
let rows: [UIView] = colorViews.chunked(by: kRowLength).map { colorViewsInRow in
|
||||
|
@ -178,10 +250,210 @@ class ColorPickerView: UIView, ColorViewDelegate {
|
|||
}
|
||||
let rowsStackView = UIStackView(arrangedSubviews: rows)
|
||||
rowsStackView.axis = .vertical
|
||||
rowsStackView.spacing = ScaleFromIPhone5To7Plus(16, 50)
|
||||
rowsStackView.spacing = ScaleFromIPhone5To7Plus(12, 50)
|
||||
|
||||
paletteView.addSubview(rowsStackView)
|
||||
rowsStackView.ows_autoPinToSuperviewMargins()
|
||||
|
||||
// no-op gesture to keep taps from dismissing SheetView
|
||||
paletteView.addGestureRecognizer(UITapGestureRecognizer(target: nil, action: nil))
|
||||
return paletteView
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Mock Classes for rendering demo conversation
|
||||
|
||||
@objc
|
||||
private class MockConversationViewItem: NSObject, ConversationViewItem {
|
||||
var interaction: TSInteraction = TSMessage()
|
||||
var interactionType: OWSInteractionType = OWSInteractionType.unknown
|
||||
var quotedReply: OWSQuotedReplyModel?
|
||||
var isGroupThread: Bool = false
|
||||
var hasBodyText: Bool = true
|
||||
var isQuotedReply: Bool = false
|
||||
var hasQuotedAttachment: Bool = false
|
||||
var hasQuotedText: Bool = false
|
||||
var hasCellHeader: Bool = false
|
||||
var isExpiringMessage: Bool = false
|
||||
var shouldShowDate: Bool = false
|
||||
var shouldShowSenderAvatar: Bool = false
|
||||
var senderName: NSAttributedString?
|
||||
var shouldHideFooter: Bool = false
|
||||
var isFirstInCluster: Bool = true
|
||||
var isLastInCluster: Bool = true
|
||||
var unreadIndicator: OWSUnreadIndicator?
|
||||
var lastAudioMessageView: OWSAudioMessageView?
|
||||
var audioDurationSeconds: CGFloat = 0
|
||||
var audioProgressSeconds: CGFloat = 0
|
||||
var messageCellType: OWSMessageCellType = .textMessage
|
||||
var displayableBodyText: DisplayableText?
|
||||
var attachmentStream: TSAttachmentStream?
|
||||
var attachmentPointer: TSAttachmentPointer?
|
||||
var mediaSize: CGSize = .zero
|
||||
var displayableQuotedText: DisplayableText?
|
||||
var quotedAttachmentMimetype: String?
|
||||
var quotedRecipientId: String?
|
||||
var didCellMediaFailToLoad: Bool = false
|
||||
var contactShare: ContactShareViewModel?
|
||||
var systemMessageText: String?
|
||||
var authorConversationColorName: String?
|
||||
var hasBodyTextActionContent: Bool = false
|
||||
var hasMediaActionContent: Bool = false
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
func dequeueCell(for collectionView: UICollectionView, indexPath: IndexPath) -> ConversationViewCell {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return ConversationViewCell(forAutoLayout: ())
|
||||
}
|
||||
|
||||
func replace(_ interaction: TSInteraction, transaction: YapDatabaseReadTransaction) {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func clearCachedLayoutState() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func copyMediaAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func copyTextAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func shareMediaAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func shareTextAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func saveMediaAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func deleteAction() {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func canSaveMedia() -> Bool {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return false
|
||||
}
|
||||
|
||||
func audioPlaybackState() -> AudioPlaybackState {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return AudioPlaybackState.paused
|
||||
}
|
||||
|
||||
func setAudioPlaybackState(_ state: AudioPlaybackState) {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func setAudioProgress(_ progress: CGFloat, duration: CGFloat) {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return
|
||||
}
|
||||
|
||||
func cellSize() -> CGSize {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return CGSize.zero
|
||||
}
|
||||
|
||||
func vSpacing(withPreviousLayoutItem previousLayoutItem: ConversationViewLayoutItem) -> CGFloat {
|
||||
owsFailDebug("unexpected invocation")
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
private class MockIncomingMessage: TSIncomingMessage {
|
||||
init(messageBody: String) {
|
||||
super.init(incomingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
in: TSThread(),
|
||||
authorId: "+fake-id",
|
||||
sourceDeviceId: 1,
|
||||
messageBody: messageBody,
|
||||
attachmentIds: [],
|
||||
expiresInSeconds: 0,
|
||||
quotedMessage: nil,
|
||||
contactShare: nil)
|
||||
}
|
||||
|
||||
required init(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
required init(dictionary dictionaryValue: [AnyHashable: Any]!) throws {
|
||||
fatalError("init(dictionary:) has not been implemented")
|
||||
}
|
||||
|
||||
override func save(with transaction: YapDatabaseReadWriteTransaction) {
|
||||
// no - op
|
||||
owsFailDebug("shouldn't save mock message")
|
||||
}
|
||||
}
|
||||
|
||||
private class MockOutgoingMessage: TSOutgoingMessage {
|
||||
init(messageBody: String) {
|
||||
super.init(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
in: nil,
|
||||
messageBody: messageBody,
|
||||
attachmentIds: [],
|
||||
expiresInSeconds: 0,
|
||||
expireStartedAt: 0,
|
||||
isVoiceMessage: false,
|
||||
groupMetaMessage: .unspecified,
|
||||
quotedMessage: nil,
|
||||
contactShare: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
required init(dictionary dictionaryValue: [AnyHashable: Any]!) throws {
|
||||
fatalError("init(dictionary:) has not been implemented")
|
||||
}
|
||||
|
||||
override func save(with transaction: YapDatabaseReadWriteTransaction) {
|
||||
// no - op
|
||||
owsFailDebug("shouldn't save mock message")
|
||||
}
|
||||
|
||||
class MockOutgoingMessageRecipientState: TSOutgoingMessageRecipientState {
|
||||
override var state: OWSOutgoingMessageRecipientState {
|
||||
return OWSOutgoingMessageRecipientState.sent
|
||||
}
|
||||
|
||||
override var deliveryTimestamp: NSNumber? {
|
||||
return NSNumber(value: NSDate.ows_millisecondTimeStamp())
|
||||
}
|
||||
|
||||
override var readTimestamp: NSNumber? {
|
||||
return NSNumber(value: NSDate.ows_millisecondTimeStamp())
|
||||
}
|
||||
}
|
||||
|
||||
override func readRecipientIds() -> [String] {
|
||||
// makes message appear as read
|
||||
return ["fake-non-empty-id"]
|
||||
}
|
||||
|
||||
override func recipientState(forRecipientId recipientId: String) -> TSOutgoingMessageRecipientState? {
|
||||
return MockOutgoingMessageRecipientState()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewCell;
|
||||
@class ConversationViewItem;
|
||||
@class OWSContactOffersInteraction;
|
||||
@class OWSContactsManager;
|
||||
@class TSAttachmentPointer;
|
||||
|
@ -19,13 +18,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class TSOutgoingMessage;
|
||||
@class TSQuotedMessage;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewCellDelegate <NSObject>
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell
|
||||
didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem;
|
||||
didLongpressSystemMessageViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
#pragma mark - System Cell
|
||||
|
||||
|
@ -68,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic, nullable, weak) id<ConversationViewCellDelegate> delegate;
|
||||
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
|
||||
// Cells are prefetched but expensive cells (e.g. media) should only load
|
||||
// when visible and unload when no longer visible. Non-visible cells can
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
@class TSAttachmentStream;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@interface OWSAudioMessageView : UIStackView
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream
|
||||
isIncoming:(BOOL)isIncoming
|
||||
viewItem:(ConversationViewItem *)viewItem
|
||||
viewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (void)createContents;
|
||||
|
|
|
@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic) BOOL isIncoming;
|
||||
@property (nonatomic, weak) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, weak) id<ConversationViewItem> viewItem;
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
@property (nonatomic, nullable) UIButton *audioPlayPauseButton;
|
||||
|
@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream
|
||||
isIncoming:(BOOL)isIncoming
|
||||
viewItem:(ConversationViewItem *)viewItem
|
||||
viewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
self = [super init];
|
||||
|
|
|
@ -6,7 +6,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class ContactShareViewModel;
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class OWSContact;
|
||||
@class OWSQuotedReplyModel;
|
||||
@class TSAttachmentPointer;
|
||||
|
@ -25,27 +27,27 @@ extern const UIDataDetectorTypes kOWSAllowedDataDetectorTypes;
|
|||
|
||||
@protocol OWSMessageBubbleViewDelegate
|
||||
|
||||
- (void)didTapImageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapImageViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView;
|
||||
|
||||
- (void)didTapVideoViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView;
|
||||
|
||||
- (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
- (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
|
||||
- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem;
|
||||
- (void)didTapTruncatedTextMessage:(id<ConversationViewItem>)conversationItem;
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply;
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply;
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem
|
||||
quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
failedThumbnailDownloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||
|
||||
- (void)didTapContactShareViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)didTapContactShareViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare
|
||||
NS_SWIFT_NAME(didTapSendMessage(toContactShare:));
|
||||
|
@ -60,7 +62,7 @@ extern const UIDataDetectorTypes kOWSAllowedDataDetectorTypes;
|
|||
|
||||
@interface OWSMessageBubbleView : UIView
|
||||
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
|
||||
@property (nonatomic) ConversationStyle *conversationStyle;
|
||||
|
||||
|
|
|
@ -2,19 +2,20 @@
|
|||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationStyle;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@interface OWSMessageFooterView : UIStackView
|
||||
|
||||
- (void)configureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
isOverlayingMedia:(BOOL)isOverlayingMedia
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
isIncoming:(BOOL)isIncoming;
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem;
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
- (void)prepareForReuse;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark - Load
|
||||
|
||||
- (void)configureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
isOverlayingMedia:(BOOL)isOverlayingMedia
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
isIncoming:(BOOL)isIncoming
|
||||
|
@ -186,7 +186,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.statusIndicatorImageView.layer addAnimation:animation forKey:@"animation"];
|
||||
}
|
||||
|
||||
- (BOOL)isFailedOutgoingMessage:(ConversationViewItem *)viewItem
|
||||
- (BOOL)isFailedOutgoingMessage:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -200,7 +200,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return messageStatus == MessageReceiptStatusFailed;
|
||||
}
|
||||
|
||||
- (void)configureLabelsWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureLabelsWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -217,7 +217,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
self.timestampLabel.text = timestampLabelText.localizedUppercaseString;
|
||||
}
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -243,7 +243,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return CGSizeCeil(result);
|
||||
}
|
||||
|
||||
- (nullable NSString *)messageStatusTextForConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (nullable NSString *)messageStatusTextForConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
if (viewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage) {
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
extern const CGFloat OWSMessageHeaderViewDateHeaderVMargin;
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSMessageHeaderView : UIStackView
|
||||
|
||||
- (void)loadForDisplayWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)loadForDisplayWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
@end
|
||||
|
|
|
@ -72,7 +72,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
[self addSubview:self.stackView];
|
||||
}
|
||||
|
||||
- (void)loadForDisplayWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)loadForDisplayWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -100,7 +100,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
];
|
||||
}
|
||||
|
||||
- (CGFloat)strokeThicknessWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGFloat)strokeThicknessWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -111,7 +111,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (UIColor *)strokeColorWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (UIColor *)strokeColorWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -122,11 +122,11 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)configureLabelsWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureLabelsWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
NSDate *date = viewItem.interaction.receivedAtDate;
|
||||
NSDate *date = viewItem.interaction.dateForSorting;
|
||||
NSString *dateString = [DateUtil formatDateForConversationDateBreaks:date].localizedUppercaseString;
|
||||
|
||||
// Update cell to reflect changes in dynamic text.
|
||||
|
@ -158,7 +158,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#import <SignalServiceKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/NSTimer+OWS.h>
|
||||
#import <SignalServiceKit/OWSAddToContactsOfferMessage.h>
|
||||
#import <SignalServiceKit/OWSAddToProfileWhitelistOfferMessage.h>
|
||||
#import <SignalServiceKit/OWSAttachmentsProcessor.h>
|
||||
#import <SignalServiceKit/OWSBlockingManager.h>
|
||||
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
|
||||
|
@ -174,8 +175,8 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic, readonly) ConversationViewLayout *layout;
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
@property (nonatomic) NSArray<ConversationViewItem *> *viewItems;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache;
|
||||
@property (nonatomic) NSArray<id<ConversationViewItem>> *viewItems;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, id<ConversationViewItem>> *viewItemCache;
|
||||
|
||||
@property (nonatomic, nullable) AVAudioRecorder *audioRecorder;
|
||||
@property (nonatomic, nullable) OWSAudioPlayer *audioAttachmentPlayer;
|
||||
|
@ -214,7 +215,7 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic) BOOL hasClearedUnreadMessagesIndicator;
|
||||
@property (nonatomic) BOOL showLoadMoreHeader;
|
||||
@property (nonatomic) UILabel *loadMoreHeader;
|
||||
@property (nonatomic) uint64_t lastVisibleSortId;
|
||||
@property (nonatomic) uint64_t lastVisibleTimestamp;
|
||||
|
||||
@property (nonatomic) BOOL isUserScrolling;
|
||||
|
||||
|
@ -705,7 +706,7 @@ typedef enum : NSUInteger {
|
|||
[self scrollToDefaultPosition];
|
||||
}
|
||||
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
|
||||
if (!self.viewHasEverAppeared) {
|
||||
NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt;
|
||||
|
@ -716,7 +717,7 @@ typedef enum : NSUInteger {
|
|||
- (NSIndexPath *_Nullable)indexPathOfUnreadMessagesIndicator
|
||||
{
|
||||
NSInteger row = 0;
|
||||
for (ConversationViewItem *viewItem in self.viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in self.viewItems) {
|
||||
if (viewItem.unreadIndicator) {
|
||||
return [NSIndexPath indexPathForRow:row inSection:0];
|
||||
}
|
||||
|
@ -1552,7 +1553,7 @@ typedef enum : NSUInteger {
|
|||
OWSLogInfo(@"didChangePreferredContentSize");
|
||||
|
||||
// Evacuate cached cell sizes.
|
||||
for (ConversationViewItem *viewItem in self.viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in self.viewItems) {
|
||||
[viewItem clearCachedLayoutState];
|
||||
}
|
||||
[self resetContentAndLayout];
|
||||
|
@ -1890,11 +1891,7 @@ typedef enum : NSUInteger {
|
|||
// DEPRECATED: we're no longer creating these incoming SN error's per message,
|
||||
// but there will be some legacy ones in the wild, behind which await
|
||||
// as-of-yet-undecrypted messages
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if ([errorMessage isKindOfClass:[TSInvalidIdentityKeyReceivingErrorMessage class]]) {
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
[errorMessage acceptNewIdentityKey];
|
||||
}
|
||||
}];
|
||||
|
@ -1936,12 +1933,12 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - MessageActionsDelegate
|
||||
|
||||
- (void)messageActionsShowDetailsForItem:(ConversationViewItem *)conversationViewItem
|
||||
- (void)messageActionsShowDetailsForItem:(id<ConversationViewItem>)conversationViewItem
|
||||
{
|
||||
[self showDetailViewForViewItem:conversationViewItem];
|
||||
}
|
||||
|
||||
- (void)messageActionsReplyToItem:(ConversationViewItem *)conversationViewItem
|
||||
- (void)messageActionsReplyToItem:(id<ConversationViewItem>)conversationViewItem
|
||||
{
|
||||
[self populateReplyForViewItem:conversationViewItem];
|
||||
}
|
||||
|
@ -2009,27 +2006,32 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - ConversationViewCellDelegate
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem mediaActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions mediaActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem textActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions textActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem quotedMessageActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions quotedMessageActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell
|
||||
didLongpressSystemMessageViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem infoMessageActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions infoMessageActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
|
@ -2144,7 +2146,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - OWSMessageBubbleViewDelegate
|
||||
|
||||
- (void)didTapImageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapImageViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView
|
||||
{
|
||||
|
@ -2175,7 +2177,7 @@ typedef enum : NSUInteger {
|
|||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapVideoViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIImageView *)imageView
|
||||
{
|
||||
|
@ -2204,7 +2206,7 @@ typedef enum : NSUInteger {
|
|||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
- (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -2234,7 +2236,7 @@ typedef enum : NSUInteger {
|
|||
[self.audioAttachmentPlayer playWithPlaybackAudioCategory];
|
||||
}
|
||||
|
||||
- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem
|
||||
- (void)didTapTruncatedTextMessage:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2244,7 +2246,7 @@ typedef enum : NSUInteger {
|
|||
[self.navigationController pushViewController:view animated:YES];
|
||||
}
|
||||
|
||||
- (void)didTapContactShareViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)didTapContactShareViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2279,7 +2281,7 @@ typedef enum : NSUInteger {
|
|||
[self.contactShareViewHelper showAddToContactsWithContactShare:contactShare fromViewController:self];
|
||||
}
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
@ -2299,7 +2301,7 @@ typedef enum : NSUInteger {
|
|||
[self handleUnsentMessageTap:message];
|
||||
}
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem
|
||||
quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
failedThumbnailDownloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
|
@ -2337,7 +2339,7 @@ typedef enum : NSUInteger {
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -2472,7 +2474,7 @@ typedef enum : NSUInteger {
|
|||
return @(groupIndex);
|
||||
}
|
||||
|
||||
- (void)showDetailViewForViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)showDetailViewForViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2487,7 +2489,7 @@ typedef enum : NSUInteger {
|
|||
[self.navigationController pushViewController:view animated:YES];
|
||||
}
|
||||
|
||||
- (void)populateReplyForViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)populateReplyForViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSLogDebug(@"user did tap reply");
|
||||
|
||||
|
@ -2562,7 +2564,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
NSIndexPath *_Nullable indexPathOfUnreadIndicator = [self indexPathOfUnreadMessagesIndicator];
|
||||
if (indexPathOfUnreadIndicator) {
|
||||
ConversationViewItem *oldIndicatorItem = [self viewItemForIndex:indexPathOfUnreadIndicator.row];
|
||||
id<ConversationViewItem> oldIndicatorItem = [self viewItemForIndex:indexPathOfUnreadIndicator.row];
|
||||
OWSAssertDebug(oldIndicatorItem);
|
||||
|
||||
// TODO ideally this would be happening within the *same* transaction that caused the unreadMessageIndicator
|
||||
|
@ -2676,10 +2678,10 @@ typedef enum : NSUInteger {
|
|||
BOOL isScrolledUp = scrollSpaceToBottom > pageHeight * 1.f;
|
||||
|
||||
if (self.viewItems.count > 0) {
|
||||
ConversationViewItem *lastViewItem = [self.viewItems lastObject];
|
||||
id<ConversationViewItem> lastViewItem = [self.viewItems lastObject];
|
||||
OWSAssertDebug(lastViewItem);
|
||||
|
||||
if (lastViewItem.interaction.sortId > self.lastVisibleSortId) {
|
||||
if (lastViewItem.interaction.timestampForSorting > self.lastVisibleTimestamp) {
|
||||
shouldShowScrollDownButton = YES;
|
||||
} else if (isScrolledUp) {
|
||||
shouldShowScrollDownButton = YES;
|
||||
|
@ -2778,6 +2780,7 @@ typedef enum : NSUInteger {
|
|||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(message);
|
||||
|
||||
[self updateLastVisibleTimestamp:message.timestampForSorting];
|
||||
self.lastMessageSentDate = [NSDate new];
|
||||
[self clearUnreadMessagesIndicator];
|
||||
self.inputToolbar.quotedReply = nil;
|
||||
|
@ -3291,7 +3294,7 @@ typedef enum : NSUInteger {
|
|||
case YapDatabaseViewChangeUpdate: {
|
||||
YapCollectionKey *collectionKey = rowChange.collectionKey;
|
||||
if (collectionKey.key) {
|
||||
ConversationViewItem *_Nullable viewItem = self.viewItemCache[collectionKey.key];
|
||||
id<ConversationViewItem> _Nullable viewItem = self.viewItemCache[collectionKey.key];
|
||||
if (viewItem) {
|
||||
[self reloadInteractionForViewItem:viewItem];
|
||||
} else {
|
||||
|
@ -3329,7 +3332,7 @@ typedef enum : NSUInteger {
|
|||
// using the more extreme actions in the debug UI.
|
||||
OWSFailDebug(@"hasMalformedRowChange");
|
||||
[self resetMappings];
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
return;
|
||||
}
|
||||
|
@ -3339,7 +3342,7 @@ typedef enum : NSUInteger {
|
|||
// These errors are rare.
|
||||
OWSFailDebug(@"could not reload view items; hard resetting message mappings.");
|
||||
[self resetMappings];
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
return;
|
||||
}
|
||||
|
@ -3375,7 +3378,8 @@ typedef enum : NSUInteger {
|
|||
(unsigned long)rowChange.finalIndex);
|
||||
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
|
||||
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem =
|
||||
[self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if ([viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
|
||||
if (!outgoingMessage.isFromLinkedDevice) {
|
||||
|
@ -3417,8 +3421,8 @@ typedef enum : NSUInteger {
|
|||
if (!finished) {
|
||||
OWSLogInfo(@"performBatchUpdates did not finish");
|
||||
}
|
||||
|
||||
[self updateLastVisibleSortId];
|
||||
|
||||
[self updateLastVisibleTimestamp];
|
||||
|
||||
if (scrollToBottom && shouldAnimateUpdates) {
|
||||
[self scrollToBottomAnimated:shouldAnimateScrollToBottom];
|
||||
|
@ -3510,7 +3514,7 @@ typedef enum : NSUInteger {
|
|||
isOnlyModifyingLastMessage = NO;
|
||||
break;
|
||||
case YapDatabaseViewChangeInsert: {
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
|
||||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
|
||||
&& rowChange.finalIndex >= oldViewItemCount) {
|
||||
|
@ -3526,7 +3530,7 @@ typedef enum : NSUInteger {
|
|||
if (rowChange.changes == YapDatabaseViewChangedDependency) {
|
||||
continue;
|
||||
}
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
|
||||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
|
||||
&& rowChange.finalIndex >= oldViewItemCount) {
|
||||
|
@ -3857,7 +3861,7 @@ typedef enum : NSUInteger {
|
|||
return lastVisibleIndexPath;
|
||||
}
|
||||
|
||||
- (nullable ConversationViewItem *)lastVisibleViewItem
|
||||
- (nullable id<ConversationViewItem>)lastVisibleViewItem
|
||||
{
|
||||
NSIndexPath *_Nullable lastVisibleIndexPath = [self lastVisibleIndexPath];
|
||||
if (!lastVisibleIndexPath) {
|
||||
|
@ -3872,10 +3876,10 @@ typedef enum : NSUInteger {
|
|||
- (void)didScrollToBottom
|
||||
{
|
||||
|
||||
ConversationViewItem *_Nullable lastVisibleViewItem = [self.viewItems lastObject];
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self.viewItems lastObject];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleSortId = lastVisibleViewItem.interaction.sortId;
|
||||
self.lastVisibleSortId = MAX(self.lastVisibleSortId, lastVisibleSortId);
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
}
|
||||
|
||||
self.scrollDownButton.hidden = YES;
|
||||
|
@ -3883,12 +3887,12 @@ typedef enum : NSUInteger {
|
|||
self.hasUnreadMessages = NO;
|
||||
}
|
||||
|
||||
- (void)updateLastVisibleSortId
|
||||
- (void)updateLastVisibleTimestamp
|
||||
{
|
||||
ConversationViewItem *_Nullable lastVisibleViewItem = [self lastVisibleViewItem];
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self lastVisibleViewItem];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleSortId = lastVisibleViewItem.interaction.sortId;
|
||||
self.lastVisibleSortId = MAX(self.lastVisibleSortId, lastVisibleSortId);
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
}
|
||||
|
||||
[self ensureScrollDownButton];
|
||||
|
@ -3901,6 +3905,15 @@ typedef enum : NSUInteger {
|
|||
self.hasUnreadMessages = numberOfUnreadMessages > 0;
|
||||
}
|
||||
|
||||
- (void)updateLastVisibleTimestamp:(uint64_t)timestamp
|
||||
{
|
||||
OWSAssertDebug(timestamp > 0);
|
||||
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, timestamp);
|
||||
|
||||
[self ensureScrollDownButton];
|
||||
}
|
||||
|
||||
- (void)markVisibleMessagesAsRead
|
||||
{
|
||||
if (self.presentedViewController) {
|
||||
|
@ -3916,16 +3929,15 @@ typedef enum : NSUInteger {
|
|||
return;
|
||||
}
|
||||
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
|
||||
uint64_t lastVisibleSortId = self.lastVisibleSortId;
|
||||
uint64_t lastVisibleTimestamp = self.lastVisibleTimestamp;
|
||||
|
||||
if (lastVisibleSortId == 0) {
|
||||
if (lastVisibleTimestamp == 0) {
|
||||
// No visible messages yet. New Thread.
|
||||
return;
|
||||
}
|
||||
|
||||
[OWSReadReceiptManager.sharedManager markAsReadLocallyBeforeSortId:self.lastVisibleSortId thread:self.thread];
|
||||
[OWSReadReceiptManager.sharedManager markAsReadLocallyBeforeTimestamp:lastVisibleTimestamp thread:self.thread];
|
||||
}
|
||||
|
||||
- (void)updateGroupModelTo:(TSGroupModel *)newGroupModel successCompletion:(void (^_Nullable)(void))successCompletion
|
||||
|
@ -4322,7 +4334,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self autoLoadMoreIfNecessary];
|
||||
}
|
||||
|
||||
|
@ -4634,7 +4646,7 @@ typedef enum : NSUInteger {
|
|||
// any new items inserted while we were not observing. We therefore find the
|
||||
// first item at or after the "view horizon". See the comments below which explain
|
||||
// the "view horizon".
|
||||
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
|
||||
id<ConversationViewItem> _Nullable lastViewItem = self.viewItems.lastObject;
|
||||
BOOL hasAddedNewItems = (lastViewItem && previousLastTimestamp
|
||||
&& lastViewItem.interaction.timestamp > previousLastTimestamp.unsignedLongLongValue);
|
||||
|
||||
|
@ -4665,7 +4677,7 @@ typedef enum : NSUInteger {
|
|||
// We'll use this later to update the view to reflect any changes made while
|
||||
// we were not observing the database. See extendRangeToIncludeUnobservedItems
|
||||
// and the logic above.
|
||||
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
|
||||
id<ConversationViewItem> _Nullable lastViewItem = self.viewItems.lastObject;
|
||||
if (lastViewItem) {
|
||||
self.previousLastTimestamp = @(lastViewItem.interaction.timestamp);
|
||||
} else {
|
||||
|
@ -4711,7 +4723,7 @@ typedef enum : NSUInteger {
|
|||
NSUInteger mid = (left + right) / 2;
|
||||
OWSAssertDebug(left <= mid);
|
||||
OWSAssertDebug(mid < right);
|
||||
ConversationViewItem *viewItem = self.viewItems[mid];
|
||||
id<ConversationViewItem> viewItem = self.viewItems[mid];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
right = mid;
|
||||
} else {
|
||||
|
@ -4720,7 +4732,7 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
OWSAssertDebug(left == right);
|
||||
ConversationViewItem *viewItem = self.viewItems[left];
|
||||
id<ConversationViewItem> viewItem = self.viewItems[left];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
OWSLogInfo(@"firstIndexPathAtViewHorizonTimestamp: %zd / %zd", left, self.viewItems.count);
|
||||
return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0];
|
||||
|
@ -4842,7 +4854,7 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
[self updateLastVisibleSortId];
|
||||
[self updateLastVisibleTimestamp];
|
||||
self.conversationStyle.viewWidth = self.collectionView.width;
|
||||
}
|
||||
|
||||
|
@ -4854,8 +4866,8 @@ typedef enum : NSUInteger {
|
|||
// Returns NO on error.
|
||||
- (BOOL)reloadViewItems
|
||||
{
|
||||
NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache = [NSMutableDictionary new];
|
||||
NSMutableArray<id<ConversationViewItem>> *viewItems = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, id<ConversationViewItem>> *viewItemCache = [NSMutableDictionary new];
|
||||
|
||||
NSUInteger count = [self.messageMappings numberOfItemsInSection:0];
|
||||
BOOL isGroupThread = self.isGroupConversation;
|
||||
|
@ -4884,12 +4896,12 @@ typedef enum : NSUInteger {
|
|||
continue;
|
||||
}
|
||||
|
||||
ConversationViewItem *_Nullable viewItem = self.viewItemCache[interaction.uniqueId];
|
||||
id<ConversationViewItem> _Nullable viewItem = self.viewItemCache[interaction.uniqueId];
|
||||
if (!viewItem) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:interaction
|
||||
isGroupThread:isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:interaction
|
||||
isGroupThread:isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}
|
||||
[viewItems addObject:viewItem];
|
||||
OWSAssertDebug(!viewItemCache[interaction.uniqueId]);
|
||||
|
@ -4910,7 +4922,7 @@ typedef enum : NSUInteger {
|
|||
uint64_t collapseCutoffTimestamp = [NSDate ows_millisecondsSince1970ForDate:self.collapseCutoffDate];
|
||||
|
||||
BOOL hasPlacedUnreadIndicator = NO;
|
||||
for (ConversationViewItem *viewItem in viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in viewItems) {
|
||||
BOOL canShowDate = NO;
|
||||
switch (viewItem.interaction.interactionType) {
|
||||
case OWSInteractionType_Unknown:
|
||||
|
@ -4926,7 +4938,7 @@ typedef enum : NSUInteger {
|
|||
break;
|
||||
}
|
||||
|
||||
uint64_t viewItemTimestamp = viewItem.interaction.receivedAtTimestamp;
|
||||
uint64_t viewItemTimestamp = viewItem.interaction.timestampForSorting;
|
||||
OWSAssertDebug(viewItemTimestamp > 0);
|
||||
|
||||
BOOL shouldShowDate = NO;
|
||||
|
@ -4958,15 +4970,17 @@ typedef enum : NSUInteger {
|
|||
&& !((id<OWSReadTracking>)viewItem.interaction).wasRead);
|
||||
if (isItemUnread && !unreadIndicator && !hasPlacedUnreadIndicator && !self.hasClearedUnreadMessagesIndicator) {
|
||||
|
||||
unreadIndicator = [[OWSUnreadIndicator alloc] initWithFirstUnseenSortId:viewItem.interaction.sortId
|
||||
hasMoreUnseenMessages:NO
|
||||
missingUnseenSafetyNumberChangeCount:0
|
||||
unreadIndicatorPosition:0];
|
||||
unreadIndicator =
|
||||
[[OWSUnreadIndicator alloc] initUnreadIndicatorWithTimestamp:viewItem.interaction.timestamp
|
||||
hasMoreUnseenMessages:NO
|
||||
missingUnseenSafetyNumberChangeCount:0
|
||||
unreadIndicatorPosition:0
|
||||
firstUnseenInteractionTimestamp:viewItem.interaction.timestamp];
|
||||
}
|
||||
|
||||
// Place the unread indicator onto the first appropriate view item,
|
||||
// if any.
|
||||
if (unreadIndicator && viewItem.interaction.sortId >= unreadIndicator.firstUnseenSortId) {
|
||||
if (unreadIndicator && viewItem.interaction.timestampForSorting >= unreadIndicator.timestamp) {
|
||||
viewItem.unreadIndicator = unreadIndicator;
|
||||
unreadIndicator = nil;
|
||||
hasPlacedUnreadIndicator = YES;
|
||||
|
@ -4984,9 +4998,9 @@ typedef enum : NSUInteger {
|
|||
//
|
||||
// NOTE: This logic uses the break properties which are set in the previous pass.
|
||||
for (NSUInteger i = 0; i < viewItems.count; i++) {
|
||||
ConversationViewItem *viewItem = viewItems[i];
|
||||
ConversationViewItem *_Nullable previousViewItem = (i > 0 ? viewItems[i - 1] : nil);
|
||||
ConversationViewItem *_Nullable nextViewItem = (i + 1 < viewItems.count ? viewItems[i + 1] : nil);
|
||||
id<ConversationViewItem> viewItem = viewItems[i];
|
||||
id<ConversationViewItem> _Nullable previousViewItem = (i > 0 ? viewItems[i - 1] : nil);
|
||||
id<ConversationViewItem> _Nullable nextViewItem = (i + 1 < viewItems.count ? viewItems[i + 1] : nil);
|
||||
BOOL shouldShowSenderAvatar = NO;
|
||||
BOOL shouldHideFooter = NO;
|
||||
BOOL isFirstInCluster = YES;
|
||||
|
@ -5116,8 +5130,7 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
|
||||
// Avoid animation churn by supressing footer-collapse on messages received recently.
|
||||
if (viewItem.interaction.receivedAtTimestamp > collapseCutoffTimestamp) {
|
||||
if (viewItem.interaction.timestampForSorting > collapseCutoffTimestamp) {
|
||||
shouldHideFooter = NO;
|
||||
}
|
||||
|
||||
|
@ -5136,7 +5149,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
// Whenever an interaction is modified, we need to reload it from the DB
|
||||
// and update the corresponding view item.
|
||||
- (void)reloadInteractionForViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)reloadInteractionForViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -5157,7 +5170,7 @@ typedef enum : NSUInteger {
|
|||
}];
|
||||
}
|
||||
|
||||
- (nullable ConversationViewItem *)viewItemForIndex:(NSInteger)index
|
||||
- (nullable id<ConversationViewItem>)viewItemForIndex:(NSInteger)index
|
||||
{
|
||||
if (index < 0 || index >= (NSInteger)self.viewItems.count) {
|
||||
OWSFailDebug(@"Invalid view item index: %lu", (unsigned long)index);
|
||||
|
@ -5176,7 +5189,7 @@ typedef enum : NSUInteger {
|
|||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:indexPath.row];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:indexPath.row];
|
||||
ConversationViewCell *cell = [viewItem dequeueCellForCollectionView:self.collectionView indexPath:indexPath];
|
||||
if (!cell) {
|
||||
OWSFailDebug(@"Could not dequeue cell.");
|
||||
|
|
|
@ -43,7 +43,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
//
|
||||
// Critically, this class implements ConversationViewLayoutItem
|
||||
// and does caching of the cell's size.
|
||||
@interface ConversationViewItem : NSObject <ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
@protocol ConversationViewItem <NSObject, ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) TSInteraction *interaction;
|
||||
|
||||
|
@ -69,14 +69,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
@property (nonatomic, nullable) OWSUnreadIndicator *unreadIndicator;
|
||||
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView
|
||||
indexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
|
@ -89,21 +81,20 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
@property (nonatomic, weak) OWSAudioMessageView *lastAudioMessageView;
|
||||
|
||||
@property (nonatomic, readonly) CGFloat audioDurationSeconds;
|
||||
|
||||
- (CGFloat)audioProgressSeconds;
|
||||
@property (nonatomic, readonly) CGFloat audioProgressSeconds;
|
||||
|
||||
#pragma mark - View State Caching
|
||||
|
||||
// These methods only apply to text & attachment messages.
|
||||
- (OWSMessageCellType)messageCellType;
|
||||
- (nullable DisplayableText *)displayableBodyText;
|
||||
- (nullable TSAttachmentStream *)attachmentStream;
|
||||
- (nullable TSAttachmentPointer *)attachmentPointer;
|
||||
- (CGSize)mediaSize;
|
||||
@property (nonatomic, readonly) OWSMessageCellType messageCellType;
|
||||
@property (nonatomic, readonly, nullable) DisplayableText *displayableBodyText;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentPointer *attachmentPointer;
|
||||
@property (nonatomic, readonly) CGSize mediaSize;
|
||||
|
||||
- (nullable DisplayableText *)displayableQuotedText;
|
||||
- (nullable NSString *)quotedAttachmentMimetype;
|
||||
- (nullable NSString *)quotedRecipientId;
|
||||
@property (nonatomic, readonly, nullable) DisplayableText *displayableQuotedText;
|
||||
@property (nonatomic, readonly, nullable) NSString *quotedAttachmentMimetype;
|
||||
@property (nonatomic, readonly, nullable) NSString *quotedRecipientId;
|
||||
|
||||
// We don't want to try to load the media for this item (if any)
|
||||
// if a load has previously failed.
|
||||
|
@ -132,4 +123,15 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
@end
|
||||
|
||||
@interface ConversationInteractionViewItem
|
||||
: NSObject <ConversationViewItem, ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -46,7 +46,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
|
||||
#pragma mark -
|
||||
|
||||
@interface ConversationViewItem ()
|
||||
@interface ConversationInteractionViewItem ()
|
||||
|
||||
@property (nonatomic, nullable) NSValue *cachedCellSize;
|
||||
|
||||
|
@ -70,12 +70,25 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
@property (nonatomic, nullable) NSString *systemMessageText;
|
||||
@property (nonatomic, nullable) TSThread *incomingMessageAuthorThread;
|
||||
@property (nonatomic, nullable) NSString *authorConversationColorName;
|
||||
@property (nonatomic, nullable) ConversationStyle *conversationStyle;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ConversationViewItem
|
||||
@implementation ConversationInteractionViewItem
|
||||
|
||||
@synthesize shouldShowDate = _shouldShowDate;
|
||||
@synthesize shouldShowSenderAvatar = _shouldShowSenderAvatar;
|
||||
@synthesize unreadIndicator = _unreadIndicator;
|
||||
@synthesize didCellMediaFailToLoad = _didCellMediaFailToLoad;
|
||||
@synthesize interaction = _interaction;
|
||||
@synthesize isFirstInCluster = _isFirstInCluster;
|
||||
@synthesize isGroupThread = _isGroupThread;
|
||||
@synthesize isLastInCluster = _isLastInCluster;
|
||||
@synthesize lastAudioMessageView = _lastAudioMessageView;
|
||||
@synthesize senderName = _senderName;
|
||||
@synthesize shouldHideFooter = _shouldHideFooter;
|
||||
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
|
@ -293,7 +306,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
return measurementCell;
|
||||
}
|
||||
|
||||
- (CGFloat)vSpacingWithPreviousLayoutItem:(ConversationViewItem *)previousLayoutItem
|
||||
- (CGFloat)vSpacingWithPreviousLayoutItem:(id<ConversationViewItem>)previousLayoutItem
|
||||
{
|
||||
OWSAssertDebug(previousLayoutItem);
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSUInteger index,
|
||||
BOOL *stop) {
|
||||
NSTimeInterval ageSeconds
|
||||
= fabs(interaction.receivedAtDate.timeIntervalSinceNow);
|
||||
= fabs(interaction.dateForSorting.timeIntervalSinceNow);
|
||||
if (ageSeconds < maxAgeSeconds) {
|
||||
*stop = YES;
|
||||
return;
|
||||
|
|
|
@ -1967,10 +1967,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(messageToQuote);
|
||||
OWSLogVerbose(@"%@", label);
|
||||
[DDLog flushLog];
|
||||
ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
id<ConversationViewItem> viewItem =
|
||||
[[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
quotedMessage = [
|
||||
[OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem transaction:transaction]
|
||||
buildQuotedMessageForSending];
|
||||
|
@ -1986,10 +1987,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:transaction];
|
||||
OWSAssertDebug(messageToQuote);
|
||||
|
||||
ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
id<ConversationViewItem> viewItem =
|
||||
[[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
quotedMessage = [
|
||||
[OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem transaction:transaction]
|
||||
buildQuotedMessageForSending];
|
||||
|
@ -3441,7 +3443,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3456,7 +3457,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3471,7 +3471,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:YES
|
||||
durationSeconds:(uint32_t)[durationSeconds intValue]];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3484,7 +3483,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initWithThreadId:thread.uniqueId
|
||||
enabled:NO
|
||||
durationSeconds:0];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[result addObject:[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3495,55 +3493,44 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
|
||||
[result addObject:[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:@"+19174054215"]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd]];
|
||||
// TODO: customMessage?
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupUpdate]];
|
||||
// TODO: customMessage?
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupQuit]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateDefault
|
||||
isLocalChange:YES]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateVerified
|
||||
isLocalChange:YES]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateNoLongerVerified
|
||||
isLocalChange:YES]];
|
||||
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateDefault
|
||||
isLocalChange:NO]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
recipientId:@"+19174054215"
|
||||
verificationState:OWSVerificationStateVerified
|
||||
isLocalChange:NO]];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
[result
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -3559,17 +3546,13 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
withTransaction:transaction]];
|
||||
[result addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *_Nullable blockingSNChangeMessage =
|
||||
[TSInvalidIdentityKeyReceivingErrorMessage untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
OWSAssertDebug(blockingSNChangeMessage);
|
||||
[result addObject:blockingSNChangeMessage];
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageNonBlockingIdentityChange
|
||||
|
@ -3732,10 +3715,9 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
OWSLogInfo(@"sendFakeMessages: %lu", (unsigned long)counter);
|
||||
|
||||
for (NSUInteger i = 0; i < counter; i++) {
|
||||
NSString *randomText = [[self randomText] stringByAppendingFormat:@" (sequence: %lu)", (unsigned long)i + 1];
|
||||
NSString *randomText = [self randomText];
|
||||
switch (arc4random_uniform(isTextOnly ? 2 : 4)) {
|
||||
case 0: {
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -3773,7 +3755,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
attachmentType:TSAttachmentTypeDefault];
|
||||
pointer.state = TSAttachmentPointerStateFailed;
|
||||
[pointer saveWithTransaction:transaction];
|
||||
// MJK - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4172,7 +4153,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
OWSDisappearingMessagesConfiguration *configuration =
|
||||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId
|
||||
transaction:initialTransaction];
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message = [[TSOutgoingMessage alloc]
|
||||
initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4240,7 +4220,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
for (NSNumber *timestamp in timestamps) {
|
||||
NSString *randomText = [self randomText];
|
||||
{
|
||||
// Legit usage of SenderTimestamp to backdate incoming sent messages for Debug
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp.unsignedLongLongValue
|
||||
inThread:thread
|
||||
|
@ -4254,7 +4233,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[message markAsReadNowWithSendReadReceipt:NO transaction:transaction];
|
||||
}
|
||||
{
|
||||
// MJK TODO - this might be the one place we actually use senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:timestamp.unsignedLongLongValue
|
||||
inThread:thread
|
||||
|
@ -4281,8 +4259,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
+ (void)createDisappearingMessagesWhichFailedToStartInThread:(TSThread *)thread
|
||||
{
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message = [[TSIncomingMessage alloc]
|
||||
initIncomingMessageWithTimestamp:now
|
||||
inThread:thread
|
||||
|
@ -4516,7 +4492,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
[attachmentIds addObject:attachmentId];
|
||||
}
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -4606,7 +4581,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
|||
// uint64_t millisAgo = (uint64_t)(((double)arc4random() / ((double)0xffffffff)) * yearsMillis);
|
||||
// uint64_t timestamp = [NSDate ows_millisecondTimeStamp] - millisAgo;
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
TSIncomingMessage *message =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
|
|
@ -41,7 +41,6 @@ class DebugUIProfile: DebugUIPage {
|
|||
OWSTableItem(title: "Send Profile Key Message") { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
let message = OWSProfileKeyMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: aThread)
|
||||
strongSelf.messageSender.sendPromise(message: message).then {
|
||||
Logger.info("Successfully sent profile key message to thread: \(String(describing: aThread))")
|
||||
|
|
|
@ -251,11 +251,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(UIFont.ows_dynamicTypeBodyFont.pointSize != 17 || minMargin == 12);
|
||||
|
||||
[self.viewConstraints addObjectsFromArray:@[
|
||||
// badge sizing
|
||||
[self.unreadBadge autoMatchDimension:ALDimensionWidth
|
||||
toDimension:ALDimensionWidth
|
||||
ofView:self.unreadLabel
|
||||
withOffset:minMargin],
|
||||
// badge sizing
|
||||
withOffset:minMargin
|
||||
relation:NSLayoutRelationGreaterThanOrEqual],
|
||||
[self.unreadBadge autoSetDimension:ALDimensionWidth
|
||||
toSize:unreadBadgeHeight
|
||||
relation:NSLayoutRelationGreaterThanOrEqual],
|
||||
|
|
|
@ -496,20 +496,31 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
|
|||
}
|
||||
|
||||
// Settings button.
|
||||
const NSUInteger kAvatarSize = 28;
|
||||
UIImage *_Nullable localProfileAvatarImage = [OWSProfileManager.sharedManager localProfileAvatarImage];
|
||||
UIImage *avatarImage = (localProfileAvatarImage
|
||||
?: [[[OWSContactAvatarBuilder alloc] initForLocalUserWithDiameter:kAvatarSize] buildDefaultImage]);
|
||||
OWSAssertDebug(avatarImage);
|
||||
|
||||
AvatarImageView *avatarView = [[AvatarImageView alloc] initWithImage:avatarImage];
|
||||
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize];
|
||||
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize];
|
||||
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithCustomView:avatarView];
|
||||
avatarView.userInteractionEnabled = YES;
|
||||
[avatarView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||
action:@selector(settingsButtonPressed:)]];
|
||||
settingsButton.accessibilityLabel = CommonStrings.openSettingsButton;
|
||||
UIBarButtonItem *settingsButton;
|
||||
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(10, 0)) {
|
||||
const NSUInteger kAvatarSize = 28;
|
||||
UIImage *_Nullable localProfileAvatarImage = [OWSProfileManager.sharedManager localProfileAvatarImage];
|
||||
UIImage *avatarImage = (localProfileAvatarImage
|
||||
?: [[[OWSContactAvatarBuilder alloc] initForLocalUserWithDiameter:kAvatarSize] buildDefaultImage]);
|
||||
OWSAssertDebug(avatarImage);
|
||||
AvatarImageView *avatarView = [[AvatarImageView alloc] initWithImage:avatarImage];
|
||||
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSize];
|
||||
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSize];
|
||||
avatarView.userInteractionEnabled = YES;
|
||||
[avatarView
|
||||
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||
action:@selector(settingsButtonPressed:)]];
|
||||
settingsButton = [[UIBarButtonItem alloc] initWithCustomView:avatarView];
|
||||
settingsButton.accessibilityLabel = CommonStrings.openSettingsButton;
|
||||
} else {
|
||||
// iOS 9 has a bug around layout of custom views in UIBarButtonItem,
|
||||
// so we just use a simple icon.
|
||||
UIImage *image = [UIImage imageNamed:@"button_settings_white"];
|
||||
settingsButton = [[UIBarButtonItem alloc] initWithImage:image
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(settingsButtonPressed:)];
|
||||
}
|
||||
self.navigationItem.leftBarButtonItem = settingsButton;
|
||||
|
||||
self.navigationItem.rightBarButtonItem =
|
||||
|
|
|
@ -37,7 +37,7 @@ public class LongTextViewController: OWSViewController {
|
|||
guard viewItem.hasBodyText else {
|
||||
return ""
|
||||
}
|
||||
guard let displayableText = viewItem.displayableBodyText() else {
|
||||
guard let displayableText = viewItem.displayableBodyText else {
|
||||
return ""
|
||||
}
|
||||
let messageBody = displayableText.fullText
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationViewItem;
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class GalleryItemBox;
|
||||
@class MediaDetailViewController;
|
||||
|
||||
|
@ -18,7 +19,7 @@ typedef NS_OPTIONS(NSInteger, MediaGalleryOption) {
|
|||
@protocol MediaDetailViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
|
||||
requestDeleteConversationViewItem:(ConversationViewItem *)conversationViewItem;
|
||||
requestDeleteConversationViewItem:(id<ConversationViewItem>)conversationViewItem;
|
||||
|
||||
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
|
||||
isPlayingVideo:(BOOL)isPlayingVideo;
|
||||
|
@ -34,7 +35,7 @@ typedef NS_OPTIONS(NSInteger, MediaGalleryOption) {
|
|||
|
||||
// If viewItem is non-null, long press will show a menu controller.
|
||||
- (instancetype)initWithGalleryItemBox:(GalleryItemBox *)galleryItemBox
|
||||
viewItem:(ConversationViewItem *_Nullable)viewItem;
|
||||
viewItem:(nullable id<ConversationViewItem>)viewItem;
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)didPressShare:(id)sender;
|
||||
|
|
|
@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic) UIButton *shareButton;
|
||||
|
||||
@property (nonatomic) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
@property (nonatomic, nullable) UIImage *image;
|
||||
|
||||
@property (nonatomic, nullable) OWSVideoPlayer *videoPlayer;
|
||||
|
@ -63,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
- (instancetype)initWithGalleryItemBox:(GalleryItemBox *)galleryItemBox
|
||||
viewItem:(ConversationViewItem *_Nullable)viewItem
|
||||
viewItem:(nullable id<ConversationViewItem>)viewItem
|
||||
{
|
||||
self = [super initWithNibName:nil bundle:nil];
|
||||
if (!self) {
|
||||
|
|
|
@ -54,7 +54,7 @@ public struct GalleryDate: Hashable, Comparable, Equatable {
|
|||
let month: Int
|
||||
|
||||
init(message: TSMessage) {
|
||||
let date = message.receivedAtDate()
|
||||
let date = message.dateForSorting()
|
||||
|
||||
self.year = Calendar.current.component(.year, from: date)
|
||||
self.month = Calendar.current.component(.month, from: date)
|
||||
|
@ -730,13 +730,13 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
|
|||
|
||||
Bench(title: "sorting gallery items") {
|
||||
galleryItems.sort { lhs, rhs -> Bool in
|
||||
return lhs.message.sortId < rhs.message.sortId
|
||||
return lhs.message.timestampForSorting() < rhs.message.timestampForSorting()
|
||||
}
|
||||
sectionDates.sort()
|
||||
|
||||
for (date, galleryItems) in sections {
|
||||
sortedSections[date] = galleryItems.sorted { lhs, rhs -> Bool in
|
||||
return lhs.message.sortId < rhs.message.sortId
|
||||
return lhs.message.timestampForSorting() < rhs.message.timestampForSorting()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -479,10 +479,10 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
let message = galleryItem.message
|
||||
let thread = message.thread(with: transaction)
|
||||
let conversationStyle = ConversationStyle(thread: thread)
|
||||
fetchedItem = ConversationViewItem(interaction: message,
|
||||
isGroupThread: thread.isGroupThread(),
|
||||
transaction: transaction,
|
||||
conversationStyle: conversationStyle)
|
||||
fetchedItem = ConversationInteractionViewItem(interaction: message,
|
||||
isGroupThread: thread.isGroupThread(),
|
||||
transaction: transaction,
|
||||
conversationStyle: conversationStyle)
|
||||
}
|
||||
|
||||
guard let viewItem = fetchedItem else {
|
||||
|
|
|
@ -294,7 +294,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
if message as? TSIncomingMessage != nil {
|
||||
rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_RECEIVED_DATE_TIME",
|
||||
comment: "Label for the 'received date & time' field of the 'message metadata' view."),
|
||||
value: DateUtil.formatPastTimestampRelativeToNow(message.receivedAtTimestamp)))
|
||||
value: DateUtil.formatPastTimestampRelativeToNow(message.timestampForSorting())))
|
||||
}
|
||||
|
||||
rows += addAttachmentMetadataRows()
|
||||
|
@ -326,7 +326,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
guard viewItem.hasBodyText else {
|
||||
return nil
|
||||
}
|
||||
guard let displayableText = viewItem.displayableBodyText() else {
|
||||
guard let displayableText = viewItem.displayableBodyText else {
|
||||
return nil
|
||||
}
|
||||
let messageBody = displayableText.fullText
|
||||
|
@ -663,7 +663,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
|
||||
if let audioAttachmentPlayer = self.audioAttachmentPlayer {
|
||||
// Is this player associated with this media adapter?
|
||||
if audioAttachmentPlayer.owner as? ConversationViewItem == viewItem {
|
||||
if audioAttachmentPlayer.owner === viewItem {
|
||||
// Tap to pause & unpause.
|
||||
audioAttachmentPlayer.togglePlayState()
|
||||
return
|
||||
|
|
|
@ -464,7 +464,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// Add an error message to the new group indicating
|
||||
// that group creation didn't succeed.
|
||||
// MJK TODO should be safe to remove senderTimestamp and just save immediately
|
||||
TSErrorMessage *errorMessage = [[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageGroupCreationFailed];
|
||||
|
|
|
@ -250,9 +250,7 @@ const CGFloat kIconViewLength = 24;
|
|||
[[OWSDisappearingMessagesConfiguration alloc] initDefaultWithThreadId:self.thread.uniqueId];
|
||||
}
|
||||
|
||||
NSString *colorName = self.thread.conversationColorName;
|
||||
OWSConversationColor *currentConversationColor = [OWSConversationColor conversationColorOrDefaultForColorName:colorName];
|
||||
self.colorPicker = [[OWSColorPicker alloc] initWithCurrentConversationColor:currentConversationColor];
|
||||
self.colorPicker = [[OWSColorPicker alloc] initWithThread:self.thread];
|
||||
self.colorPicker.delegate = self;
|
||||
|
||||
[self updateTableContents];
|
||||
|
@ -909,9 +907,7 @@ const CGFloat kIconViewLength = 24;
|
|||
}
|
||||
|
||||
if (self.disappearingMessagesConfiguration.dictionaryValueDidChange) {
|
||||
// TODO - put these two saves in a single transaction
|
||||
[self.disappearingMessagesConfiguration save];
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
|
|
|
@ -372,7 +372,6 @@ private class SignalCallData: NSObject {
|
|||
let callData = SignalCallData(call: call)
|
||||
self.callData = callData
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeOutgoingIncomplete, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
@ -528,7 +527,6 @@ private class SignalCallData: NSObject {
|
|||
callRecord.updateCallType(RPRecentCallTypeIncomingMissed)
|
||||
}
|
||||
} else {
|
||||
// MJK TODO remove this timestamp param
|
||||
call.callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
withCallNumber: call.thread.contactIdentifier(),
|
||||
callType: RPRecentCallTypeIncomingMissed,
|
||||
|
@ -615,7 +613,6 @@ private class SignalCallData: NSObject {
|
|||
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: newCall, callerName: callerName)
|
||||
}
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
withCallNumber: thread.contactIdentifier(),
|
||||
callType: RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity,
|
||||
|
@ -1038,7 +1035,6 @@ private class SignalCallData: NSObject {
|
|||
|
||||
Logger.info("\(call.identifiersForLogs).")
|
||||
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingIncomplete, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
@ -1128,7 +1124,6 @@ private class SignalCallData: NSObject {
|
|||
owsFailDebug("Not expecting callrecord to already be set")
|
||||
callRecord.updateCallType(RPRecentCallTypeIncomingDeclined)
|
||||
} else {
|
||||
// MJK TODO remove this timestamp param
|
||||
let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncomingDeclined, in: call.thread)
|
||||
callRecord.save()
|
||||
call.callRecord = callRecord
|
||||
|
|
|
@ -39,22 +39,22 @@
|
|||
return @"abc";
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)textViewItem
|
||||
- (ConversationInteractionViewItem *)textViewItem
|
||||
{
|
||||
TSOutgoingMessage *message =
|
||||
[TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:self.fakeTextMessageText attachmentId:nil];
|
||||
[message save];
|
||||
__block ConversationViewItem *viewItem = nil;
|
||||
__block ConversationInteractionViewItem *viewItem = nil;
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}];
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename
|
||||
- (ConversationInteractionViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename
|
||||
{
|
||||
OWSAssertDebug(filename.length > 0);
|
||||
|
||||
|
@ -74,33 +74,33 @@
|
|||
[TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:nil attachmentId:attachment.uniqueId];
|
||||
[message save];
|
||||
|
||||
__block ConversationViewItem *viewItem = nil;
|
||||
__block ConversationInteractionViewItem *viewItem = nil;
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}];
|
||||
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)stillImageViewItem
|
||||
- (ConversationInteractionViewItem *)stillImageViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageJpeg filename:@"test-jpg.jpg"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)animatedImageViewItem
|
||||
- (ConversationInteractionViewItem *)animatedImageViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageGif filename:@"test-gif.gif"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)videoViewItem
|
||||
- (ConversationInteractionViewItem *)videoViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:@"video/mp4" filename:@"test-mp4.mp4"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)audioViewItem
|
||||
- (ConversationInteractionViewItem *)audioViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:@"audio/mp3" filename:@"test-mp3.mp3"];
|
||||
}
|
||||
|
@ -109,7 +109,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithNonMediaMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.textViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.textViewItem;
|
||||
|
||||
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
|
||||
[viewItem deleteAction];
|
||||
|
@ -118,7 +118,7 @@
|
|||
|
||||
- (void)testPerformDeleteActionWithPhotoMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.stillImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.stillImageViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -140,7 +140,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithAnimatedMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.animatedImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.animatedImageViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -162,7 +162,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithVideoMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.videoViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.videoViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -184,7 +184,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithAudioMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.audioViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.audioViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -212,7 +212,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil(UIPasteboard.generalPasteboard.string);
|
||||
|
||||
ConversationViewItem *viewItem = self.textViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.textViewItem;
|
||||
[viewItem copyTextAction];
|
||||
XCTAssertEqualObjects(self.fakeTextMessageText, UIPasteboard.generalPasteboard.string);
|
||||
}
|
||||
|
@ -224,7 +224,7 @@
|
|||
XCTAssertNil(UIPasteboard.generalPasteboard.image);
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]);
|
||||
|
||||
ConversationViewItem *viewItem = self.stillImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.stillImageViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -237,7 +237,7 @@
|
|||
XCTAssertNil(UIPasteboard.generalPasteboard.image);
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]);
|
||||
|
||||
ConversationViewItem *viewItem = self.animatedImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.animatedImageViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -249,7 +249,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]);
|
||||
|
||||
ConversationViewItem *viewItem = self.videoViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.videoViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -261,7 +261,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]);
|
||||
|
||||
ConversationViewItem *viewItem = self.audioViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.audioViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
|
|
@ -386,6 +386,12 @@
|
|||
/* Error indicating that the app was prevented from accessing the user's CloudKit account. */
|
||||
"CLOUDKIT_STATUS_RESTRICTED" = "Signal was not allowed to access your iCloud account for backups.";
|
||||
|
||||
/* The first of two messages demonstrating the chosen conversation color, by rendering this message in an outgoing message bubble. */
|
||||
"COLOR_PICKER_DEMO_MESSAGE_1" = "Choose the color of outgoing messages in this conversation.";
|
||||
|
||||
/* The second of two messages demonstrating the chosen conversation color, by rendering this message in an incoming message bubble. */
|
||||
"COLOR_PICKER_DEMO_MESSAGE_2" = "Only you will see the color you choose.";
|
||||
|
||||
/* Modal Sheet title when picking a conversation color. */
|
||||
"COLOR_PICKER_SHEET_TITLE" = "Conversation Color";
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
#import <SignalServiceKit/TSInteraction.h>
|
||||
|
||||
@class YapDatabaseReadWriteTransaction;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSContactOffersInteraction : TSInteraction
|
||||
|
@ -13,16 +11,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, readonly) BOOL hasBlockOffer;
|
||||
@property (nonatomic, readonly) BOOL hasAddToContactsOffer;
|
||||
@property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer;
|
||||
|
||||
// TODO - remove this recipientId param
|
||||
// it's redundant with the interaction's TSContactThread
|
||||
@property (nonatomic, readonly) NSString *recipientId;
|
||||
|
||||
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
// MJK TODO should be safe to remove this timestamp param
|
||||
- (instancetype)initContactOffersWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
hasBlockOffer:(BOOL)hasBlockOffer
|
||||
|
@ -30,11 +24,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
|
||||
recipientId:(NSString *)recipientId NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)updateHasBlockOffer:(BOOL)hasBlockOffer
|
||||
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSContactOffersInteraction ()
|
||||
|
||||
@property (nonatomic) BOOL hasBlockOffer;
|
||||
@property (nonatomic) BOOL hasAddToContactsOffer;
|
||||
@property (nonatomic) BOOL hasAddToProfileWhitelistOffer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSContactOffersInteraction
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
|
@ -60,18 +52,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return OWSInteractionType_Offer;
|
||||
}
|
||||
|
||||
- (void)updateHasBlockOffer:(BOOL)hasBlockOffer
|
||||
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self applyChangeToSelfAndLatestCopy:transaction
|
||||
changeBlock:^(OWSContactOffersInteraction *offers) {
|
||||
offers.hasBlockOffer = hasBlockOffer;
|
||||
offers.hasAddToContactsOffer = hasAddToContactsOffer;
|
||||
offers.hasAddToProfileWhitelistOffer = hasAddToProfileWhitelistOffer;
|
||||
}];
|
||||
}
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This class is vestigial.
|
||||
__attribute__((deprecated))
|
||||
@interface TSUnreadIndicatorInteraction : TSInteraction
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
|
|
@ -6,10 +6,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation TSUnreadIndicatorInteraction
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
|
|
|
@ -50,6 +50,7 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[];
|
|||
#import <SignalMessaging/SelectRecipientViewController.h>
|
||||
#import <SignalMessaging/SharingThreadPickerViewController.h>
|
||||
#import <SignalMessaging/SignalKeyingStorage.h>
|
||||
#import <SignalMessaging/TSUnreadIndicatorInteraction.h>
|
||||
#import <SignalMessaging/Theme.h>
|
||||
#import <SignalMessaging/ThreadUtil.h>
|
||||
#import <SignalMessaging/ThreadViewHelper.h>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationViewItem;
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class TSAttachmentPointer;
|
||||
@class TSAttachmentStream;
|
||||
@class TSMessage;
|
||||
|
@ -42,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
// Builds a not-yet-sent QuotedReplyModel
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(ConversationViewItem *)conversationItem
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(id<ConversationViewItem>)conversationItem
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (TSQuotedMessage *)buildQuotedMessageForSending;
|
||||
|
|
|
@ -115,7 +115,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
thumbnailDownloadFailed:thumbnailDownloadFailed];
|
||||
}
|
||||
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(ConversationViewItem *)conversationItem
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(id<ConversationViewItem>)conversationItem
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
{
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -241,7 +241,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
NSArray *attachments = self.attachmentStream ? @[ self.attachmentStream ] : @[];
|
||||
|
||||
// Legit usage of senderTimestamp to reference existing message
|
||||
return [[TSQuotedMessage alloc] initWithTimestamp:self.timestamp
|
||||
authorId:self.authorId
|
||||
body:self.body
|
||||
|
|
|
@ -25,14 +25,12 @@ public class ThreadViewModel: NSObject {
|
|||
@objc
|
||||
public init(thread: TSThread, transaction: YapDatabaseReadTransaction) {
|
||||
self.threadRecord = thread
|
||||
|
||||
self.lastMessageDate = thread.lastMessageDate()
|
||||
self.isGroupThread = thread.isGroupThread()
|
||||
self.name = thread.name()
|
||||
self.isMuted = thread.isMuted
|
||||
self.lastMessageText = thread.lastMessageText(transaction: transaction)
|
||||
let lastInteraction = thread.lastInteractionForInbox(transaction: transaction)
|
||||
self.lastMessageForInbox = lastInteraction
|
||||
self.lastMessageDate = lastInteraction?.receivedAtDate() ?? thread.creationDate
|
||||
self.lastMessageForInbox = thread.lastInteractionForInbox(transaction: transaction)
|
||||
|
||||
if let contactThread = thread as? TSContactThread {
|
||||
self.contactIdentifier = contactThread.contactIdentifier()
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class OWS110SortIdMigration: OWSDatabaseMigration {
|
||||
// increment a similar constant for each migration.
|
||||
@objc
|
||||
class func migrationId() -> String {
|
||||
return "110"
|
||||
}
|
||||
|
||||
override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
Logger.debug("")
|
||||
BenchAsync(title: "Sort Migration") { completeBenchmark in
|
||||
self.doMigration {
|
||||
completeBenchmark()
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func doMigration(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
// TODO batch this?
|
||||
self.dbReadWriteConnection().readWrite { transaction in
|
||||
|
||||
var archivedThreads: [TSThread] = []
|
||||
|
||||
// get archived threads before migration
|
||||
TSThread.enumerateCollectionObjects(with: transaction) { (object, _) in
|
||||
guard let thread = object as? TSThread else {
|
||||
owsFailDebug("unexpected object: \(type(of: object))")
|
||||
return
|
||||
}
|
||||
|
||||
if thread.isArchivedByLegacyTimestampForSorting {
|
||||
archivedThreads.append(thread)
|
||||
}
|
||||
}
|
||||
|
||||
guard let legacySorting: YapDatabaseAutoViewTransaction = transaction.extension(TSMessageDatabaseViewExtensionName_Legacy) as? YapDatabaseAutoViewTransaction else {
|
||||
owsFailDebug("legacySorting was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
let totalCount: UInt = legacySorting.numberOfItemsInAllGroups()
|
||||
var completedCount: UInt = 0
|
||||
legacySorting.enumerateGroups { group, _ in
|
||||
autoreleasepool {
|
||||
legacySorting.enumerateKeysAndObjects(inGroup: group) { (_, _, object, _, _) in
|
||||
autoreleasepool {
|
||||
guard let interaction = object as? TSInteraction else {
|
||||
owsFailDebug("unexpected object: \(type(of: object))")
|
||||
return
|
||||
}
|
||||
|
||||
interaction.saveNextSortId(transaction: transaction)
|
||||
|
||||
completedCount += 1
|
||||
|
||||
if completedCount % 100 == 0 {
|
||||
// Legit usage of legacy sorting for migration to new sorting
|
||||
Logger.info("thread: \(interaction.uniqueThreadId), timestampForLegacySorting:\(interaction.timestampForLegacySorting()), sortId: \(interaction.sortId) totalCount: \(totalCount), completedcount: \(completedCount)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("re-archiving \(archivedThreads.count) threads which were previously archived")
|
||||
for archivedThread in archivedThreads {
|
||||
archivedThread.archiveThread(with: transaction)
|
||||
}
|
||||
|
||||
self.save(with: transaction)
|
||||
}
|
||||
|
||||
completion()
|
||||
}
|
||||
|
||||
}
|
|
@ -44,8 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[[OWS106EnsureProfileComplete alloc] initWithPrimaryStorage:primaryStorage],
|
||||
[[OWS107LegacySounds alloc] initWithPrimaryStorage:primaryStorage],
|
||||
[[OWS108CallLoggingPreference alloc] initWithPrimaryStorage:primaryStorage],
|
||||
[[OWS109OutgoingMessageState alloc] initWithPrimaryStorage:primaryStorage],
|
||||
[[OWS110SortIdMigration alloc] initWithPrimaryStorage:primaryStorage]
|
||||
[[OWS109OutgoingMessageState alloc] initWithPrimaryStorage:primaryStorage]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -1124,7 +1124,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
OWSProfileKeyMessage *message =
|
||||
[[OWSProfileKeyMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread];
|
||||
|
||||
|
|
|
@ -4,16 +4,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// Benchmark async code by calling the passed in block parameter when the work
|
||||
/// is done.
|
||||
///
|
||||
/// BenchAsync(title: "my benchmark") { completeBenchmark in
|
||||
/// foo {
|
||||
/// completeBenchmark()
|
||||
/// fooCompletion()
|
||||
/// }
|
||||
/// }
|
||||
public func BenchAsync(title: String, block: (@escaping () -> Void) -> Void) {
|
||||
public func BenchAsync(title: String, block: (() -> Void) -> Void) {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
block {
|
||||
|
|
|
@ -5,21 +5,7 @@
|
|||
import Foundation
|
||||
import SignalServiceKit
|
||||
|
||||
public typealias MessageSortKey = UInt64
|
||||
public struct ConversationSortKey: Comparable {
|
||||
let creationDate: Date
|
||||
let lastMessageReceivedAtDate: Date?
|
||||
|
||||
// MARK: Comparable
|
||||
|
||||
public static func < (lhs: ConversationSortKey, rhs: ConversationSortKey) -> Bool {
|
||||
let lhsDate = lhs.lastMessageReceivedAtDate ?? lhs.creationDate
|
||||
let rhsDate = rhs.lastMessageReceivedAtDate ?? rhs.creationDate
|
||||
return lhsDate < rhsDate
|
||||
}
|
||||
}
|
||||
|
||||
public class ConversationSearchResult<SortKey>: Comparable where SortKey: Comparable {
|
||||
public class ConversationSearchResult: Comparable {
|
||||
public let thread: ThreadViewModel
|
||||
|
||||
public let messageId: String?
|
||||
|
@ -27,9 +13,9 @@ public class ConversationSearchResult<SortKey>: Comparable where SortKey: Compar
|
|||
|
||||
public let snippet: String?
|
||||
|
||||
private let sortKey: SortKey
|
||||
private let sortKey: UInt64
|
||||
|
||||
init(thread: ThreadViewModel, sortKey: SortKey, messageId: String? = nil, messageDate: Date? = nil, snippet: String? = nil) {
|
||||
init(thread: ThreadViewModel, sortKey: UInt64, messageId: String? = nil, messageDate: Date? = nil, snippet: String? = nil) {
|
||||
self.thread = thread
|
||||
self.sortKey = sortKey
|
||||
self.messageId = messageId
|
||||
|
@ -79,11 +65,11 @@ public class ContactSearchResult: Comparable {
|
|||
|
||||
public class SearchResultSet {
|
||||
public let searchText: String
|
||||
public let conversations: [ConversationSearchResult<ConversationSortKey>]
|
||||
public let conversations: [ConversationSearchResult]
|
||||
public let contacts: [ContactSearchResult]
|
||||
public let messages: [ConversationSearchResult<MessageSortKey>]
|
||||
public let messages: [ConversationSearchResult]
|
||||
|
||||
public init(searchText: String, conversations: [ConversationSearchResult<ConversationSortKey>], contacts: [ContactSearchResult], messages: [ConversationSearchResult<MessageSortKey>]) {
|
||||
public init(searchText: String, conversations: [ConversationSearchResult], contacts: [ContactSearchResult], messages: [ConversationSearchResult]) {
|
||||
self.searchText = searchText
|
||||
self.conversations = conversations
|
||||
self.contacts = contacts
|
||||
|
@ -115,9 +101,9 @@ public class ConversationSearcher: NSObject {
|
|||
transaction: YapDatabaseReadTransaction,
|
||||
contactsManager: ContactsManagerProtocol) -> SearchResultSet {
|
||||
|
||||
var conversations: [ConversationSearchResult<ConversationSortKey>] = []
|
||||
var conversations: [ConversationSearchResult] = []
|
||||
var contacts: [ContactSearchResult] = []
|
||||
var messages: [ConversationSearchResult<MessageSortKey>] = []
|
||||
var messages: [ConversationSearchResult] = []
|
||||
|
||||
var existingConversationRecipientIds: Set<String> = Set()
|
||||
|
||||
|
@ -125,8 +111,7 @@ public class ConversationSearcher: NSObject {
|
|||
|
||||
if let thread = match as? TSThread {
|
||||
let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction)
|
||||
let sortKey = ConversationSortKey(creationDate: thread.creationDate,
|
||||
lastMessageReceivedAtDate: thread.lastInteractionForInbox(transaction: transaction)?.receivedAtDate())
|
||||
let sortKey = NSDate.ows_millisecondsSince1970(for: threadViewModel.lastMessageDate)
|
||||
let searchResult = ConversationSearchResult(thread: threadViewModel, sortKey: sortKey)
|
||||
|
||||
if let contactThread = thread as? TSContactThread {
|
||||
|
@ -139,7 +124,7 @@ public class ConversationSearcher: NSObject {
|
|||
let thread = message.thread(with: transaction)
|
||||
|
||||
let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction)
|
||||
let sortKey = message.sortId
|
||||
let sortKey = message.timestamp
|
||||
let searchResult = ConversationSearchResult(thread: threadViewModel,
|
||||
sortKey: sortKey,
|
||||
messageId: message.uniqueId,
|
||||
|
|
|
@ -6,11 +6,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface OWSUnreadIndicator : NSObject
|
||||
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasMoreUnseenMessages;
|
||||
|
||||
@property (nonatomic, readonly) NSUInteger missingUnseenSafetyNumberChangeCount;
|
||||
|
||||
// The sortId of the oldest unseen message.
|
||||
// The timestamp of the oldest unseen message.
|
||||
//
|
||||
// Once we enter messages view, we mark all messages read, so we need
|
||||
// a snapshot of what the first unread message was when we entered the
|
||||
|
@ -18,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// repeatedly. The unread indicator should continue to show up until
|
||||
// it has been cleared, at which point hideUnreadMessagesIndicator is
|
||||
// YES in ensureDynamicInteractionsForThread:...
|
||||
@property (nonatomic, readonly) uint64_t firstUnseenSortId;
|
||||
@property (nonatomic, readonly) uint64_t firstUnseenInteractionTimestamp;
|
||||
|
||||
// The index of the unseen indicator, counting from the _end_ of the conversation
|
||||
// history.
|
||||
|
@ -30,10 +32,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithFirstUnseenSortId:(uint64_t)firstUnseenSortId
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initUnreadIndicatorWithTimestamp:(uint64_t)timestamp
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:(uint64_t)firstUnseenInteractionTimestamp NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -8,10 +8,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@implementation OWSUnreadIndicator
|
||||
|
||||
- (instancetype)initWithFirstUnseenSortId:(uint64_t)firstUnseenSortId
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition
|
||||
- (instancetype)initUnreadIndicatorWithTimestamp:(uint64_t)timestamp
|
||||
hasMoreUnseenMessages:(BOOL)hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:(NSUInteger)missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:(NSInteger)unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:(uint64_t)firstUnseenInteractionTimestamp
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
@ -19,10 +20,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return self;
|
||||
}
|
||||
|
||||
_firstUnseenSortId = firstUnseenSortId;
|
||||
_timestamp = timestamp;
|
||||
_hasMoreUnseenMessages = hasMoreUnseenMessages;
|
||||
_missingUnseenSafetyNumberChangeCount = missingUnseenSafetyNumberChangeCount;
|
||||
_unreadIndicatorPosition = unreadIndicatorPosition;
|
||||
_firstUnseenInteractionTimestamp = firstUnseenInteractionTimestamp;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -38,8 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
OWSUnreadIndicator *other = object;
|
||||
return (self.firstUnseenSortId == other.firstUnseenSortId
|
||||
&& self.hasMoreUnseenMessages == other.hasMoreUnseenMessages
|
||||
return (self.timestamp == other.timestamp && self.hasMoreUnseenMessages == other.hasMoreUnseenMessages
|
||||
&& self.missingUnseenSafetyNumberChangeCount == other.missingUnseenSafetyNumberChangeCount
|
||||
&& self.unreadIndicatorPosition == other.unreadIndicatorPosition);
|
||||
}
|
||||
|
|
|
@ -128,7 +128,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
|
||||
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -180,7 +179,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId];
|
||||
|
||||
uint32_t expiresInSeconds = (configuration.isEnabled ? configuration.durationSeconds : 0);
|
||||
// MJK TODO - remove senderTimestamp
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
|
@ -305,31 +303,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
enumerateRowsInGroup:thread.uniqueId
|
||||
usingBlock:^(
|
||||
NSString *collection, NSString *key, id object, id metadata, NSUInteger index, BOOL *stop) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
if ([object isKindOfClass:[OWSUnknownContactBlockOfferMessage class]]) {
|
||||
#pragma clang diagnostic pop
|
||||
// Delete this legacy interactions, which has been superseded by
|
||||
// the OWSContactOffersInteraction.
|
||||
[interactionsToDelete addObject:object];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
} else if ([object isKindOfClass:[OWSAddToContactsOfferMessage class]]) {
|
||||
#pragma clang diagnostic pop
|
||||
// Delete this legacy interactions, which has been superseded by
|
||||
// the OWSContactOffersInteraction.
|
||||
[interactionsToDelete addObject:object];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
} else if ([object isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]) {
|
||||
#pragma clang diagnostic pop
|
||||
// Delete this legacy interactions, which has been superseded by
|
||||
// the OWSContactOffersInteraction.
|
||||
[interactionsToDelete addObject:object];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
} else if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
|
||||
#pragma clang diagnostic pop
|
||||
// Remove obsolete unread indicator interactions;
|
||||
[interactionsToDelete addObject:object];
|
||||
} else if ([object isKindOfClass:[OWSContactOffersInteraction class]]) {
|
||||
|
@ -363,14 +350,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// have been marked as read.
|
||||
//
|
||||
// IFF this variable is non-null, there are unseen messages in the thread.
|
||||
NSNumber *_Nullable firstUnseenSortId = nil;
|
||||
NSNumber *_Nullable firstUnseenInteractionTimestamp = nil;
|
||||
if (lastUnreadIndicator) {
|
||||
firstUnseenSortId = @(lastUnreadIndicator.firstUnseenSortId);
|
||||
firstUnseenInteractionTimestamp = @(lastUnreadIndicator.firstUnseenInteractionTimestamp);
|
||||
} else {
|
||||
TSInteraction *_Nullable firstUnseenInteraction =
|
||||
[[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:thread.uniqueId];
|
||||
if (firstUnseenInteraction) {
|
||||
firstUnseenSortId = @(firstUnseenInteraction.sortId);
|
||||
firstUnseenInteractionTimestamp = @(firstUnseenInteraction.timestampForSorting);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,51 +468,59 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
if (existingContactOffers && !shouldHaveContactOffers) {
|
||||
OWSLogInfo(
|
||||
@"Removing contact offers: %@ (%llu)", existingContactOffers.uniqueId, existingContactOffers.sortId);
|
||||
[existingContactOffers removeWithTransaction:transaction];
|
||||
} else if (shouldHaveContactOffers) {
|
||||
if (existingContactOffers) {
|
||||
// If the contact offers' properties have changed, update them
|
||||
if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer
|
||||
|| existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer
|
||||
|| existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) {
|
||||
OWSLogInfo(@"Updating stale contact offers: %@ (%llu)",
|
||||
existingContactOffers.uniqueId,
|
||||
existingContactOffers.sortId);
|
||||
// We want the offers to be the first interactions in their
|
||||
// conversation's timeline, so we back-date them to slightly before
|
||||
// the first message - or at an aribtrary old timestamp if the
|
||||
// conversation has no messages.
|
||||
uint64_t contactOffersTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
[existingContactOffers updateHasBlockOffer:shouldHaveBlockOffer
|
||||
hasAddToContactsOffer:shouldHaveAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer
|
||||
transaction:transaction];
|
||||
}
|
||||
} else {
|
||||
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
|
||||
|
||||
// TODO MJK - remove this timestamp
|
||||
TSInteraction *offersMessage = [[OWSContactOffersInteraction alloc]
|
||||
initContactOffersWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
hasBlockOffer:shouldHaveBlockOffer
|
||||
hasAddToContactsOffer:shouldHaveAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer
|
||||
recipientId:recipientId];
|
||||
[offersMessage saveWithTransaction:transaction];
|
||||
|
||||
OWSLogInfo(@"Creating contact offers: %@ (%llu)", offersMessage.uniqueId, offersMessage.sortId);
|
||||
// If the contact offers' properties have changed, discard the current
|
||||
// one and create a new one.
|
||||
if (existingContactOffers) {
|
||||
if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer
|
||||
|| existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer
|
||||
|| existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) {
|
||||
OWSLogInfo(@"Removing stale contact offers: %@ (%llu)",
|
||||
existingContactOffers.uniqueId,
|
||||
existingContactOffers.timestampForSorting);
|
||||
// Preserve the timestamp of the existing "contact offers" so that
|
||||
// we replace it in the same position in the timeline.
|
||||
contactOffersTimestamp = existingContactOffers.timestamp;
|
||||
[existingContactOffers removeWithTransaction:transaction];
|
||||
existingContactOffers = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingContactOffers && !shouldHaveContactOffers) {
|
||||
OWSLogInfo(@"Removing contact offers: %@ (%llu)",
|
||||
existingContactOffers.uniqueId,
|
||||
existingContactOffers.timestampForSorting);
|
||||
[existingContactOffers removeWithTransaction:transaction];
|
||||
} else if (!existingContactOffers && shouldHaveContactOffers) {
|
||||
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
|
||||
|
||||
TSInteraction *offersMessage =
|
||||
[[OWSContactOffersInteraction alloc] initContactOffersWithTimestamp:contactOffersTimestamp
|
||||
thread:thread
|
||||
hasBlockOffer:shouldHaveBlockOffer
|
||||
hasAddToContactsOffer:shouldHaveAddToContactsOffer
|
||||
hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer
|
||||
recipientId:recipientId];
|
||||
[offersMessage saveWithTransaction:transaction];
|
||||
|
||||
OWSLogInfo(
|
||||
@"Creating contact offers: %@ (%llu)", offersMessage.uniqueId, offersMessage.timestampForSorting);
|
||||
}
|
||||
|
||||
[self ensureUnreadIndicator:result
|
||||
thread:thread
|
||||
transaction:transaction
|
||||
shouldHaveContactOffers:shouldHaveContactOffers
|
||||
maxRangeSize:maxRangeSize
|
||||
blockingSafetyNumberChanges:blockingSafetyNumberChanges
|
||||
nonBlockingSafetyNumberChanges:nonBlockingSafetyNumberChanges
|
||||
hideUnreadMessagesIndicator:hideUnreadMessagesIndicator
|
||||
firstUnseenSortId:firstUnseenSortId];
|
||||
thread:thread
|
||||
transaction:transaction
|
||||
shouldHaveContactOffers:shouldHaveContactOffers
|
||||
maxRangeSize:maxRangeSize
|
||||
blockingSafetyNumberChanges:blockingSafetyNumberChanges
|
||||
nonBlockingSafetyNumberChanges:nonBlockingSafetyNumberChanges
|
||||
hideUnreadMessagesIndicator:hideUnreadMessagesIndicator
|
||||
firstUnseenInteractionTimestamp:firstUnseenInteractionTimestamp];
|
||||
|
||||
// Determine the position of the focus message _after_ performing any mutations
|
||||
// around dynamic interactions.
|
||||
|
@ -539,14 +534,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
+ (void)ensureUnreadIndicator:(ThreadDynamicInteractions *)dynamicInteractions
|
||||
thread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
shouldHaveContactOffers:(BOOL)shouldHaveContactOffers
|
||||
maxRangeSize:(int)maxRangeSize
|
||||
blockingSafetyNumberChanges:(NSArray<TSInvalidIdentityKeyErrorMessage *> *)blockingSafetyNumberChanges
|
||||
nonBlockingSafetyNumberChanges:(NSArray<TSInteraction *> *)nonBlockingSafetyNumberChanges
|
||||
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
|
||||
firstUnseenSortId:(nullable NSNumber *)firstUnseenSortId
|
||||
thread:(TSThread *)thread
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
shouldHaveContactOffers:(BOOL)shouldHaveContactOffers
|
||||
maxRangeSize:(int)maxRangeSize
|
||||
blockingSafetyNumberChanges:(NSArray<TSInvalidIdentityKeyErrorMessage *> *)blockingSafetyNumberChanges
|
||||
nonBlockingSafetyNumberChanges:(NSArray<TSInteraction *> *)nonBlockingSafetyNumberChanges
|
||||
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
|
||||
firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp
|
||||
{
|
||||
OWSAssertDebug(dynamicInteractions);
|
||||
OWSAssertDebug(thread);
|
||||
|
@ -557,7 +552,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (hideUnreadMessagesIndicator) {
|
||||
return;
|
||||
}
|
||||
if (!firstUnseenSortId) {
|
||||
if (!firstUnseenInteractionTimestamp) {
|
||||
// If there are no unseen interactions, don't show an unread indicator.
|
||||
return;
|
||||
}
|
||||
|
@ -593,7 +588,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return;
|
||||
}
|
||||
|
||||
if (interaction.sortId < firstUnseenSortId.unsignedLongLongValue) {
|
||||
if (interaction.timestampForSorting < firstUnseenInteractionTimestamp.unsignedLongLongValue) {
|
||||
// By default we want the unread indicator to appear just before
|
||||
// the first unread message.
|
||||
*stop = YES;
|
||||
|
@ -625,12 +620,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (hasMoreUnseenMessages) {
|
||||
NSMutableSet<NSData *> *missingUnseenSafetyNumberChanges = [NSMutableSet set];
|
||||
for (TSInvalidIdentityKeyErrorMessage *safetyNumberChange in blockingSafetyNumberChanges) {
|
||||
BOOL isUnseen = safetyNumberChange.sortId >= firstUnseenSortId.unsignedLongLongValue;
|
||||
BOOL isUnseen
|
||||
= safetyNumberChange.timestampForSorting >= firstUnseenInteractionTimestamp.unsignedLongLongValue;
|
||||
if (!isUnseen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOL isMissing = safetyNumberChange.sortId < interactionAfterUnreadIndicator.sortId;
|
||||
BOOL isMissing
|
||||
= safetyNumberChange.timestampForSorting < interactionAfterUnreadIndicator.timestampForSorting;
|
||||
if (!isMissing) {
|
||||
continue;
|
||||
}
|
||||
|
@ -655,12 +651,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
unreadIndicatorPosition++;
|
||||
}
|
||||
|
||||
dynamicInteractions.unreadIndicator =
|
||||
[[OWSUnreadIndicator alloc] initWithFirstUnseenSortId:firstUnseenSortId.unsignedLongLongValue
|
||||
hasMoreUnseenMessages:hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:unreadIndicatorPosition];
|
||||
OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.firstUnseenSortId);
|
||||
dynamicInteractions.unreadIndicator = [[OWSUnreadIndicator alloc]
|
||||
initUnreadIndicatorWithTimestamp:interactionAfterUnreadIndicator.timestampForSorting
|
||||
hasMoreUnseenMessages:hasMoreUnseenMessages
|
||||
missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount
|
||||
unreadIndicatorPosition:unreadIndicatorPosition
|
||||
firstUnseenInteractionTimestamp:firstUnseenInteractionTimestamp.unsignedLongLongValue];
|
||||
OWSLogInfo(@"Creating Unread Indicator: %llu", dynamicInteractions.unreadIndicator.timestamp);
|
||||
}
|
||||
|
||||
+ (nullable NSNumber *)focusMessagePositionForThread:(TSThread *)thread
|
||||
|
|
|
@ -18,8 +18,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// YES IFF this thread has ever had a message.
|
||||
@property (nonatomic) BOOL hasEverHadMessage;
|
||||
@property (nonatomic, readonly) NSDate *creationDate;
|
||||
@property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting;
|
||||
|
||||
/**
|
||||
* Whether the object is a group thread or not.
|
||||
|
@ -61,10 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
* Get all messages in the thread we weren't able to decrypt
|
||||
*/
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
- (NSArray<TSInvalidIdentityKeyReceivingErrorMessage *> *)receivedMessagesForInvalidKey:(NSData *)key;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
NS_SWIFT_NAME(unreadMessageCount(transaction:));
|
||||
|
@ -73,6 +68,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Returns the latest date of a message in the thread or the thread creation date if there are no messages in that
|
||||
*thread.
|
||||
*
|
||||
* @return The date of the last message or thread creation date.
|
||||
*/
|
||||
- (NSDate *)lastMessageDate;
|
||||
|
||||
/**
|
||||
* Returns the string that will be displayed typically in a conversations view as a preview of the last message
|
||||
*received in this thread.
|
||||
|
@ -96,19 +99,31 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
#pragma mark Archival
|
||||
|
||||
/**
|
||||
* @return YES if no new messages have been sent or received since the thread was last archived.
|
||||
* Returns the last date at which a string was archived or nil if the thread was never archived or brought back to the
|
||||
*inbox.
|
||||
*
|
||||
* @return Last archival date.
|
||||
*/
|
||||
- (BOOL)isArchivedWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (nullable NSDate *)archivalDate;
|
||||
|
||||
/**
|
||||
* Archives a thread
|
||||
* Archives a thread with the current date.
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
*/
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Unarchives a thread
|
||||
* Archives a thread with the reference date. This is currently only used for migrating older data that has already
|
||||
* been archived.
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
* @param date Date at which the thread was archived.
|
||||
*/
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction referenceDate:(NSDate *)date;
|
||||
|
||||
/**
|
||||
* Unarchives a thread that was archived previously.
|
||||
*
|
||||
* @param transaction Database transaction.
|
||||
*/
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#import "TSInteraction.h"
|
||||
#import "TSInvalidIdentityKeyReceivingErrorMessage.h"
|
||||
#import "TSOutgoingMessage.h"
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -23,8 +22,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface TSThread ()
|
||||
|
||||
@property (nonatomic) NSDate *creationDate;
|
||||
@property (nonatomic, copy, nullable) NSDate *archivalDate;
|
||||
@property (nonatomic) NSString *conversationColorName;
|
||||
@property (nonatomic) NSNumber *archivedAsOfMessageSortId;
|
||||
@property (nonatomic, nullable) NSDate *lastMessageDate;
|
||||
|
||||
@property (nonatomic, copy, nullable) NSString *messageDraft;
|
||||
@property (atomic, nullable) NSDate *mutedUntilDate;
|
||||
|
||||
|
@ -43,6 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
self = [super initWithUniqueId:uniqueId];
|
||||
|
||||
if (self) {
|
||||
_archivalDate = nil;
|
||||
_lastMessageDate = nil;
|
||||
_creationDate = [NSDate date];
|
||||
_messageDraft = nil;
|
||||
|
||||
|
@ -74,12 +77,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
_conversationColorName = [self.class stableConversationColorNameForString:self.uniqueId];
|
||||
}
|
||||
}
|
||||
|
||||
NSDate *_Nullable lastMessageDate = [coder decodeObjectOfClass:NSDate.class forKey:@"lastMessageDate"];
|
||||
NSDate *_Nullable archivalDate = [coder decodeObjectOfClass:NSDate.class forKey:@"archivalDate"];
|
||||
_isArchivedByLegacyTimestampForSorting =
|
||||
[self.class legacyIsArchivedWithLastMessageDate:lastMessageDate archivalDate:archivalDate];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -209,8 +207,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [interactions copy];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
- (NSArray<TSInvalidIdentityKeyReceivingErrorMessage *> *)receivedMessagesForInvalidKey:(NSData *)key
|
||||
{
|
||||
NSMutableArray *errorMessages = [NSMutableArray new];
|
||||
|
@ -225,7 +221,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
return [errorMessages copy];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (NSUInteger)numberOfInteractions
|
||||
{
|
||||
|
@ -303,6 +298,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return last;
|
||||
}
|
||||
|
||||
- (NSDate *)lastMessageDate {
|
||||
if (_lastMessageDate) {
|
||||
return _lastMessageDate;
|
||||
} else {
|
||||
return _creationDate;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)lastMessageTextWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
TSInteraction *interaction = [self lastInteractionForInboxWithTransaction:transaction];
|
||||
|
@ -348,8 +351,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return;
|
||||
}
|
||||
|
||||
if (!self.hasEverHadMessage) {
|
||||
self.hasEverHadMessage = YES;
|
||||
self.hasEverHadMessage = YES;
|
||||
|
||||
NSDate *lastMessageDate = [lastMessage dateForSorting];
|
||||
if (!_lastMessageDate || [lastMessageDate timeIntervalSinceDate:self.lastMessageDate] > 0) {
|
||||
_lastMessageDate = lastMessageDate;
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
}
|
||||
|
@ -374,54 +381,30 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - Archival
|
||||
#pragma mark Archival
|
||||
|
||||
- (BOOL)isArchivedWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (nullable NSDate *)archivalDate
|
||||
{
|
||||
if (!self.archivedAsOfMessageSortId) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
TSInteraction *_Nullable latestInteraction = [self lastInteractionForInboxWithTransaction:transaction];
|
||||
uint64_t latestSortIdForInbox = latestInteraction ? latestInteraction.sortId : 0;
|
||||
return self.archivedAsOfMessageSortId.unsignedLongLongValue >= latestSortIdForInbox;
|
||||
return _archivalDate;
|
||||
}
|
||||
|
||||
+ (BOOL)legacyIsArchivedWithLastMessageDate:(nullable NSDate *)lastMessageDate
|
||||
archivalDate:(nullable NSDate *)archivalDate
|
||||
{
|
||||
if (!archivalDate) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!lastMessageDate) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [archivalDate compare:lastMessageDate] != NSOrderedAscending;
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
[self archiveThreadWithTransaction:transaction referenceDate:[NSDate date]];
|
||||
}
|
||||
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self applyChangeToSelfAndLatestCopy:transaction
|
||||
changeBlock:^(TSThread *thread) {
|
||||
uint64_t latestId = [SSKIncrementingIdFinder previousIdWithKey:TSInteraction.collection
|
||||
transaction:transaction];
|
||||
thread.archivedAsOfMessageSortId = @(latestId);
|
||||
}];
|
||||
|
||||
- (void)archiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction referenceDate:(NSDate *)date {
|
||||
[self markAllAsReadWithTransaction:transaction];
|
||||
_archivalDate = date;
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
- (void)unarchiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self applyChangeToSelfAndLatestCopy:transaction
|
||||
changeBlock:^(TSThread *thread) {
|
||||
thread.archivedAsOfMessageSortId = nil;
|
||||
}];
|
||||
- (void)unarchiveThreadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
_archivalDate = nil;
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
#pragma mark - Drafts
|
||||
#pragma mark Drafts
|
||||
|
||||
- (NSString *)currentDraftWithTransaction:(YapDatabaseReadTransaction *)transaction {
|
||||
TSThread *thread = [TSThread fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
|
||||
|
|
|
@ -21,7 +21,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithThread:(nullable TSThread *)thread messageTimestamps:(NSArray<NSNumber *> *)messageTimestamps
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -70,8 +70,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
if (transcript.isEndSessionMessage) {
|
||||
OWSLogInfo(@"EndSession was sent to recipient: %@.", transcript.recipientId);
|
||||
[self.primaryStorage deleteAllSessionsForContact:transcript.recipientId protocolContext:transaction];
|
||||
|
||||
// MJK TODO - we don't use this timestamp, safe to remove
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp
|
||||
inThread:transcript.thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
|
||||
|
@ -129,13 +127,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
}
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:outgoingMessage.expiresInSeconds
|
||||
thread:transcript.thread
|
||||
createdByRemoteRecipientId:nil
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
if (transcript.isExpirationTimerUpdate) {
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage
|
||||
contactsManager:self.contactsManager
|
||||
transaction:transaction];
|
||||
|
||||
|
||||
// early return to avoid saving an empty incoming message.
|
||||
OWSAssertDebug(transcript.body.length == 0);
|
||||
OWSAssertDebug(outgoingMessage.attachmentIds.count == 0);
|
||||
|
@ -150,6 +147,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
[outgoingMessage saveWithTransaction:transaction];
|
||||
[outgoingMessage updateWithWasSentFromLinkedDeviceWithTransaction:transaction];
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage
|
||||
contactsManager:self.contactsManager
|
||||
transaction:transaction];
|
||||
[[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage
|
||||
expirationStartedAt:transcript.expirationStartedAt
|
||||
transaction:transaction];
|
||||
|
|
|
@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)init
|
||||
{
|
||||
// MJK TODO - remove SenderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:nil
|
||||
messageBody:nil
|
||||
|
|
|
@ -20,7 +20,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithThread:(nullable TSThread *)thread groupId:(NSData *)groupId
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -16,7 +16,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
* @param remoteName is nil when created by the local user
|
||||
*/
|
||||
// MJK TODO - can we remove sendertimestamp here
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
configuration:(OWSDisappearingMessagesConfiguration *)configuration
|
||||
|
|
|
@ -74,7 +74,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [NSString stringWithFormat:infoFormat, self.createdByRemoteName];
|
||||
}
|
||||
} else {
|
||||
// Changed by localNumber on this device or via synced transcript
|
||||
// Changed by local request
|
||||
if (self.configurationIsEnabled && self.configurationDurationSeconds > 0) {
|
||||
NSString *infoFormat = NSLocalizedString(@"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION",
|
||||
@"Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context.");
|
||||
|
|
|
@ -10,7 +10,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@interface OWSDisappearingMessagesConfigurationMessage : TSOutgoingMessage
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
messageBody:(nullable NSString *)body
|
||||
|
|
|
@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithConfiguration:(OWSDisappearingMessagesConfiguration *)configuration thread:(TSThread *)thread
|
||||
{
|
||||
// MJK TODO - remove sender timestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -11,7 +11,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
typedef NSData *_Nonnull (^DynamicOutgoingMessageBlock)(SignalRecipient *);
|
||||
|
||||
/// This class is only used in debug tools
|
||||
@interface OWSDynamicOutgoingMessage : TSOutgoingMessage
|
||||
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
|
|
|
@ -23,7 +23,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self initWithPlainTextDataBlock:block timestamp:[NSDate ows_millisecondTimeStamp] thread:thread];
|
||||
}
|
||||
|
||||
// MJK TODO can we remove sender timestamp?
|
||||
- (instancetype)initWithPlainTextDataBlock:(DynamicOutgoingMessageBlock)block
|
||||
timestamp:(uint64_t)timestamp
|
||||
thread:(nullable TSThread *)thread
|
||||
|
|
|
@ -20,7 +20,6 @@ NS_SWIFT_NAME(EndSessionMessage)
|
|||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
contactShare:(nullable OWSContact *)contactShare NS_UNAVAILABLE;
|
||||
|
||||
// MJK TODO can we remove the sender timestamp?
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(nullable TSThread *)thread NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSRecipientIdentity.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSVerificationStateChangeMessage.h"
|
||||
|
|
|
@ -51,6 +51,10 @@ typedef NS_ENUM(int32_t, TSErrorMessageType) {
|
|||
failedMessageType:(TSErrorMessageType)errorMessageType
|
||||
recipientId:(nullable NSString *)recipientId NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
failedMessageType:(TSErrorMessageType)errorMessageType;
|
||||
|
||||
+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
|
|
|
@ -91,11 +91,14 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp. We don't actually currently surface it in the UI, but it serves as
|
||||
// a reference to the envelope which we failed to process.
|
||||
return [self initWithTimestamp:envelope.timestamp inThread:contactThread failedMessageType:errorMessageType];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFailedMessageType:(TSErrorMessageType)errorMessageType
|
||||
{
|
||||
return [self initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:nil failedMessageType:errorMessageType];
|
||||
}
|
||||
|
||||
- (OWSInteractionType)interactionType
|
||||
{
|
||||
return OWSInteractionType_Error;
|
||||
|
@ -153,10 +156,7 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
|
||||
+ (instancetype)corruptedMessageInUnknownThread
|
||||
{
|
||||
// MJK TODO - Seems like we could safely remove this timestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:nil
|
||||
failedMessageType:TSErrorMessageInvalidMessage];
|
||||
return [[self alloc] initWithFailedMessageType:TSErrorMessageInvalidMessage];
|
||||
}
|
||||
|
||||
+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
|
@ -184,7 +184,6 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
|
|||
|
||||
+ (instancetype)nonblockingIdentityChangeInThread:(TSThread *)thread recipientId:(NSString *)recipientId
|
||||
{
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageNonBlockingIdentityChange
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
|
||||
#import "TSErrorMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TSErrorMessage ()
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
inThread:(TSThread *)thread
|
||||
failedMessageType:(TSErrorMessageType)errorMessageType NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (atomic, nullable) NSData *envelopeData;
|
||||
|
||||
@end
|
||||
@property NSDictionary *pendingOutgoingMessage;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
#define TSPendingOutgoingMessageKey @"TSPendingOutgoingMessageKey"
|
||||
#define TSPendingOutgoingMessageRecipientKey @"TSPendingOutgoingMessageRecipientKey"
|
||||
|
||||
@end
|
||||
|
|
|
@ -48,7 +48,6 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
|
|||
inThread:(TSThread *)thread
|
||||
messageType:(TSInfoMessageType)infoMessage
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initMessageWithTimestamp:timestamp
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
@ -101,7 +100,6 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
|
|||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(recipientId);
|
||||
|
||||
// MJK TODO - remove senderTimestamp
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageUserNotRegistered
|
||||
|
|
|
@ -33,9 +33,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
||||
@property (nonatomic, readonly) TSThread *thread;
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
@property (nonatomic, readonly) uint64_t sortId;
|
||||
@property (nonatomic, readonly) uint64_t receivedAtTimestamp;
|
||||
- (NSDate *)receivedAtDate;
|
||||
|
||||
- (OWSInteractionType)interactionType;
|
||||
|
||||
|
@ -57,8 +54,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
filter:(BOOL (^_Nonnull)(TSInteraction *))filter
|
||||
withTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (NSDate *)dateForLegacySorting;
|
||||
- (uint64_t)timestampForLegacySorting;
|
||||
- (NSDate *)dateForSorting;
|
||||
- (uint64_t)timestampForSorting;
|
||||
- (NSComparisonResult)compareForSorting:(TSInteraction *)other;
|
||||
|
||||
// "Dynamic" interactions are not messages or static events (like
|
||||
|
@ -69,9 +66,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
|||
// unseen message indicators, etc.
|
||||
- (BOOL)isDynamicInteraction;
|
||||
|
||||
- (void)saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
NS_SWIFT_NAME(saveNextSortId(transaction:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#import "OWSPrimaryStorage+messageIDs.h"
|
||||
#import "TSDatabaseSecondaryIndexes.h"
|
||||
#import "TSThread.h"
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -31,12 +30,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
}
|
||||
}
|
||||
|
||||
@interface TSInteraction ()
|
||||
|
||||
@property (nonatomic) uint64_t sortId;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TSInteraction
|
||||
|
||||
+ (NSArray<TSInteraction *> *)interactionsWithTimestamp:(uint64_t)timestamp
|
||||
|
@ -64,6 +57,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
[TSDatabaseSecondaryIndexes
|
||||
enumerateMessagesWithTimestamp:timestamp
|
||||
withBlock:^(NSString *collection, NSString *key, BOOL *stop) {
|
||||
|
||||
TSInteraction *interaction =
|
||||
[TSInteraction fetchObjectWithUniqueID:key transaction:transaction];
|
||||
if (!filter(interaction)) {
|
||||
|
@ -92,37 +86,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
_timestamp = timestamp;
|
||||
_uniqueThreadId = thread.uniqueId;
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Previously the receivedAtTimestamp field lived on TSMessage, but we've moved it up
|
||||
// to the TSInteraction superclass.
|
||||
if (_receivedAtTimestamp == 0) {
|
||||
// Upgrade from the older "TSMessage.receivedAtDate" and "TSMessage.receivedAt" properties if
|
||||
// necessary.
|
||||
NSDate *receivedAtDate = [coder decodeObjectForKey:@"receivedAtDate"];
|
||||
if (!receivedAtDate) {
|
||||
receivedAtDate = [coder decodeObjectForKey:@"receivedAt"];
|
||||
}
|
||||
|
||||
if (receivedAtDate) {
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondsSince1970ForDate:receivedAtDate];
|
||||
}
|
||||
|
||||
// For TSInteractions which are not TSMessage's, the timestamp *is* the receivedAtTimestamp
|
||||
if (_receivedAtTimestamp == 0) {
|
||||
_receivedAtTimestamp = _timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -147,31 +110,26 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
|
||||
#pragma mark Date operations
|
||||
|
||||
- (NSDate *)dateForLegacySorting
|
||||
- (NSDate *)dateForSorting
|
||||
{
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForLegacySorting];
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.timestampForSorting];
|
||||
}
|
||||
|
||||
- (uint64_t)timestampForLegacySorting
|
||||
- (uint64_t)timestampForSorting
|
||||
{
|
||||
return self.timestamp;
|
||||
}
|
||||
|
||||
- (NSDate *)receivedAtDate
|
||||
{
|
||||
return [NSDate ows_dateWithMillisecondsSince1970:self.receivedAtTimestamp];
|
||||
}
|
||||
|
||||
- (NSComparisonResult)compareForSorting:(TSInteraction *)other
|
||||
{
|
||||
OWSAssertDebug(other);
|
||||
|
||||
uint64_t sortId1 = self.sortId;
|
||||
uint64_t sortId2 = self.sortId;
|
||||
uint64_t timestamp1 = self.timestampForSorting;
|
||||
uint64_t timestamp2 = other.timestampForSorting;
|
||||
|
||||
if (sortId1 > sortId2) {
|
||||
if (timestamp1 > timestamp2) {
|
||||
return NSOrderedDescending;
|
||||
} else if (sortId1 < sortId2) {
|
||||
} else if (timestamp1 < timestamp2) {
|
||||
return NSOrderedAscending;
|
||||
} else {
|
||||
return NSOrderedSame;
|
||||
|
@ -193,20 +151,14 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
(unsigned long)self.timestamp];
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// MJK can we remove this? We can't trust the legacy order of this id field. Any reason not to use UUID like for
|
||||
// other objects?
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
if (!self.uniqueId) {
|
||||
self.uniqueId = [OWSPrimaryStorage getAndIncrementMessageIdWithTransaction:transaction];
|
||||
}
|
||||
if (self.sortId == 0) {
|
||||
self.sortId = [SSKIncrementingIdFinder nextIdWithKey:[TSInteraction collection] transaction:transaction];
|
||||
}
|
||||
|
||||
[super saveWithTransaction:transaction];
|
||||
|
||||
TSThread *fetchedThread = [self threadWithTransaction:transaction];
|
||||
TSThread *fetchedThread = [TSThread fetchObjectWithUniqueID:self.uniqueThreadId transaction:transaction];
|
||||
|
||||
[fetchedThread updateWithLastMessage:self transaction:transaction];
|
||||
}
|
||||
|
@ -223,20 +175,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
|||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - sorting migration
|
||||
|
||||
- (void)saveNextSortIdWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
if (self.sortId != 0) {
|
||||
// This could happen if something else in our startup process saved the interaction
|
||||
// e.g. another migration ran.
|
||||
// During the migration, since we're enumerating the interactions in the proper order,
|
||||
// we want to ignore any previously assigned sortId
|
||||
self.sortId = 0;
|
||||
}
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -47,6 +47,13 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
*/
|
||||
@property (nonatomic, readonly) NSUInteger schemaVersion;
|
||||
|
||||
// The timestamp property is populated by the envelope,
|
||||
// which is created by the sender.
|
||||
//
|
||||
// We typically want to order messages locally by when
|
||||
// they were received & decrypted, not by when they were sent.
|
||||
@property (nonatomic) uint64_t receivedAtTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -75,6 +82,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
_expiresInSeconds = expiresInSeconds;
|
||||
_expireStartedAt = expireStartedAt;
|
||||
[self updateExpiresAt];
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
_quotedMessage = quotedMessage;
|
||||
_contactShare = contactShare;
|
||||
|
||||
|
@ -127,6 +135,18 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
_attachmentIds = [NSMutableArray new];
|
||||
}
|
||||
|
||||
if (_receivedAtTimestamp == 0) {
|
||||
// Upgrade from the older "receivedAtDate" and "receivedAt" properties if
|
||||
// necessary.
|
||||
NSDate *receivedAtDate = [coder decodeObjectForKey:@"receivedAtDate"];
|
||||
if (!receivedAtDate) {
|
||||
receivedAtDate = [coder decodeObjectForKey:@"receivedAt"];
|
||||
}
|
||||
if (receivedAtDate) {
|
||||
_receivedAtTimestamp = [NSDate ows_millisecondsSince1970ForDate:receivedAtDate];
|
||||
}
|
||||
}
|
||||
|
||||
_schemaVersion = OWSMessageSchemaVersion;
|
||||
|
||||
return self;
|
||||
|
@ -320,7 +340,7 @@ static const NSUInteger OWSMessageSchemaVersion = 4;
|
|||
return self.expiresInSeconds > 0;
|
||||
}
|
||||
|
||||
- (uint64_t)timestampForLegacySorting
|
||||
- (uint64_t)timestampForSorting
|
||||
{
|
||||
if ([self shouldUseReceiptDateForSorting] && self.receivedAtTimestamp > 0) {
|
||||
return self.receivedAtTimestamp;
|
||||
|
|
|
@ -77,7 +77,6 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
|
|||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
contactShare:(nullable OWSContact *)contactShare NS_UNAVAILABLE;
|
||||
|
||||
// MJK TODO - Can we remove the sender timestamp param?
|
||||
- (instancetype)initOutgoingMessageWithTimestamp:(uint64_t)timestamp
|
||||
inThread:(nullable TSThread *)thread
|
||||
messageBody:(nullable NSString *)body
|
||||
|
|
|
@ -261,7 +261,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
|
|||
[attachmentIds addObject:attachmentId];
|
||||
}
|
||||
|
||||
// MJK TODO remove SenderTimestamp?
|
||||
return [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:body
|
||||
|
@ -278,7 +277,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt
|
|||
groupMetaMessage:(TSGroupMetaMessage)groupMetaMessage
|
||||
expiresInSeconds:(uint32_t)expiresInSeconds;
|
||||
{
|
||||
// MJK TODO remove SenderTimestamp?
|
||||
return [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -208,7 +208,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
// Legit usage of senderTimestamp - this class references the message it is quoting by it's sender timestamp
|
||||
return [[TSQuotedMessage alloc] initWithTimestamp:timestamp
|
||||
authorId:authorId
|
||||
body:body
|
||||
|
@ -230,6 +229,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSArray<TSMessage *> *quotedMessages = (NSArray<TSMessage *> *)[TSInteraction
|
||||
interactionsWithTimestamp:timestamp
|
||||
filter:^BOOL(TSInteraction *interaction) {
|
||||
|
||||
if (![threadId isEqual:interaction.uniqueThreadId]) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -243,6 +243,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// ignore other interaction types
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
withTransaction:transaction];
|
||||
|
||||
|
|
|
@ -10,13 +10,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
__attribute__((deprecated))
|
||||
@interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
|
||||
#ifdef DEBUG
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
__attribute__((deprecated))
|
||||
/// TODO we can eventually deprecate this, since incoming messages are now always decrypted.
|
||||
@interface TSInvalidIdentityKeyReceivingErrorMessage ()
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *authorId;
|
||||
|
@ -33,20 +33,15 @@ __attribute__((deprecated))
|
|||
|
||||
@synthesize envelopeData = _envelopeData;
|
||||
|
||||
#ifdef DEBUG
|
||||
// We no longer create these messages, but they might exist on legacy clients so it's useful to be able to
|
||||
// create them with the debug UI
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp, references message which failed to decrypt
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *errorMessage =
|
||||
[[self alloc] initForUnknownIdentityKeyWithTimestamp:envelope.timestamp
|
||||
inThread:contactThread
|
||||
incomingEnvelope:envelope];
|
||||
[[self alloc] initForUnknownIdentityKeyWithTimestamp:envelope.timestamp
|
||||
inThread:contactThread
|
||||
incomingEnvelope:envelope];
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
|
@ -70,7 +65,6 @@ __attribute__((deprecated))
|
|||
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (nullable SSKProtoEnvelope *)envelope
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInvalidIdentityKeyErrorMessage.h"
|
||||
|
@ -13,9 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
extern NSString *TSInvalidPreKeyBundleKey;
|
||||
extern NSString *TSInvalidRecipientKey;
|
||||
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
__attribute__((deprecated))
|
||||
@interface TSInvalidIdentityKeySendingErrorMessage : TSInvalidIdentityKeyErrorMessage
|
||||
|
||||
@property (nonatomic, readonly) NSString *messageId;
|
||||
|
|
|
@ -24,12 +24,26 @@ NSString *TSInvalidRecipientKey = @"TSInvalidRecipientKey";
|
|||
|
||||
@end
|
||||
|
||||
// DEPRECATED - we no longer create new instances of this class (as of mid-2017); However, existing instances may
|
||||
// exist, so we should keep this class around to honor their old behavior.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation TSInvalidIdentityKeySendingErrorMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage *)message
|
||||
inThread:(TSThread *)thread
|
||||
forRecipient:(NSString *)recipientId
|
||||
preKeyBundle:(PreKeyBundle *)preKeyBundle
|
||||
{
|
||||
// We want the error message to appear after the message.
|
||||
self = [super initWithTimestamp:message.timestamp + 1
|
||||
inThread:thread
|
||||
failedMessageType:TSErrorMessageWrongTrustedIdentityKey
|
||||
recipientId:recipientId];
|
||||
|
||||
if (self) {
|
||||
_messageId = message.uniqueId;
|
||||
_preKeyBundle = preKeyBundle;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)acceptNewIdentityKey
|
||||
{
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInfoMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated))
|
||||
@interface OWSAddToContactsOfferMessage : TSInfoMessage
|
||||
|
||||
+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId;
|
||||
+ (instancetype)addToContactsOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId;
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSAddToContactsOfferMessage.h"
|
||||
|
@ -14,16 +14,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSAddToContactsOfferMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (instancetype)addToContactsOfferMessageWithTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId
|
||||
+ (instancetype)addToContactsOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId
|
||||
{
|
||||
return [[OWSAddToContactsOfferMessage alloc] initWithTimestamp:timestamp thread:thread contactId:contactId];
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSInfoMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated)) @interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
|
||||
@interface OWSAddToProfileWhitelistOfferMessage : TSInfoMessage
|
||||
|
||||
+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSAddToProfileWhitelistOfferMessage.h"
|
||||
|
@ -7,14 +7,9 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSAddToProfileWhitelistOfferMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (instancetype)addToProfileWhitelistOfferMessageWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
+ (instancetype)addToProfileWhitelistOfferMessage:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
{
|
||||
return [[OWSAddToProfileWhitelistOfferMessage alloc]
|
||||
initWithTimestamp:timestamp
|
||||
|
|
|
@ -21,23 +21,41 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
expirationStartedAt:(uint64_t)expirationStartedAt
|
||||
transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction;
|
||||
|
||||
/**
|
||||
* Synchronize our disappearing messages settings with that of the given message. Useful so we can
|
||||
* become eventually consistent with remote senders.
|
||||
*
|
||||
* @param message
|
||||
* Can be an expiring or non expiring message. We match the expiration timer of the message, including disabling
|
||||
* expiring messages if the message is not an expiring message.
|
||||
*
|
||||
* @param contactsManager
|
||||
* Provides the contact name responsible for any configuration changes in an info message.
|
||||
*/
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
/**
|
||||
* Synchronize our disappearing messages settings with that of the given message. Useful so we can
|
||||
* become eventually consistent with remote senders.
|
||||
*
|
||||
* @param duration
|
||||
* Can be 0, indicating a non-expiring message, or greater, indicating an expiring message. We match the expiration
|
||||
* timer of the message, including disabling expiring messages if the message is not an expiring message.
|
||||
* timer of the message, including disabling expiring messages if the message is not an expiring message.
|
||||
*
|
||||
* @param remoteRecipientId
|
||||
* nil for outgoing messages, otherwise the recipientId of the sender
|
||||
* @param timestampForSorting
|
||||
* timestampForSorting of the message before which we want to appear.
|
||||
*
|
||||
* @param remoteContactName
|
||||
* nil for outgoing messages, otherwise the name of the sender
|
||||
* @param createdInExistingGroup
|
||||
* YES when being added to a group which already has DM enabled, otherwise NO
|
||||
*/
|
||||
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
|
||||
thread:(TSThread *)thread
|
||||
createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
|
||||
appearBeforeTimestamp:(uint64_t)timestampForSorting
|
||||
createdByRemoteContactName:(nullable NSString *)remoteContactName
|
||||
createdInExistingGroup:(BOOL)createdInExistingGroup
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#import "OWSDisappearingMessagesConfiguration.h"
|
||||
#import "OWSDisappearingMessagesFinder.h"
|
||||
#import "OWSPrimaryStorage.h"
|
||||
#import "SSKEnvironment.h"
|
||||
#import "TSIncomingMessage.h"
|
||||
#import "TSMessage.h"
|
||||
#import "TSThread.h"
|
||||
|
@ -111,15 +110,6 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
return queue;
|
||||
}
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
return SSKEnvironment.shared.contactsManager;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSUInteger)deleteExpiredMessages
|
||||
{
|
||||
AssertIsOnDisappearingMessagesQueue();
|
||||
|
@ -203,25 +193,38 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
TSThread *thread = [message threadWithTransaction:transaction];
|
||||
NSString *remoteContactName = nil;
|
||||
if ([message isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
|
||||
remoteContactName = [contactsManager displayNameForPhoneIdentifier:incomingMessage.messageAuthorId];
|
||||
}
|
||||
|
||||
#pragma mark - Apply Remote Configuration
|
||||
[self becomeConsistentWithDisappearingDuration:message.expiresInSeconds
|
||||
thread:thread
|
||||
appearBeforeTimestamp:message.timestampForSorting
|
||||
createdByRemoteContactName:remoteContactName
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
- (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration
|
||||
thread:(TSThread *)thread
|
||||
createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId
|
||||
appearBeforeTimestamp:(uint64_t)timestampForSorting
|
||||
createdByRemoteContactName:(nullable NSString *)remoteContactName
|
||||
createdInExistingGroup:(BOOL)createdInExistingGroup
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(timestampForSorting > 0);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
||||
NSString *_Nullable remoteContactName = nil;
|
||||
if (remoteRecipientId) {
|
||||
remoteContactName = [self.contactsManager displayNameForPhoneIdentifier:remoteRecipientId];
|
||||
}
|
||||
|
||||
// Become eventually consistent in the case that the remote changed their settings at the same time.
|
||||
// Also in case remote doesn't support expiring messages
|
||||
OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration =
|
||||
|
@ -243,9 +246,9 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
|
||||
[disappearingMessagesConfiguration saveWithTransaction:transaction];
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
// We want the info message to appear _before_ the message.
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *infoMessage =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:timestampForSorting - 1
|
||||
thread:thread
|
||||
configuration:disappearingMessagesConfiguration
|
||||
createdByRemoteName:remoteContactName
|
||||
|
@ -256,8 +259,6 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
backgroundTask = nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)startIfNecessary
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
@ -393,7 +394,7 @@ void AssertIsOnDisappearingMessagesQueue()
|
|||
OWSFailDebug(@"starting old timer for message timestamp: %lu", (unsigned long)message.timestamp);
|
||||
|
||||
// We don't know when it was actually read, so assume it was read as soon as it was received.
|
||||
uint64_t readTimeBestGuess = message.receivedAtTimestamp;
|
||||
uint64_t readTimeBestGuess = message.timestampForSorting;
|
||||
[self startAnyExpirationForMessage:message expirationStartedAt:readTimeBestGuess transaction:transaction];
|
||||
}
|
||||
transaction:transaction];
|
||||
|
|
|
@ -528,7 +528,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
[messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]];
|
||||
}
|
||||
|
||||
// MJK TODO - why not save immediately, why build up this array?
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
|
@ -846,7 +845,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
||||
OWSAssertDebug(contactThread);
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[messages addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:contactThread
|
||||
recipientId:recipientId
|
||||
|
@ -855,7 +853,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
|
||||
for (TSGroupThread *groupThread in
|
||||
[TSGroupThread groupThreadsWithRecipientId:recipientId transaction:transaction]) {
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[messages
|
||||
addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:groupThread
|
||||
|
@ -864,7 +861,6 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
isLocalChange:isLocalChange]];
|
||||
}
|
||||
|
||||
// MJK TODO - why not save in-line, vs storing in an array and saving the array?
|
||||
for (TSMessage *message in messages) {
|
||||
[message saveWithTransaction:transaction];
|
||||
}
|
||||
|
|
|
@ -879,7 +879,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
|
||||
|
@ -928,7 +927,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(disappearingMessagesConfiguration);
|
||||
[disappearingMessagesConfiguration saveWithTransaction:transaction];
|
||||
NSString *name = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
OWSDisappearingConfigurationUpdateInfoMessage *message =
|
||||
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
thread:thread
|
||||
|
@ -1146,6 +1144,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
TSGroupThread *newGroupThread =
|
||||
[TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction];
|
||||
|
||||
|
||||
uint64_t now = [NSDate ows_millisecondTimeStamp];
|
||||
TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name
|
||||
memberIds:newMemberIds.allObjects
|
||||
image:oldGroupThread.groupModel.groupImage
|
||||
|
@ -1155,19 +1155,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
newGroupThread.groupModel = newGroupModel;
|
||||
[newGroupThread saveWithTransaction:transaction];
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:newGroupThread
|
||||
createdByRemoteRecipientId:nil
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithTimestamp:now
|
||||
inThread:newGroupThread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
customMessage:updateGroupInfo];
|
||||
[infoMessage saveWithTransaction:transaction];
|
||||
|
||||
if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) {
|
||||
[[OWSDisappearingMessagesJob sharedJob]
|
||||
becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:newGroupThread
|
||||
appearBeforeTimestamp:now
|
||||
createdByRemoteContactName:nil
|
||||
createdInExistingGroup:YES
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
case SSKProtoGroupContextTypeQuit: {
|
||||
|
@ -1182,7 +1185,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSString *nameString = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
|
||||
NSString *updateGroupInfo =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString];
|
||||
// MJK TODO - should be safe to remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:oldGroupThread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
|
@ -1203,12 +1205,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return nil;
|
||||
}
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:oldGroupThread
|
||||
createdByRemoteRecipientId:envelope.source
|
||||
createdInExistingGroup:YES
|
||||
transaction:transaction];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:oldGroupThread
|
||||
transaction:transaction];
|
||||
|
@ -1218,7 +1214,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
groupId,
|
||||
(unsigned long)timestamp);
|
||||
|
||||
// Legit usage of senderTimestamp when creating an incoming group message record
|
||||
TSIncomingMessage *incomingMessage =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
|
||||
inThread:oldGroupThread
|
||||
|
@ -1254,17 +1249,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
TSContactThread *thread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer
|
||||
thread:thread
|
||||
createdByRemoteRecipientId:envelope.source
|
||||
createdInExistingGroup:NO
|
||||
transaction:transaction];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:thread
|
||||
transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp when creating incoming message from received envelope
|
||||
TSIncomingMessage *incomingMessage =
|
||||
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
|
||||
inThread:thread
|
||||
|
@ -1374,6 +1362,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage
|
||||
transaction:transaction];
|
||||
|
||||
[[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:incomingMessage
|
||||
contactsManager:self.contactsManager
|
||||
transaction:transaction];
|
||||
|
||||
// Update thread preview in inbox
|
||||
[thread touchWithTransaction:transaction];
|
||||
|
||||
|
|
|
@ -467,7 +467,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *recipientId in message.sendingRecipientIds) {
|
||||
[message updateWithReadRecipientId:recipientId
|
||||
readTimestamp:message.timestamp
|
||||
readTimestamp:message.timestampForSorting
|
||||
transaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
@ -1416,13 +1416,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
// TODO: Why is this necessary?
|
||||
[message save];
|
||||
} else if (message.groupMetaMessage == TSGroupMetaMessageQuit) {
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupQuit
|
||||
customMessage:message.customMessage] save];
|
||||
} else {
|
||||
// MJK TODO - remove senderTimestamp
|
||||
[[[TSInfoMessage alloc] initWithTimestamp:message.timestamp
|
||||
inThread:thread
|
||||
messageType:TSInfoMessageTypeGroupUpdate
|
||||
|
|
|
@ -15,7 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithThread:(TSThread *)thread
|
||||
{
|
||||
// MJK TODO - safe to remove senderTimestamp
|
||||
// These records aren't saved, but their timestamp is used in the event
|
||||
// of a failing message send to insert the error at the appropriate place.
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:nil
|
||||
|
|
|
@ -24,7 +24,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (instancetype)initWithContactThread:(TSContactThread *)contactThread
|
||||
verificationStateSyncMessage:(OWSVerificationStateSyncMessage *)verificationStateSyncMessage
|
||||
{
|
||||
// MJK TODO - remove senderTimestamp
|
||||
self = [super initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:contactThread
|
||||
messageBody:nil
|
||||
|
|
|
@ -69,7 +69,7 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification;
|
|||
// This method can be called from any thread.
|
||||
- (void)messageWasReadLocally:(TSIncomingMessage *)message;
|
||||
|
||||
- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread;
|
||||
- (void)markAsReadLocallyBeforeTimestamp:(uint64_t)timestamp thread:(TSThread *)thread;
|
||||
|
||||
#pragma mark - Settings
|
||||
|
||||
|
|
|
@ -281,17 +281,17 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
|
||||
#pragma mark - Mark as Read Locally
|
||||
|
||||
- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread
|
||||
- (void)markAsReadLocallyBeforeTimestamp:(uint64_t)timestamp thread:(TSThread *)thread
|
||||
{
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self markAsReadBeforeSortId:sortId
|
||||
thread:thread
|
||||
readTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
wasLocal:YES
|
||||
transaction:transaction];
|
||||
[self markAsReadBeforeTimestamp:timestamp
|
||||
thread:thread
|
||||
readTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
wasLocal:YES
|
||||
transaction:transaction];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
@ -493,23 +493,26 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
// Always re-mark the message as read to ensure any earlier read time is applied to disappearing messages.
|
||||
[message markAsReadAtTimestamp:readTimestamp sendReadReceipt:NO transaction:transaction];
|
||||
|
||||
// Also mark any unread messages appearing earlier in the thread as read as well.
|
||||
[self markAsReadBeforeSortId:message.sortId
|
||||
thread:[message threadWithTransaction:transaction]
|
||||
readTimestamp:readTimestamp
|
||||
wasLocal:NO
|
||||
transaction:transaction];
|
||||
// Also mark any messages appearing earlier in the thread as read.
|
||||
//
|
||||
// Use `timestampForSorting` which reflects local received order, rather than `timestamp`
|
||||
// which reflect sender time.
|
||||
[self markAsReadBeforeTimestamp:message.timestampForSorting
|
||||
thread:[message threadWithTransaction:transaction]
|
||||
readTimestamp:readTimestamp
|
||||
wasLocal:NO
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
#pragma mark - Mark As Read
|
||||
|
||||
- (void)markAsReadBeforeSortId:(uint64_t)sortId
|
||||
thread:(TSThread *)thread
|
||||
readTimestamp:(uint64_t)readTimestamp
|
||||
wasLocal:(BOOL)wasLocal
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
- (void)markAsReadBeforeTimestamp:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
readTimestamp:(uint64_t)readTimestamp
|
||||
wasLocal:(BOOL)wasLocal
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(sortId > 0);
|
||||
OWSAssertDebug(timestamp > 0);
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
|
@ -533,11 +536,12 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
|
|||
return;
|
||||
}
|
||||
id<OWSReadTracking> possiblyRead = (id<OWSReadTracking>)object;
|
||||
if (possiblyRead.sortId > sortId) {
|
||||
|
||||
if (possiblyRead.timestampForSorting > timestamp) {
|
||||
*stop = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
OWSAssertDebug(!possiblyRead.read);
|
||||
OWSAssertDebug(possiblyRead.expireStartedAt == 0);
|
||||
if (!possiblyRead.read) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
@property (nonatomic, readonly, getter=wasRead) BOOL read;
|
||||
|
||||
@property (nonatomic, readonly) uint64_t expireStartedAt;
|
||||
@property (nonatomic, readonly) uint64_t sortId;
|
||||
@property (nonatomic, readonly) uint64_t timestampForSorting;
|
||||
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TSErrorMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
__attribute__((deprecated))
|
||||
@interface OWSUnknownContactBlockOfferMessage : TSErrorMessage
|
||||
|
||||
+ (instancetype)unknownContactBlockOfferMessage:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId;
|
||||
|
||||
@property (nonatomic, readonly) NSString *contactId;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSUnknownContactBlockOfferMessage.h"
|
||||
|
@ -14,12 +14,25 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark -
|
||||
|
||||
// This is a deprecated class, we're keeping it around to avoid YapDB serialization errors
|
||||
// TODO - remove this class, clean up existing instances, ensure any missed ones don't explode (UnknownDBObject)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@implementation OWSUnknownContactBlockOfferMessage
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+ (instancetype)unknownContactBlockOfferMessage:(uint64_t)timestamp
|
||||
thread:(TSThread *)thread
|
||||
contactId:(NSString *)contactId
|
||||
{
|
||||
return [[OWSUnknownContactBlockOfferMessage alloc] initWithTimestamp:timestamp thread:thread contactId:contactId];
|
||||
}
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread contactId:(NSString *)contactId
|
||||
{
|
||||
self = [super initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageUnknownContactBlockOffer];
|
||||
|
||||
if (self) {
|
||||
_contactId = contactId;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)shouldUseReceiptDateForSorting
|
||||
{
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc
|
||||
public class SSKIncrementingIdFinder: NSObject {
|
||||
|
||||
private static let collectionName = "IncrementingIdCollection"
|
||||
|
||||
@objc
|
||||
public class func previousId(key: String, transaction: YapDatabaseReadTransaction) -> UInt64 {
|
||||
let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0
|
||||
return previousId
|
||||
}
|
||||
|
||||
@objc
|
||||
public class func nextId(key: String, transaction: YapDatabaseReadWriteTransaction) -> UInt64 {
|
||||
let previousId: UInt64 = transaction.object(forKey: key, inCollection: collectionName) as? UInt64 ?? 0
|
||||
let nextId: UInt64 = previousId + 1
|
||||
|
||||
transaction.setObject(nextId, forKey: key, inCollection: collectionName)
|
||||
Logger.debug("key: \(key) nextId: \(nextId)")
|
||||
return nextId
|
||||
}
|
||||
}
|
|
@ -137,7 +137,8 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
|
|||
return NSOrderedSame;
|
||||
}
|
||||
TSMessage *message2 = (TSMessage *)object2;
|
||||
return [message1 compareForSorting:message2];
|
||||
|
||||
return [@(message1.timestampForSorting) compare:@(message2.timestampForSorting)];
|
||||
}];
|
||||
|
||||
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:^NSString * _Nullable(YapDatabaseReadTransaction * _Nonnull transaction, NSString * _Nonnull collection, NSString * _Nonnull key, id _Nonnull object) {
|
||||
|
@ -163,7 +164,7 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
|
|||
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
|
||||
options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSMessage.collection]];
|
||||
|
||||
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"4" options:options];
|
||||
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"3" options:options];
|
||||
}
|
||||
|
||||
+ (BOOL)attachmentIdShouldAppearInMediaGallery:(NSString *)attachmentId transaction:(YapDatabaseReadTransaction *)transaction
|
||||
|
|
|
@ -190,7 +190,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
|
|||
//
|
||||
// All sync registrations must be done before all async registrations,
|
||||
// or the sync registrations will block on the async registrations.
|
||||
[TSDatabaseView asyncRegisterLegacyThreadInteractionsDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterThreadDatabaseView:self];
|
||||
[TSDatabaseView asyncRegisterUnreadDatabaseView:self];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue