From 185f6ab269a49ad817c9721626ea862c63bf7b9a Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 22 Jul 2022 15:20:18 +1000 Subject: [PATCH 01/50] remove text from quote protobuf --- Podfile.lock | 2 +- .../Message Cells/Content Views/QuoteView.swift | 1 - Session/Meta/Translations/en.lproj/Localizable.strings | 1 + SessionMessagingKit/Database/Models/Quote.swift | 5 +---- .../Messages/Visible Messages/VisibleMessage+Quote.swift | 1 - 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 70045a1da..bab1ae426 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -232,4 +232,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 6ab902a81a379cc2c0a9a92c334c78d413190338 -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2 diff --git a/Session/Conversations/Message Cells/Content Views/QuoteView.swift b/Session/Conversations/Message Cells/Content Views/QuoteView.swift index 2a47a91d9..b6558ab0c 100644 --- a/Session/Conversations/Message Cells/Content Views/QuoteView.swift +++ b/Session/Conversations/Message Cells/Content Views/QuoteView.swift @@ -186,7 +186,6 @@ final class QuoteView: UIView { } }() let bodyLabel = UILabel() - bodyLabel.numberOfLines = 0 bodyLabel.lineBreakMode = .byTruncatingTail let isOutgoing = (direction == .outgoing) diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 70292f244..956dc193d 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index 9ac83853c..faa8bee1a 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -100,11 +100,8 @@ public extension Quote { if let quotedInteraction: Interaction = quotedInteraction, quotedInteraction.body?.isEmpty == false { self.body = quotedInteraction.body } - else if let body: String = quoteProto.text, !body.isEmpty { - self.body = body - } else { - self.body = nil + self.body = "QUOTED_MESSAGE_NOT_FOUND".localized() } // We only use the first attachment diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index fdd50732c..2c30d72d0 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -44,7 +44,6 @@ public extension VisibleMessage { return nil } let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) - if let text = text { quoteProto.setText(text) } addAttachmentsIfNeeded(db, to: quoteProto) do { return try quoteProto.build() From cf961d173dd599499c0f5bcfc85a745b51a41933 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 25 Jul 2022 15:04:55 +1000 Subject: [PATCH 02/50] add text back for smooth migration --- .../Messages/Visible Messages/VisibleMessage+Quote.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index 2c30d72d0..fdd50732c 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -44,6 +44,7 @@ public extension VisibleMessage { return nil } let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) + if let text = text { quoteProto.setText(text) } addAttachmentsIfNeeded(db, to: quoteProto) do { return try quoteProto.build() From 6b4dba0908dda4c64a72a1214258c190a1e49ec1 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 25 Jul 2022 16:10:53 +1000 Subject: [PATCH 03/50] redo quote from proto --- SessionMessagingKit/Database/Models/Quote.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index faa8bee1a..2e7a3ce83 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -97,11 +97,20 @@ public extension Quote { .filter(Interaction.Columns.timestampMs == Double(quoteProto.id)) .fetchOne(db) + guard quotedInteraction != nil else { + self.body = "QUOTED_MESSAGE_NOT_FOUND".localized() + self.attachmentId = nil + return + } + if let quotedInteraction: Interaction = quotedInteraction, quotedInteraction.body?.isEmpty == false { self.body = quotedInteraction.body } + else if let body: String = quoteProto.text, !body.isEmpty { + self.body = body + } else { - self.body = "QUOTED_MESSAGE_NOT_FOUND".localized() + self.body = nil } // We only use the first attachment From 83b40915a161a093e5d2bef0d20cb0f00a674a74 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 26 Jul 2022 16:23:54 +1000 Subject: [PATCH 04/50] remove quote content when original message is removed --- .../ConversationVC+Interaction.swift | 21 +++++++++++++++++++ .../Database/Models/Quote.swift | 15 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 33dfce0fb..0d272ee29 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1075,6 +1075,13 @@ extension ConversationVC: .done { _ in // Delete the interaction (and associated data) from the database Storage.shared.writeAsync { db in + try Quote + .updateBeforeQuotedInterationDeletion( + db, + timestampMs: cellViewModel.timestampMs, + authorId: cellViewModel.authorId + ) + _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) @@ -1155,6 +1162,13 @@ extension ConversationVC: // For incoming interactions or interactions with no serverHash just delete them locally guard cellViewModel.variant == .standardOutgoing, let serverHash: String = serverHash else { Storage.shared.writeAsync { db in + try Quote + .updateBeforeQuotedInterationDeletion( + db, + timestampMs: cellViewModel.timestampMs, + authorId: cellViewModel.authorId + ) + _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) @@ -1178,6 +1192,13 @@ extension ConversationVC: let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) alertVC.addAction(UIAlertAction(title: "delete_message_for_me".localized(), style: .destructive) { [weak self] _ in Storage.shared.writeAsync { db in + try Quote + .updateBeforeQuotedInterationDeletion( + db, + timestampMs: cellViewModel.timestampMs, + authorId: cellViewModel.authorId + ) + _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index 2e7a3ce83..b6ba5b39f 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -76,6 +76,21 @@ public struct Quote: Codable, Equatable, Hashable, FetchableRecord, PersistableR } } +public extension Quote { + /// This method updates the all Quotes before the quoted interation is deleted + /// + static func updateBeforeQuotedInterationDeletion(_ db: Database, timestampMs: Int64, authorId: String) throws { + try Quote + .filter(Columns.authorId == authorId) + .filter(Columns.timestampMs == timestampMs) + .updateAll( + db, + Columns.body.set(to: "QUOTED_MESSAGE_NOT_FOUND".localized()), + Columns.attachmentId.set(to: nil) + ) + } +} + // MARK: - Protobuf public extension Quote { From 170ac8a498a170cc9d0be0626013bed6bbf3c4ad Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 27 Jul 2022 10:47:50 +1000 Subject: [PATCH 05/50] add observer to refresh UI when quoted message is deleted --- Session/Conversations/ConversationViewModel.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index 28bf921a7..45966586c 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -192,6 +192,16 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { return SQL("LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(interaction[.authorId])") }() + ), + PagedData.ObservedChanges( + table: Quote.self, + columns: [.body], + joinToPagedType: { + let interaction: TypedTableAlias = TypedTableAlias() + let quote: TypedTableAlias = TypedTableAlias() + + return SQL("LEFT JOIN \(Quote.self) ON \(quote[.interactionId]) = \(interaction[.id])") + }() ) ], filterSQL: MessageViewModel.filterSQL(threadId: threadId), From 4d66d3fea52d61c30dd5b4b314cf9aecf262c0f1 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 27 Jul 2022 10:48:34 +1000 Subject: [PATCH 06/50] observe attachment change as well --- Session/Conversations/ConversationViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index 45966586c..9261160a9 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -195,7 +195,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { ), PagedData.ObservedChanges( table: Quote.self, - columns: [.body], + columns: [.body, .attachmentId], joinToPagedType: { let interaction: TypedTableAlias = TypedTableAlias() let quote: TypedTableAlias = TypedTableAlias() From 01be564649c49f118de72c9cff4e95ccd8501ea5 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 11 Aug 2022 09:31:52 +1000 Subject: [PATCH 07/50] tweak: add localised strings --- Session/Meta/Translations/de.lproj/Localizable.strings | 1 + Session/Meta/Translations/es.lproj/Localizable.strings | 1 + Session/Meta/Translations/fa.lproj/Localizable.strings | 1 + Session/Meta/Translations/fi.lproj/Localizable.strings | 1 + Session/Meta/Translations/fr.lproj/Localizable.strings | 1 + Session/Meta/Translations/hi.lproj/Localizable.strings | 1 + Session/Meta/Translations/hr.lproj/Localizable.strings | 1 + Session/Meta/Translations/id-ID.lproj/Localizable.strings | 1 + Session/Meta/Translations/it.lproj/Localizable.strings | 1 + Session/Meta/Translations/ja.lproj/Localizable.strings | 1 + Session/Meta/Translations/nl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pt_BR.lproj/Localizable.strings | 1 + Session/Meta/Translations/ru.lproj/Localizable.strings | 1 + Session/Meta/Translations/si.lproj/Localizable.strings | 1 + Session/Meta/Translations/sk.lproj/Localizable.strings | 1 + Session/Meta/Translations/sv.lproj/Localizable.strings | 1 + Session/Meta/Translations/th.lproj/Localizable.strings | 1 + Session/Meta/Translations/vi-VN.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh-Hant.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh_CN.lproj/Localizable.strings | 1 + 21 files changed, 21 insertions(+) diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index d12868e54..362bdfe99 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index e5d4f9d44..7be87ea63 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index f333f1b70..82a4cade7 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index b9e9b8267..6bc45479a 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index f99011932..0b74fd37f 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index eca955776..09b10b985 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index bb4556500..3784a354a 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 6322bf9f2..806d7a49a 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index eedf2137b..1ea6f9a9e 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 253f72de8..46b75b828 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index d58ebff00..c2ae093ef 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 5a08f7e35..5b19b879f 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index a848b7587..7a2526795 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index a3984387e..527e65051 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index cacf3f5d1..57015b6c1 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 102514ede..8a7eb4c2e 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index da8933ad7..9e621af4d 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index b8f6e41ac..09abc064d 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index fd93b1f63..45fd11a4e 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index f936369d4..f8880e793 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 9145c3fe8..ccccec0c5 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -684,3 +684,4 @@ "SEND_FAILED_NOTIFICATION_BODY" = "Your message failed to send."; "INVALID_SESSION_ID_MESSAGE" = "Please check the Session ID and try again."; "INVALID_RECOVERY_PHRASE_MESSAGE" = "Please check the Recovery Phrase and try again."; +"QUOTED_MESSAGE_NOT_FOUND" = "Original message not found."; From 51a0093ceb40ce52ea739b8f00de310dd479c4e8 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 11 Aug 2022 09:36:52 +1000 Subject: [PATCH 08/50] update cocoapods --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index 5e750d933..37f4ac9c5 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -244,4 +244,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: f0857369c4831b2e5c1946345e76e493f3286805 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 From bedf3ab44b2dd07456d9a347464615d6c47208b5 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 11 Aug 2022 14:41:08 +1000 Subject: [PATCH 09/50] WIP: select quote body from original interaction --- .../Database/Models/Quote.swift | 54 +------------------ .../Shared Models/MessageViewModel.swift | 12 ++++- 2 files changed, 13 insertions(+), 53 deletions(-) diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index ae4526d60..f24ae3e4f 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -104,57 +104,7 @@ public extension Quote { self.interactionId = interactionId self.timestampMs = Int64(quoteProto.id) self.authorId = quoteProto.author - - // Prefer to generate the text snippet locally if available. - let quotedInteraction: Interaction? = try? thread - .interactions - .filter(Interaction.Columns.authorId == quoteProto.author) - .filter(Interaction.Columns.timestampMs == Double(quoteProto.id)) - .fetchOne(db) - - guard quotedInteraction != nil else { - self.body = "QUOTED_MESSAGE_NOT_FOUND".localized() - self.attachmentId = nil - return - } - - if let quotedInteraction: Interaction = quotedInteraction, quotedInteraction.body?.isEmpty == false { - self.body = quotedInteraction.body - } - else if let body: String = quoteProto.text, !body.isEmpty { - self.body = body - } - else { - self.body = nil - } - - // We only use the first attachment - if let attachment = quoteProto.attachments.first(where: { $0.thumbnail != nil })?.thumbnail { - self.attachmentId = try quotedInteraction - .map { quotedInteraction -> Attachment? in - // If the quotedInteraction has an attachment then try clone it - if let attachment: Attachment = try? quotedInteraction.attachments.fetchOne(db) { - return attachment.cloneAsQuoteThumbnail() - } - - // Otherwise if the quotedInteraction has a link preview, try clone that - return try? quotedInteraction.linkPreview - .fetchOne(db)? - .attachment - .fetchOne(db)? - .cloneAsQuoteThumbnail() - } - .defaulting(to: Attachment(proto: attachment)) - .inserted(db) - .id - } - else { - self.attachmentId = nil - } - - // Make sure the quote is valid before completing - if self.body == nil && self.attachmentId == nil { - return nil - } + self.body = nil + self.attachmentId = nil } } diff --git a/SessionMessagingKit/Shared Models/MessageViewModel.swift b/SessionMessagingKit/Shared Models/MessageViewModel.swift index bad4cb96e..69b28faff 100644 --- a/SessionMessagingKit/Shared Models/MessageViewModel.swift +++ b/SessionMessagingKit/Shared Models/MessageViewModel.swift @@ -656,7 +656,17 @@ public extension MessageViewModel { LEFT JOIN \(DisappearingMessagesConfiguration.self) ON \(disappearingMessagesConfig[.threadId]) = \(interaction[.threadId]) LEFT JOIN \(OpenGroup.self) ON \(openGroup[.threadId]) = \(interaction[.threadId]) LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(interaction[.authorId]) - LEFT JOIN \(Quote.self) ON \(quote[.interactionId]) = \(interaction[.id]) + LEFT JOIN ( + SELECT \(quote[.interactionId]), + \(quote[.authorId]), + \(quote[.timestampMs]), + FROM \(Quote.self) + LEFT JOIN ( + SELECT \(interaction[.authorId]), + \(interaction[.timestampMs]), + \(interaction[.body]) + ) + ) AS \(ViewModel.quoteKey) ON \(quote[.interactionId]) = \(interaction[.id]) LEFT JOIN \(Attachment.self) AS \(ViewModel.quoteAttachmentKey) ON \(ViewModel.quoteAttachmentKey).\(attachmentIdColumnLiteral) = \(quote[.attachmentId]) LEFT JOIN \(LinkPreview.self) ON ( \(linkPreview[.url]) = \(interaction[.linkPreviewUrl]) AND From 8ba7f927d8a4eb6d97cec895556dad043673a3ae Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 11 Aug 2022 16:44:22 +1000 Subject: [PATCH 10/50] feat: deal with quoted text --- .../Conversations/Message Cells/VisibleMessageCell.swift | 2 +- SessionMessagingKit/Shared Models/MessageViewModel.swift | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index ccb099d8e..e3450b4ad 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -457,7 +457,7 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel let quoteView: QuoteView = QuoteView( for: .regular, authorId: quote.authorId, - quotedText: quote.body, + quotedText: quote.body ?? "QUOTED_MESSAGE_NOT_FOUND".localized(), threadVariant: cellViewModel.threadVariant, currentUserPublicKey: cellViewModel.currentUserPublicKey, currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey, diff --git a/SessionMessagingKit/Shared Models/MessageViewModel.swift b/SessionMessagingKit/Shared Models/MessageViewModel.swift index 69b28faff..753c50078 100644 --- a/SessionMessagingKit/Shared Models/MessageViewModel.swift +++ b/SessionMessagingKit/Shared Models/MessageViewModel.swift @@ -660,11 +660,12 @@ public extension MessageViewModel { SELECT \(quote[.interactionId]), \(quote[.authorId]), \(quote[.timestampMs]), + \(interaction[.body]) AS \(Quote.Columns.body), + \(quote[.attachmentId]) FROM \(Quote.self) - LEFT JOIN ( - SELECT \(interaction[.authorId]), - \(interaction[.timestampMs]), - \(interaction[.body]) + LEFT JOIN \(Interaction.self) ON ( + \(quote[.authorId]) = \(interaction[.authorId]) AND + \(quote[.timestampMs]) = \(interaction[.timestampMs]) ) ) AS \(ViewModel.quoteKey) ON \(quote[.interactionId]) = \(interaction[.id]) LEFT JOIN \(Attachment.self) AS \(ViewModel.quoteAttachmentKey) ON \(ViewModel.quoteAttachmentKey).\(attachmentIdColumnLiteral) = \(quote[.attachmentId]) From 229e8376e5eccb9e036f0630df5b9c379c23d5e7 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 11 Aug 2022 17:15:56 +1000 Subject: [PATCH 11/50] WIP: observe quote update --- .../ConversationVC+Interaction.swift | 21 ------------------- .../Database/Models/Quote.swift | 15 ------------- 2 files changed, 36 deletions(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 27209404c..caef86415 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1077,13 +1077,6 @@ extension ConversationVC: .done { _ in // Delete the interaction (and associated data) from the database Storage.shared.writeAsync { db in - try Quote - .updateBeforeQuotedInterationDeletion( - db, - timestampMs: cellViewModel.timestampMs, - authorId: cellViewModel.authorId - ) - _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) @@ -1164,13 +1157,6 @@ extension ConversationVC: // For incoming interactions or interactions with no serverHash just delete them locally guard cellViewModel.variant == .standardOutgoing, let serverHash: String = serverHash else { Storage.shared.writeAsync { db in - try Quote - .updateBeforeQuotedInterationDeletion( - db, - timestampMs: cellViewModel.timestampMs, - authorId: cellViewModel.authorId - ) - _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) @@ -1194,13 +1180,6 @@ extension ConversationVC: let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) alertVC.addAction(UIAlertAction(title: "delete_message_for_me".localized(), style: .destructive) { [weak self] _ in Storage.shared.writeAsync { db in - try Quote - .updateBeforeQuotedInterationDeletion( - db, - timestampMs: cellViewModel.timestampMs, - authorId: cellViewModel.authorId - ) - _ = try Interaction .filter(id: cellViewModel.id) .deleteAll(db) diff --git a/SessionMessagingKit/Database/Models/Quote.swift b/SessionMessagingKit/Database/Models/Quote.swift index f24ae3e4f..af92ee454 100644 --- a/SessionMessagingKit/Database/Models/Quote.swift +++ b/SessionMessagingKit/Database/Models/Quote.swift @@ -76,21 +76,6 @@ public struct Quote: Codable, Equatable, Hashable, FetchableRecord, PersistableR } } -public extension Quote { - /// This method updates the all Quotes before the quoted interation is deleted - /// - static func updateBeforeQuotedInterationDeletion(_ db: Database, timestampMs: Int64, authorId: String) throws { - try Quote - .filter(Columns.authorId == authorId) - .filter(Columns.timestampMs == timestampMs) - .updateAll( - db, - Columns.body.set(to: "QUOTED_MESSAGE_NOT_FOUND".localized()), - Columns.attachmentId.set(to: nil) - ) - } -} - // MARK: - Protobuf public extension Quote { From 6565c3fe73b5dad9695d5ae20c5360045c3ec578 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 12 Aug 2022 11:46:28 +1000 Subject: [PATCH 12/50] feat: quotes refer to original attachments. --- SessionMessagingKit/Shared Models/MessageViewModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Shared Models/MessageViewModel.swift b/SessionMessagingKit/Shared Models/MessageViewModel.swift index 753c50078..367e645e8 100644 --- a/SessionMessagingKit/Shared Models/MessageViewModel.swift +++ b/SessionMessagingKit/Shared Models/MessageViewModel.swift @@ -584,6 +584,7 @@ public extension MessageViewModel { let disappearingMessagesConfig: TypedTableAlias = TypedTableAlias() let profile: TypedTableAlias = TypedTableAlias() let quote: TypedTableAlias = TypedTableAlias() + let interactionAttachment: TypedTableAlias = TypedTableAlias() let linkPreview: TypedTableAlias = TypedTableAlias() let threadProfileTableLiteral: SQL = SQL(stringLiteral: "threadProfile") @@ -661,12 +662,13 @@ public extension MessageViewModel { \(quote[.authorId]), \(quote[.timestampMs]), \(interaction[.body]) AS \(Quote.Columns.body), - \(quote[.attachmentId]) + \(interactionAttachment[.attachmentId]) AS \(Quote.Columns.attachmentId) FROM \(Quote.self) LEFT JOIN \(Interaction.self) ON ( \(quote[.authorId]) = \(interaction[.authorId]) AND \(quote[.timestampMs]) = \(interaction[.timestampMs]) ) + LEFT JOIN \(InteractionAttachment.self) ON \(interaction[.id]) = \(interactionAttachment[.interactionId]) ) AS \(ViewModel.quoteKey) ON \(quote[.interactionId]) = \(interaction[.id]) LEFT JOIN \(Attachment.self) AS \(ViewModel.quoteAttachmentKey) ON \(ViewModel.quoteAttachmentKey).\(attachmentIdColumnLiteral) = \(quote[.attachmentId]) LEFT JOIN \(LinkPreview.self) ON ( From 47d41ea64deec070ddb2235d84dda502af3b278b Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 28 Sep 2022 11:32:45 +1000 Subject: [PATCH 13/50] support landscape and autorotate for iPad --- Session.xcodeproj/project.pbxproj | 2 -- Session/Meta/AppDelegate.swift | 4 ++++ Session/Meta/Session-Info.plist | 7 +++++++ .../Shared View Controllers/OWSNavigationController.m | 7 +------ 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 95be399f6..a3827e5b6 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -169,7 +169,6 @@ 7BAF54D827ACD0E3003D12F8 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54D527ACD0E2003D12F8 /* ReusableView.swift */; }; 7BAF54DC27ACD12B003D12F8 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */; }; 7BB92B3F28C825FD0082762F /* NewConversationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BB92B3E28C825FD0082762F /* NewConversationViewModel.swift */; }; - 7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */; }; 7BBBDC44286EAD2D00747E59 /* TappableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC43286EAD2D00747E59 /* TappableLabel.swift */; }; 7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */; }; 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; }; @@ -1217,7 +1216,6 @@ 7BAF54D527ACD0E2003D12F8 /* ReusableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = ""; }; 7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; 7BB92B3E28C825FD0082762F /* NewConversationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationViewModel.swift; sourceTree = ""; }; - 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentTitleViewController.swift; sourceTree = ""; }; 7BBBDC43286EAD2D00747E59 /* TappableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TappableLabel.swift; sourceTree = ""; }; 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentTitleViewController.swift; sourceTree = ""; }; 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 92e0295c0..0db20fced 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -193,6 +193,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Orientation func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { + if UIDevice.current.isIPad { + return .all + } + return .portrait } diff --git a/Session/Meta/Session-Info.plist b/Session/Meta/Session-Info.plist index 54e23fb8d..1c8e77c13 100644 --- a/Session/Meta/Session-Info.plist +++ b/Session/Meta/Session-Info.plist @@ -144,6 +144,13 @@ UIInterfaceOrientationPortrait + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIViewControllerBasedStatusBarAppearance diff --git a/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m b/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m index 3fa1aa29a..945403c46 100644 --- a/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m +++ b/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m @@ -178,12 +178,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)shouldAutorotate { - return NO; -} - -- (UIInterfaceOrientationMask)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskPortrait; + return YES; } @end From bd1e1b266b7f69672d8e65ea9caa62db9ea6bc68 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 28 Sep 2022 14:26:07 +1000 Subject: [PATCH 14/50] fix gradient background --- Session/Onboarding/FakeChatView.swift | 2 +- Session/Shared/BaseVC.swift | 11 +++++++++-- SessionUIKit/Style Guide/Gradients.swift | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Session/Onboarding/FakeChatView.swift b/Session/Onboarding/FakeChatView.swift index 8fcf6bbfa..c55096971 100644 --- a/Session/Onboarding/FakeChatView.swift +++ b/Session/Onboarding/FakeChatView.swift @@ -46,12 +46,12 @@ final class FakeChatView : UIView { stackView.axis = .vertical stackView.spacing = spacing stackView.alignment = .fill - stackView.set(.width, to: UIScreen.main.bounds.width) let vInset = Values.smallSpacing stackView.layoutMargins = UIEdgeInsets(top: vInset, leading: Values.veryLargeSpacing, bottom: vInset, trailing: Values.veryLargeSpacing) stackView.isLayoutMarginsRelativeArrangement = true scrollView.addSubview(stackView) stackView.pin(to: scrollView) + stackView.set(.width, to: .width, of: scrollView) addSubview(scrollView) scrollView.pin(to: self) let height = chatBubbles.reduce(0) { $0 + $1.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize).height } + CGFloat(chatBubbles.count - 1) * spacing + 2 * vInset diff --git a/Session/Shared/BaseVC.swift b/Session/Shared/BaseVC.swift index f84514f4d..1c0659f39 100644 --- a/Session/Shared/BaseVC.swift +++ b/Session/Shared/BaseVC.swift @@ -28,6 +28,13 @@ class BaseVC : UIViewController { NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive(_:)), name: .OWSApplicationDidBecomeActive, object: nil) } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + if hasGradient { + let frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) + setUpGradientBackground(frame: frame) + } + } + internal func ensureWindowBackground() { let appMode = AppModeManager.shared.currentAppMode switch appMode { @@ -38,11 +45,11 @@ class BaseVC : UIViewController { } } - internal func setUpGradientBackground() { + internal func setUpGradientBackground(frame: CGRect = UIScreen.main.bounds) { hasGradient = true view.backgroundColor = .clear let gradient = Gradients.defaultBackground - view.setGradient(gradient) + view.setGradient(gradient, frame: frame) } internal func setUpNavBarStyle() { diff --git a/SessionUIKit/Style Guide/Gradients.swift b/SessionUIKit/Style Guide/Gradients.swift index 1970ecc42..a08c24bdb 100644 --- a/SessionUIKit/Style Guide/Gradients.swift +++ b/SessionUIKit/Style Guide/Gradients.swift @@ -16,9 +16,9 @@ public final class Gradient : NSObject { @objc public extension UIView { - @objc func setGradient(_ gradient: Gradient) { + @objc func setGradient(_ gradient: Gradient, frame: CGRect = UIScreen.main.bounds) { let layer = CAGradientLayer() - layer.frame = UIScreen.main.bounds + layer.frame = frame layer.colors = [ gradient.start.cgColor, gradient.end.cgColor ] if let existingSublayer = self.layer.sublayers?[0], existingSublayer is CAGradientLayer { self.layer.replaceSublayer(existingSublayer, with: layer) From cc3591a207f97737ca94a1c8f2300a6bca9d3596 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 28 Sep 2022 15:58:53 +1000 Subject: [PATCH 15/50] minor tweak on the width of fake chat bubble --- Session/Onboarding/FakeChatView.swift | 4 ++-- SessionUIKit/Utilities/UIView+Constraints.swift | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Session/Onboarding/FakeChatView.swift b/Session/Onboarding/FakeChatView.swift index c55096971..92180b771 100644 --- a/Session/Onboarding/FakeChatView.swift +++ b/Session/Onboarding/FakeChatView.swift @@ -22,7 +22,7 @@ final class FakeChatView : UIView { return result }() - private static let bubbleWidth = CGFloat(224) + private static let bubbleWidth = UIDevice.current.isIPad ? CGFloat(468) : CGFloat(224) private static let bubbleCornerRadius = CGFloat(10) private static let startDelay: TimeInterval = 1 private static let animationDuration: TimeInterval = 0.4 @@ -61,7 +61,7 @@ final class FakeChatView : UIView { private func getChatBubble(withText text: String, wasSentByCurrentUser: Bool) -> UIView { let result = UIView() let bubbleView = UIView() - bubbleView.set(.width, to: FakeChatView.bubbleWidth) + bubbleView.set(.width, lessThanOrEqualTo: FakeChatView.bubbleWidth) bubbleView.layer.cornerRadius = FakeChatView.bubbleCornerRadius bubbleView.layer.shadowColor = UIColor.black.cgColor bubbleView.layer.shadowRadius = isLightMode ? 4 : 8 diff --git a/SessionUIKit/Utilities/UIView+Constraints.swift b/SessionUIKit/Utilities/UIView+Constraints.swift index f9b237c64..b00e02872 100644 --- a/SessionUIKit/Utilities/UIView+Constraints.swift +++ b/SessionUIKit/Utilities/UIView+Constraints.swift @@ -127,4 +127,17 @@ public extension UIView { constraint.isActive = true return constraint } + + @discardableResult + func set(_ dimension: Dimension, lessThanOrEqualTo size: CGFloat) -> NSLayoutConstraint { + translatesAutoresizingMaskIntoConstraints = false + let constraint: NSLayoutConstraint = { + switch dimension { + case .width: return widthAnchor.constraint(lessThanOrEqualToConstant: size) + case .height: return heightAnchor.constraint(lessThanOrEqualToConstant: size) + } + }() + constraint.isActive = true + return constraint + } } From b20e123bfd8515b58d500927d1a2b4ee93f94e10 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 28 Sep 2022 16:57:13 +1000 Subject: [PATCH 16/50] WIP: fix message bubble UI in conversation view when rotating the device --- Session/Conversations/ConversationVC.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 8142600ea..de52e02a5 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -476,6 +476,11 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers stopObservingChanges() } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + tableView.reloadData() + } + // MARK: - Updating private func startObservingChanges(didReturnFromBackground: Bool = false) { From ce73cc7e986033c94735bc146f26f1ef5373ee15 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 29 Sep 2022 14:50:44 +1000 Subject: [PATCH 17/50] fix home screen conversation cell UI --- Session/Meta/AppDelegate.swift | 2 +- Session/Meta/Session-Info.plist | 1 - Session/Shared/FullConversationCell.swift | 14 ++++---------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 0db20fced..e4523d53a 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -194,7 +194,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if UIDevice.current.isIPad { - return .all + return .allButUpsideDown } return .portrait diff --git a/Session/Meta/Session-Info.plist b/Session/Meta/Session-Info.plist index 1c8e77c13..e186b98c9 100644 --- a/Session/Meta/Session-Info.plist +++ b/Session/Meta/Session-Info.plist @@ -149,7 +149,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIViewControllerBasedStatusBarAppearance diff --git a/Session/Shared/FullConversationCell.swift b/Session/Shared/FullConversationCell.swift index 8739de5c5..f98a612be 100644 --- a/Session/Shared/FullConversationCell.swift +++ b/Session/Shared/FullConversationCell.swift @@ -191,7 +191,7 @@ public final class FullConversationCell: UITableViewCell { let labelContainerView = UIStackView(arrangedSubviews: [ topLabelStackView, bottomLabelStackView ]) labelContainerView.axis = .vertical - labelContainerView.alignment = .leading + labelContainerView.alignment = .fill labelContainerView.spacing = 6 labelContainerView.isUserInteractionEnabled = false @@ -207,12 +207,10 @@ public final class FullConversationCell: UITableViewCell { accentLineView.pin(.bottom, to: .bottom, of: contentView) timestampLabel.setContentCompressionResistancePriority(.required, for: NSLayoutConstraint.Axis.horizontal) - // HACK: The six lines below are part of a workaround for a weird layout bug - topLabelStackView.set(.width, to: UIScreen.main.bounds.width - Values.accentLineThickness - profilePictureViewSize - 3 * Values.mediumSpacing) + // HACK: The 4 lines below are part of a workaround for a weird layout bug topLabelStackView.set(.height, to: 20) topLabelSpacer.set(.height, to: 20) - bottomLabelStackView.set(.width, to: UIScreen.main.bounds.width - Values.accentLineThickness - profilePictureViewSize - 3 * Values.mediumSpacing) bottomLabelStackView.set(.height, to: 18) bottomLabelSpacer.set(.height, to: 18) @@ -224,12 +222,8 @@ public final class FullConversationCell: UITableViewCell { typingIndicatorView.pin(.leading, to: .leading, of: snippetLabelContainer) typingIndicatorView.centerYAnchor.constraint(equalTo: snippetLabel.centerYAnchor).isActive = true - stackView.pin(.leading, to: .leading, of: contentView) - stackView.pin(.top, to: .top, of: contentView) - - // HACK: The two lines below are part of a workaround for a weird layout bug - stackView.set(.width, to: UIScreen.main.bounds.width - Values.mediumSpacing) - stackView.set(.height, to: cellHeight) + stackView.pin([ UIView.VerticalEdge.bottom, UIView.VerticalEdge.top, UIView.HorizontalEdge.leading ], to: contentView) + stackView.pin(.trailing, to: .trailing, of: contentView, withInset: -Values.mediumSpacing) } // MARK: - Content From 361c6c729c4420403d271271ca6bd78d9273beba Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 29 Sep 2022 15:08:11 +1000 Subject: [PATCH 18/50] extent message bubble width for iPad --- Session/Conversations/Message Cells/VisibleMessageCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index a56bf9119..6dfc88fff 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -147,7 +147,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { var result = groupThreadHSpacing + profilePictureSize + groupThreadHSpacing if UIDevice.current.isIPad { - result += CGFloat(UIScreen.main.bounds.width / 2 - 88) + result += 168 } return result From c82e4ab11f9b098c967be8c33331a61f677e7de9 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 29 Sep 2022 15:14:19 +1000 Subject: [PATCH 19/50] fix a localised string --- .../Message Cells/Content Views/ReactionContainerView.swift | 2 +- Session/Meta/Translations/de.lproj/Localizable.strings | 1 + Session/Meta/Translations/en.lproj/Localizable.strings | 1 + Session/Meta/Translations/es.lproj/Localizable.strings | 1 + Session/Meta/Translations/fa.lproj/Localizable.strings | 1 + Session/Meta/Translations/fi.lproj/Localizable.strings | 1 + Session/Meta/Translations/fr.lproj/Localizable.strings | 1 + Session/Meta/Translations/hi.lproj/Localizable.strings | 1 + Session/Meta/Translations/hr.lproj/Localizable.strings | 1 + Session/Meta/Translations/id-ID.lproj/Localizable.strings | 1 + Session/Meta/Translations/it.lproj/Localizable.strings | 1 + Session/Meta/Translations/ja.lproj/Localizable.strings | 1 + Session/Meta/Translations/nl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pt_BR.lproj/Localizable.strings | 1 + Session/Meta/Translations/ru.lproj/Localizable.strings | 1 + Session/Meta/Translations/si.lproj/Localizable.strings | 1 + Session/Meta/Translations/sk.lproj/Localizable.strings | 1 + Session/Meta/Translations/sv.lproj/Localizable.strings | 1 + Session/Meta/Translations/th.lproj/Localizable.strings | 1 + Session/Meta/Translations/vi-VN.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh-Hant.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh_CN.lproj/Localizable.strings | 1 + 23 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index 982195f50..dc5fb0c2e 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -36,7 +36,7 @@ final class ReactionContainerView: UIView { arrow.tintColor = Colors.text let textLabel = UILabel() - textLabel.text = "Show less" + textLabel.text = "EMOJI_REACTS_SHOW_LESS".localized() textLabel.font = .systemFont(ofSize: Values.verySmallFontSize) textLabel.textColor = Colors.text diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 0f3da385f..ddbe30436 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index cc1c26a72..a0ccdb557 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index e447a29e6..b1a1905b7 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 82423e38e..97a7d53af 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/fi.lproj/Localizable.strings b/Session/Meta/Translations/fi.lproj/Localizable.strings index 7989da67f..fcc54e445 100644 --- a/Session/Meta/Translations/fi.lproj/Localizable.strings +++ b/Session/Meta/Translations/fi.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 54da86768..476a9fb88 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/hi.lproj/Localizable.strings b/Session/Meta/Translations/hi.lproj/Localizable.strings index d79703f35..fa86873a1 100644 --- a/Session/Meta/Translations/hi.lproj/Localizable.strings +++ b/Session/Meta/Translations/hi.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/hr.lproj/Localizable.strings b/Session/Meta/Translations/hr.lproj/Localizable.strings index 17fa91859..81f632d73 100644 --- a/Session/Meta/Translations/hr.lproj/Localizable.strings +++ b/Session/Meta/Translations/hr.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index d50e08397..4ca937a6a 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 8f20f588d..963e7ef75 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 6185b3ad5..0904264ed 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index ada8b4092..82039b3d9 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index ad77428b6..433df8a79 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index a13ec240b..50246ecdb 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 28eb7d371..70e67700b 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/si.lproj/Localizable.strings b/Session/Meta/Translations/si.lproj/Localizable.strings index 2bc02f293..794e8e676 100644 --- a/Session/Meta/Translations/si.lproj/Localizable.strings +++ b/Session/Meta/Translations/si.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index 90da4af9e..2d7efef0c 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/sv.lproj/Localizable.strings b/Session/Meta/Translations/sv.lproj/Localizable.strings index 12cf7b6f1..d44de70e2 100644 --- a/Session/Meta/Translations/sv.lproj/Localizable.strings +++ b/Session/Meta/Translations/sv.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/th.lproj/Localizable.strings b/Session/Meta/Translations/th.lproj/Localizable.strings index aa3d751f0..17fc5c318 100644 --- a/Session/Meta/Translations/th.lproj/Localizable.strings +++ b/Session/Meta/Translations/th.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index f1a783851..526941fb8 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings index 61045a1fa..a5426caa5 100644 --- a/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh-Hant.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index f833919df..2d6327e45 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -711,6 +711,7 @@ "EMOJI_REACTS_NOTIFICATION" = "%@ reacts to a message with %@."; "EMOJI_REACTS_MORE_REACTORS_ONE" = "And 1 other has reacted %@ to this message."; "EMOJI_REACTS_MORE_REACTORS_MUTIPLE" = "And %@ others have reacted %@ to this message."; +"EMOJI_REACTS_SHOW_LESS" = "Show less"; /* New conversation screen*/ "vc_new_conversation_title" = "New Conversation"; "CREATE_GROUP_BUTTON_TITLE" = "Create"; From 2c14073b04fb28185cb96c5eba51dae3b7f2842b Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 29 Sep 2022 17:00:23 +1000 Subject: [PATCH 20/50] fix global search search bar width --- .../Home/GlobalSearch/GlobalSearchViewController.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Session/Home/GlobalSearch/GlobalSearchViewController.swift b/Session/Home/GlobalSearch/GlobalSearchViewController.swift index c88b527be..ebbb24927 100644 --- a/Session/Home/GlobalSearch/GlobalSearchViewController.swift +++ b/Session/Home/GlobalSearch/GlobalSearchViewController.swift @@ -55,6 +55,8 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo result.showsCancelButton = true return result }() + + private var searchBarWidth: NSLayoutConstraint? internal lazy var tableView: UITableView = { let result: UITableView = UITableView(frame: .zero, style: .grouped) @@ -97,6 +99,11 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo super.viewWillDisappear(animated) searchBar.resignFirstResponder() } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + searchBarWidth?.constant = size.width - 32 + } private func setupNavigationBar() { // This is a workaround for a UI issue that the navigation bar can be a bit higher if @@ -107,7 +114,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo searchBar.sizeToFit() searchBar.layoutMargins = UIEdgeInsets.zero searchBarContainer.set(.height, to: 44) - searchBarContainer.set(.width, to: UIScreen.main.bounds.width - 32) + searchBarWidth = searchBarContainer.set(.width, to: UIScreen.main.bounds.width - 32) searchBarContainer.addSubview(searchBar) navigationItem.titleView = searchBarContainer From c5c2d7e8a1d078a22d652c47d2902abbee9c445e Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 29 Sep 2022 17:21:40 +1000 Subject: [PATCH 21/50] fix conversation search bar width when rotating --- Session/Conversations/ConversationVC.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index de52e02a5..f0a45d9c6 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -39,6 +39,8 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers var audioRecorder: AVAudioRecorder? var audioTimer: Timer? + private var searchBarWidth: NSLayoutConstraint? + // Context menu var contextMenuWindow: ContextMenuWindow? var contextMenuVC: ContextMenuVC? @@ -478,6 +480,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) + searchBarWidth?.constant = size.width - 32 tableView.reloadData() } @@ -1398,7 +1401,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers searchBar.sizeToFit() searchBar.layoutMargins = UIEdgeInsets.zero searchBarContainer.set(.height, to: 44) - searchBarContainer.set(.width, to: UIScreen.main.bounds.width - 32) + searchBarWidth = searchBarContainer.set(.width, to: UIScreen.main.bounds.width - 32) searchBarContainer.addSubview(searchBar) navigationItem.titleView = searchBarContainer From 4c2b01ca424a7f23729f4bbfbc134d7f8e4cf5dd Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 10:54:40 +1000 Subject: [PATCH 22/50] fix create closed group screen --- Session/Closed Groups/NewClosedGroupVC.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index b468a56ee..2120ed2f3 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -27,6 +27,10 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate private var selectedContacts: Set = [] private var searchText: String = "" + // MARK: - Layout + + private var tableViewWidth: NSLayoutConstraint? + // MARK: - Components private lazy var nameTextField: TextField = { @@ -105,6 +109,11 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate // Set up content setUpViewHierarchy() } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + tableViewWidth?.constant = size.width + } private func setUpViewHierarchy() { guard !contactProfiles.isEmpty else { @@ -158,15 +167,13 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate mainStackView.addArrangedSubview(separator) tableView.set(.height, to: CGFloat(contactProfiles.count * 65 + 100)) // A cell is exactly 65 points high - tableView.set(.width, to: UIScreen.main.bounds.width) + tableViewWidth = tableView.set(.width, to: UIScreen.main.bounds.width) mainStackView.addArrangedSubview(tableView) let scrollView: UIScrollView = UIScrollView(wrapping: mainStackView, withInsets: UIEdgeInsets.zero) scrollView.showsVerticalScrollIndicator = false scrollView.delegate = self view.addSubview(scrollView) - - scrollView.set(.width, to: UIScreen.main.bounds.width) scrollView.pin(to: view) view.addSubview(fadeView) From 420af95f6802cc3ed47eea17799615d8fce824c1 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 11:31:06 +1000 Subject: [PATCH 23/50] fix new dm screen --- Session/Home/New Conversation/NewDMVC.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Session/Home/New Conversation/NewDMVC.swift b/Session/Home/New Conversation/NewDMVC.swift index 47fd20390..cf04c4cff 100644 --- a/Session/Home/New Conversation/NewDMVC.swift +++ b/Session/Home/New Conversation/NewDMVC.swift @@ -102,6 +102,12 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll scanQRCodePlaceholderVC.constrainHeight(to: height) } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + enterPublicKeyVC.viewWidth?.constant = size.width + scanQRCodePlaceholderVC.viewWidth?.constant = size.width + } + // MARK: General func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { guard let index = pages.firstIndex(of: viewController), index != 0 else { return nil } @@ -269,6 +275,8 @@ private final class EnterPublicKeyVC : UIViewController { return result }() + var viewWidth: NSLayoutConstraint? + // MARK: Lifecycle override func viewDidLoad() { // Remove background color @@ -329,12 +337,10 @@ private final class EnterPublicKeyVC : UIViewController { mainStackView.layoutMargins = UIEdgeInsets(top: Values.largeSpacing, left: Values.largeSpacing, bottom: Values.largeSpacing, right: Values.largeSpacing) mainStackView.isLayoutMarginsRelativeArrangement = true view.addSubview(mainStackView) - mainStackView.pin(.leading, to: .leading, of: view) - mainStackView.pin(.top, to: .top, of: view) - view.pin(.trailing, to: .trailing, of: mainStackView) + mainStackView.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.top ], to: view) bottomConstraint = view.pin(.bottom, to: .bottom, of: mainStackView, withInset: bottomMargin) // Width constraint - view.set(.width, to: UIScreen.main.bounds.width) + viewWidth = view.set(.width, to: UIScreen.main.bounds.width) // Dismiss keyboard on tap let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) view.addGestureRecognizer(tapGestureRecognizer) @@ -430,6 +436,8 @@ private final class EnterPublicKeyVC : UIViewController { private final class ScanQRCodePlaceholderVC : UIViewController { weak var NewDMVC: NewDMVC! + var viewWidth: NSLayoutConstraint? + override func viewDidLoad() { // Remove background color view.backgroundColor = .clear @@ -453,7 +461,7 @@ private final class ScanQRCodePlaceholderVC : UIViewController { stackView.spacing = Values.mediumSpacing stackView.alignment = .center // Set up constraints - view.set(.width, to: UIScreen.main.bounds.width) + viewWidth = view.set(.width, to: UIScreen.main.bounds.width) view.addSubview(stackView) stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) From dafd63db5ffd3cfcc87fbfbc0718ad1ea2325cfd Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 13:54:29 +1000 Subject: [PATCH 24/50] fix join open group screen --- Session/Open Groups/JoinOpenGroupVC.swift | 17 ++++++++++++++--- .../Open Groups/OpenGroupSuggestionGrid.swift | 7 ++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index c6fb9c912..29fd90510 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -88,6 +88,13 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC enterURLVC.constrainHeight(to: height) scanQRCodePlaceholderVC.constrainHeight(to: height) } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + enterURLVC.viewWidth?.constant = size.width + enterURLVC.suggestionGrid.refreshLayout(with: size.width - 2 * Values.largeSpacing) + scanQRCodePlaceholderVC.viewWidth?.constant = size.width + } // MARK: - General @@ -230,13 +237,15 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O return result }() - private lazy var suggestionGrid: OpenGroupSuggestionGrid = { + lazy var suggestionGrid: OpenGroupSuggestionGrid = { let maxWidth: CGFloat = (UIScreen.main.bounds.width - Values.largeSpacing * 2) let result: OpenGroupSuggestionGrid = OpenGroupSuggestionGrid(maxWidth: maxWidth) result.delegate = self return result }() + + var viewWidth: NSLayoutConstraint? // MARK: - Lifecycle @@ -270,7 +279,7 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O bottomConstraint = view.pin(.bottom, to: .bottom, of: stackView, withInset: bottomMargin) // Constraints - view.set(.width, to: UIScreen.main.bounds.width) + viewWidth = view.set(.width, to: UIScreen.main.bounds.width) // Dismiss keyboard on tap let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) @@ -374,6 +383,8 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O private final class ScanQRCodePlaceholderVC: UIViewController { weak var joinOpenGroupVC: JoinOpenGroupVC? + var viewWidth: NSLayoutConstraint? + // MARK: - Lifecycle override func viewDidLoad() { @@ -403,7 +414,7 @@ private final class ScanQRCodePlaceholderVC: UIViewController { stackView.alignment = .center // Constraints - view.set(.width, to: UIScreen.main.bounds.width) + viewWidth = view.set(.width, to: UIScreen.main.bounds.width) view.addSubview(stackView) stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) diff --git a/Session/Open Groups/OpenGroupSuggestionGrid.swift b/Session/Open Groups/OpenGroupSuggestionGrid.swift index 7ab0611f6..c6563d82e 100644 --- a/Session/Open Groups/OpenGroupSuggestionGrid.swift +++ b/Session/Open Groups/OpenGroupSuggestionGrid.swift @@ -5,7 +5,7 @@ import SessionUIKit final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { private let itemsPerSection: Int = (UIDevice.current.isIPad ? 4 : 2) - private let maxWidth: CGFloat + private var maxWidth: CGFloat private var rooms: [OpenGroupAPI.Room] = [] { didSet { update() } } private var heightConstraint: NSLayoutConstraint! var delegate: OpenGroupSuggestionGridDelegate? @@ -142,6 +142,11 @@ final class OpenGroupSuggestionGrid: UIView, UICollectionViewDataSource, UIColle errorView.isHidden = (roomCount > 0) } + public func refreshLayout(with maxWidth: CGFloat) { + self.maxWidth = maxWidth + collectionView.collectionViewLayout.invalidateLayout() + } + // MARK: - Layout func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { From a45ed574807c5d44224c25091faab5c7b2ff72c7 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 14:29:40 +1000 Subject: [PATCH 25/50] fix settings screen --- Session/Settings/SettingsVC.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Session/Settings/SettingsVC.swift b/Session/Settings/SettingsVC.swift index aa8e84e21..9b4c4177c 100644 --- a/Session/Settings/SettingsVC.swift +++ b/Session/Settings/SettingsVC.swift @@ -10,6 +10,8 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate { private var displayNameToBeUploaded: String? private var isEditingDisplayName = false { didSet { handleIsEditingDisplayNameChanged() } } + private var viewWidth: NSLayoutConstraint? + // MARK: - Components private lazy var profilePictureView: ProfilePictureView = { @@ -246,7 +248,7 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate { stackView.alignment = .fill stackView.layoutMargins = UIEdgeInsets(top: Values.mediumSpacing, left: 0, bottom: Values.mediumSpacing, right: 0) stackView.isLayoutMarginsRelativeArrangement = true - stackView.set(.width, to: UIScreen.main.bounds.width) + viewWidth = stackView.set(.width, to: UIScreen.main.bounds.width) // Scroll view let scrollView = UIScrollView() @@ -257,6 +259,11 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate { scrollView.pin(to: view) } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + viewWidth?.constant = size.width + } + private func getSettingButtons() -> [UIView] { func getSeparator() -> UIView { let result = UIView() From 2968a3cf066906f62e5ec8e5113bc66286a5201d Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 15:42:03 +1000 Subject: [PATCH 26/50] fix mini call screen size --- Session/Calls/Views & Modals/CallVideoView.swift | 4 ++-- Session/Calls/Views & Modals/MiniCallView.swift | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Session/Calls/Views & Modals/CallVideoView.swift b/Session/Calls/Views & Modals/CallVideoView.swift index 7bf90dcf1..1f10930f3 100644 --- a/Session/Calls/Views & Modals/CallVideoView.swift +++ b/Session/Calls/Views & Modals/CallVideoView.swift @@ -78,8 +78,8 @@ class RemoteVideoView: TargetView { class LocalVideoView: TargetView { - static let width: CGFloat = 80 - static let height: CGFloat = 173 + static let width: CGFloat = UIDevice.current.isIPad ? 160 : 80 + static let height: CGFloat = UIDevice.current.isIPad ? 346: 173 override func renderFrame(_ frame: RTCVideoFrame?) { super.renderFrame(frame) diff --git a/Session/Calls/Views & Modals/MiniCallView.swift b/Session/Calls/Views & Modals/MiniCallView.swift index 86d17e508..3d3455df2 100644 --- a/Session/Calls/Views & Modals/MiniCallView.swift +++ b/Session/Calls/Views & Modals/MiniCallView.swift @@ -5,7 +5,8 @@ final class MiniCallView: UIView, RTCVideoViewDelegate { var callVC: CallVC // MARK: UI - private static let defaultSize: CGFloat = 100 + private static let defaultSize: CGFloat = UIDevice.current.isIPad ? 200 : 100 + private static let defaultVideoSize: CGFloat = UIDevice.current.isIPad ? 320 : 160 private let topMargin = UIApplication.shared.keyWindow!.safeAreaInsets.top + Values.veryLargeSpacing private let bottomMargin = UIApplication.shared.keyWindow!.safeAreaInsets.bottom @@ -70,7 +71,7 @@ final class MiniCallView: UIView, RTCVideoViewDelegate { private func setUpViewHierarchy() { self.width = self.set(.width, to: MiniCallView.defaultSize) self.height = self.set(.height, to: MiniCallView.defaultSize) - self.layer.cornerRadius = 10 + self.layer.cornerRadius = UIDevice.current.isIPad ? 20 : 10 self.layer.masksToBounds = true // Background let background = getBackgroudView() @@ -139,7 +140,10 @@ final class MiniCallView: UIView, RTCVideoViewDelegate { // MARK: RTCVideoViewDelegate func videoView(_ videoView: RTCVideoRenderer, didChangeVideoSize size: CGSize) { - let newSize = CGSize(width: min(160.0, 160.0 * size.width / size.height), height: min(160.0, 160.0 * size.height / size.width)) + let newSize = CGSize( + width: min(Self.defaultVideoSize, Self.defaultVideoSize * size.width / size.height), + height: min(Self.defaultVideoSize, Self.defaultVideoSize * size.height / size.width) + ) persistCurrentPosition(newSize: newSize) self.width?.constant = newSize.width self.height?.constant = newSize.height From fbcdd1358c420a11a389d1a0a732b13002835d67 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 30 Sep 2022 16:44:48 +1000 Subject: [PATCH 27/50] WIP: fix video call view --- Session/Calls/CallVC.swift | 15 ++++++++++++++- Session/Calls/Views & Modals/CallVideoView.swift | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 704df50d8..8ccef1ea1 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -23,7 +23,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate { private lazy var localVideoView: LocalVideoView = { let result = LocalVideoView() result.isHidden = !call.isVideoEnabled - result.layer.cornerRadius = 10 + result.layer.cornerRadius = UIDevice.current.isIPad ? 20 : 10 result.layer.masksToBounds = true result.set(.width, to: LocalVideoView.width) result.set(.height, to: LocalVideoView.height) @@ -284,6 +284,18 @@ final class CallVC: UIViewController, VideoPreviewDelegate { NotificationCenter.default.addObserver(self, selector: #selector(audioRouteDidChange), name: AVAudioSession.routeChangeNotification, object: nil) } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + let layer = CAGradientLayer() + layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) + layer.colors = [ UIColor(hex: 0x000000).withAlphaComponent(0.4).cgColor, UIColor(hex: 0x000000).withAlphaComponent(0).cgColor ] + if let existingSublayer = fadeView.layer.sublayers?[0], existingSublayer is CAGradientLayer { + fadeView.layer.replaceSublayer(existingSublayer, with: layer) + } else { + fadeView.layer.insertSublayer(layer, at: 0) + } + } + deinit { UIDevice.current.endGeneratingDeviceOrientationNotifications() NotificationCenter.default.removeObserver(self) @@ -373,6 +385,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate { } @objc func didChangeDeviceOrientation(notification: Notification) { + if UIDevice.current.isIPad { return } func rotateAllButtons(rotationAngle: CGFloat) { let transform = CGAffineTransform(rotationAngle: rotationAngle) diff --git a/Session/Calls/Views & Modals/CallVideoView.swift b/Session/Calls/Views & Modals/CallVideoView.swift index 1f10930f3..899732f66 100644 --- a/Session/Calls/Views & Modals/CallVideoView.swift +++ b/Session/Calls/Views & Modals/CallVideoView.swift @@ -16,6 +16,16 @@ class RemoteVideoView: TargetView { override func renderFrame(_ frame: RTCVideoFrame?) { super.renderFrame(frame) guard let frame = frame else { return } + if UIDevice.current.isIPad { + DispatchMainThreadSafe { +#if targetEnvironment(simulator) + self.contentMode = .scaleAspectFit +#else + self.videoContentMode = .scaleAspectFit +#endif + } + return + } DispatchMainThreadSafe { let frameRatio = Double(frame.height) / Double(frame.width) From 15694aeeb0367c0768294493539da8c5aa301d35 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Tue, 4 Oct 2022 17:13:05 +1100 Subject: [PATCH 28/50] minor fix to adapt to theming --- Session/Calls/CallVC.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 49bb6a1e0..3ff0a65f9 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -374,13 +374,12 @@ final class CallVC: UIViewController, VideoPreviewDelegate { override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - let layer = CAGradientLayer() - layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) - layer.colors = [ UIColor(hex: 0x000000).withAlphaComponent(0.4).cgColor, UIColor(hex: 0x000000).withAlphaComponent(0).cgColor ] - if let existingSublayer = fadeView.layer.sublayers?[0], existingSublayer is CAGradientLayer { + + if let existingSublayer = fadeView.layer.sublayers?[0] as? CAGradientLayer { + let layer = CAGradientLayer() + layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) + layer.colors = existingSublayer.colors fadeView.layer.replaceSublayer(existingSublayer, with: layer) - } else { - fadeView.layer.insertSublayer(layer, at: 0) } } From ccc517746d409d39ee7716fcadba3551a783aeb4 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 5 Oct 2022 11:58:58 +1100 Subject: [PATCH 29/50] fix settings screen --- Session/Shared/Views/SessionAvatarCell.swift | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Session/Shared/Views/SessionAvatarCell.swift b/Session/Shared/Views/SessionAvatarCell.swift index 8016641bb..3ccea1689 100644 --- a/Session/Shared/Views/SessionAvatarCell.swift +++ b/Session/Shared/Views/SessionAvatarCell.swift @@ -114,17 +114,7 @@ class SessionAvatarCell: UITableViewCell { stackView.alignment = .center stackView.distribution = .fillEqually stackView.spacing = (UIDevice.current.isIPad ? Values.iPadButtonSpacing : Values.mediumSpacing) - - if (UIDevice.current.isIPad) { - stackView.layoutMargins = UIEdgeInsets( - top: 0, - left: Values.iPadButtonContainerMargin, - bottom: 0, - right: Values.iPadButtonContainerMargin - ) - stackView.isLayoutMarginsRelativeArrangement = true - } - + return stackView }() @@ -242,6 +232,10 @@ class SessionAvatarCell: UITableViewCell { descriptionSeparator.update(title: style.separatorTitle) descriptionSeparator.isHidden = (style.separatorTitle == nil) + if (UIDevice.current.isIPad) { + descriptionActionStackView.addArrangedSubview(UIView.hStretchingSpacer()) + } + style.descriptionActions.forEach { action in let result: SessionButton = SessionButton(style: .bordered, size: .medium) result.setTitle(action.title, for: UIControl.State.normal) @@ -252,6 +246,10 @@ class SessionAvatarCell: UITableViewCell { descriptionActionStackView.addArrangedSubview(result) } + + if (UIDevice.current.isIPad) { + descriptionActionStackView.addArrangedSubview(UIView.hStretchingSpacer()) + } descriptionActionStackView.isHidden = style.descriptionActions.isEmpty } From 202a2de1b5b4a8e9bc1f72eb1cbc315049ea06fa Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 5 Oct 2022 13:35:05 +1100 Subject: [PATCH 30/50] dismiss context menu view when the screen rotates --- Session/Conversations/Context Menu/ContextMenuVC.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Session/Conversations/Context Menu/ContextMenuVC.swift b/Session/Conversations/Context Menu/ContextMenuVC.swift index 3f3146df2..2e12cd093 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC.swift @@ -283,6 +283,11 @@ final class ContextMenuVC: UIViewController { } } + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + snDismiss() + } + func calculateFrame(menuHeight: CGFloat, spacing: CGFloat) -> CGRect { var finalFrame: CGRect = frame let ratio: CGFloat = (frame.width / frame.height) From 2638fe4025e3ad1db61cca01ba641a4e72158f90 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 5 Oct 2022 14:19:01 +1100 Subject: [PATCH 31/50] fix share button in my qr code view --- Session/Settings/QRCodeVC.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Session/Settings/QRCodeVC.swift b/Session/Settings/QRCodeVC.swift index c1b34d08e..d4e622337 100644 --- a/Session/Settings/QRCodeVC.swift +++ b/Session/Settings/QRCodeVC.swift @@ -234,9 +234,14 @@ private final class ViewMyQRCodeVC : UIViewController { let shareButtonContainer = UIView() shareButtonContainer.addSubview(shareButton) shareButton.pin(.top, to: .top, of: shareButtonContainer) - shareButton.pin(.leading, to: .leading, of: shareButtonContainer, withInset: 80) - shareButton.pin(.trailing, to: .trailing, of: shareButtonContainer, withInset: -80) shareButton.pin(.bottom, to: .bottom, of: shareButtonContainer) + if UIDevice.current.isIPad { + shareButton.center(in: shareButtonContainer) + shareButton.set(.width, to: Values.iPadButtonWidth) + } else { + shareButton.pin(.leading, to: .leading, of: shareButtonContainer, withInset: 80) + shareButton.pin(.trailing, to: .trailing, of: shareButtonContainer, withInset: -80) + } // Set up stack view let spacing = (isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) From 1bee35b139e33bfb90f298d9dd7d3924ef7f29df Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 5 Oct 2022 15:24:43 +1100 Subject: [PATCH 32/50] fix scan qr code screen --- Session/Shared/ScanQRCodeWrapperVC.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Session/Shared/ScanQRCodeWrapperVC.swift b/Session/Shared/ScanQRCodeWrapperVC.swift index 60fe2a29f..a80b2305c 100644 --- a/Session/Shared/ScanQRCodeWrapperVC.swift +++ b/Session/Shared/ScanQRCodeWrapperVC.swift @@ -10,8 +10,6 @@ final class ScanQRCodeWrapperVC: BaseVC { private let message: String? private let scanQRCodeVC = QRCodeScanningViewController() - override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } - // MARK: - Lifecycle init(message: String?) { @@ -47,7 +45,7 @@ final class ScanQRCodeWrapperVC: BaseVC { scanQRCodeVCView.autoPinEdge(.top, to: .top, of: view) if let message = message { - scanQRCodeVCView.autoPinToSquareAspectRatio() + scanQRCodeVCView.set(.height, lessThanOrEqualTo: UIScreen.main.bounds.width) // Set up bottom view let bottomView = UIView() @@ -78,8 +76,6 @@ final class ScanQRCodeWrapperVC: BaseVC { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - UIDevice.current.ows_setOrientation(.portrait) - self.scanQRCodeVC.startCapture() } From 46b156b2c4380485e6f95e702d222cdf995c5134 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 5 Oct 2022 16:44:14 +1100 Subject: [PATCH 33/50] increase max emojis per line for iPad --- .../Message Cells/Content Views/ReactionContainerView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index 622a23900..564f2c1ad 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -7,7 +7,7 @@ import SignalUtilitiesKit final class ReactionContainerView: UIView { var showingAllReactions = false private var showNumbers = true - private var maxEmojisPerLine = isIPhone6OrSmaller ? 5 : 6 + private var maxEmojisPerLine = UIDevice.current.isIPad ? 10 : (isIPhone6OrSmaller ? 5 : 6) private var oldSize: CGSize = .zero var reactions: [ReactionViewModel] = [] From 3563d7d469ecacb93f4fa50d8534a4649c2d096d Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 6 Oct 2022 13:11:17 +1100 Subject: [PATCH 34/50] clean --- .../Content Views/ReactionContainerView.swift | 3 +- .../Message Cells/VisibleMessageCell.swift | 2 +- Session/Settings/SettingsVC.swift | 681 ------------------ .../OWSNavigationController.m | 186 ----- 4 files changed, 2 insertions(+), 870 deletions(-) delete mode 100644 Session/Settings/SettingsVC.swift delete mode 100644 SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index febc2ee61..583142633 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -13,7 +13,6 @@ final class ReactionContainerView: UIView { private var collapsedCount: Int = 0 private var showingAllReactions: Bool = false private var showNumbers: Bool = true - private var maxEmojisPerLine = UIDevice.current.isIPad ? 10 : (isIPhone6OrSmaller ? 5 : 6) private var oldSize: CGSize = .zero var reactions: [ReactionViewModel] = [] @@ -114,7 +113,7 @@ final class ReactionContainerView: UIView { // button appear horizontally centered (if we don't do this it gets offset to one side) guard frame != CGRect.zero, frame.size != oldSize else { return } - var targetSuperview: UIView? = { + let targetSuperview: UIView? = { var result: UIView? = self.superview while result != nil, result?.isKind(of: UITableViewCell.self) != true { diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index d70a5f3d3..5c0641334 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -372,7 +372,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { for: cellViewModel, maxWidth: VisibleMessageCell.getMaxWidth( for: cellViewModel, - includingOppositeGutter: false + includingOppositeGutter: UIDevice.current.isIPad ), showExpandedReactions: showExpandedReactions ) diff --git a/Session/Settings/SettingsVC.swift b/Session/Settings/SettingsVC.swift deleted file mode 100644 index 9b4c4177c..000000000 --- a/Session/Settings/SettingsVC.swift +++ /dev/null @@ -1,681 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import UIKit -import SessionUIKit -import SessionUtilitiesKit -import SessionMessagingKit -import SignalUtilitiesKit - -final class SettingsVC: BaseVC, AvatarViewHelperDelegate { - private var displayNameToBeUploaded: String? - private var isEditingDisplayName = false { didSet { handleIsEditingDisplayNameChanged() } } - - private var viewWidth: NSLayoutConstraint? - - // MARK: - Components - - private lazy var profilePictureView: ProfilePictureView = { - let result = ProfilePictureView() - let size = Values.largeProfilePictureSize - result.size = size - result.set(.width, to: size) - result.set(.height, to: size) - result.accessibilityLabel = "Edit profile picture button" - result.isAccessibilityElement = true - - return result - }() - - private lazy var profilePictureUtilities: AvatarViewHelper = { - let result = AvatarViewHelper() - result.delegate = self - - return result - }() - - private lazy var displayNameLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = .boldSystemFont(ofSize: Values.veryLargeFontSize) - result.lineBreakMode = .byTruncatingTail - result.textAlignment = .center - - return result - }() - - private lazy var displayNameTextField: TextField = { - let result = TextField(placeholder: NSLocalizedString("vc_settings_display_name_text_field_hint", comment: ""), usesDefaultHeight: false) - result.textAlignment = .center - result.accessibilityLabel = "Edit display name text field" - - return result - }() - - private lazy var publicKeyLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text - result.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : Values.largeFontSize) - result.numberOfLines = 0 - result.textAlignment = .center - result.lineBreakMode = .byCharWrapping - result.text = getUserHexEncodedPublicKey() - - return result - }() - - private lazy var copyButton: Button = { - let result = Button(style: .prominentOutline, size: .medium) - result.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) - result.addTarget(self, action: #selector(copyPublicKey), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var settingButtonsStackView: UIStackView = { - let result = UIStackView() - result.axis = .vertical - result.alignment = .fill - - return result - }() - - private lazy var inviteButton: UIButton = { - let result = UIButton() - result.setTitle(NSLocalizedString("vc_settings_invite_a_friend_button_title", comment: ""), for: UIControl.State.normal) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.titleLabel!.font = .boldSystemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(sendInvitation), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var faqButton: UIButton = { - let result = UIButton() - result.setTitle(NSLocalizedString("vc_settings_faq_button_title", comment: ""), for: UIControl.State.normal) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.titleLabel!.font = .boldSystemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(openFAQ), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var surveyButton: UIButton = { - let result = UIButton() - result.setTitle(NSLocalizedString("vc_settings_survey_button_title", comment: ""), for: UIControl.State.normal) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.titleLabel?.font = .boldSystemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(openSurvey), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var supportButton: UIButton = { - let result = UIButton() - result.setTitle(NSLocalizedString("vc_settings_support_button_title", comment: ""), for: UIControl.State.normal) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.titleLabel!.font = .boldSystemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(shareLogs), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var helpTranslateButton: UIButton = { - let result = UIButton() - result.setTitle(NSLocalizedString("vc_settings_help_us_translate_button_title", comment: ""), for: UIControl.State.normal) - result.setTitleColor(Colors.text, for: UIControl.State.normal) - result.titleLabel!.font = .boldSystemFont(ofSize: Values.smallFontSize) - result.addTarget(self, action: #selector(helpTranslate), for: UIControl.Event.touchUpInside) - - return result - }() - - private lazy var logoImageView: UIImageView = { - let result = UIImageView() - result.set(.height, to: 24) - result.contentMode = .scaleAspectFit - - return result - }() - - private lazy var versionLabel: UILabel = { - let result = UILabel() - result.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity) - result.font = .systemFont(ofSize: Values.verySmallFontSize) - result.numberOfLines = 0 - result.textAlignment = .center - result.lineBreakMode = .byCharWrapping - let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"]! - let buildNumber = Bundle.main.infoDictionary!["CFBundleVersion"]! - result.text = "Version \(version) (\(buildNumber))" - - return result - }() - - // MARK: - Settings - - private static let buttonHeight = isIPhone5OrSmaller ? CGFloat(52) : CGFloat(75) - - // MARK: - Lifecycle - - override func viewDidLoad() { - super.viewDidLoad() - - setUpGradientBackground() - setUpNavBarStyle() - setNavBarTitle(NSLocalizedString("vc_settings_title", comment: "")) - - // Navigation bar buttons - updateNavigationBarButtons() - - // Profile picture view - let profile: Profile = Profile.fetchOrCreateCurrentUser() - let profilePictureTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditProfilePictureUI)) - profilePictureView.addGestureRecognizer(profilePictureTapGestureRecognizer) - profilePictureView - .update( - publicKey: profile.id, - profile: profile, - threadVariant: .contact - ) - // Display name label - displayNameLabel.text = profile.name - - // Display name container - let displayNameContainer = UIView() - displayNameContainer.accessibilityLabel = "Edit display name text field" - displayNameContainer.isAccessibilityElement = true - displayNameContainer.addSubview(displayNameLabel) - displayNameLabel.pin(to: displayNameContainer) - displayNameContainer.addSubview(displayNameTextField) - displayNameTextField.pin(to: displayNameContainer) - displayNameContainer.set(.height, to: 40) - displayNameTextField.alpha = 0 - let displayNameContainerTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showEditDisplayNameUI)) - displayNameContainer.addGestureRecognizer(displayNameContainerTapGestureRecognizer) - - // Header view - let headerStackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameContainer ]) - headerStackView.axis = .vertical - headerStackView.spacing = Values.smallSpacing - headerStackView.alignment = .center - - // Separator - let separator = Separator(title: NSLocalizedString("your_session_id", comment: "")) - - // Share button - let shareButton = Button(style: .regular, size: .medium) - shareButton.setTitle(NSLocalizedString("share", comment: ""), for: UIControl.State.normal) - shareButton.addTarget(self, action: #selector(sharePublicKey), for: UIControl.Event.touchUpInside) - - // Button container - let buttonContainer = UIStackView(arrangedSubviews: [ copyButton, shareButton ]) - buttonContainer.axis = .horizontal - buttonContainer.spacing = UIDevice.current.isIPad ? Values.iPadButtonSpacing : Values.mediumSpacing - buttonContainer.distribution = .fillEqually - - if (UIDevice.current.isIPad) { - buttonContainer.layoutMargins = UIEdgeInsets(top: 0, left: Values.iPadButtonContainerMargin, bottom: 0, right: Values.iPadButtonContainerMargin) - buttonContainer.isLayoutMarginsRelativeArrangement = true - } - // User session id container - let userPublicKeyContainer = UIView(wrapping: publicKeyLabel, withInsets: .zero, shouldAdaptForIPadWithWidth: Values.iPadUserSessionIdContainerWidth) - - // Top stack view - let topStackView = UIStackView(arrangedSubviews: [ headerStackView, separator, userPublicKeyContainer, buttonContainer ]) - topStackView.axis = .vertical - topStackView.spacing = Values.largeSpacing - topStackView.alignment = .fill - topStackView.layoutMargins = UIEdgeInsets(top: 0, left: Values.largeSpacing, bottom: 0, right: Values.largeSpacing) - topStackView.isLayoutMarginsRelativeArrangement = true - - // Setting buttons stack view - getSettingButtons().forEach { settingButtonOrSeparator in - settingButtonsStackView.addArrangedSubview(settingButtonOrSeparator) - } - - // Oxen logo - updateLogo() - let logoContainer = UIView() - logoContainer.addSubview(logoImageView) - logoImageView.pin(.top, to: .top, of: logoContainer) - logoContainer.pin(.bottom, to: .bottom, of: logoImageView) - logoImageView.centerXAnchor.constraint(equalTo: logoContainer.centerXAnchor, constant: -2).isActive = true - - // Main stack view - let stackView = UIStackView(arrangedSubviews: [ topStackView, settingButtonsStackView, inviteButton, faqButton, surveyButton, supportButton, helpTranslateButton, logoContainer, versionLabel ]) - stackView.axis = .vertical - stackView.spacing = Values.largeSpacing - stackView.alignment = .fill - stackView.layoutMargins = UIEdgeInsets(top: Values.mediumSpacing, left: 0, bottom: Values.mediumSpacing, right: 0) - stackView.isLayoutMarginsRelativeArrangement = true - viewWidth = stackView.set(.width, to: UIScreen.main.bounds.width) - - // Scroll view - let scrollView = UIScrollView() - scrollView.showsVerticalScrollIndicator = false - scrollView.addSubview(stackView) - stackView.pin(to: scrollView) - view.addSubview(scrollView) - scrollView.pin(to: view) - } - - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - viewWidth?.constant = size.width - } - - private func getSettingButtons() -> [UIView] { - func getSeparator() -> UIView { - let result = UIView() - result.backgroundColor = Colors.separator - result.set(.height, to: Values.separatorThickness) - - return result - } - - func getSettingButton(withTitle title: String, color: UIColor, action selector: Selector) -> UIButton { - let button = UIButton() - button.setTitle(title, for: UIControl.State.normal) - button.setTitleColor(color, for: UIControl.State.normal) - button.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize) - button.titleLabel!.textAlignment = .center - - func getImage(withColor color: UIColor) -> UIImage { - let rect = CGRect(origin: CGPoint.zero, size: CGSize(width: 1, height: 1)) - UIGraphicsBeginImageContext(rect.size) - - let context = UIGraphicsGetCurrentContext()! - context.setFillColor(color.cgColor) - context.fill(rect) - - let image = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return image! - } - - let backgroundColor = isLightMode ? UIColor(hex: 0xF9F9F9) : UIColor(hex: 0x1B1B1B) - button.setBackgroundImage(getImage(withColor: backgroundColor), for: UIControl.State.normal) - - let selectedColor = isLightMode ? UIColor(hex: 0xDFDFDF) : UIColor(hex: 0x0C0C0C) - button.setBackgroundImage(getImage(withColor: selectedColor), for: UIControl.State.highlighted) - button.addTarget(self, action: selector, for: UIControl.Event.touchUpInside) - button.set(.height, to: SettingsVC.buttonHeight) - - return button - } - - let pathButton = getSettingButton(withTitle: NSLocalizedString("vc_path_title", comment: ""), color: Colors.text, action: #selector(showPath)) - let pathStatusView = PathStatusView() - pathStatusView.set(.width, to: PathStatusView.size) - pathStatusView.set(.height, to: PathStatusView.size) - - pathButton.addSubview(pathStatusView) - pathStatusView.pin(.leading, to: .trailing, of: pathButton.titleLabel!, withInset: Values.smallSpacing) - pathStatusView.autoVCenterInSuperview() - - return [ - getSeparator(), - pathButton, - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("vc_settings_privacy_button_title", comment: ""), color: Colors.text, action: #selector(showPrivacySettings)), - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("vc_settings_notifications_button_title", comment: ""), color: Colors.text, action: #selector(showNotificationSettings)), - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("MESSAGE_REQUESTS_TITLE", comment: ""), color: Colors.text, action: #selector(showMessageRequests)), - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("CHATS_TITLE", comment: ""), color: Colors.text, action: #selector(showChatSettings)), - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("vc_settings_recovery_phrase_button_title", comment: ""), color: Colors.text, action: #selector(showSeed)), - getSeparator(), - getSettingButton(withTitle: NSLocalizedString("vc_settings_clear_all_data_button_title", comment: ""), color: Colors.destructive, action: #selector(clearAllData)), - getSeparator() - ] - } - - // MARK: - General - - @objc private func enableCopyButton() { - copyButton.isUserInteractionEnabled = true - - UIView.transition( - with: copyButton, - duration: 0.25, - options: .transitionCrossDissolve, - animations: { - self.copyButton.setTitle("copy".localized(), for: .normal) - }, - completion: nil - ) - } - - func avatarActionSheetTitle() -> String? { return "Update Profile Picture" } - func fromViewController() -> UIViewController { return self } - func hasClearAvatarAction() -> Bool { return false } - func clearAvatarActionLabel() -> String { return "Clear" } - - // MARK: - Updating - - private func handleIsEditingDisplayNameChanged() { - updateNavigationBarButtons() - - UIView.animate(withDuration: 0.25) { - self.displayNameLabel.alpha = self.isEditingDisplayName ? 0 : 1 - self.displayNameTextField.alpha = self.isEditingDisplayName ? 1 : 0 - } - - if isEditingDisplayName { - displayNameTextField.becomeFirstResponder() - } - else { - displayNameTextField.resignFirstResponder() - } - } - - private func updateNavigationBarButtons() { - if isEditingDisplayName { - let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(handleCancelDisplayNameEditingButtonTapped)) - cancelButton.tintColor = Colors.text - cancelButton.accessibilityLabel = "Cancel button" - cancelButton.isAccessibilityElement = true - navigationItem.leftBarButtonItem = cancelButton - - let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleSaveDisplayNameButtonTapped)) - doneButton.tintColor = Colors.text - doneButton.accessibilityLabel = "Done button" - doneButton.isAccessibilityElement = true - navigationItem.rightBarButtonItem = doneButton - } - else { - let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close)) - closeButton.tintColor = Colors.text - closeButton.accessibilityLabel = "Close button" - closeButton.isAccessibilityElement = true - navigationItem.leftBarButtonItem = closeButton - - let appModeIcon: UIImage - if isSystemDefault { - appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.white) : #imageLiteral(resourceName: "ic_theme_auto").withTintColor(.black) - } - else { - appModeIcon = isDarkMode ? #imageLiteral(resourceName: "ic_dark_theme_on").withTintColor(.white) : #imageLiteral(resourceName: "ic_dark_theme_off").withTintColor(.black) - } - - let appModeButton = UIButton() - appModeButton.setImage(appModeIcon, for: UIControl.State.normal) - appModeButton.tintColor = Colors.text - appModeButton.addTarget(self, action: #selector(switchAppMode), for: UIControl.Event.touchUpInside) - appModeButton.accessibilityLabel = "Switch app mode button" - - let qrCodeIcon = isDarkMode ? #imageLiteral(resourceName: "QRCode").withTintColor(.white) : #imageLiteral(resourceName: "QRCode").withTintColor(.black) - let qrCodeButton = UIButton() - qrCodeButton.setImage(qrCodeIcon, for: UIControl.State.normal) - qrCodeButton.tintColor = Colors.text - qrCodeButton.addTarget(self, action: #selector(showQRCode), for: UIControl.Event.touchUpInside) - qrCodeButton.accessibilityLabel = "Show QR code button" - - let stackView = UIStackView(arrangedSubviews: [ appModeButton, qrCodeButton ]) - stackView.axis = .horizontal - stackView.spacing = Values.mediumSpacing - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: stackView) - } - } - - func avatarDidChange(_ image: UIImage?, filePath: String?) { - updateProfile( - profilePicture: image, - profilePictureFilePath: filePath, - isUpdatingDisplayName: false, - isUpdatingProfilePicture: true - ) - } - - func clearAvatar() { - updateProfile( - profilePicture: nil, - profilePictureFilePath: nil, - isUpdatingDisplayName: false, - isUpdatingProfilePicture: true - ) - } - - private func updateProfile( - profilePicture: UIImage?, - profilePictureFilePath: String?, - isUpdatingDisplayName: Bool, - isUpdatingProfilePicture: Bool - ) { - let userDefaults = UserDefaults.standard - let name: String? = (displayNameToBeUploaded ?? Profile.fetchOrCreateCurrentUser().name) - let imageFilePath: String? = (profilePictureFilePath ?? ProfileManager.profileAvatarFilepath(id: getUserHexEncodedPublicKey())) - - ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self, displayNameToBeUploaded] modalActivityIndicator in - ProfileManager.updateLocal( - queue: DispatchQueue.global(qos: .default), - profileName: (name ?? ""), - image: profilePicture, - imageFilePath: imageFilePath, - requiredSync: true, - success: { db, updatedProfile in - if displayNameToBeUploaded != nil { - userDefaults[.lastDisplayNameUpdate] = Date() - } - - if isUpdatingProfilePicture { - userDefaults[.lastProfilePictureUpdate] = Date() - } - - try MessageSender.syncConfiguration(db, forceSyncNow: true).retainUntilComplete() - - // Wait for the database transaction to complete before updating the UI - db.afterNextTransactionCommit { _ in - DispatchQueue.main.async { - modalActivityIndicator.dismiss { - self?.profilePictureView.update( - publicKey: updatedProfile.id, - profile: updatedProfile, - threadVariant: .contact - ) - self?.displayNameLabel.text = name - self?.displayNameToBeUploaded = nil - } - } - } - }, - failure: { error in - DispatchQueue.main.async { - modalActivityIndicator.dismiss { - let isMaxFileSizeExceeded = (error == .avatarUploadMaxFileSizeExceeded) - let title = isMaxFileSizeExceeded ? "Maximum File Size Exceeded" : "Couldn't Update Profile" - let message = isMaxFileSizeExceeded ? "Please select a smaller photo and try again" : "Please check your internet connection and try again" - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - self?.present(alert, animated: true, completion: nil) - } - } - } - ) - } - } - - @objc override internal func handleAppModeChangedNotification(_ notification: Notification) { - super.handleAppModeChangedNotification(notification) - - updateNavigationBarButtons() - settingButtonsStackView.arrangedSubviews.forEach { settingButton in - settingButtonsStackView.removeArrangedSubview(settingButton) - settingButton.removeFromSuperview() - } - getSettingButtons().forEach { settingButtonOrSeparator in - settingButtonsStackView.addArrangedSubview(settingButtonOrSeparator) // Re-do the setting buttons - } - updateLogo() - } - - private func updateLogo() { - let logoName = isLightMode ? "OxenLightMode" : "OxenDarkMode" - logoImageView.image = UIImage(named: logoName)! - } - - // MARK: - Interaction - - @objc private func close() { - dismiss(animated: true, completion: nil) - } - - @objc private func switchAppMode() { - let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) - let systemModeAction = UIAlertAction.init(title: NSLocalizedString("system_mode_theme", comment: ""), style: .default) { _ in - AppModeManager.shared.setAppModeToSystemDefault() - } - alertVC.addAction(systemModeAction) - - let darkModeAction = UIAlertAction.init(title: NSLocalizedString("dark_mode_theme", comment: ""), style: .default) { _ in - AppModeManager.shared.setCurrentAppMode(to: .dark) - } - alertVC.addAction(darkModeAction) - - let lightModeAction = UIAlertAction.init(title: NSLocalizedString("light_mode_theme", comment: ""), style: .default) { _ in - AppModeManager.shared.setCurrentAppMode(to: .light) - } - alertVC.addAction(lightModeAction) - - let cancelAction = UIAlertAction.init(title: NSLocalizedString("TXT_CANCEL_TITLE", comment: ""), style: .cancel) {_ in } - alertVC.addAction(cancelAction) - - self.presentAlert(alertVC) - } - - @objc private func showQRCode() { - let qrCodeVC = QRCodeVC() - navigationController!.pushViewController(qrCodeVC, animated: true) - } - - @objc private func handleCancelDisplayNameEditingButtonTapped() { - isEditingDisplayName = false - } - - @objc private func handleSaveDisplayNameButtonTapped() { - func showError(title: String, message: String = "") { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil)) - presentAlert(alert) - } - let displayName = displayNameTextField.text!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - guard !displayName.isEmpty else { - return showError(title: NSLocalizedString("vc_settings_display_name_missing_error", comment: "")) - } - guard !ProfileManager.isToLong(profileName: displayName) else { - return showError(title: NSLocalizedString("vc_settings_display_name_too_long_error", comment: "")) - } - isEditingDisplayName = false - displayNameToBeUploaded = displayName - updateProfile( - profilePicture: nil, - profilePictureFilePath: nil, - isUpdatingDisplayName: true, - isUpdatingProfilePicture: false - ) - } - - @objc private func showEditProfilePictureUI() { - profilePictureUtilities.showChangeAvatarUI() - } - - @objc private func showEditDisplayNameUI() { - isEditingDisplayName = true - } - - @objc private func copyPublicKey() { - UIPasteboard.general.string = getUserHexEncodedPublicKey() - copyButton.isUserInteractionEnabled = false - UIView.transition(with: copyButton, duration: 0.25, options: .transitionCrossDissolve, animations: { - self.copyButton.setTitle(NSLocalizedString("copied", comment: ""), for: UIControl.State.normal) - }, completion: nil) - Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false) - } - - @objc private func sharePublicKey() { - let shareVC = UIActivityViewController(activityItems: [ getUserHexEncodedPublicKey() ], applicationActivities: nil) - if UIDevice.current.isIPad { - shareVC.excludedActivityTypes = [] - shareVC.popoverPresentationController?.permittedArrowDirections = [] - shareVC.popoverPresentationController?.sourceView = self.view - shareVC.popoverPresentationController?.sourceRect = self.view.bounds - } - navigationController!.present(shareVC, animated: true, completion: nil) - } - - @objc private func showPath() { - let pathVC = PathVC() - navigationController!.pushViewController(pathVC, animated: true) - } - - @objc private func showPrivacySettings() { - let privacySettingsVC = PrivacySettingsTableViewController() - navigationController!.pushViewController(privacySettingsVC, animated: true) - } - - @objc private func showNotificationSettings() { - let notificationSettingsVC = NotificationSettingsViewController() - navigationController!.pushViewController(notificationSettingsVC, animated: true) - } - - @objc private func showMessageRequests() { - let viewController: MessageRequestsViewController = MessageRequestsViewController() - self.navigationController?.pushViewController(viewController, animated: true) - } - - @objc private func showChatSettings() { - let chatSettingsVC = ChatSettingsViewController() - navigationController!.pushViewController(chatSettingsVC, animated: true) - } - - @objc private func showSeed() { - let seedModal = SeedModal() - seedModal.modalPresentationStyle = .overFullScreen - seedModal.modalTransitionStyle = .crossDissolve - present(seedModal, animated: true, completion: nil) - } - - @objc private func clearAllData() { - let nukeDataModal = NukeDataModal() - nukeDataModal.modalPresentationStyle = .overFullScreen - nukeDataModal.modalTransitionStyle = .crossDissolve - present(nukeDataModal, animated: true, completion: nil) - } - - @objc private func sendInvitation() { - let invitation = "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is \(getUserHexEncodedPublicKey()) !" - let shareVC = UIActivityViewController(activityItems: [ invitation ], applicationActivities: nil) - if UIDevice.current.isIPad { - shareVC.excludedActivityTypes = [] - shareVC.popoverPresentationController?.permittedArrowDirections = [] - shareVC.popoverPresentationController?.sourceView = self.view - shareVC.popoverPresentationController?.sourceRect = self.view.bounds - } - navigationController!.present(shareVC, animated: true, completion: nil) - } - - @objc private func openFAQ() { - let url = URL(string: "https://getsession.org/faq")! - UIApplication.shared.open(url) - } - - @objc private func openSurvey() { - let url = URL(string: "https://getsession.org/survey")! - UIApplication.shared.open(url) - } - - @objc private func shareLogs() { - let shareLogsModal = ShareLogsModal() - shareLogsModal.modalPresentationStyle = .overFullScreen - shareLogsModal.modalTransitionStyle = .crossDissolve - present(shareLogsModal, animated: true, completion: nil) - } - - @objc private func helpTranslate() { - let url = URL(string: "https://crowdin.com/project/session-ios")! - UIApplication.shared.open(url) - } -} diff --git a/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m b/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m deleted file mode 100644 index 945403c46..000000000 --- a/SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m +++ /dev/null @@ -1,186 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "AppContext.h" -#import "OWSNavigationController.h" -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface UINavigationController (OWSNavigationController) - -@end - -#pragma mark - - -// Expose that UINavigationController already secretly implements UIGestureRecognizerDelegate -// so we can call [super navigationBar:shouldPopItem] in our own implementation to take advantage -// of the important side effects of that method. -@interface OWSNavigationController () - -@end - -#pragma mark - - -@implementation OWSNavigationController - -- (instancetype)init -{ - self = [super initWithNavigationBarClass:[OWSNavigationBar class] toolbarClass:nil]; - if (!self) { - return self; - } - [self setupNavbar]; - - return self; -} - -- (instancetype)initWithRootViewController:(UIViewController *)rootViewController -{ - self = [self init]; - if (!self) { - return self; - } - [self pushViewController:rootViewController animated:NO]; - - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark - - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.interactivePopGestureRecognizer.delegate = self; -} - -- (BOOL)prefersStatusBarHidden -{ - if (self.ows_prefersStatusBarHidden) { - return self.ows_prefersStatusBarHidden.boolValue; - } - return [super prefersStatusBarHidden]; -} - -#pragma mark - UINavigationBarDelegate - -- (void)setupNavbar -{ - if (![self.navigationBar isKindOfClass:[OWSNavigationBar class]]) { - OWSFailDebug(@"navigationBar was unexpected class: %@", self.navigationBar); - return; - } - OWSNavigationBar *navbar = (OWSNavigationBar *)self.navigationBar; - navbar.navBarLayoutDelegate = self; - [self updateLayoutForNavbar:navbar]; -} - -// All OWSNavigationController serve as the UINavigationBarDelegate for their navbar. -// We override shouldPopItem: in order to cancel some back button presses - for example, -// if a view has unsaved changes. -- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item -{ - OWSAssertDebug(self.interactivePopGestureRecognizer.delegate == self); - UIViewController *topViewController = self.topViewController; - - // wasBackButtonClicked is YES if the back button was pressed but not - // if a back gesture was performed or if the view is popped programmatically. - BOOL wasBackButtonClicked = topViewController.navigationItem == item; - BOOL result = YES; - if (wasBackButtonClicked) { - if ([topViewController conformsToProtocol:@protocol(OWSNavigationView)]) { - id navigationView = (id)topViewController; - result = ![navigationView shouldCancelNavigationBack]; - } - } - - // If we're not going to cancel the pop/back, we need to call the super - // implementation since it has important side effects. - if (result) { - // NOTE: result might end up NO if the super implementation cancels the - // the pop/back. - [super navigationBar:navigationBar shouldPopItem:item]; - result = YES; - } - return result; -} - -#pragma mark - UIGestureRecognizerDelegate - -// We serve as the UIGestureRecognizerDelegate of the interactivePopGestureRecognizer -// in order to cancel some "back" gestures - for example, -// if a view has unsaved changes. -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - OWSAssertDebug(gestureRecognizer == self.interactivePopGestureRecognizer); - - UIViewController *topViewController = self.topViewController; - if ([topViewController conformsToProtocol:@protocol(OWSNavigationView)]) { - id navigationView = (id)topViewController; - return ![navigationView shouldCancelNavigationBack]; - } else { - UIViewController *rootViewController = self.viewControllers.firstObject; - if (topViewController == rootViewController) { - return NO; - } else { - return YES; - } - } -} - -#pragma mark - NavBarLayoutDelegate - -- (void)navBarCallLayoutDidChangeWithNavbar:(OWSNavigationBar *)navbar -{ - [self updateLayoutForNavbar:navbar]; - [self setNeedsStatusBarAppearanceUpdate]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle -{ - if (!CurrentAppContext().isMainApp) { - return super.preferredStatusBarStyle; - } else if (OWSWindowManager.sharedManager.hasCall) { - // Status bar is overlaying the green "call banner" - return UIStatusBarStyleLightContent; - } else { - return LKAppModeUtilities.isLightMode ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent; - } -} - -- (void)updateLayoutForNavbar:(OWSNavigationBar *)navbar -{ - OWSLogDebug(@""); - - [UIView setAnimationsEnabled:NO]; - - if (!CurrentAppContext().isMainApp) { - self.additionalSafeAreaInsets = UIEdgeInsetsZero; - } else if (OWSWindowManager.sharedManager.hasCall) { - self.additionalSafeAreaInsets = UIEdgeInsetsMake(20, 0, 0, 0); - } else { - self.additionalSafeAreaInsets = UIEdgeInsetsZero; - } - - [navbar layoutSubviews]; - [UIView setAnimationsEnabled:YES]; -} - -#pragma mark - Orientation - -- (BOOL)shouldAutorotate -{ - return YES; -} - -@end - -NS_ASSUME_NONNULL_END From 080f147a33ea5dea9bdb40c08598e90fe9117183 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 6 Oct 2022 13:54:04 +1100 Subject: [PATCH 35/50] clean --- .../Message Cells/Content Views/ReactionContainerView.swift | 1 + Session/Conversations/Message Cells/VisibleMessageCell.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index 583142633..78410b688 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -75,6 +75,7 @@ final class ReactionContainerView: UIView { arrow.pin(.top, to: .top, of: result) arrow.pin(.leading, to: .leading, of: result) arrow.pin(.bottom, to: .bottom, of: result) +// arrow.set(.width, to: Self.arrowSize.width) textLabel.pin(.top, to: .top, of: result) textLabel.pin(.leading, to: .trailing, of: arrow, withInset: ReactionContainerView.arrowSpacing) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 5c0641334..d70a5f3d3 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -372,7 +372,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { for: cellViewModel, maxWidth: VisibleMessageCell.getMaxWidth( for: cellViewModel, - includingOppositeGutter: UIDevice.current.isIPad + includingOppositeGutter: false ), showExpandedReactions: showExpandedReactions ) From 00fb27b59ad430d9b35d31592966e768e040562b Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 6 Oct 2022 14:03:12 +1100 Subject: [PATCH 36/50] clean --- .../Message Cells/Content Views/ReactionContainerView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift index 78410b688..583142633 100644 --- a/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift +++ b/Session/Conversations/Message Cells/Content Views/ReactionContainerView.swift @@ -75,7 +75,6 @@ final class ReactionContainerView: UIView { arrow.pin(.top, to: .top, of: result) arrow.pin(.leading, to: .leading, of: result) arrow.pin(.bottom, to: .bottom, of: result) -// arrow.set(.width, to: Self.arrowSize.width) textLabel.pin(.top, to: .top, of: result) textLabel.pin(.leading, to: .trailing, of: arrow, withInset: ReactionContainerView.arrowSpacing) From 27214e8478448287499cfa42615097aafc5fcc62 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 14:34:49 +1100 Subject: [PATCH 37/50] fix NewDMVC --- Session/Home/New Conversation/NewDMVC.swift | 93 ++++++++++++++------- Session/Open Groups/JoinOpenGroupVC.swift | 50 ++++++++--- 2 files changed, 102 insertions(+), 41 deletions(-) diff --git a/Session/Home/New Conversation/NewDMVC.swift b/Session/Home/New Conversation/NewDMVC.swift index 2f1dfce6e..f9a48812e 100644 --- a/Session/Home/New Conversation/NewDMVC.swift +++ b/Session/Home/New Conversation/NewDMVC.swift @@ -92,36 +92,41 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle navigationItem.leftBarButtonItem = closeButton } - // Set up tab bar - view.addSubview(tabBar) - tabBar.pin(.top, to: .top, of: view) - tabBar.pin(.leading, to: .leading, of: view) - tabBar.pin(.trailing, to: .trailing, of: view) - - // Set up page VC - let containerView: UIView = UIView() - view.addSubview(containerView) - containerView.pin(.top, to: .bottom, of: tabBar) - containerView.pin(.leading, to: .leading, of: view) - containerView.pin(.trailing, to: .trailing, of: view) - containerView.pin(.bottom, to: .bottom, of: view) - + // Page VC let hasCameraAccess = (AVCaptureDevice.authorizationStatus(for: .video) == .authorized) pages = [ enterPublicKeyVC, (hasCameraAccess ? scanQRCodeWrapperVC : scanQRCodePlaceholderVC) ] pageVC.dataSource = self pageVC.delegate = self pageVC.setViewControllers([ enterPublicKeyVC ], direction: .forward, animated: false, completion: nil) - addChild(pageVC) - containerView.addSubview(pageVC.view) - pageVC.view.pin(to: containerView) - pageVC.didMove(toParent: self) + // Tab bar + view.addSubview(tabBar) + tabBar.pin(.top, to: .top, of: view) + tabBar.pin(.leading, to: .leading, of: view) + tabBar.pin(.trailing, to: .trailing, of: view) + + // Page VC constraints + let pageVCView = pageVC.view! + view.addSubview(pageVCView) + pageVCView.pin(.leading, to: .leading, of: view) + pageVCView.pin(.top, to: .bottom, of: tabBar) + pageVCView.pin(.trailing, to: .trailing, of: view) + pageVCView.pin(.bottom, to: .bottom, of: view) + + let navBarHeight: CGFloat = (navigationController?.navigationBar.frame.size.height ?? 0) + let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height + let height: CGFloat = ((navigationController?.view.bounds.height ?? 0) - navBarHeight - TabBar.snHeight - statusBarHeight) + let size: CGSize = CGSize(width: UIScreen.main.bounds.width, height: height) + enterPublicKeyVC.constrainSize(to: size) + scanQRCodePlaceholderVC.constrainSize(to: size) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - enterPublicKeyVC.viewWidth?.constant = size.width - scanQRCodePlaceholderVC.viewWidth?.constant = size.width + let height: CGFloat = (size.height - TabBar.snHeight) + let size: CGSize = CGSize(width: size.width, height: height) + enterPublicKeyVC.constrainSize(to: size) + scanQRCodePlaceholderVC.constrainSize(to: size) } // MARK: - General @@ -400,7 +405,8 @@ private final class EnterPublicKeyVC: UIViewController { return result }() - var viewWidth: NSLayoutConstraint? + private var viewWidth: NSLayoutConstraint? + private var viewHeight: NSLayoutConstraint? // MARK: - Lifecycle @@ -436,9 +442,7 @@ private final class EnterPublicKeyVC: UIViewController { view.addSubview(mainStackView) mainStackView.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.top ], to: view) - bottomConstraint = view.pin(.bottom, to: .bottom, of: mainStackView, withInset: bottomMargin) - // Width constraint - viewWidth = view.set(.width, to: UIScreen.main.bounds.width) + bottomConstraint = mainStackView.pin(.bottom, to: .bottom, of: view, withInset: bottomMargin) // Dismiss keyboard on tap let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) @@ -456,6 +460,21 @@ private final class EnterPublicKeyVC: UIViewController { // MARK: - General + func constrainSize(to size: CGSize) { + if viewWidth == nil { + viewWidth = view.set(.width, to: size.width) + } else { + viewWidth?.constant = size.width + } + + if viewHeight == nil { + viewHeight = view.set(.height, to: size.height) + } else { + viewHeight?.constant = size.height + } + } + + func setSessionId(to sessionId: String) { publicKeyTextView.insertText(sessionId) } @@ -615,7 +634,8 @@ private final class EnterPublicKeyVC: UIViewController { private final class ScanQRCodePlaceholderVC: UIViewController { weak var newDMVC: NewDMVC! - var viewWidth: NSLayoutConstraint? + private var viewWidth: NSLayoutConstraint? + private var viewHeight: NSLayoutConstraint? override func viewDidLoad() { // Remove background color @@ -644,14 +664,29 @@ private final class ScanQRCodePlaceholderVC: UIViewController { stackView.alignment = .center // Set up constraints - viewWidth = view.set(.width, to: UIScreen.main.bounds.width) - view.addSubview(stackView) stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) - stackView.pin(.trailing, to: .trailing, of: view, withInset: -Values.massiveSpacing) - stackView.center(.vertical, in: view, withInset: -16) // Makes things appear centered visually + view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) + + let verticalCenteringConstraint = stackView.center(.vertical, in: view) + verticalCenteringConstraint.constant = -16 // Makes things appear centered visually } + func constrainSize(to size: CGSize) { + if viewWidth == nil { + viewWidth = view.set(.width, to: size.width) + } else { + viewWidth?.constant = size.width + } + + if viewHeight == nil { + viewHeight = view.set(.height, to: size.height) + } else { + viewHeight?.constant = size.height + } + } + + @objc private func requestCameraAccess() { Permissions.requestCameraPermissionIfNeeded { [weak self] in self?.newDMVC.handleCameraAccessGranted() diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index 1842b6ed0..79885ae45 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -84,17 +84,22 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC pageVCView.pin(.top, to: .bottom, of: tabBar) pageVCView.pin(.trailing, to: .trailing, of: view) pageVCView.pin(.bottom, to: .bottom, of: view) + let navBarHeight: CGFloat = (navigationController?.navigationBar.frame.size.height ?? 0) - let height: CGFloat = ((navigationController?.view.bounds.height ?? 0) - navBarHeight - TabBar.snHeight) - enterURLVC.constrainHeight(to: height) - scanQRCodePlaceholderVC.constrainHeight(to: height) + let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height + let height: CGFloat = ((navigationController?.view.bounds.height ?? 0) - navBarHeight - TabBar.snHeight - statusBarHeight) + let size: CGSize = CGSize(width: UIScreen.main.bounds.width, height: height) + enterURLVC.constrainSize(to: size) + scanQRCodePlaceholderVC.constrainSize(to: size) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - enterURLVC.viewWidth?.constant = size.width + let height: CGFloat = (size.height - TabBar.snHeight) + let size: CGSize = CGSize(width: size.width, height: height) + enterURLVC.constrainSize(to: size) + scanQRCodePlaceholderVC.constrainSize(to: size) enterURLVC.suggestionGrid.refreshLayout(with: size.width - 2 * Values.largeSpacing) - scanQRCodePlaceholderVC.viewWidth?.constant = size.width } // MARK: - General @@ -256,7 +261,8 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O return result }() - var viewWidth: NSLayoutConstraint? + private var viewWidth: NSLayoutConstraint? + private var viewHeight: NSLayoutConstraint? // MARK: - Lifecycle @@ -332,8 +338,18 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O // MARK: - General - func constrainHeight(to height: CGFloat) { - view.set(.height, to: height) + func constrainSize(to size: CGSize) { + if viewWidth == nil { + viewWidth = view.set(.width, to: size.width) + } else { + viewWidth?.constant = size.width + } + + if viewHeight == nil { + viewHeight = view.set(.height, to: size.height) + } else { + viewHeight?.constant = size.height + } } @objc private func dismissKeyboard() { @@ -445,7 +461,8 @@ private final class EnterURLVC: UIViewController, UIGestureRecognizerDelegate, O private final class ScanQRCodePlaceholderVC: UIViewController { weak var joinOpenGroupVC: JoinOpenGroupVC? - var viewWidth: NSLayoutConstraint? + private var viewWidth: NSLayoutConstraint? + private var viewHeight: NSLayoutConstraint? // MARK: - Lifecycle @@ -476,7 +493,6 @@ private final class ScanQRCodePlaceholderVC: UIViewController { stackView.alignment = .center // Constraints - viewWidth = view.set(.width, to: UIScreen.main.bounds.width) view.addSubview(stackView) stackView.pin(.leading, to: .leading, of: view, withInset: Values.massiveSpacing) view.pin(.trailing, to: .trailing, of: stackView, withInset: Values.massiveSpacing) @@ -485,8 +501,18 @@ private final class ScanQRCodePlaceholderVC: UIViewController { verticalCenteringConstraint.constant = -16 // Makes things appear centered visually } - func constrainHeight(to height: CGFloat) { - view.set(.height, to: height) + func constrainSize(to size: CGSize) { + if viewWidth == nil { + viewWidth = view.set(.width, to: size.width) + } else { + viewWidth?.constant = size.width + } + + if viewHeight == nil { + viewHeight = view.set(.height, to: size.height) + } else { + viewHeight?.constant = size.height + } } @objc private func requestCameraAccess() { From 5d36f81a8cb345d9e99a95c91fb741058280622f Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 14:38:46 +1100 Subject: [PATCH 38/50] clean --- SessionUIKit/Style Guide/Gradients.swift | 65 ------------------------ 1 file changed, 65 deletions(-) delete mode 100644 SessionUIKit/Style Guide/Gradients.swift diff --git a/SessionUIKit/Style Guide/Gradients.swift b/SessionUIKit/Style Guide/Gradients.swift deleted file mode 100644 index a08c24bdb..000000000 --- a/SessionUIKit/Style Guide/Gradients.swift +++ /dev/null @@ -1,65 +0,0 @@ -import UIKit - -@objc(LKGradient) -public final class Gradient : NSObject { - public let start: UIColor - public let end: UIColor - - private override init() { preconditionFailure("Use init(start:end:) instead.") } - - @objc public init(start: UIColor, end: UIColor) { - self.start = start - self.end = end - super.init() - } -} - -@objc public extension UIView { - - @objc func setGradient(_ gradient: Gradient, frame: CGRect = UIScreen.main.bounds) { - let layer = CAGradientLayer() - layer.frame = frame - layer.colors = [ gradient.start.cgColor, gradient.end.cgColor ] - if let existingSublayer = self.layer.sublayers?[0], existingSublayer is CAGradientLayer { - self.layer.replaceSublayer(existingSublayer, with: layer) - } else { - self.layer.insertSublayer(layer, at: 0) - } - } - - func setHalfWayGradient(_ gradient: Gradient, frame: CGRect = UIScreen.main.bounds) { - let layer = CAGradientLayer() - layer.frame = frame - layer.colors = [ gradient.start.cgColor, gradient.end.cgColor, gradient.end.cgColor ] - if let existingSublayer = self.layer.sublayers?[0], existingSublayer is CAGradientLayer { - self.layer.replaceSublayer(existingSublayer, with: layer) - } else { - self.layer.insertSublayer(layer, at: 0) - } - } -} - -@objc(LKGradients) -final public class Gradients : NSObject { - - @objc public static var defaultBackground: Gradient { - switch AppModeManager.shared.currentAppMode { - case .light: return Gradient(start: UIColor(hex: 0xF9F9F9), end: UIColor(hex: 0xFFFFFF)) - case .dark: return Gradient(start: UIColor(hex: 0x171717), end: UIColor(hex: 0x121212)) - } - } - - @objc public static var homeVCFade: Gradient { - switch AppModeManager.shared.currentAppMode { - case .light: return Gradient(start: UIColor(hex: 0xFFFFFF).withAlphaComponent(0), end: UIColor(hex: 0xFFFFFF)) - case .dark: return Gradient(start: UIColor(hex: 0x000000).withAlphaComponent(0), end: UIColor(hex: 0x000000)) - } - } - - @objc public static var newClosedGroupVCFade: Gradient { - switch AppModeManager.shared.currentAppMode { - case .light: return Gradient(start: UIColor(hex: 0xF9F9F9).withAlphaComponent(0), end: UIColor(hex: 0xF9F9F9)) - case .dark: return Gradient(start: UIColor(hex: 0x1B1B1B).withAlphaComponent(0), end: UIColor(hex: 0x1B1B1B)) - } - } -} From b7616dea0bd1919bd9836065c4f8e795b529a84f Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 14:42:37 +1100 Subject: [PATCH 39/50] clean --- Session/Closed Groups/NewClosedGroupVC.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index 674a28f90..b57b93ec1 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -159,11 +159,6 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate // Set up content setUpViewHierarchy() } - - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - tableViewWidth?.constant = size.width - } private func setUpViewHierarchy() { guard !contactProfiles.isEmpty else { From be670a5516002167a5a3e129b347a00e735b7455 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 14:43:09 +1100 Subject: [PATCH 40/50] clean --- Session/Closed Groups/NewClosedGroupVC.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index b57b93ec1..efadfcde6 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -32,11 +32,7 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate ] private var selectedContacts: Set = [] private var searchText: String = "" - - // MARK: - Layout - - private var tableViewWidth: NSLayoutConstraint? - + // MARK: - Components private static let textFieldHeight: CGFloat = 50 From d9ea06008bdfbd4d5223ec430d0ac4e8a808b4e6 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 14:54:53 +1100 Subject: [PATCH 41/50] clean --- Session/Calls/CallVC.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 7b128fb04..6cbb255eb 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -363,16 +363,16 @@ final class CallVC: UIViewController, VideoPreviewDelegate { NotificationCenter.default.addObserver(self, selector: #selector(audioRouteDidChange), name: AVAudioSession.routeChangeNotification, object: nil) } - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - - if let existingSublayer = fadeView.layer.sublayers?[0] as? CAGradientLayer { - let layer = CAGradientLayer() - layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) - layer.colors = existingSublayer.colors - fadeView.layer.replaceSublayer(existingSublayer, with: layer) - } - } +// override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { +// super.viewWillTransition(to: size, with: coordinator) +// +// if let existingSublayer = fadeView.layer.sublayers?[0] as? CAGradientLayer { +// let layer = CAGradientLayer() +// layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) +// layer.colors = existingSublayer.colors +// fadeView.layer.replaceSublayer(existingSublayer, with: layer) +// } +// } deinit { UIDevice.current.endGeneratingDeviceOrientationNotifications() From 98c5c996fc57ac5a9af6346de7edbde1ad4f9274 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 11 Oct 2022 16:37:48 +1100 Subject: [PATCH 42/50] clean --- Session/Conversations/ConversationViewModel.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index ed3e3b262..48a81fbd1 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -197,16 +197,6 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { return SQL("LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(interaction[.authorId])") }() - ), - PagedData.ObservedChanges( - table: Quote.self, - columns: [.body, .attachmentId], - joinToPagedType: { - let interaction: TypedTableAlias = TypedTableAlias() - let quote: TypedTableAlias = TypedTableAlias() - - return SQL("LEFT JOIN \(Quote.self) ON \(quote[.interactionId]) = \(interaction[.id])") - }() ) ], joinSQL: MessageViewModel.optimisedJoinSQL, From e16180c007350123eb16e793849b7f71402b9f75 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 12 Oct 2022 09:05:21 +1100 Subject: [PATCH 43/50] Removed commented code and fixed a minor layout issue on SE devices --- Session/Calls/CallVC.swift | 11 ----------- SessionUIKit/Components/Separator.swift | 1 + 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 6cbb255eb..adb72deb1 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -363,17 +363,6 @@ final class CallVC: UIViewController, VideoPreviewDelegate { NotificationCenter.default.addObserver(self, selector: #selector(audioRouteDidChange), name: AVAudioSession.routeChangeNotification, object: nil) } -// override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { -// super.viewWillTransition(to: size, with: coordinator) -// -// if let existingSublayer = fadeView.layer.sublayers?[0] as? CAGradientLayer { -// let layer = CAGradientLayer() -// layer.frame = CGRect(x: 0, y: 0, width: size.width, height: 64) -// layer.colors = existingSublayer.colors -// fadeView.layer.replaceSublayer(existingSublayer, with: layer) -// } -// } - deinit { UIDevice.current.endGeneratingDeviceOrientationNotifications() NotificationCenter.default.removeObserver(self) diff --git a/SessionUIKit/Components/Separator.swift b/SessionUIKit/Components/Separator.swift index f4d8957c3..178c27748 100644 --- a/SessionUIKit/Components/Separator.swift +++ b/SessionUIKit/Components/Separator.swift @@ -25,6 +25,7 @@ public final class Separator: UIView { private lazy var titleLabel: UILabel = { let result = UILabel() + result.setContentCompressionResistancePriority(.required, for: .vertical) result.font = .systemFont(ofSize: Values.smallFontSize) result.themeTextColor = .textSecondary result.textAlignment = .center From 7cbdca672edd190dfd0bce81d184f990807c53f2 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 9 Nov 2022 11:07:13 +1100 Subject: [PATCH 44/50] Fixed a bug where copying the open group url wasn't working correctly --- .../ConversationVC+Interaction.swift | 5 ++ .../Settings/ThreadSettingsViewModel.swift | 43 ++++++++++++--- .../Database/Models/OpenGroup.swift | 52 ++----------------- .../ConfigurationMessage+Convenience.swift | 8 ++- .../SessionThreadViewModel.swift | 9 ++++ .../Open Groups/Models/OpenGroupSpec.swift | 26 ++++++++++ 6 files changed, 86 insertions(+), 57 deletions(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index bb70bea7f..afd586d78 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1578,6 +1578,11 @@ extension ConversationVC: case .typingIndicator, .dateHeader: break case .textOnlyMessage: + if cellViewModel.body == nil, let linkPreview: LinkPreview = cellViewModel.linkPreview { + UIPasteboard.general.string = linkPreview.url + return + } + UIPasteboard.general.string = cellViewModel.body case .audio, .genericAttachment, .mediaMessage: diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index e771e26fb..fe23f06f8 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -241,7 +241,24 @@ class ThreadSettingsViewModel: SessionTableViewModel) { - let threadId: String = self.threadId + private func addUsersToOpenGoup(threadViewModel: SessionThreadViewModel, selectedUsers: Set) { + guard + let name: String = threadViewModel.openGroupName, + let server: String = threadViewModel.openGroupServer, + let roomToken: String = threadViewModel.openGroupRoomToken, + let publicKey: String = threadViewModel.openGroupPublicKey + else { return } dependencies.storage.writeAsync { db in - guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else { return } - - let urlString: String = "\(openGroup.server)/\(openGroup.roomToken)?public_key=\(openGroup.publicKey)" + let urlString: String = OpenGroup.urlFor( + server: server, + roomToken: roomToken, + publicKey: publicKey + ) try selectedUsers.forEach { userId in let thread: SessionThread = try SessionThread.fetchOrCreate(db, id: userId, variant: .contact) @@ -575,7 +602,7 @@ class ThreadSettingsViewModel: SessionTableViewModel String { + return "\(server)/\(roomToken)?public_key=\(publicKey)" + } } extension OpenGroup: CustomStringConvertible, CustomDebugStringConvertible { @@ -243,51 +247,3 @@ extension OpenGroup: CustomStringConvertible, CustomDebugStringConvertible { ].joined(separator: ", ") } } - -// MARK: - Objective-C Support - -// TODO: Remove this when possible - -@objc(SMKOpenGroup) -public class SMKOpenGroup: NSObject { - @objc(inviteUsers:toOpenGroupFor:) - public static func invite(selectedUsers: Set, openGroupThreadId: String) { - Storage.shared.write { db in - guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: openGroupThreadId) else { return } - - let urlString: String = "\(openGroup.server)/\(openGroup.roomToken)?public_key=\(openGroup.publicKey)" - - try selectedUsers.forEach { userId in - let thread: SessionThread = try SessionThread.fetchOrCreate(db, id: userId, variant: .contact) - - try LinkPreview( - url: urlString, - variant: .openGroupInvitation, - title: openGroup.name - ) - .save(db) - - let interaction: Interaction = try Interaction( - threadId: thread.id, - authorId: userId, - variant: .standardOutgoing, - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)), - expiresInSeconds: try? DisappearingMessagesConfiguration - .select(.durationSeconds) - .filter(id: userId) - .filter(DisappearingMessagesConfiguration.Columns.isEnabled == true) - .asRequest(of: TimeInterval.self) - .fetchOne(db), - linkPreviewUrl: urlString - ) - .inserted(db) - - try MessageSender.send( - db, - interaction: interaction, - in: thread - ) - } - } - } -} diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift index a2d7bf096..72289c200 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift @@ -42,7 +42,13 @@ extension ConfigurationMessage { .filter(OpenGroup.Columns.roomToken != "") .filter(OpenGroup.Columns.isActive) .fetchAll(db) - .map { "\($0.server)/\($0.roomToken)?public_key=\($0.publicKey)" } + .map { openGroup in + OpenGroup.urlFor( + server: openGroup.server, + roomToken: openGroup.roomToken, + publicKey: openGroup.publicKey + ) + } .asSet() let contacts: Set = try Contact .filter(Contact.Columns.id != currentUserProfile.id) diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index 2280a8542..616b7c15a 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -43,6 +43,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public static let openGroupNameKey: SQL = SQL(stringLiteral: CodingKeys.openGroupName.stringValue) public static let openGroupServerKey: SQL = SQL(stringLiteral: CodingKeys.openGroupServer.stringValue) public static let openGroupRoomTokenKey: SQL = SQL(stringLiteral: CodingKeys.openGroupRoomToken.stringValue) + public static let openGroupPublicKeyKey: SQL = SQL(stringLiteral: CodingKeys.openGroupPublicKey.stringValue) public static let openGroupProfilePictureDataKey: SQL = SQL(stringLiteral: CodingKeys.openGroupProfilePictureData.stringValue) public static let openGroupUserCountKey: SQL = SQL(stringLiteral: CodingKeys.openGroupUserCount.stringValue) public static let openGroupPermissionsKey: SQL = SQL(stringLiteral: CodingKeys.openGroupPermissions.stringValue) @@ -117,6 +118,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public let openGroupName: String? public let openGroupServer: String? public let openGroupRoomToken: String? + public let openGroupPublicKey: String? public let openGroupProfilePictureData: Data? private let openGroupUserCount: Int? private let openGroupPermissions: OpenGroup.Permissions? @@ -274,6 +276,7 @@ public extension SessionThreadViewModel { self.openGroupName = nil self.openGroupServer = nil self.openGroupRoomToken = nil + self.openGroupPublicKey = nil self.openGroupProfilePictureData = nil self.openGroupUserCount = nil self.openGroupPermissions = nil @@ -334,6 +337,7 @@ public extension SessionThreadViewModel { openGroupName: self.openGroupName, openGroupServer: self.openGroupServer, openGroupRoomToken: self.openGroupRoomToken, + openGroupPublicKey: self.openGroupPublicKey, openGroupProfilePictureData: self.openGroupProfilePictureData, openGroupUserCount: self.openGroupUserCount, openGroupPermissions: self.openGroupPermissions, @@ -387,6 +391,7 @@ public extension SessionThreadViewModel { openGroupName: self.openGroupName, openGroupServer: self.openGroupServer, openGroupRoomToken: self.openGroupRoomToken, + openGroupPublicKey: self.openGroupPublicKey, openGroupProfilePictureData: self.openGroupProfilePictureData, openGroupUserCount: self.openGroupUserCount, openGroupPermissions: self.openGroupPermissions, @@ -753,6 +758,7 @@ public extension SessionThreadViewModel { \(openGroup[.name]) AS \(ViewModel.openGroupNameKey), \(openGroup[.server]) AS \(ViewModel.openGroupServerKey), \(openGroup[.roomToken]) AS \(ViewModel.openGroupRoomTokenKey), + \(openGroup[.publicKey]) AS \(ViewModel.openGroupPublicKeyKey), \(openGroup[.userCount]) AS \(ViewModel.openGroupUserCountKey), \(openGroup[.permissions]) AS \(ViewModel.openGroupPermissionsKey), @@ -847,6 +853,9 @@ public extension SessionThreadViewModel { \(closedGroup[.name]) AS \(ViewModel.closedGroupNameKey), (\(groupMember[.profileId]) IS NOT NULL) AS \(ViewModel.currentUserIsClosedGroupMemberKey), \(openGroup[.name]) AS \(ViewModel.openGroupNameKey), + \(openGroup[.server]) AS \(ViewModel.openGroupServerKey), + \(openGroup[.roomToken]) AS \(ViewModel.openGroupRoomTokenKey), + \(openGroup[.publicKey]) AS \(ViewModel.openGroupPublicKeyKey), \(openGroup[.imageData]) AS \(ViewModel.openGroupProfilePictureDataKey), \(SQL("\(userPublicKey)")) AS \(ViewModel.currentUserPublicKeyKey) diff --git a/SessionMessagingKitTests/Open Groups/Models/OpenGroupSpec.swift b/SessionMessagingKitTests/Open Groups/Models/OpenGroupSpec.swift index b6083b47a..5225a130a 100644 --- a/SessionMessagingKitTests/Open Groups/Models/OpenGroupSpec.swift +++ b/SessionMessagingKitTests/Open Groups/Models/OpenGroupSpec.swift @@ -79,6 +79,32 @@ class OpenGroupSpec: QuickSpec { .to(equal("OpenGroup(server: \"server\", roomToken: \"room\", id: \"server.room\", publicKey: \"1234\", isActive: true, name: \"name\", roomDescription: null, imageId: null, userCount: 0, infoUpdates: 0, sequenceNumber: 0, inboxLatestMessageId: 0, outboxLatestMessageId: 0, pollFailureCount: 0, permissions: ---)")) } } + + context("when generating an id") { + it("generates correctly") { + expect(OpenGroup.idFor(roomToken: "room", server: "server")).to(equal("server.room")) + } + + it("converts the server to lowercase") { + expect(OpenGroup.idFor(roomToken: "room", server: "SeRVeR")).to(equal("server.room")) + } + + it("maintains the casing of the roomToken") { + expect(OpenGroup.idFor(roomToken: "RoOM", server: "server")).to(equal("server.RoOM")) + } + } + + context("when generating a url") { + it("generates the url correctly") { + expect(OpenGroup.urlFor(server: "server", roomToken: "room", publicKey: "key")) + .to(equal("server/room?public_key=key")) + } + + it("maintains the casing provided") { + expect(OpenGroup.urlFor(server: "SeRVer", roomToken: "RoOM", publicKey: "KEy")) + .to(equal("SeRVer/RoOM?public_key=KEy")) + } + } } } } From e808f385e8bb0e0d1493d54bc549a00edd93eebd Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Thu, 10 Nov 2022 15:54:02 +1100 Subject: [PATCH 45/50] Fixed a crash which could occur in global search --- SessionUtilitiesKit/Database/Utilities/Database+Utilities.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SessionUtilitiesKit/Database/Utilities/Database+Utilities.swift b/SessionUtilitiesKit/Database/Utilities/Database+Utilities.swift index d736dfc35..b8e849c74 100644 --- a/SessionUtilitiesKit/Database/Utilities/Database+Utilities.swift +++ b/SessionUtilitiesKit/Database/Utilities/Database+Utilities.swift @@ -32,6 +32,8 @@ public extension Database { } func interrupt() { + guard sqliteConnection != nil else { return } + sqlite3_interrupt(sqliteConnection) } } From 02400012013d4ff53a4ae85b21ef5d3e639de6a8 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 16 Nov 2022 10:28:07 +1100 Subject: [PATCH 46/50] fix copy and share buttons are getting squashed when switching from landscape to portrait in new DM VC --- Session/Home/New Conversation/NewDMVC.swift | 11 ++++++----- SessionUIKit/Style Guide/Values.swift | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Session/Home/New Conversation/NewDMVC.swift b/Session/Home/New Conversation/NewDMVC.swift index 3c2e22eba..54ae31d23 100644 --- a/Session/Home/New Conversation/NewDMVC.swift +++ b/Session/Home/New Conversation/NewDMVC.swift @@ -362,11 +362,6 @@ private final class EnterPublicKeyVC: UIViewController { result.spacing = UIDevice.current.isIPad ? Values.iPadButtonSpacing : Values.mediumSpacing result.distribution = .fillEqually - if (UIDevice.current.isIPad) { - result.layoutMargins = UIEdgeInsets(top: 0, left: Values.iPadButtonContainerMargin, bottom: 0, right: Values.iPadButtonContainerMargin) - result.isLayoutMarginsRelativeArrangement = true - } - return result }() @@ -474,6 +469,12 @@ private final class EnterPublicKeyVC: UIViewController { } else { viewHeight?.constant = size.height } + + if (UIDevice.current.isIPad) { + let iPadButtonContainerMargin: CGFloat = (size.width - Values.iPadButtonSpacing) / 2 - Values.iPadButtonWidth - Values.largeSpacing + buttonContainer.layoutMargins = UIEdgeInsets(top: 0, left: iPadButtonContainerMargin, bottom: 0, right: iPadButtonContainerMargin) + buttonContainer.isLayoutMarginsRelativeArrangement = true + } } diff --git a/SessionUIKit/Style Guide/Values.swift b/SessionUIKit/Style Guide/Values.swift index fd03c9dcb..fd12c70c9 100644 --- a/SessionUIKit/Style Guide/Values.swift +++ b/SessionUIKit/Style Guide/Values.swift @@ -57,5 +57,4 @@ public final class Values : NSObject { @objc public static let iPadButtonWidth = CGFloat(196) @objc public static let iPadButtonSpacing = CGFloat(32) @objc public static let iPadUserSessionIdContainerWidth = iPadButtonWidth * 2 + iPadButtonSpacing - @objc public static let iPadButtonContainerMargin = (UIScreen.main.bounds.width - iPadButtonSpacing) / 2 - iPadButtonWidth - largeSpacing } From d827bb2770a50e545f5b67d2b67c279c97d2ca02 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 16 Nov 2022 13:13:25 +1100 Subject: [PATCH 47/50] fix message request empty state --- .../Home/Message Requests/MessageRequestsViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session/Home/Message Requests/MessageRequestsViewController.swift b/Session/Home/Message Requests/MessageRequestsViewController.swift index b64ccfdc7..3e332ec9f 100644 --- a/Session/Home/Message Requests/MessageRequestsViewController.swift +++ b/Session/Home/Message Requests/MessageRequestsViewController.swift @@ -235,8 +235,8 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat loadingConversationsLabel.isHidden = true // Show the empty state if there is no data - clearAllButton.isHidden = updatedData.isEmpty - emptyStateLabel.isHidden = !updatedData.isEmpty + clearAllButton.isHidden = !(updatedData.first?.elements.isEmpty == false) + emptyStateLabel.isHidden = !clearAllButton.isHidden CATransaction.begin() CATransaction.setCompletionBlock { [weak self] in From 47523054b2f67c5689582040055752846556463b Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 16 Nov 2022 15:40:49 +1100 Subject: [PATCH 48/50] slightly reduce max width of media message on iPad --- Session/Conversations/Message Cells/VisibleMessageCell.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 567abe565..2c47807d8 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -1025,11 +1025,12 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { static func getMaxWidth(for cellViewModel: MessageViewModel, includingOppositeGutter: Bool = true) -> CGFloat { let screen: CGRect = UIScreen.main.bounds + let width: CGFloat = UIDevice.current.isIPad ? screen.width * 0.75 : screen.width let oppositeEdgePadding: CGFloat = (includingOppositeGutter ? gutterSize : contactThreadHSpacing) switch cellViewModel.variant { case .standardOutgoing: - return (screen.width - contactThreadHSpacing - oppositeEdgePadding) + return (width - contactThreadHSpacing - oppositeEdgePadding) case .standardIncoming, .standardIncomingDeleted: let isGroupThread = ( @@ -1038,7 +1039,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { ) let leftGutterSize = (isGroupThread ? leftGutterSize : contactThreadHSpacing) - return (screen.width - leftGutterSize - oppositeEdgePadding) + return (width - leftGutterSize - oppositeEdgePadding) default: preconditionFailure() } From 9d71ae141b0786e45151202b84cf87667f071939 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 16 Nov 2022 15:43:55 +1100 Subject: [PATCH 49/50] bump up build & version number --- Session.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 3b89e7edc..59c6f6999 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -7212,7 +7212,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 2.2.2; + MARKETING_VERSION = 2.2.3; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -7284,7 +7284,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 2.2.2; + MARKETING_VERSION = 2.2.3; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From ff813e4376d331befa85eaddd8fc05eafa621534 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 16 Nov 2022 16:52:49 +1100 Subject: [PATCH 50/50] update build number --- Session.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 59c6f6999..6aecc3fc4 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -7173,7 +7173,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 387; + CURRENT_PROJECT_VERSION = 388; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7245,7 +7245,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 387; + CURRENT_PROJECT_VERSION = 388; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)",