Merge pull request #693 from mpretty-cyro/fix/regression-issues

Fixed a few bugs found during regression testing
pull/694/head
Morgan Pretty 3 years ago committed by GitHub
commit d01e756c67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6959,7 +6959,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 374;
CURRENT_PROJECT_VERSION = 375;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -6998,7 +6998,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.1.1;
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@ -7031,7 +7031,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 374;
CURRENT_PROJECT_VERSION = 375;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7070,7 +7070,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.1.1;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
PRODUCT_NAME = Session;

@ -315,12 +315,11 @@ extension ConversationVC:
let modal = SendSeedModal()
modal.modalPresentationStyle = .overFullScreen
modal.modalTransitionStyle = .crossDissolve
modal.proceed = { self.sendMessage(hasPermissionToSendSeed: true) }
modal.proceed = { [weak self] in self?.sendMessage(hasPermissionToSendSeed: true) }
return present(modal, animated: true, completion: nil)
}
// Clearing this out immediately (even though it already happens in 'messageSent') to prevent
// "double sending" if the user rapidly taps the send button
// Clearing this out immediately to make this appear more snappy
DispatchQueue.main.async { [weak self] in
self?.snInputView.text = ""
self?.snInputView.quoteDraftInfo = nil
@ -416,7 +415,7 @@ extension ConversationVC:
)
}
func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) {
func sendAttachments(_ attachments: [SignalAttachment], with text: String, hasPermissionToSendSeed: Bool = false, onComplete: (() -> ())? = nil) {
guard !showBlockedModalIfNeeded() else { return }
for attachment in attachments {
@ -426,6 +425,25 @@ extension ConversationVC:
}
let text = replaceMentions(in: snInputView.text.trimmingCharacters(in: .whitespacesAndNewlines))
if text.contains(mnemonic) && !viewModel.threadData.threadIsNoteToSelf && !hasPermissionToSendSeed {
// Warn the user if they're about to send their seed to someone
let modal = SendSeedModal()
modal.modalPresentationStyle = .overFullScreen
modal.modalTransitionStyle = .crossDissolve
modal.proceed = { [weak self] in
self?.sendAttachments(attachments, with: text, hasPermissionToSendSeed: true, onComplete: onComplete)
}
return present(modal, animated: true, completion: nil)
}
// Clearing this out immediately to make this appear more snappy
DispatchQueue.main.async { [weak self] in
self?.snInputView.text = ""
self?.snInputView.quoteDraftInfo = nil
self?.resetMentions()
}
// Note: 'shouldBeVisible' is set to true the first time a thread is saved so we can
// use it to determine if the user is creating a new thread and update the 'isApproved'
@ -492,13 +510,6 @@ extension ConversationVC:
}
func handleMessageSent() {
DispatchQueue.main.async { [weak self] in
self?.snInputView.text = ""
self?.snInputView.quoteDraftInfo = nil
self?.resetMentions()
}
if Storage.shared[.playNotificationSoundInForeground] {
let soundID = Preferences.Sound.systemSoundId(for: .messageSent, quiet: true)
AudioServicesPlaySystemSound(soundID)

@ -892,7 +892,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
deleteSectionsAnimation: .none,
insertSectionsAnimation: .none,
reloadSectionsAnimation: .none,
deleteRowsAnimation: .bottom,
deleteRowsAnimation: .fade,
insertRowsAnimation: .none,
reloadRowsAnimation: .none,
interrupt: { itemChangeInfo?.isInsertAtTop == true || $0.changeCount > ConversationViewModel.pageSize }

@ -47,12 +47,24 @@ final class CallMessageCell: MessageCell {
private lazy var container: UIView = {
let result: UIView = UIView()
result.set(.height, to: 50)
result.layer.cornerRadius = 18
result.backgroundColor = Colors.callMessageBackground
result.addSubview(label)
label.autoCenterInSuperview()
label.pin(.top, to: .top, of: result, withInset: CallMessageCell.inset)
label.pin(
.left,
to: .left,
of: result,
withInset: ((CallMessageCell.inset * 2) + infoImageView.bounds.size.width)
)
label.pin(
.right,
to: .right,
of: result,
withInset: -((CallMessageCell.inset * 2) + infoImageView.bounds.size.width)
)
label.pin(.bottom, to: .bottom, of: result, withInset: -CallMessageCell.inset)
result.addSubview(iconImageView)
iconImageView.autoVCenterInSuperview()

@ -250,16 +250,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
Configuration.performMainSetup()
JobRunner.add(executor: SyncPushTokensJob.self, for: .syncPushTokens)
// Trigger any launch-specific jobs and start the JobRunner
JobRunner.appDidFinishLaunching()
/// Setup the UI
///
/// **Note:** This **MUST** be run before calling `AppReadiness.setAppIsReady()` otherwise if
/// we are launching the app from a push notification the HomeVC won't be setup yet and it won't open the
/// related thread
/// **Note:** This **MUST** be run before calling:
/// - `AppReadiness.setAppIsReady()`:
/// If we are launching the app from a push notification the HomeVC won't be setup yet
/// and it won't open the related thread
///
/// - `JobRunner.appDidFinishLaunching()`:
/// The jobs which run on launch (eg. DisappearingMessages job) can impact the interactions
/// which get fetched to display on the home screen, if the PagedDatabaseObserver hasn't
/// been setup yet then the home screen can show stale (ie. deleted) interactions incorrectly
self.ensureRootViewController(isPreAppReadyCall: true)
// Trigger any launch-specific jobs and start the JobRunner
JobRunner.appDidFinishLaunching()
// Note that this does much more than set a flag;
// it will also run all deferred blocks (including the JobRunner
// 'appDidBecomeActive' method)

@ -523,8 +523,13 @@ public extension Interaction {
.asRequest(of: Int64.self)
.fetchAll(db)
// Don't bother continuing if there are not interactions to mark as read
guard !interactionIdsToMarkAsRead.isEmpty else { return }
// If there are no other interactions to mark as read then just schedule the jobs
// for this interaction (need to ensure the disapeparing messages run for sync'ed
// outgoing messages which will always have 'wasRead' as false)
guard !interactionIdsToMarkAsRead.isEmpty else {
scheduleJobs(interactionIds: [interactionId])
return
}
// Update the `wasRead` flag to true
try interactionQuery.updateAll(db, Columns.wasRead.set(to: true))

@ -17,7 +17,7 @@ public enum DisappearingMessagesJob: JobExecutor {
deferred: @escaping (Job) -> ()
) {
// The 'backgroundTask' gets captured and cleared within the 'completion' block
let timestampNowMs: TimeInterval = (Date().timeIntervalSince1970 * 1000)
let timestampNowMs: TimeInterval = ceil(Date().timeIntervalSince1970 * 1000)
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: #function)
let updatedJob: Job? = Storage.shared.write { db in
@ -29,12 +29,9 @@ public enum DisappearingMessagesJob: JobExecutor {
// Update the next run timestamp for the DisappearingMessagesJob (if the call
// to 'updateNextRunIfNeeded' returns 'nil' then it doesn't need to re-run so
// should have it's 'nextRunTimestamp' cleared)
return updateNextRunIfNeeded(db)
.defaulting(
to: try job
.with(nextRunTimestamp: 0)
.saved(db)
)
return try updateNextRunIfNeeded(db)
.defaulting(to: job.with(nextRunTimestamp: 0))
.saved(db)
}
success(updatedJob ?? job, false)
@ -65,7 +62,7 @@ public extension DisappearingMessagesJob {
return try? Job
.filter(Job.Columns.variant == Job.Variant.disappearingMessages)
.fetchOne(db)?
.with(nextRunTimestamp: ((nextExpirationTimestampMs / 1000) + 1))
.with(nextRunTimestamp: ceil(nextExpirationTimestampMs / 1000))
.saved(db)
}

@ -369,9 +369,15 @@ public extension ClosedGroupControlMessage.Kind {
return String(format: "GROUP_TITLE_CHANGED".localized(), name)
case .membersAdded(let membersAsData):
let addedMemberNames: [String] = try Profile
.fetchAll(db, ids: membersAsData.map { $0.toHexString() })
.map { $0.displayName() }
let memberIds: [String] = membersAsData.map { $0.toHexString() }
let knownMemberNameMap: [String: String] = try Profile
.fetchAll(db, ids: memberIds)
.reduce(into: [:]) { result, next in result[next.id] = next.displayName() }
let addedMemberNames: [String] = memberIds
.map {
knownMemberNameMap[$0] ??
Profile.truncated(id: $0, threadVariant: .closedGroup)
}
return String(
format: "GROUP_MEMBER_JOINED".localized(),
@ -387,9 +393,14 @@ public extension ClosedGroupControlMessage.Kind {
var infoMessage: String = ""
if !memberIds.removing(userPublicKey).isEmpty {
let removedMemberNames: [String] = try Profile
let knownMemberNameMap: [String: String] = try Profile
.fetchAll(db, ids: memberIds.removing(userPublicKey))
.map { $0.displayName() }
.reduce(into: [:]) { result, next in result[next.id] = next.displayName() }
let removedMemberNames: [String] = memberIds.removing(userPublicKey)
.map {
knownMemberNameMap[$0] ??
Profile.truncated(id: $0, threadVariant: .closedGroup)
}
let format: String = (removedMemberNames.count > 1 ?
"GROUP_MEMBERS_REMOVED".localized() :
"GROUP_MEMBER_REMOVED".localized()

@ -377,7 +377,7 @@ extension MessageReceiver {
.membersRemoved(
members: removedMembers
.asSet()
.subtracting(groupMembers.map { $0.profileId })
.intersection(groupMembers.map { $0.profileId })
.map { Data(hex: $0) }
)
.infoMessage(db, sender: sender),

@ -98,7 +98,7 @@ public class TypingIndicators {
withTimeInterval: (direction == .outgoing ? 3 : 5),
repeats: false
) { _ in
Storage.shared.write { db in
Storage.shared.writeAsync { db in
TypingIndicators.didStopTyping(db, threadId: threadId, direction: direction)
}
}
@ -123,7 +123,7 @@ public class TypingIndicators {
withTimeInterval: 10,
repeats: false
) { [weak self] _ in
Storage.shared.write { db in
Storage.shared.writeAsync { db in
self?.scheduleRefreshCallback(db)
}
}

@ -888,30 +888,36 @@ private final class JobQueue {
// but we want at least 1 second to pass before doing so - the job itself should
// really update it's own 'nextRunTimestamp' (this is just a safety net)
case .recurring where job.nextRunTimestamp <= Date().timeIntervalSince1970:
guard let jobId: Int64 = job.id else { break }
Storage.shared.write { db in
_ = try job
.with(nextRunTimestamp: (Date().timeIntervalSince1970 + 1))
.saved(db)
_ = try Job
.filter(id: jobId)
.updateAll(
db,
Job.Columns.failureCount.set(to: 0),
Job.Columns.nextRunTimestamp.set(to: (Date().timeIntervalSince1970 + 1))
)
}
// For `recurringOnLaunch/Active` jobs which have already run, we want to clear their
// `failureCount` and `nextRunTimestamp` to prevent them from endlessly running over
// and over and reset their retry backoff in case they fail next time
// For `recurringOnLaunch/Active` jobs which have already run but failed once, we need to
// clear their `failureCount` and `nextRunTimestamp` to prevent them from endlessly running
// over and over again
case .recurringOnLaunch, .recurringOnActive:
if
guard
let jobId: Int64 = job.id,
job.failureCount != 0 &&
job.nextRunTimestamp > TimeInterval.leastNonzeroMagnitude
{
Storage.shared.write { db in
_ = try Job
.filter(id: jobId)
.updateAll(
db,
Job.Columns.failureCount.set(to: 0),
Job.Columns.nextRunTimestamp.set(to: 0)
)
}
else { break }
Storage.shared.write { db in
_ = try Job
.filter(id: jobId)
.updateAll(
db,
Job.Columns.failureCount.set(to: 0),
Job.Columns.nextRunTimestamp.set(to: 0)
)
}
default: break

Loading…
Cancel
Save