From dfb2369ab868388d14101d96fff84e6542a62390 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 2 Mar 2021 11:46:29 +1100 Subject: [PATCH 1/2] Show unread count on scroll to bottom button --- .../ConversationVC+Interaction.swift | 1 + Session/Conversations/ConversationVC.swift | 51 +++++++++++++++++++ Session/Shared/ConversationCell.swift | 1 - 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index cc46161c1a..cfe50349de 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -354,6 +354,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc self.scrollButton.alpha = 0 UIView.animate(withDuration: 0.25) { self.scrollButton.alpha = self.getScrollButtonOpacity() + self.unreadCountView.alpha = self.scrollButton.alpha } } self.contextMenuVC = contextMenuVC diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 49c56dd5e6..a899b46566 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -7,6 +7,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversationSettingsViewDelegate, ConversationSearchControllerDelegate, UITableViewDataSource, UITableViewDelegate { let thread: TSThread let focusedMessageID: String? // This isn't actually used ATM + var unreadViewItems: [ConversationViewItem] = [] var didConstrainScrollButton = false // Part of a workaround to get the scroll button to show up in the right place // Search var isShowingSearchUI = false @@ -90,6 +91,25 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat lazy var snInputView = InputView(delegate: self) + lazy var unreadCountView: UIView = { + let result = UIView() + result.backgroundColor = Colors.text.withAlphaComponent(Values.veryLowOpacity) + let size = ConversationVC.unreadCountViewSize + result.set(.width, to: size) + result.set(.height, to: size) + result.layer.masksToBounds = true + result.layer.cornerRadius = size / 2 + return result + }() + + lazy var unreadCountLabel: UILabel = { + let result = UILabel() + result.font = .boldSystemFont(ofSize: Values.verySmallFontSize) + result.textColor = Colors.text + result.textAlignment = .center + return result + }() + lazy var scrollButton = ScrollToBottomButton(delegate: self) lazy var blockedBanner: InfoBanner = { @@ -109,6 +129,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat }() // MARK: Settings + static let unreadCountViewSize: CGFloat = 20 /// The table view's bottom inset (content will have this distance to the bottom if the table view is fully scrolled down). static let bottomInset = Values.mediumSpacing /// The table view will start loading more content when the content offset becomes less than this. @@ -123,6 +144,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat self.thread = thread self.focusedMessageID = focusedMessageID super.init(nibName: nil, bundle: nil) + var unreadCount: UInt = 0 + Storage.read { transaction in + unreadCount = self.thread.unreadMessageCount(transaction: transaction) + } + unreadViewItems = unreadCount != 0 ? [ConversationViewItem](viewItems[viewItems.endIndex - Int(unreadCount) ..< viewItems.endIndex]) : [] } required init?(coder: NSCoder) { @@ -142,6 +168,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat messagesTableView.pin(to: view) view.addSubview(scrollButton) scrollButton.pin(.right, to: .right, of: view, withInset: -16) + // Unread count view + view.addSubview(unreadCountView) + unreadCountView.addSubview(unreadCountLabel) + unreadCountLabel.pin(to: unreadCountView) + unreadCountView.centerYAnchor.constraint(equalTo: scrollButton.topAnchor).isActive = true + unreadCountView.center(.horizontal, in: scrollButton) + updateUnreadCountView() // Blocked banner addOrRemoveBlockedBanner() // Notifications @@ -174,6 +207,8 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat DispatchQueue.main.async { if unreadCount > 0, let viewItem = self.viewItems[ifValid: self.viewItems.count - Int(unreadCount)], let interactionID = viewItem.interaction.uniqueId { self.scrollToInteraction(with: interactionID, position: .top, isAnimated: false) + self.scrollButton.alpha = self.getScrollButtonOpacity() + self.unreadCountView.alpha = self.scrollButton.alpha } else { self.scrollToBottom(isAnimated: false) } @@ -267,6 +302,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat UIView.animate(withDuration: 0.25) { self.messagesTableView.keyboardHeight = 0 self.scrollButton.alpha = self.getScrollButtonOpacity() + self.unreadCountView.alpha = self.scrollButton.alpha } } @@ -412,7 +448,22 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat func scrollViewDidScroll(_ scrollView: UIScrollView) { scrollButton.alpha = getScrollButtonOpacity() + unreadCountView.alpha = scrollButton.alpha autoLoadMoreIfNeeded() + updateUnreadCountView() + } + + func updateUnreadCountView() { + let visibleViewItems = (messagesTableView.indexPathsForVisibleRows ?? []).map { viewItems[$0.row] } + for visibleItem in visibleViewItems { + guard let index = unreadViewItems.firstIndex(where: { $0 === visibleItem }) else { continue } + unreadViewItems.remove(at: index) + } + let unreadCount = unreadViewItems.count + unreadCountLabel.text = unreadCount < 100 ? "\(unreadCount)" : "99+" + let fontSize = (unreadCount < 100) ? Values.verySmallFontSize : 8 + unreadCountLabel.font = .boldSystemFont(ofSize: fontSize) + unreadCountView.isHidden = (unreadCount == 0) } func autoLoadMoreIfNeeded() { diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index e6106a9068..dd3066c1ce 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -98,7 +98,6 @@ final class ConversationCell : UITableViewCell { // Unread count view unreadCountView.addSubview(unreadCountLabel) unreadCountLabel.pin(to: unreadCountView) - unreadCountLabel.text = "4" // Label stack view let topLabelSpacer = UIView.hStretchingSpacer() let topLabelStackView = UIStackView(arrangedSubviews: [ displayNameLabel, unreadCountView, topLabelSpacer, timestampLabel ]) From b202ea878c90d03347f8088a901090e4da76e006 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 2 Mar 2021 11:46:50 +1100 Subject: [PATCH 2/2] Update build number --- Session.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index ecbd8baf94..b08a875b35 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5153,7 +5153,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5222,7 +5222,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5283,7 +5283,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5353,7 +5353,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6238,7 +6238,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6306,7 +6306,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 201; + CURRENT_PROJECT_VERSION = 202; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)",