Merge branch 'dev' of https://github.com/oxen-io/session-ios into filtered-push-notification
This commit is contained in:
commit
369034d790
|
@ -5063,7 +5063,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
|
@ -5132,7 +5132,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
@ -5193,7 +5193,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
|
@ -5263,7 +5263,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
@ -6148,7 +6148,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -6216,7 +6216,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
CURRENT_PROJECT_VERSION = 279;
|
CURRENT_PROJECT_VERSION = 284;
|
||||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|
|
@ -689,7 +689,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
|
||||||
return cancelVoiceMessageRecording()
|
return cancelVoiceMessageRecording()
|
||||||
}
|
}
|
||||||
// Limit voice messages to a minute
|
// Limit voice messages to a minute
|
||||||
audioTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: false, block: { [weak self] _ in
|
audioTimer = Timer.scheduledTimer(withTimeInterval: 180, repeats: false, block: { [weak self] _ in
|
||||||
self?.snInputView.hideVoiceMessageUI()
|
self?.snInputView.hideVoiceMessageUI()
|
||||||
self?.endVoiceMessageRecording()
|
self?.endVoiceMessageRecording()
|
||||||
})
|
})
|
||||||
|
|
|
@ -55,6 +55,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
||||||
return messagesTableView.contentSize.height - tableViewUnobscuredHeight
|
return messagesTableView.contentSize.height - tableViewUnobscuredHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isCloseToBottom: Bool {
|
||||||
|
let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y)
|
||||||
|
return margin <= ConversationVC.scrollToBottomMargin
|
||||||
|
}
|
||||||
|
|
||||||
lazy var mnemonic: String = {
|
lazy var mnemonic: String = {
|
||||||
let identityManager = OWSIdentityManager.shared()
|
let identityManager = OWSIdentityManager.shared()
|
||||||
let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection
|
let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection
|
||||||
|
@ -150,7 +155,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
||||||
/// The button will be invisible until the user has scrolled at least this amount from the bottom of the table view.
|
/// The button will be invisible until the user has scrolled at least this amount from the bottom of the table view.
|
||||||
static let scrollButtonNoVisibilityThreshold: CGFloat = 20
|
static let scrollButtonNoVisibilityThreshold: CGFloat = 20
|
||||||
/// Automatically scroll to the bottom of the conversation when sending a message if the scroll distance from the bottom is less than this number.
|
/// Automatically scroll to the bottom of the conversation when sending a message if the scroll distance from the bottom is less than this number.
|
||||||
static let scrollToBottomMargin: CGFloat = 40
|
static let scrollToBottomMargin: CGFloat = 60
|
||||||
|
|
||||||
// MARK: Lifecycle
|
// MARK: Lifecycle
|
||||||
init(thread: TSThread, focusedMessageID: String? = nil) {
|
init(thread: TSThread, focusedMessageID: String? = nil) {
|
||||||
|
@ -314,6 +319,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
||||||
baselineKeyboardHeight = newHeight
|
baselineKeyboardHeight = newHeight
|
||||||
self.messagesTableView.keyboardHeight = newHeight
|
self.messagesTableView.keyboardHeight = newHeight
|
||||||
}
|
}
|
||||||
|
let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y)
|
||||||
|
// HACK: If the keyboard is coming up and we're very close to the bottom, scroll to the
|
||||||
|
// bottom. This "fixes" an issue where the conversation would randomly scroll up sometimes
|
||||||
|
// when bringing up the keyboard.
|
||||||
|
if newHeight > 200 && margin <= 2 {
|
||||||
|
scrollToBottom(isAnimated: false)
|
||||||
|
}
|
||||||
scrollButtonConstraint?.constant = -(newHeight + 16)
|
scrollButtonConstraint?.constant = -(newHeight + 16)
|
||||||
let newContentOffsetY = max(self.messagesTableView.contentOffset.y + min(lastPageTop, 0) + newHeight - self.messagesTableView.keyboardHeight, 0.0)
|
let newContentOffsetY = max(self.messagesTableView.contentOffset.y + min(lastPageTop, 0) + newHeight - self.messagesTableView.keyboardHeight, 0.0)
|
||||||
self.messagesTableView.contentOffset.y = newContentOffsetY
|
self.messagesTableView.contentOffset.y = newContentOffsetY
|
||||||
|
@ -353,13 +365,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
||||||
if update.viewItem?.interaction is TSOutgoingMessage {
|
if update.viewItem?.interaction is TSOutgoingMessage {
|
||||||
shouldScrollToBottom = true
|
shouldScrollToBottom = true
|
||||||
} else {
|
} else {
|
||||||
let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y)
|
shouldScrollToBottom = self.isCloseToBottom
|
||||||
shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin
|
|
||||||
}
|
}
|
||||||
case .update:
|
case .update:
|
||||||
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade)
|
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade)
|
||||||
let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y)
|
shouldScrollToBottom = self.isCloseToBottom
|
||||||
shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin
|
|
||||||
default: preconditionFailure()
|
default: preconditionFailure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -546,7 +546,7 @@ CGFloat kIconViewLength = 24;
|
||||||
[topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom];
|
[topRow autoPinEdgesToSuperviewMarginsExcludingEdge:ALEdgeBottom];
|
||||||
|
|
||||||
UILabel *subtitleLabel = [UILabel new];
|
UILabel *subtitleLabel = [UILabel new];
|
||||||
subtitleLabel.text = NSLocalizedString(@"When enabled, only messages mentioned you will be notified.", @"");
|
subtitleLabel.text = NSLocalizedString(@"vc_conversation_settings_notify_for_mentions_only_explanation", @"");
|
||||||
subtitleLabel.textColor = LKColors.text;
|
subtitleLabel.textColor = LKColors.text;
|
||||||
subtitleLabel.font = [UIFont systemFontOfSize:LKValues.smallFontSize];
|
subtitleLabel.font = [UIFont systemFontOfSize:LKValues.smallFontSize];
|
||||||
subtitleLabel.numberOfLines = 0;
|
subtitleLabel.numberOfLines = 0;
|
||||||
|
|
|
@ -168,8 +168,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
||||||
|
|
||||||
// Don't fire the notification if the current user isn't mentioned
|
// Don't fire the notification if the current user isn't mentioned
|
||||||
// and isOnlyNotifyingForMentions is on.
|
// and isOnlyNotifyingForMentions is on.
|
||||||
let isUserMentioned = MentionUtilities.isUserMentioned(in: messageText ?? "")
|
if let groupThread = thread as? TSGroupThread, groupThread.isOnlyNotifyingForMentions && !incomingMessage.isUserMentioned {
|
||||||
if let groupThread = thread as? TSGroupThread, groupThread.isOnlyNotifyingForMentions && !isUserMentioned {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,8 +157,7 @@ final class ConversationCell : UITableViewCell {
|
||||||
// MARK: Updating
|
// MARK: Updating
|
||||||
private func update() {
|
private func update() {
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
guard let thread = threadViewModel?.threadRecord, let threadID = thread.uniqueId else { return }
|
guard let thread = threadViewModel?.threadRecord else { return }
|
||||||
MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID) // FIXME: This is a terrible place to do this
|
|
||||||
let isBlocked: Bool
|
let isBlocked: Bool
|
||||||
if let thread = thread as? TSContactThread {
|
if let thread = thread as? TSContactThread {
|
||||||
isBlocked = SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(thread.contactSessionID())
|
isBlocked = SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(thread.contactSessionID())
|
||||||
|
|
|
@ -16,6 +16,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@property (nonatomic, readonly) BOOL wasReceivedByUD;
|
@property (nonatomic, readonly) BOOL wasReceivedByUD;
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) BOOL isUserMentioned;
|
||||||
|
|
||||||
- (instancetype)initMessageWithTimestamp:(uint64_t)timestamp
|
- (instancetype)initMessageWithTimestamp:(uint64_t)timestamp
|
||||||
inThread:(nullable TSThread *)thread
|
inThread:(nullable TSThread *)thread
|
||||||
messageBody:(nullable NSString *)body
|
messageBody:(nullable NSString *)body
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#import "TSGroupThread.h"
|
#import "TSGroupThread.h"
|
||||||
#import <YapDatabase/YapDatabaseConnection.h>
|
#import <YapDatabase/YapDatabaseConnection.h>
|
||||||
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
|
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
|
||||||
|
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@ -121,6 +122,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
return self.isExpiringMessage;
|
return self.isExpiringMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isUserMentioned
|
||||||
|
{
|
||||||
|
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
|
||||||
|
return (self.body != nil && [self.body containsString:[NSString stringWithFormat:@"@%@", userPublicKey]]) || (self.quotedMessage != nil && [self.quotedMessage.authorId isEqualToString:userPublicKey]);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - OWSReadTracking
|
#pragma mark - OWSReadTracking
|
||||||
|
|
||||||
- (BOOL)shouldAffectUnreadCounts
|
- (BOOL)shouldAffectUnreadCounts
|
||||||
|
|
|
@ -288,7 +288,11 @@ extension MessageReceiver {
|
||||||
// Notify the user if needed
|
// Notify the user if needed
|
||||||
guard (isMainAppAndActive || isBackgroundPoll), let tsIncomingMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) as? TSIncomingMessage,
|
guard (isMainAppAndActive || isBackgroundPoll), let tsIncomingMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) as? TSIncomingMessage,
|
||||||
let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return tsMessageID }
|
let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) else { return tsMessageID }
|
||||||
SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction)
|
DispatchQueue.main.async {
|
||||||
|
Storage.read { transaction in
|
||||||
|
SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
return tsMessageID
|
return tsMessageID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ public final class ClosedGroupPoller : NSObject {
|
||||||
private var timers: [String:Timer] = [:]
|
private var timers: [String:Timer] = [:]
|
||||||
|
|
||||||
// MARK: Settings
|
// MARK: Settings
|
||||||
private static let minPollInterval: Double = 4
|
private static let minPollInterval: Double = 2
|
||||||
private static let maxPollInterval: Double = 2 * 60
|
private static let maxPollInterval: Double = 30
|
||||||
|
|
||||||
// MARK: Error
|
// MARK: Error
|
||||||
private enum Error : LocalizedError {
|
private enum Error : LocalizedError {
|
||||||
|
|
|
@ -72,11 +72,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
[LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
[LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||||
YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName];
|
YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName];
|
||||||
NSArray<NSString *> *allGroups = [unreadMessages allGroups];
|
NSArray<NSString *> *allGroups = [unreadMessages allGroups];
|
||||||
|
// FIXME: Confusingly, `allGroups` includes contact threads as well
|
||||||
for (NSString *groupID in allGroups) {
|
for (NSString *groupID in allGroups) {
|
||||||
TSThread *thread = [TSThread fetchObjectWithUniqueID:groupID transaction:transaction];
|
TSThread *thread = [TSThread fetchObjectWithUniqueID:groupID transaction:transaction];
|
||||||
if (thread.isMuted) continue;
|
if (thread.isMuted) { continue; }
|
||||||
|
BOOL isGroupThread = thread.isGroupThread;
|
||||||
[unreadMessages enumerateKeysAndObjectsInGroup:groupID
|
[unreadMessages enumerateKeysAndObjectsInGroup:groupID
|
||||||
usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) {
|
usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) {
|
||||||
if (![object conformsToProtocol:@protocol(OWSReadTracking)]) {
|
if (![object conformsToProtocol:@protocol(OWSReadTracking)]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
NSLog(@"Found an already read message in the * unread * messages list.");
|
NSLog(@"Found an already read message in the * unread * messages list.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ([object isKindOfClass:TSIncomingMessage.class] && isGroupThread) {
|
||||||
|
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)object;
|
||||||
|
if (((TSGroupThread *)thread).isOnlyNotifyingForMentions && !incomingMessage.isUserMentioned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public final class ProfilePictureView : UIView {
|
||||||
publicKey = ""
|
publicKey = ""
|
||||||
useFallbackPicture = true
|
useFallbackPicture = true
|
||||||
} else { // A closed group
|
} else { // A closed group
|
||||||
var users = MentionsManager.userPublicKeyCache[thread.uniqueId!] ?? []
|
var users = Set(thread.groupModel.groupMemberIds)
|
||||||
users.remove(getUserHexEncodedPublicKey())
|
users.remove(getUserHexEncodedPublicKey())
|
||||||
var randomUsers = users.sorted() // Sort to provide a level of stability
|
var randomUsers = users.sorted() // Sort to provide a level of stability
|
||||||
if users.count == 1 {
|
if users.count == 1 {
|
||||||
|
|
Loading…
Reference in New Issue