diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index b8afd5b76..e61bc81a7 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -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 */; }; @@ -1218,7 +1217,6 @@ 7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = ""; }; 7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSENotificationPresenter.swift; sourceTree = ""; }; 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Timeout.swift"; sourceTree = ""; }; - 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMentionMigtation.swift; sourceTree = ""; }; 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timer+MainThread.swift"; sourceTree = ""; }; 7B2DB2AD26F1B0FF0035B509 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = ""; }; 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; @@ -3271,7 +3269,6 @@ isa = PBXGroup; children = ( B8B32044258C117C0020074B /* ContactsMigration.swift */, - 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */, FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */, FD0BA51C27CDC34600CC6805 /* SOGSV4Migration.swift */, C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, @@ -5158,7 +5155,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 */, @@ -5827,7 +5823,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5900,7 +5896,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5966,7 +5962,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -6040,7 +6036,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6976,7 +6972,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7047,7 +7043,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 322; + CURRENT_PROJECT_VERSION = 325; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index e22525811..e4e1f471c 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -622,6 +622,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 @@ -642,6 +646,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 { diff --git a/Session/Meta/Images.xcassets/Session/warning.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/warning.imageset/Contents.json new file mode 100644 index 000000000..0b55f782a --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/warning.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "warning.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/warning.imageset/warning.pdf b/Session/Meta/Images.xcassets/Session/warning.imageset/warning.pdf new file mode 100644 index 000000000..80fc5e25f --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/warning.imageset/warning.pdf @@ -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 \ No newline at end of file diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 191df72c7..7b49db844 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 4152f23ad..4bbd9ab35 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -630,3 +630,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"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 882168f97..d9953348d 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 5d203e3f1..49f09d1b7 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index a964f7b10..922f8801f 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index a46436ab6..779033e2b 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index 50dc8836e..841191470 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 4b3cc4f92..790b03294 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index d37981455..3465c5ba0 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 84830091a..8d546e68a 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index a9ab4de29..a6ad2cd88 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index f1dd572ba..b01291b78 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 6b7fc5195..0a367870c 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 17d977882..feb610949 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 1694788c1..e4fc5c53a 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index ec4d12dd6..88831290c 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -621,3 +621,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"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 3aea597db..d9c33e232 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index dd873fce6..7e099ee72 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index b39834963..51fbf50fe 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index fa1a72c4d..e9ea519d0 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 871282699..ddd0aedda 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index aa5bc4a74..fcd1c1310 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -620,3 +620,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"; diff --git a/Session/Notifications/AppNotifications.swift b/Session/Notifications/AppNotifications.swift index c4118e3a6..1c68a4d06 100644 --- a/Session/Notifications/AppNotifications.swift +++ b/Session/Notifications/AppNotifications.swift @@ -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: "") } diff --git a/Session/Open Groups/OpenGroupSuggestionGrid.swift b/Session/Open Groups/OpenGroupSuggestionGrid.swift index 90c807ba6..7aedb8374 100644 --- a/Session/Open Groups/OpenGroupSuggestionGrid.swift +++ b/Session/Open Groups/OpenGroupSuggestionGrid.swift @@ -1,8 +1,9 @@ import PromiseKit import NVActivityIndicatorView import SessionMessagingKit +import SessionUIKit -final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { +final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { private let maxWidth: CGFloat private var rooms: [OpenGroupAPI.Room] = [] { didSet { update() } } private var heightConstraint: NSLayoutConstraint! @@ -10,6 +11,9 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl // MARK: - UI + private static let cellHeight: CGFloat = 40 + private static let separatorWidth = 1 / UIScreen.main.scale + private lazy var layout: UICollectionViewFlowLayout = { let result = UICollectionViewFlowLayout() result.minimumLineSpacing = 0 @@ -33,11 +37,42 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl result.set(.height, to: OpenGroupSuggestionGrid.cellHeight) 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 + }() - // MARK: - Settings + 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 static let cellHeight: CGFloat = 40 - private static let separatorWidth = 1 / UIScreen.main.scale + 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: - Initialization @@ -58,16 +93,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 OpenGroupManager.getDefaultRoomsIfNeeded() - _ = OpenGroupManager.shared.cache.defaultRoomsPromise?.done { [weak self] rooms in - self?.rooms = rooms - } + .done { [weak self] rooms in + self?.rooms = rooms + } + .catch { [weak self] _ in + self?.update() + } } // MARK: - Updating @@ -79,6 +138,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 @@ -183,13 +243,27 @@ extension OpenGroupSuggestionGrid { label.text = room.name - if let imageId: UInt64 = room.imageId { - let promise = OpenGroupManager.roomImage(imageId, for: room.token, on: OpenGroupAPI.defaultServer) - imageView.image = given(promise.value) { UIImage(data: $0)! } + // Only continue if we have a room image + guard let imageId: UInt64 = room.imageId else { + imageView.isHidden = true + return + } + + let promise = OpenGroupManager.roomImage(imageId, for: room.token, on: OpenGroupAPI.defaultServer) + + 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) + } + } } } } diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 3150b60c6..760b2326f 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -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 diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m index b4852c07a..338058af9 100644 --- a/SessionMessagingKit/Database/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -173,6 +173,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]]; [TSDatabaseView asyncRegisterUnseenDatabaseView:self]; + [TSDatabaseView asyncRegisterUnreadMentionDatabaseView:self]; [TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self]; [FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self]; diff --git a/SessionMessagingKit/Database/TSDatabaseView.h b/SessionMessagingKit/Database/TSDatabaseView.h index b4484abee..817347368 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.h +++ b/SessionMessagingKit/Database/TSDatabaseView.h @@ -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 diff --git a/SessionMessagingKit/Database/TSDatabaseView.m b/SessionMessagingKit/Database/TSDatabaseView.m index aa7ab2837..87baf72f2 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.m +++ b/SessionMessagingKit/Database/TSDatabaseView.m @@ -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 { diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift index 7bc727311..bd13ad885 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift @@ -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) ) ) } diff --git a/SessionMessagingKit/Messages/Signal/TSInfoMessage.h b/SessionMessagingKit/Messages/Signal/TSInfoMessage.h index d04ce1d6e..627afc492 100644 --- a/SessionMessagingKit/Messages/Signal/TSInfoMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSInfoMessage.h @@ -16,7 +16,7 @@ typedef NS_ENUM(NSInteger, TSInfoMessageType) { TSInfoMessageTypeDisappearingMessagesUpdate, TSInfoMessageTypeScreenshotNotification, TSInfoMessageTypeMediaSavedNotification, - TSInfoMessageTypeMessageRequestAccepted + TSInfoMessageTypeMessageRequestAccepted = 99 }; @property (atomic, readonly) TSInfoMessageType messageType; diff --git a/SessionMessagingKit/Open Groups/OpenGroupManager.swift b/SessionMessagingKit/Open Groups/OpenGroupManager.swift index 58850f33a..8e096e5fb 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManager.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManager.swift @@ -527,10 +527,14 @@ public final class OpenGroupManager: NSObject { } } - public static func getDefaultRoomsIfNeeded(using dependencies: Dependencies = Dependencies()) { + @discardableResult public static func getDefaultRoomsIfNeeded(using dependencies: Dependencies = Dependencies()) -> Promise<[OpenGroupAPI.Room]> { // Note: If we already have a 'defaultRoomsPromise' then there is no need to get it again - guard OpenGroupManager.shared.cache.defaultRoomsPromise == nil else { return } + if let existingPromise: Promise<[OpenGroupAPI.Room]> = OpenGroupManager.shared.cache.defaultRoomsPromise { + return existingPromise + } + let (promise, seal) = Promise<[OpenGroupAPI.Room]>.pending() + dependencies.storage.write( with: { transaction in dependencies.storage.setOpenGroupPublicKey( @@ -540,13 +544,11 @@ public final class OpenGroupManager: NSObject { ) }, completion: { - OpenGroupManager.shared.mutableCache.mutate { cache in - cache.defaultRoomsPromise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) { - OpenGroupAPI.rooms(for: OpenGroupAPI.defaultServer, using: dependencies) - .map { _, data in data } - } + let internalPromise: Promise<[OpenGroupAPI.Room]> = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) { + OpenGroupAPI.rooms(for: OpenGroupAPI.defaultServer, using: dependencies) + .map { _, data in data } } - OpenGroupManager.shared.cache.defaultRoomsPromise? + internalPromise .done(on: OpenGroupAPI.workQueue) { items in items .compactMap { room -> (UInt64, String)? in @@ -558,14 +560,25 @@ public final class OpenGroupManager: NSObject { roomImage(imageId, for: roomToken, on: OpenGroupAPI.defaultServer, using: dependencies) .retainUntilComplete() } + seal.fulfill(items) } - .catch(on: OpenGroupAPI.workQueue) { _ in + .retainUntilComplete() + + internalPromise + .catch(on: OpenGroupAPI.workQueue) { error in OpenGroupManager.shared.mutableCache.mutate { cache in cache.defaultRoomsPromise = nil } + seal.reject(error) } } ) + + OpenGroupManager.shared.mutableCache.mutate { cache in + cache.defaultRoomsPromise = promise + } + + return promise } public static func roomImage( @@ -638,6 +651,6 @@ public final class OpenGroupManager: NSObject { extension OpenGroupManager { @objc(getDefaultRoomsIfNeeded) public static func objc_getDefaultRoomsIfNeeded() { - return getDefaultRoomsIfNeeded() + getDefaultRoomsIfNeeded() } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index a09711615..baf2beeb4 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -192,6 +192,7 @@ extension MessageReceiver { SNLog("Configuration message received.") let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction + let isInitialSync: Bool = (!UserDefaults.standard[.hasSyncedInitialConfiguration]) let messageSentTimestamp: TimeInterval = TimeInterval((message.sentTimestamp ?? 0) / 1000) // `sentTimestamp` is in ms let lastConfigTimestamp: TimeInterval = (UserDefaults.standard[.lastConfigurationSync]?.timeIntervalSince1970 ?? Date(timeIntervalSince1970: 0).timeIntervalSince1970) @@ -201,8 +202,8 @@ extension MessageReceiver { updateProfileIfNeeded(publicKey: userPublicKey, name: message.displayName, profilePictureURL: message.profilePictureURL, profileKey: userProfileKey, sentTimestamp: message.sentTimestamp!, transaction: transaction) - if !UserDefaults.standard[.hasSyncedInitialConfiguration] || messageSentTimestamp > lastConfigTimestamp { - if !UserDefaults.standard[.hasSyncedInitialConfiguration] { + if isInitialSync || messageSentTimestamp > lastConfigTimestamp { + if isInitialSync { UserDefaults.standard[.hasSyncedInitialConfiguration] = true NotificationCenter.default.post(name: .initialConfigurationMessageReceived, object: nil) } @@ -212,7 +213,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 @@ -259,13 +260,21 @@ extension MessageReceiver { } // Closed groups - let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() - for closedGroup in message.closedGroups { - guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } - handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, - members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: closedGroup.expirationTimer, - messageSentTimestamp: message.sentTimestamp!, using: transaction) + // + // Note: Only want to add these for initial sync to avoid re-adding closed groups the user + // intentionally left (any closed groups joined since the first processed sync message should + // get added via the 'handleNewClosedGroup' method anyway as they will have come through in the + // past two weeks) + if isInitialSync { + let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() + for closedGroup in message.closedGroups { + guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } + handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, + members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: closedGroup.expirationTimer, + messageSentTimestamp: message.sentTimestamp!, using: transaction) + } } + // Open groups for openGroupURL in message.openGroups { if let (room, server, publicKey) = OpenGroupManager.parseV2OpenGroup(from: openGroupURL) { @@ -410,11 +419,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 } diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index e9ecae6e0..4517e2be4 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -287,10 +287,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE for (id readItem in newlyReadList) { [readItem markAsReadAtTimestamp:readTimestamp trySendReadReceipt:trySendReadReceipt transaction:transaction]; } - - // Update unread mention. - thread.hasUnreadMentionMessage = false; - [thread saveWithTransaction:transaction]; } #pragma mark - Settings diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index 0542b390a..9a925a177 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -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; /** diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index a848527bc..3311f5705 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -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> *)unseenMessagesWithTransaction:(YapDatabaseReadTransaction *)transaction { NSMutableArray> *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 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; diff --git a/SessionNotificationServiceExtension/NSENotificationPresenter.swift b/SessionNotificationServiceExtension/NSENotificationPresenter.swift index ea04e9975..6e330b94a 100644 --- a/SessionNotificationServiceExtension/NSENotificationPresenter.swift +++ b/SessionNotificationServiceExtension/NSENotificationPresenter.swift @@ -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() } diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m index ae9f58f11..a7d38515a 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m @@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)allMigrations { return @[ - [SNUnreadMentionMigration new], [SNMessageRequestsMigration new], [SNContactsMigration new] ]; diff --git a/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift b/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift deleted file mode 100644 index c23c327fb..000000000 --- a/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift +++ /dev/null @@ -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() - }) - } -} diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m index d0facfff8..cbc703c91 100644 --- a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m +++ b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m @@ -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 unread = (id)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]; + } } }]; diff --git a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift index d68bf7d75..12bcfd560 100644 --- a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift +++ b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift @@ -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 diff --git a/SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift b/SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift index 07a3f00cf..28345aa6a 100644 --- a/SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift +++ b/SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift @@ -8,7 +8,17 @@ public final class Identicon : NSObject { if content.count > 2 && SessionId.Prefix(from: content) != nil { 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) } diff --git a/SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift b/SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift index 2e763c2e7..450fcbcb4 100644 --- a/SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift +++ b/SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift @@ -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