Fixed a bug with the blocked contacts list

Fixed a bug where blocked contacts without profile information wouldn't be included in the blocked contacts list
Fixed broken test build issues
Increased build and version numbers
This commit is contained in:
Morgan Pretty 2023-10-03 13:43:09 +11:00
parent 4a95b4c921
commit 2cff251e8d
5 changed files with 74 additions and 48 deletions

View File

@ -6594,7 +6594,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6618,7 +6618,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -6666,7 +6666,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6695,7 +6695,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -6731,7 +6731,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6754,7 +6754,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@ -6805,7 +6805,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6833,7 +6833,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@ -7765,7 +7765,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7803,7 +7803,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@ -7836,7 +7836,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 426;
CURRENT_PROJECT_VERSION = 427;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7874,7 +7874,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.4.2;
MARKETING_VERSION = 2.4.3;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
PRODUCT_NAME = Session;

View File

@ -8,7 +8,7 @@ import SessionUIKit
import SignalUtilitiesKit
import SessionUtilitiesKit
class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsViewModel.Section, Profile> {
class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsViewModel.Section, BlockedContactsViewModel.DataModel> {
// MARK: - Section
public enum Section: SessionTableSection {
@ -39,10 +39,14 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
// doesn't stutter (it should load basically immediately but without this there is a
// distinct stutter)
_pagedDataObserver = PagedDatabaseObserver(
pagedTable: Profile.self,
pagedTable: Contact.self,
pageSize: BlockedContactsViewModel.pageSize,
idColumn: .id,
observedChanges: [
PagedData.ObservedChanges(
table: Contact.self,
columns: [.id, .isBlocked]
),
PagedData.ObservedChanges(
table: Profile.self,
columns: [
@ -50,16 +54,12 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
.name,
.nickname,
.profilePictureFileName
]
),
PagedData.ObservedChanges(
table: Contact.self,
columns: [.isBlocked],
],
joinToPagedType: {
let profile: TypedTableAlias<Profile> = TypedTableAlias()
let contact: TypedTableAlias<Contact> = TypedTableAlias()
let profile: TypedTableAlias<Profile> = TypedTableAlias()
return SQL("JOIN \(Contact.self) ON \(contact[.id]) = \(profile[.id])")
return SQL("JOIN \(Profile.self) ON \(profile[.id]) = \(contact[.id])")
}()
)
],
@ -101,7 +101,7 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
private let contactDataSubject: CurrentValueSubject<([SectionModel], StagedChangeset<[SectionModel]>), Never> = CurrentValueSubject(([], StagedChangeset()))
private let selectedContactIdsSubject: CurrentValueSubject<Set<String>, Never> = CurrentValueSubject([])
private var _pagedDataObserver: PagedDatabaseObserver<Profile, DataModel>?
private var _pagedDataObserver: PagedDatabaseObserver<Contact, DataModel>?
public override var pagedDataObserver: TransactionObserver? { _pagedDataObserver }
public override var observableTableData: ObservableData { _observableTableData }
@ -138,26 +138,32 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
section: .contacts,
elements: data
.sorted { lhs, rhs -> Bool in
lhs.profile.displayName() < rhs.profile.displayName()
let lhsValue: String = (lhs.profile?.displayName() ?? lhs.id)
let rhsValue: String = (rhs.profile?.displayName() ?? rhs.id)
return (lhsValue < rhsValue)
}
.map { [weak self] model -> SessionCell.Info<Profile> in
.map { [weak self] model -> SessionCell.Info<DataModel> in
SessionCell.Info(
id: model.profile,
leftAccessory: .profile(id: model.profile.id, profile: model.profile),
title: model.profile.displayName(),
id: model,
leftAccessory: .profile(id: model.id, profile: model.profile),
title: (
model.profile?.displayName() ??
Profile.truncated(id: model.id, truncating: .middle)
),
rightAccessory: .radio(
isSelected: {
self?.selectedContactIdsSubject.value.contains(model.profile.id) == true
self?.selectedContactIdsSubject.value.contains(model.id) == true
}
),
onTap: {
var updatedSelectedIds: Set<String> = (self?.selectedContactIdsSubject.value ?? [])
if !updatedSelectedIds.contains(model.profile.id) {
updatedSelectedIds.insert(model.profile.id)
if !updatedSelectedIds.contains(model.id) {
updatedSelectedIds.insert(model.id)
}
else {
updatedSelectedIds.remove(model.profile.id)
updatedSelectedIds.remove(model.id)
}
self?.selectedContactIdsSubject.send(updatedSelectedIds)
@ -182,7 +188,7 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
guard
let section: BlockedContactsViewModel.SectionModel = self.tableData
.first(where: { section in section.model == .contacts }),
let info: SessionCell.Info<Profile> = section.elements
let info: SessionCell.Info<DataModel> = section.elements
.first(where: { info in info.id.id == contactId })
else { return contactId }
@ -262,20 +268,22 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
public typealias Columns = CodingKeys
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
case rowId
case id
case profile
}
public var differenceIdentifier: String { profile.id }
public var id: String { profile.id }
public var differenceIdentifier: String { id }
public let rowId: Int64
public let profile: Profile
public let id: String
public let profile: Profile?
static func query(
filterSQL: SQL,
orderSQL: SQL
) -> (([Int64]) -> any FetchRequest<DataModel>) {
return { rowIds -> any FetchRequest<DataModel> in
let contact: TypedTableAlias<Contact> = TypedTableAlias()
let profile: TypedTableAlias<Profile> = TypedTableAlias()
/// **Note:** The `numColumnsBeforeProfile` value **MUST** match the number of fields before
@ -283,15 +291,17 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
/// parse and might throw
///
/// Explicitly set default values for the fields ignored for search results
let numColumnsBeforeProfile: Int = 1
let numColumnsBeforeProfile: Int = 2
let request: SQLRequest<DataModel> = """
SELECT
\(profile[.rowId]) AS \(DataModel.Columns.rowId),
\(contact[.rowId]) AS \(DataModel.Columns.rowId),
\(contact[.id]),
\(profile.allColumns)
FROM \(Profile.self)
WHERE \(profile[.rowId]) IN \(rowIds)
FROM \(Contact.self)
LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(contact[.id])
WHERE \(contact[.rowId]) IN \(rowIds)
ORDER BY \(orderSQL)
"""
@ -309,10 +319,10 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
}
static var optimisedJoinSQL: SQL = {
let profile: TypedTableAlias<Profile> = TypedTableAlias()
let contact: TypedTableAlias<Contact> = TypedTableAlias()
let profile: TypedTableAlias<Profile> = TypedTableAlias()
return SQL("JOIN \(Contact.self) ON \(contact[.id]) = \(profile[.id])")
return SQL("LEFT JOIN \(Profile.self) ON \(profile[.id]) = \(contact[.id])")
}()
static var filterSQL: SQL = {
@ -322,9 +332,10 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
}()
static let orderSQL: SQL = {
let contact: TypedTableAlias<Contact> = TypedTableAlias()
let profile: TypedTableAlias<Profile> = TypedTableAlias()
return SQL("IFNULL(IFNULL(\(profile[.nickname]), \(profile[.name])), \(profile[.id])) ASC")
return SQL("IFNULL(IFNULL(\(profile[.nickname]), \(profile[.name])), \(contact[.id])) ASC")
}()
}

View File

@ -77,13 +77,16 @@ class BlockedContactCell: UITableViewCell {
public func update(with cellViewModel: BlockedContactsViewModel.DataModel, isSelected: Bool) {
profilePictureView.update(
publicKey: cellViewModel.profile.id,
publicKey: cellViewModel.id,
threadVariant: .contact,
customImageData: nil,
profile: cellViewModel.profile,
additionalProfile: nil
)
selectionView.text = cellViewModel.profile.displayName()
selectionView.text = (
cellViewModel.profile?.displayName() ??
Profile.truncated(id: cellViewModel.id, truncating: .middle)
)
selectionView.update(isSelected: isSelected)
}
}

View File

@ -11,7 +11,7 @@ import DifferenceKit
/// **Note:** We **MUST** have accurate `filterSQL` and `orderSQL` values otherwise the indexing won't work
public class PagedDatabaseObserver<ObservedTable, T>: TransactionObserver where ObservedTable: TableRecord & ColumnExpressible & Identifiable, T: FetchableRecordWithRowId & Identifiable {
private let commitProcessingQueue: DispatchQueue = DispatchQueue(
label: "PagedDatabaseObserver.commitProcessingQueue",
label: "PagedDatabaseObserver.commitProcessingQueue", // stringlint:disable
qos: .userInitiated,
attributes: [] // Must be serial in order to avoid updates getting processed in the wrong order
)

View File

@ -43,8 +43,11 @@ class SynchronousStorage: Storage {
}
@discardableResult override func read<T>(
fileName: String = #file,
functionName: String = #function,
lineNumber: Int = #line,
using dependencies: Dependencies = Dependencies(),
_ value: (Database) throws -> T?
_ value: @escaping (Database) throws -> T?
) -> T? {
guard isValid, let dbWriter: DatabaseWriter = testDbWriter else { return nil }
@ -56,16 +59,25 @@ class SynchronousStorage: Storage {
return try? dbWriter.unsafeReentrantRead(value)
}
return super.read(using: dependencies, value)
return super.read(
fileName: fileName,
functionName: functionName,
lineNumber: lineNumber,
using: dependencies,
value
)
}
// MARK: - Async Methods
override func readPublisher<T>(
fileName: String = #file,
functionName: String = #function,
lineNumber: Int = #line,
using dependencies: Dependencies = Dependencies(),
value: @escaping (Database) throws -> T
) -> AnyPublisher<T, Error> {
guard let result: T = self.read(using: dependencies, value) else {
guard let result: T = self.read(fileName: fileName, functionName: functionName, lineNumber: lineNumber, using: dependencies, value) else {
return Fail(error: StorageError.generic)
.eraseToAnyPublisher()
}