Fixed a handful more bugs

Fixed an issue where I'd shifted push notification logic to a background thread resulting in crashes
Fixed a bug where the status indicator view on the FullConversationCell was incorrectly showing for incoming messages
Fixed a bug where outgoing messages to closed groups would all be flagged as failed to send
Fixed a bug with the "autoLoadNextPageIfNeeded" on the conversation screen
Fixed a bug where the input view on a closed group wouldn't appear correctly based on whether the user was a member or not
Added the "autoLoadNextPageIfNeeded" logic to the home screen
pull/612/head
Morgan Pretty 3 years ago
parent 2cd9f571da
commit ff2d96e0d5

@ -591,12 +591,13 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
snInputView.text = draft
}
// Now we have done all the needed diffs, update the viewModel with the latest data
self.viewModel.updateThreadData(updatedThreadData)
/// **Note:** This needs to happen **after** we have update the viewModel's thread data
if viewModel.threadData.currentUserIsClosedGroupMember != updatedThreadData.currentUserIsClosedGroupMember {
reloadInputViews()
}
// Now we have done all the needed diffs, update the viewModel with the latest data
self.viewModel.updateThreadData(updatedThreadData)
}
private func handleInteractionUpdates(_ updatedData: [ConversationViewModel.SectionModel], initialLoad: Bool = false) {
@ -837,7 +838,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
// Note: We sort the headers as we want to prioritise loading newer pages over older ones
let sections: [(ConversationViewModel.Section, CGRect)] = (self?.viewModel.interactionData
.enumerated()
.map { index, section in (section.model, (self?.tableView.rectForHeader(inSection: 0) ?? .zero)) })
.map { index, section in (section.model, (self?.tableView.rectForHeader(inSection: index) ?? .zero)) })
.defaulting(to: [])
let shouldLoadOlder: Bool = sections
.contains { section, headerRect in

@ -98,7 +98,20 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
// MARK: - Thread Data
/// This value is the current state of the view
public private(set) var threadData: SessionThreadViewModel = SessionThreadViewModel()
public private(set) lazy var threadData: SessionThreadViewModel = SessionThreadViewModel(
threadId: self.threadId,
threadVariant: self.initialThreadVariant,
currentUserIsClosedGroupMember: (self.initialThreadVariant != .closedGroup ?
nil :
GRDBStorage.shared.read { db in
try GroupMember
.filter(GroupMember.Columns.groupId == self.threadId)
.filter(GroupMember.Columns.profileId == getUserHexEncodedPublicKey(db))
.filter(GroupMember.Columns.role == GroupMember.Role.standard)
.isNotEmpty(db)
}
)
)
/// This is all the data the screen needs to populate itself, please see the following link for tips to help optimise
/// performance https://github.com/groue/GRDB.swift#valueobservation-performance

@ -15,6 +15,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
private var hasLoadedInitialStateData: Bool = false
private var hasLoadedInitialThreadData: Bool = false
private var isLoadingMore: Bool = false
private var isAutoLoadingNextPage: Bool = false
// MARK: - Intialization
@ -319,6 +320,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
CATransaction.setCompletionBlock { [weak self] in
// Complete page loading
self?.isLoadingMore = false
self?.autoLoadNextPageIfNeeded()
}
// Reload the table content (animate changes after the first load)
@ -328,7 +330,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
insertSectionsAnimation: .none,
reloadSectionsAnimation: .none,
deleteRowsAnimation: .bottom,
insertRowsAnimation: .top,
insertRowsAnimation: .none,
reloadRowsAnimation: .none,
interrupt: { $0.changeCount > 100 } // Prevent too many changes from causing performance issues
) { [weak self] updatedData in
@ -338,6 +340,36 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
CATransaction.commit()
}
private func autoLoadNextPageIfNeeded() {
guard !self.isAutoLoadingNextPage && !self.isLoadingMore else { return }
self.isAutoLoadingNextPage = true
DispatchQueue.main.asyncAfter(deadline: .now() + PagedData.autoLoadNextPageDelay) { [weak self] in
self?.isAutoLoadingNextPage = false
// Note: We sort the headers as we want to prioritise loading newer pages over older ones
let sections: [(HomeViewModel.Section, CGRect)] = (self?.viewModel.threadData
.enumerated()
.map { index, section in (section.model, (self?.tableView.rectForHeader(inSection: index) ?? .zero)) })
.defaulting(to: [])
let shouldLoadMore: Bool = sections
.contains { section, headerRect in
section == .loadMore &&
headerRect != .zero &&
(self?.tableView.bounds.contains(headerRect) == true)
}
guard shouldLoadMore else { return }
self?.isLoadingMore = true
DispatchQueue.global(qos: .default).async { [weak self] in
self?.viewModel.pagedDataObserver?.load(.pageAfter)
}
}
}
private func updateNavBarButtons() {
// Profile picture view
let profilePictureSize = Values.verySmallProfilePictureSize

@ -19,7 +19,7 @@ public class HomeViewModel {
// MARK: - Variables
public static let pageSize: Int = 14
public static let pageSize: Int = 15
public struct State: Equatable {
let showViewedSeedBanner: Bool

@ -33,31 +33,8 @@ public enum SyncPushTokensJob: JobExecutor {
}
return
}
let isRegisteredForRemoteNotifications: Bool = UIApplication.shared.isRegisteredForRemoteNotifications
// Swap back to the correct queue before continuing (don't want to inadvertantly do stuff on the main
// thread that could block the user)
queue.async {
SyncPushTokensJob.internalRun(
job,
queue: queue,
isRegisteredForRemoteNotifications: isRegisteredForRemoteNotifications,
success: success,
failure: failure,
deferred: deferred
)
}
}
private static func internalRun(
_ job: Job,
queue: DispatchQueue,
isRegisteredForRemoteNotifications: Bool,
success: @escaping (Job, Bool) -> (),
failure: @escaping (Job, Error?, Bool) -> (),
deferred: @escaping (Job) -> ()
) {
guard !isRegisteredForRemoteNotifications else {
guard !UIApplication.shared.isRegisteredForRemoteNotifications else {
deferred(job) // Don't need to do anything if push notifications are already registered
return
}
@ -97,7 +74,7 @@ public enum SyncPushTokensJob: JobExecutor {
)
return promise
.done { _ in
.done(on: queue) { _ in
Logger.warn("Recording push tokens locally. pushToken: \(redact(pushToken)), voipToken: \(redact(voipToken))")
GRDBStorage.shared.write { db in

@ -374,7 +374,7 @@ public final class FullConversationCell: UITableViewCell {
statusIndicatorView.isHidden = false
default:
statusIndicatorView.isHidden = false
statusIndicatorView.isHidden = true
}
}

@ -356,13 +356,18 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu
return
}
try members.forEach { member in
try RecipientState(
interactionId: interactionId,
recipientId: member.profileId,
state: .sending
).insert(db)
}
// Exclude the current user when creating recipient states (as they will never
// receive the message resulting in the message getting flagged as failed)
let userPublicKey: String = getUserHexEncodedPublicKey(db)
try members
.filter { member -> Bool in member.profileId != userPublicKey }
.forEach { member in
try RecipientState(
interactionId: interactionId,
recipientId: member.profileId,
state: .sending
).insert(db)
}
case .openGroup:
// Since we use the 'RecipientState' type to manage the message state

@ -194,11 +194,18 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat
// MARK: - Convenience Initialization
public extension SessionThreadViewModel {
static let invalidId: String = "INVALID_THREAD_ID"
// Note: This init method is only used system-created cells or empty states
init(unreadCount: UInt = 0) {
init(
threadId: String? = nil,
threadVariant: SessionThread.Variant? = nil,
currentUserIsClosedGroupMember: Bool? = nil,
unreadCount: UInt = 0
) {
self.rowId = -1
self.threadId = "INVALID_THREAD_ID"
self.threadVariant = .contact
self.threadId = (threadId ?? SessionThreadViewModel.invalidId)
self.threadVariant = (threadVariant ?? .contact)
self.threadCreationDateTimestamp = 0
self.threadMemberNames = nil
@ -224,7 +231,7 @@ public extension SessionThreadViewModel {
self.closedGroupProfileBackFallback = nil
self.closedGroupName = nil
self.closedGroupUserCount = nil
self.currentUserIsClosedGroupMember = nil
self.currentUserIsClosedGroupMember = currentUserIsClosedGroupMember
self.currentUserIsClosedGroupAdmin = nil
self.openGroupName = nil
self.openGroupServer = nil

Loading…
Cancel
Save