Merge pull request #581 from oxen-io/dev

1.11.22 Fixes
This commit is contained in:
RyanZhao 2022-03-11 16:04:57 +11:00 committed by GitHub
commit b7520ed1cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 413 additions and 129 deletions

View File

@ -135,7 +135,6 @@
7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E1271E743B00848B49 /* OWSSounds.swift */; };
7B1D74AA27BCC16E0030B423 /* NSENotificationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */; };
7B1D74AC27BDE7510030B423 /* Promise+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */; };
7B1D74AE27C346220030B423 /* UnreadMentionMigtation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */; };
7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */; };
7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; };
7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; };
@ -1130,7 +1129,6 @@
7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = "<group>"; };
7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSENotificationPresenter.swift; sourceTree = "<group>"; };
7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Timeout.swift"; sourceTree = "<group>"; };
7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMentionMigtation.swift; sourceTree = "<group>"; };
7B1D74AF27C365960030B423 /* Timer+MainThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timer+MainThread.swift"; sourceTree = "<group>"; };
7B2DB2AD26F1B0FF0035B509 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = "<group>"; };
7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = "<group>"; };
@ -3070,7 +3068,6 @@
isa = PBXGroup;
children = (
B8B32044258C117C0020074B /* ContactsMigration.swift */,
7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */,
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */,
C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */,
C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */,
@ -4615,7 +4612,6 @@
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */,
7B1D74AE27C346220030B423 /* UnreadMentionMigtation.swift in Sources */,
B8F5F52925EC4F8A003BF8D4 /* BlockListUIUtils.m in Sources */,
C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */,
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
@ -5189,7 +5185,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -5262,7 +5258,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -5328,7 +5324,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -5402,7 +5398,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6338,7 +6334,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -6409,7 +6405,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 324;
CURRENT_PROJECT_VERSION = 325;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",

View File

@ -613,6 +613,10 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
let updateType = conversationUpdate.conversationUpdateType
guard updateType != .minor else { return } // No view items were affected
if updateType == .reload {
if threadStartedAsMessageRequest {
updateNavBarButtons() // In case the message request was approved
}
return messagesTableView.reloadData()
}
var shouldScrollToBottom = false
@ -633,6 +637,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .none)
default: preconditionFailure()
}
// Update the nav items if the message request was approved
if (update.viewItem?.interaction as? TSInfoMessage)?.messageType == .messageRequestAccepted {
self.updateNavBarButtons()
}
}
}
UIView.performWithoutAnimation {

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "warning.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,125 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 9.791016 13.111328 cm
0.000000 0.000000 0.000000 scn
13.476560 -0.000008 m
88.623062 -0.000008 l
91.389732 -0.000008 93.782394 0.602219 95.801064 1.806664 c
97.819061 3.011093 99.373398 4.630554 100.464066 6.665062 c
101.554733 8.699562 102.100060 10.970070 102.100060 13.476585 c
102.100060 14.583359 101.945396 15.706406 101.636063 16.845726 c
101.326729 17.985054 100.879059 19.075554 100.293060 20.117218 c
62.646458 85.693398 l
61.376923 87.939461 59.700493 89.640297 57.617161 90.795898 c
55.533829 91.951500 53.352856 92.529297 51.074257 92.529297 c
48.795589 92.529297 46.606461 91.951500 44.506859 90.795898 c
42.407257 89.640297 40.722694 87.939461 39.453159 85.693398 c
1.806660 20.068382 l
0.602220 17.985046 0.000000 15.787788 0.000000 13.476585 c
0.000000 10.970070 0.545253 8.699562 1.635759 6.665062 c
2.726226 4.630554 4.280593 3.011093 6.298860 1.806664 c
8.317060 0.602219 10.709626 -0.000008 13.476560 -0.000008 c
h
13.525359 7.666031 m
11.832692 7.666031 10.473660 8.260109 9.448260 9.448265 c
8.422860 10.636414 7.910159 11.979187 7.910159 13.476585 c
7.910159 13.932312 7.958992 14.412453 8.056659 14.917015 c
8.154325 15.421577 8.317092 15.917992 8.544959 16.406273 c
46.142559 81.982498 l
46.695957 82.926498 47.412125 83.618195 48.291058 84.057594 c
49.169926 84.497063 50.097656 84.716797 51.074257 84.716797 c
52.018257 84.716797 52.921558 84.497063 53.784157 84.057594 c
54.646824 83.618195 55.354828 82.926498 55.908161 81.982498 c
93.457062 16.357445 l
93.977730 15.445984 94.238060 14.485703 94.238060 13.476585 c
94.238060 11.979187 93.709061 10.636414 92.651062 9.448265 c
91.593063 8.260109 90.217827 7.666031 88.525360 7.666031 c
13.525359 7.666031 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 55.591797 30.201187 cm
0.000000 0.000000 0.000000 scn
5.273499 15.869133 m
7.714899 15.869133 8.951868 17.154930 8.984402 19.726532 c
9.716801 45.507832 l
9.749334 46.744831 9.334299 47.778366 8.471699 48.608433 c
7.609099 49.438499 6.526735 49.853531 5.224602 49.853531 c
3.890002 49.853531 2.807667 49.446632 1.977600 48.632832 c
1.147467 47.819031 0.748700 46.793633 0.781300 45.556633 c
1.416000 19.726532 l
1.481134 17.154930 2.766965 15.869133 5.273499 15.869133 c
h
5.273499 0.000000 m
6.673232 0.000000 7.902070 0.488285 8.960003 1.464851 c
10.017937 2.441410 10.546902 3.645840 10.546902 5.078133 c
10.546902 6.510399 10.026069 7.714832 8.984402 8.691433 c
7.942735 9.667965 6.705765 10.156235 5.273499 10.156235 c
3.841165 10.156235 2.604167 9.659832 1.562500 8.667030 c
0.520833 7.674164 0.000000 6.477867 0.000000 5.078133 c
0.000000 3.678394 0.520833 2.482101 1.562500 1.489262 c
2.604167 0.496422 3.841165 0.000000 5.273499 0.000000 c
h
f
n
Q
endstream
endobj
3 0 obj
2758
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 122.000000 119.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002848 00000 n
0000002871 00000 n
0000003046 00000 n
0000003120 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3179
%%EOF

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -628,3 +628,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -619,3 +619,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -618,3 +618,5 @@
"NEW_CONVERSATION_MENU_OPEN_GROUP" = "Open Group";
"NEW_CONVERSATION_MENU_DIRECT_MESSAGE" = "Direct Message";
"NEW_CONVERSATION_MENU_CLOSED_GROUP" = "Closed Group";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE" = "Oops, an error occurred";
"DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE" = "Please try again later";

View File

@ -161,21 +161,22 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
public func notifyUser(for incomingMessage: TSIncomingMessage, in thread: TSThread, transaction: YapDatabaseReadTransaction) {
guard !thread.isMuted else { return }
guard let threadId = thread.uniqueId else { return }
let isMessageRequest = thread.isMessageRequest(using: transaction)
// If the thread is a message request and the user hasn't hidden message requests then we need
// to check if this is the only message request thread (group threads can't be message requests
// so just ignore those and if the user has hidden message requests then we want to show the
// notification regardless of how many message requests there are)
if !thread.isGroupThread() && thread.isMessageRequest() && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
if !thread.isGroupThread() && isMessageRequest && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
let threads = transaction.ext(TSThreadDatabaseViewExtensionName) as! YapDatabaseViewTransaction
let numMessageRequests = threads.numberOfItems(inGroup: TSMessageRequestGroup)
// Allow this to show a notification if there are no message requests (ie. this is the first one)
guard numMessageRequests == 0 else { return }
}
else if thread.isMessageRequest() && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
else if isMessageRequest && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
// If there are other interactions on this thread already then don't show the notification
if thread.numberOfInteractions() > 1 { return }
if thread.numberOfInteractions(with: transaction) > 1 { return }
CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
}
@ -214,7 +215,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
case .nameNoPreview, .namePreview:
switch thread {
case is TSContactThread:
notificationTitle = (thread.isMessageRequest() ? "Session" : senderName)
notificationTitle = (isMessageRequest ? "Session" : senderName)
case is TSGroupThread:
var groupName = thread.name(with: transaction)
@ -240,7 +241,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
// If it's a message request then overwrite the body to be something generic (only show a notification
// when receiving a new message request if there aren't any others or the user had hidden them)
if thread.isMessageRequest() {
if isMessageRequest {
notificationBody = NSLocalizedString("MESSAGE_REQUESTS_NOTIFICATION", comment: "")
}

View File

@ -1,5 +1,6 @@
import PromiseKit
import NVActivityIndicatorView
import SessionUIKit
final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private let maxWidth: CGFloat
@ -32,6 +33,42 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
return result
}()
private lazy var errorView: UIView = {
let result: UIView = UIView()
result.isHidden = true
return result
}()
private lazy var errorImageView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "warning").withRenderingMode(.alwaysTemplate))
result.tintColor = Colors.destructive
return result
}()
private lazy var errorTitleLabel: UILabel = {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.mediumFontSize, weight: .medium)
result.text = "DEFAULT_OPEN_GROUP_LOAD_ERROR_TITLE".localized()
result.textColor = Colors.text
result.textAlignment = .center
result.numberOfLines = 0
return result
}()
private lazy var errorSubtitleLabel: UILabel = {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.smallFontSize, weight: .medium)
result.text = "DEFAULT_OPEN_GROUP_LOAD_ERROR_SUBTITLE".localized()
result.textColor = Colors.text
result.textAlignment = .center
result.numberOfLines = 0
return result
}()
// MARK: Settings
private static let cellHeight: CGFloat = 40
private static let separatorWidth = 1 / UIScreen.main.scale
@ -54,17 +91,40 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
private func initialize() {
addSubview(collectionView)
collectionView.pin(to: self)
addSubview(spinner)
spinner.pin([ UIView.HorizontalEdge.left, UIView.VerticalEdge.top ], to: self)
spinner.pin(.top, to: .top, of: self)
spinner.center(.horizontal, in: self)
spinner.startAnimating()
addSubview(errorView)
errorView.pin(.top, to: .top, of: self, withInset: 10)
errorView.pin( [HorizontalEdge.leading, HorizontalEdge.trailing], to: self)
errorView.addSubview(errorImageView)
errorImageView.pin(.top, to: .top, of: errorView)
errorImageView.center(.horizontal, in: errorView)
errorImageView.set(.width, to: 60)
errorImageView.set(.height, to: 60)
errorView.addSubview(errorTitleLabel)
errorTitleLabel.pin(.top, to: .bottom, of: errorImageView, withInset: 10)
errorTitleLabel.center(.horizontal, in: errorView)
errorView.addSubview(errorSubtitleLabel)
errorSubtitleLabel.pin(.top, to: .bottom, of: errorTitleLabel, withInset: 20)
errorSubtitleLabel.center(.horizontal, in: errorView)
heightConstraint = set(.height, to: OpenGroupSuggestionGrid.cellHeight)
widthAnchor.constraint(greaterThanOrEqualToConstant: OpenGroupSuggestionGrid.cellHeight).isActive = true
if OpenGroupAPIV2.defaultRoomsPromise == nil {
OpenGroupAPIV2.getDefaultRoomsIfNeeded()
}
let _ = OpenGroupAPIV2.defaultRoomsPromise?.done { [weak self] rooms in
self?.rooms = rooms
}
OpenGroupAPIV2.getDefaultRoomsIfNeeded()
.done { [weak self] rooms in
self?.rooms = rooms
}
.catch { [weak self] _ in
self?.update()
}
}
// MARK: Updating
@ -75,6 +135,7 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
let height = OpenGroupSuggestionGrid.cellHeight * ceil(CGFloat(roomCount) / 2)
heightConstraint.constant = height
collectionView.reloadData()
errorView.isHidden = (roomCount > 0)
}
// MARK: Layout
@ -173,8 +234,22 @@ extension OpenGroupSuggestionGrid {
private func update() {
guard let room = room else { return }
let promise = OpenGroupAPIV2.getGroupImage(for: room.id, on: OpenGroupAPIV2.defaultServer)
imageView.image = given(promise.value) { UIImage(data: $0)! }
imageView.isHidden = (imageView.image == nil)
if let imageData: Data = promise.value {
imageView.image = UIImage(data: imageData)
imageView.isHidden = (imageView.image == nil)
}
else {
imageView.isHidden = true
_ = promise.done { [weak self] imageData in
DispatchQueue.main.async {
self?.imageView.image = UIImage(data: imageData)
self?.imageView.isHidden = (self?.imageView.image == nil)
}
}
}
label.text = room.name
}
}

View File

@ -239,7 +239,6 @@ final class ConversationCell : UITableViewCell {
// Contact
if threadViewModel.isGroupThread, let thread = threadViewModel.threadRecord as? TSGroupThread {
displayNameLabel.attributedText = getHighlightedSnippet(snippet: getDisplayName(), searchText: normalizedSearchText, fontSize: Values.mediumFontSize)
bottomLabelStackView.isHidden = false
let context: Contact.Context = thread.isOpenGroup ? .openGroup : .regular
var rawSnippet: String = ""
thread.groupModel.groupMemberIds.forEach{ id in
@ -252,7 +251,12 @@ final class ConversationCell : UITableViewCell {
}
}
}
snippetLabel.attributedText = getHighlightedSnippet(snippet: rawSnippet, searchText: normalizedSearchText, fontSize: Values.smallFontSize)
if rawSnippet.isEmpty {
bottomLabelStackView.isHidden = true
} else {
bottomLabelStackView.isHidden = false
snippetLabel.attributedText = getHighlightedSnippet(snippet: rawSnippet, searchText: normalizedSearchText, fontSize: Values.smallFontSize)
}
} else {
displayNameLabel.attributedText = getHighlightedSnippet(snippet: getDisplayNameForSearch(threadViewModel.contactSessionID!), searchText: normalizedSearchText, fontSize: Values.mediumFontSize)
bottomLabelStackView.isHidden = true

View File

@ -173,6 +173,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]];
[TSDatabaseView asyncRegisterUnseenDatabaseView:self];
[TSDatabaseView asyncRegisterUnreadMentionDatabaseView:self];
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self];
[FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self];

View File

@ -22,6 +22,7 @@ extern NSString *const TSMessageDatabaseViewExtensionName_Legacy;
extern NSString *const TSUnreadDatabaseViewExtensionName;
extern NSString *const TSUnseenDatabaseViewExtensionName;
extern NSString *const TSUnreadMentionDatabaseViewExtensionName;
extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName;
extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName;
@ -66,6 +67,11 @@ extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName;
// Instances of OWSReadTracking for wasRead is NO.
+ (void)asyncRegisterUnseenDatabaseView:(OWSStorage *)storage;
// Should be used for "mention indicator".
//
// Instances of OWSReadTracking for wasRead is NO and isUserMentioned is YES.
+ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage;
+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage;
@end

View File

@ -47,6 +47,7 @@ NSString *const TSMessageDatabaseViewExtensionName_Legacy = @"TSMessageDatabaseV
NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName";
NSString *const TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
NSString *const TSUnreadMentionDatabaseViewExtensionName = @"TSUnreadMentionDatabaseViewExtensionName";
NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName";
NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName
@ -134,6 +135,25 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
storage:storage];
}
+ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if ([object isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *message = (TSIncomingMessage *)object;
if (!message.wasRead && message.isUserMentioned) {
return message.uniqueThreadId;
}
}
return nil;
}];
[self registerMessageDatabaseViewWithName:TSUnreadMentionDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"
storage:storage];
}
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage
{
YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy];
@ -287,7 +307,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
}
TSThread *thread = (TSThread *)object;
if (thread.isMessageRequest) {
if ([thread isMessageRequestUsingTransaction:transaction]) {
return nil;
}
else {

View File

@ -55,17 +55,16 @@ extension ConfigurationMessage {
return (
// Skip the current user
contact.sessionID != currentUserPublicKey && (
contact.sessionID != currentUserPublicKey &&
// Contacts which have visible threads
TSContactThread.fetch(uniqueId: threadID, transaction: transaction)?.shouldBeVisible == true && (
// Include already approved contacts
contact.isApproved ||
contact.didApproveMe ||
// Sync blocked contacts
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID) ||
// Contacts which have visible threads (sanity check - should be included as already approved)
TSContactThread.fetch(uniqueId: threadID, transaction: transaction)?.shouldBeVisible == true
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID)
)
)
}

View File

@ -14,6 +14,6 @@ extension OpenGroupAPIV2 {
@objc(getDefaultRoomsIfNeeded)
public static func objc_getDefaultRoomsIfNeeded() {
return getDefaultRoomsIfNeeded()
getDefaultRoomsIfNeeded()
}
}

View File

@ -422,21 +422,37 @@ public final class OpenGroupAPIV2 : NSObject {
}
// MARK: General
public static func getDefaultRoomsIfNeeded() {
@discardableResult public static func getDefaultRoomsIfNeeded() -> Promise<[OpenGroupAPIV2.Info]> {
if let existingPromise: Promise<[OpenGroupAPIV2.Info]> = defaultRoomsPromise {
return existingPromise
}
let (promise, seal) = Promise<[OpenGroupAPIV2.Info]>.pending()
Storage.shared.write(with: { transaction in
Storage.shared.setOpenGroupPublicKey(for: defaultServer, to: defaultServerPublicKey, using: transaction)
}, completion: {
let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
let internalPromise: Promise<[OpenGroupAPIV2.Info]> = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
OpenGroupAPIV2.getAllRooms(from: defaultServer)
}
let _ = promise.done(on: OpenGroupAPIV2.workQueue) { items in
items.forEach { getGroupImage(for: $0.id, on: defaultServer).retainUntilComplete() }
}
promise.catch(on: OpenGroupAPIV2.workQueue) { _ in
OpenGroupAPIV2.defaultRoomsPromise = nil
}
defaultRoomsPromise = promise
internalPromise
.done(on: OpenGroupAPIV2.workQueue) { items in
items.forEach { getGroupImage(for: $0.id, on: defaultServer).retainUntilComplete() }
seal.fulfill(items)
}
.retainUntilComplete()
internalPromise
.catch(on: OpenGroupAPIV2.workQueue) { error in
OpenGroupAPIV2.defaultRoomsPromise = nil
seal.reject(error)
}
})
defaultRoomsPromise = promise
return promise
}
public static func getInfo(for room: String, on server: String) -> Promise<Info> {

View File

@ -30,6 +30,15 @@ public final class OpenGroupManagerV2 : NSObject {
// MARK: Adding & Removing
public func add(room: String, server: String, publicKey: String, using transaction: Any) -> Promise<Void> {
// If we are currently polling for this server and already have a TSGroupThread for this room the do nothing
let transaction = transaction as! YapDatabaseReadWriteTransaction
let groupId: Data = LKGroupUtilities.getEncodedOpenGroupIDAsData("\(server).\(room)")
if OpenGroupManagerV2.shared.pollers[server] != nil && TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupId), transaction: transaction) != nil {
SNLog("Ignoring join open group attempt (already joined)")
return Promise.value(())
}
let storage = Storage.shared
// Clear any existing data if needed
storage.removeLastMessageServerID(for: room, on: server, using: transaction)
@ -38,7 +47,7 @@ public final class OpenGroupManagerV2 : NSObject {
// Store the public key
storage.setOpenGroupPublicKey(for: server, to: publicKey, using: transaction)
let (promise, seal) = Promise<Void>.pending()
let transaction = transaction as! YapDatabaseReadWriteTransaction
transaction.addCompletionQueue(DispatchQueue.global(qos: .userInitiated)) {
// Get the group info
OpenGroupAPIV2.getInfo(for: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { info in

View File

@ -211,7 +211,7 @@ extension MessageReceiver {
// Contacts
for contactInfo in message.contacts {
let sessionID = contactInfo.publicKey!
let contact = Contact(sessionID: sessionID)
let contact = (Storage.shared.getContact(with: sessionID, using: transaction) ?? Contact(sessionID: sessionID))
if let profileKey = contactInfo.profileKey { contact.profileEncryptionKey = OWSAES256Key(data: profileKey) }
contact.profilePictureURL = contactInfo.profilePictureURL
contact.name = contactInfo.displayName
@ -417,11 +417,7 @@ extension MessageReceiver {
// Use the same identifier for notifications when in backgroud polling to prevent spam
let notificationIdentifier = isBackgroundPoll ? thread.uniqueId : UUID().uuidString
tsIncomingMessage.setNotificationIdentifier(notificationIdentifier, transaction: transaction)
DispatchQueue.main.async {
Storage.read { transaction in
SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction)
}
}
SSKEnvironment.shared.notificationsManager!.notifyUser(for: tsIncomingMessage, in: thread, transaction: transaction)
return tsMessageID
}

View File

@ -287,10 +287,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE
for (id<OWSReadTracking> readItem in newlyReadList) {
[readItem markAsReadAtTimestamp:readTimestamp trySendReadReceipt:trySendReadReceipt transaction:transaction];
}
// Update unread mention.
thread.hasUnreadMentionMessage = false;
[thread saveWithTransaction:transaction];
}
#pragma mark - Settings

View File

@ -16,7 +16,6 @@ BOOL IsNoteToSelfEnabled(void);
*/
@interface TSThread : TSYapDatabaseObject
@property (nonatomic) BOOL hasUnreadMentionMessage;
@property (nonatomic) BOOL isPinned;
@property (nonatomic) BOOL shouldBeVisible;
@property (nonatomic, readonly) NSDate *creationDate;
@ -67,9 +66,18 @@ BOOL IsNoteToSelfEnabled(void);
*/
- (NSUInteger)numberOfInteractions;
- (NSUInteger)numberOfInteractionsWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction
NS_SWIFT_NAME(unreadMessageCount(transaction:));
/**
* @return If there is any message mentioning current user in this thread.
*/
- (NSUInteger)unreadMentionMessageCount;
- (NSUInteger)unreadMentionMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
/**

View File

@ -233,12 +233,17 @@ BOOL IsNoteToSelfEnabled(void)
{
__block NSUInteger count;
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
count = [interactionsByThread numberOfItemsInGroup:self.uniqueId];
count = [self numberOfInteractionsWithTransaction:transaction];
}];
return count;
}
- (NSUInteger)numberOfInteractionsWithTransaction:(YapDatabaseReadTransaction *)transaction
{
YapDatabaseViewTransaction *interactionsByThread = [transaction ext:TSMessageDatabaseViewExtensionName];
return [interactionsByThread numberOfItemsInGroup:self.uniqueId];
}
- (NSArray<id<OWSReadTracking>> *)unseenMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction
{
NSMutableArray<id<OWSReadTracking>> *messages = [NSMutableArray new];
@ -285,14 +290,27 @@ BOOL IsNoteToSelfEnabled(void)
// return count;
}
- (NSUInteger)unreadMentionMessageCount
{
__block NSUInteger unreadMentionMessageCount;
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
unreadMentionMessageCount = [self unreadMentionMessageCountWithTransaction:transaction];
}];
return unreadMentionMessageCount;
}
- (NSUInteger)unreadMentionMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction
{
YapDatabaseViewTransaction *unreadMentions = [transaction ext:TSUnreadMentionDatabaseViewExtensionName];
return [unreadMentions numberOfItemsInGroup:self.uniqueId];
}
- (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
for (id<OWSReadTracking> message in [self unseenMessagesWithTransaction:transaction]) {
[message markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] trySendReadReceipt:YES transaction:transaction];
}
// Update unread mention.
self.hasUnreadMentionMessage = false;
[super saveWithTransaction:transaction];
}
@ -359,12 +377,6 @@ BOOL IsNoteToSelfEnabled(void)
_lastInteractionDate = lastMessage.receivedAtDate;
[super saveWithTransaction:transaction];
}
// Update unread mention if there is a new incoming message.
if ([lastMessage isKindOfClass:[TSIncomingMessage class]] && ((TSIncomingMessage *)lastMessage).isUserMentioned) {
self.hasUnreadMentionMessage = true;
[super saveWithTransaction:transaction];
}
if (!self.shouldBeVisible) {
self.shouldBeVisible = YES;

View File

@ -22,7 +22,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
}
else if thread.isMessageRequest() && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
// If there are other interactions on this thread already then don't show the notification
if thread.numberOfInteractions() > 1 { return }
if thread.numberOfInteractions(with: transaction) > 1 { return }
CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
}
@ -86,6 +86,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
// If it's a message request then overwrite the body to be something generic (only show a notification
// when receiving a new message request if there aren't any others or the user had hidden them)
if thread.isMessageRequest() {
notificationContent.title = "Session"
notificationContent.body = "MESSAGE_REQUESTS_NOTIFICATION".localized()
}

View File

@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
- (NSArray<OWSDatabaseMigration *> *)allMigrations
{
return @[
[SNUnreadMentionMigration new],
[SNMessageRequestsMigration new],
[SNContactsMigration new]
];

View File

@ -1,41 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
@objc(SNUnreadMentionMigration)
public class UnreadMentionMigration : OWSDatabaseMigration {
@objc
class func migrationId() -> String {
return "003" // leave "002" for message request migration
}
override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) {
self.doMigrationAsync(completion: completion)
}
private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) {
var threads: [TSThread] = []
Storage.read { transaction in
TSThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSThread, let threadID = thread.uniqueId else { return }
let unreadMessages = transaction.ext(TSUnreadDatabaseViewExtensionName) as! YapDatabaseViewTransaction
unreadMessages.enumerateKeysAndObjects(inGroup: threadID) { collection, key, object, index, stop in
guard let unreadMessage = object as? TSIncomingMessage else { return }
if unreadMessage.wasRead { return }
if unreadMessage.isUserMentioned {
thread.hasUnreadMentionMessage = true
stop.pointee = true
}
}
threads.append(thread)
}
}
Storage.write(with: { transaction in
threads.forEach { thread in
thread.save(with: transaction)
}
self.save(with: transaction) // Intentionally capture self
}, completion: {
completion()
})
}
}

View File

@ -81,25 +81,12 @@ NS_ASSUME_NONNULL_BEGIN
BOOL isGroupThread = thread.isGroupThread;
[unreadMessages enumerateKeysAndObjectsInGroup:groupID
usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) {
if (![object conformsToProtocol:@protocol(OWSReadTracking)]) {
return;
}
id<OWSReadTracking> unread = (id<OWSReadTracking>)object;
if (unread.read) {
NSLog(@"Found an already read message in the * unread * messages list.");
return;
}
// We have to filter those unread messages for groups that only notifiy for mentions
if ([object isKindOfClass:TSIncomingMessage.class] && isGroupThread) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)object;
if (((TSGroupThread *)thread).isOnlyNotifyingForMentions && !incomingMessage.isUserMentioned) {
return;
}
}
count += 1;
}];
// For groups that only notifiy for mentions
if (isGroupThread && ((TSGroupThread *)thread).isOnlyNotifyingForMentions) {
count += [thread unreadMentionMessageCountWithTransaction:transaction];
} else {
count += [thread unreadMessageCountWithTransaction:transaction];
}
}
}];

View File

@ -52,7 +52,7 @@ public class ThreadViewModel: NSObject {
self.unreadCount = thread.unreadMessageCount(transaction: transaction)
self.hasUnreadMessages = unreadCount > 0
self.hasUnreadMentions = thread.hasUnreadMentionMessage
self.hasUnreadMentions = thread.unreadMentionMessageCount(with: transaction) > 0
}
@objc

View File

@ -8,7 +8,17 @@ public final class Identicon : NSObject {
if content.count > 2 && content.hasPrefix("05") {
content.removeFirst(2)
}
let layer = icon.generateLayer(with: size, text: content.substring(to: 1))
let initials: String = content
.split(separator: " ")
.compactMap { word in word.first.map { String($0) } }
.joined()
let layer = icon.generateLayer(
with: size,
text: (initials.count >= 2 ?
initials.substring(to: 2).uppercased() :
content.substring(to: 2).uppercased()
)
)
let rect = CGRect(origin: CGPoint.zero, size: layer.frame.size)
let renderer = UIGraphicsImageRenderer(size: rect.size)
return renderer.image { layer.render(in: $0.cgContext) }

View File

@ -37,7 +37,6 @@ public class PlaceholderIcon {
}
private func getTextLayer(with diameter: CGFloat, colour: CGColor? = nil, text: String) -> CALayer {
let text = text.capitalized
let font = UIFont.boldSystemFont(ofSize: diameter / 2)
let height = NSString(string: text).boundingRect(with: CGSize(width: diameter, height: CGFloat.greatestFiniteMagnitude),
options: .usesLineFragmentOrigin, attributes: [ NSAttributedString.Key.font : font ], context: nil).height