From 91802e481294bb2d724987ac1fbd20bc2109a4c5 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Fri, 30 Sep 2022 14:31:05 +1000 Subject: [PATCH] Fixed a number of crashes and bugs Fixed a crash which would occur when rendering a message containing both a mention and a url Fixed a crash which could occur during migration due to the openGroupServerMessageId essentially being the max UInt64 value which was overflowing the Int64 storage Fixed a bug where empty read receipt updates were sending messages (even for non one-to-one conversations) Fixed a bug where loading in large numbers of messages (via the poller) was auto scrolling to the bottom if the user was close to the bottom (now limited to <5) Fixed a memory leak with the AllMediaViewController (strong delegate references) Fixed an issue where non-alphanumeric characters would cause issues with global search Fixed an issue where search result highlighting wasn't working properly Fixed an issue where the app switcher UI blocking wasn't working Updated the conversations to mark messages as read while scrolling (rather than all messages when entering/participating in a conversation) Updated the modal button font weight to be closer to the designs Added the ability to delete "unsent" messages --- .../Context Menu/ContextMenuVC+Action.swift | 3 + .../Context Menu/ContextMenuVC.swift | 6 +- .../ConversationVC+Interaction.swift | 8 ++ Session/Conversations/ConversationVC.swift | 68 +++++++++++--- .../Conversations/ConversationViewModel.swift | 20 +++- .../Message Cells/VisibleMessageCell.swift | 91 +++++++++++-------- Session/Home/HomeVC.swift | 4 +- .../DocumentTitleViewController.swift | 2 +- .../MediaTileViewController.swift | 2 +- Session/Shared/FullConversationCell.swift | 24 ++++- Session/Shared/ScreenLockUI.swift | 9 +- .../Database/LegacyDatabase/SMKLegacy.swift | 1 - .../Migrations/_003_YDBToGRDBMigration.swift | 32 ++++--- .../Jobs/Types/SendReadReceiptsJob.swift | 6 +- .../SessionThreadViewModel.swift | 14 ++- .../Utilities/Preferences.swift | 6 -- SessionUIKit/Components/Modal.swift | 4 +- SessionUtilitiesKit/Database/Storage.swift | 16 +++- .../AttachmentApprovalViewController.swift | 9 +- .../Screen Lock/ScreenLock.swift | 10 +- 20 files changed, 224 insertions(+), 111 deletions(-) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index cbe87d1b0..a7b9fc76d 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -109,6 +109,9 @@ extension ContextMenuVC { delegate: ContextMenuActionDelegate? ) -> [Action]? { // No context items for info messages + guard cellViewModel.variant != .standardIncomingDeleted else { + return [ Action.delete(cellViewModel, delegate) ] + } guard cellViewModel.variant == .standardOutgoing || cellViewModel.variant == .standardIncoming else { return nil } diff --git a/Session/Conversations/Context Menu/ContextMenuVC.swift b/Session/Conversations/Context Menu/ContextMenuVC.swift index 4f32de036..3f3146df2 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC.swift @@ -221,7 +221,7 @@ final class ContextMenuVC: UIViewController { menuView.pin(.right, to: .right, of: view, withInset: -(UIScreen.main.bounds.width - targetFrame.maxX)) emojiBar.pin(.right, to: .right, of: view, withInset: -(UIScreen.main.bounds.width - targetFrame.maxX)) - case .standardIncoming: + case .standardIncoming, .standardIncomingDeleted: menuView.pin(.left, to: .left, of: view, withInset: targetFrame.minX) emojiBar.pin(.left, to: .left, of: view, withInset: targetFrame.minX) @@ -288,8 +288,8 @@ final class ContextMenuVC: UIViewController { let ratio: CGFloat = (frame.width / frame.height) // FIXME: Need to update this when an appropriate replacement is added (see https://teng.pub/technical/2021/11/9/uiapplication-key-window-replacement) - let topMargin = max(UIApplication.shared.keyWindow!.safeAreaInsets.top, Values.mediumSpacing) - let bottomMargin = max(UIApplication.shared.keyWindow!.safeAreaInsets.bottom, Values.mediumSpacing) + let topMargin = max((UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0), Values.mediumSpacing) + let bottomMargin = max((UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0), Values.mediumSpacing) let diffY = finalFrame.height + menuHeight + Self.actionViewHeight + 2 * spacing + topMargin + bottomMargin - UIScreen.main.bounds.height if diffY > 0 { diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index d9e90db04..8f6317be5 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1594,6 +1594,14 @@ extension ConversationVC: func delete(_ cellViewModel: MessageViewModel) { // Only allow deletion on incoming and outgoing messages + guard cellViewModel.variant != .standardIncomingDeleted else { + Storage.shared.writeAsync { db in + _ = try Interaction + .filter(id: cellViewModel.id) + .deleteAll(db) + } + return + } guard cellViewModel.variant == .standardIncoming || cellViewModel.variant == .standardOutgoing else { return } diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 4ef01d631..9deefda38 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -138,11 +138,13 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl result.showsVerticalScrollIndicator = false result.contentInsetAdjustmentBehavior = .never result.keyboardDismissMode = .interactive - let bottomInset: CGFloat = viewModel.threadData.canWrite ? Values.mediumSpacing : Values.mediumSpacing + UIApplication.shared.keyWindow!.safeAreaInsets.bottom result.contentInset = UIEdgeInsets( top: 0, leading: 0, - bottom: bottomInset, + bottom: (viewModel.threadData.canWrite ? + Values.mediumSpacing : + (Values.mediumSpacing + (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0)) + ), trailing: 0 ) result.registerHeaderFooterView(view: UITableViewHeaderFooterView.self) @@ -604,11 +606,8 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl snInputView.text = draft } - // Now we have done all the needed diffs, update the viewModel with the latest data and mark - // all messages as read (we do it in here as the 'threadData' actually contains the last - // 'interactionId' for the thread) + // Now we have done all the needed diffs update the viewModel with the latest data self.viewModel.updateThreadData(updatedThreadData) - self.viewModel.markAllAsRead() /// **Note:** This needs to happen **after** we have update the viewModel's thread data if initialLoad || viewModel.threadData.currentUserIsClosedGroupMember != updatedThreadData.currentUserIsClosedGroupMember { @@ -682,7 +681,8 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl source: viewModel.interactionData, target: updatedData ) - let isInsert: Bool = (changeset.map({ $0.elementInserted.count }).reduce(0, +) > 0) + let numItemsInserted: Int = changeset.map { $0.elementInserted.count }.reduce(0, +) + let isInsert: Bool = (numItemsInserted > 0) let wasLoadingMore: Bool = self.isLoadingMore let wasOffsetCloseToBottom: Bool = self.isCloseToBottom let numItemsInUpdatedData: [Int] = updatedData.map { $0.elements.count } @@ -758,10 +758,12 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl } } } - else if wasOffsetCloseToBottom && !wasLoadingMore { - // Scroll to the bottom if an interaction was just inserted and we either - // just sent a message or are close enough to the bottom (wait a tiny fraction - // to avoid buggy animation behaviour) + else if wasOffsetCloseToBottom && !wasLoadingMore && numItemsInserted < 5 { + /// Scroll to the bottom if an interaction was just inserted and we either just sent a message or are close enough to the + /// bottom (wait a tiny fraction to avoid buggy animation behaviour) + /// + /// **Note:** We won't automatically scroll to the bottom if 5 or more messages were inserted (to avoid endlessly + /// auto-scrolling to the bottom when fetching new pages of data within open groups DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.scrollToBottom(isAnimated: true) } @@ -771,6 +773,11 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl self.isLoadingMore = false self.autoLoadNextPageIfNeeded() } + else { + // Need to update the scroll button alpha in case new messages were added but we didn't scroll + self.scrollButton.alpha = self.getScrollButtonOpacity() + self.unreadCountView.alpha = self.scrollButton.alpha + } return } @@ -1311,6 +1318,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl ) self.handleInitialOffsetBounceBug(targetIndexPath: targetIndexPath, at: .bottom) + self.viewModel.markAsRead(beforeInclusive: nil) } func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { @@ -1322,8 +1330,41 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl } func scrollViewDidScroll(_ scrollView: UIScrollView) { - scrollButton.alpha = getScrollButtonOpacity() - unreadCountView.alpha = scrollButton.alpha + self.scrollButton.alpha = self.getScrollButtonOpacity() + self.unreadCountView.alpha = self.scrollButton.alpha + + // We want to mark messages as read while we scroll, so grab the newest message and mark + // everything older as read + // + // Note: For the 'tableVisualBottom' we remove the 'Values.mediumSpacing' as that is the distance + // the table content appears above the input view + let tableVisualBottom: CGFloat = (tableView.frame.maxY - (tableView.contentInset.bottom - Values.mediumSpacing)) + + if + let visibleIndexPaths: [IndexPath] = self.tableView.indexPathsForVisibleRows, + let messagesSection: Int = visibleIndexPaths + .first(where: { self.viewModel.interactionData[$0.section].model == .messages })? + .section, + let newestCellViewModel: MessageViewModel = visibleIndexPaths + .sorted() + .filter({ $0.section == messagesSection }) + .compactMap({ indexPath -> (frame: CGRect, cellViewModel: MessageViewModel)? in + guard let frame: CGRect = tableView.cellForRow(at: indexPath)?.frame else { + return nil + } + + return ( + view.convert(frame, from: tableView), + self.viewModel.interactionData[indexPath.section].elements[indexPath.row] + ) + }) + // Exclude messages that are partially off the bottom of the screen + .filter({ $0.frame.maxY <= tableVisualBottom }) + .last? + .cellViewModel + { + self.viewModel.markAsRead(beforeInclusive: newestCellViewModel.id) + } } func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { @@ -1472,6 +1513,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl // Store the info incase we need to load more data (call will be re-triggered) self.focusedInteractionId = interactionId self.shouldHighlightNextScrollToInteraction = highlight + self.viewModel.markAsRead(beforeInclusive: interactionId) // Ensure the target interaction has been loaded guard diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index 2be7fd079..3cd2d9388 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -149,6 +149,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { // MARK: - Interaction Data + private var lastInteractionIdMarkedAsRead: Int64? public private(set) var unobservedInteractionDataChanges: [SectionModel]? public private(set) var interactionData: [SectionModel] = [] public private(set) var reactionExpandedInteractionIds: Set = [] @@ -380,21 +381,30 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { } } - public func markAllAsRead() { - // Don't bother marking anything as read if there are no unread interactions (we can rely - // on the 'threadData.threadUnreadCount' to always be accurate) + /// This method will mark all interactions as read before the specified interaction id, if no id is provided then all interactions for + /// the thread will be marked as read + public func markAsRead(beforeInclusive interactionId: Int64?) { + /// Since this method now gets triggered when scrolling we want to try to optimise it and avoid busying the database + /// write queue when it isn't needed, in order to do this we: + /// + /// - Don't bother marking anything as read if there are no unread interactions (we can rely on the + /// `threadData.threadUnreadCount` to always be accurate) + /// - Don't bother marking anything as read if this was called with the same `interactionId` that we + /// previously marked as read (ie. when scrolling and the last message hasn't changed) guard (self.threadData.threadUnreadCount ?? 0) > 0, - let lastInteractionId: Int64 = self.threadData.interactionId + let targetInteractionId: Int64 = (interactionId ?? self.threadData.interactionId), + self.lastInteractionIdMarkedAsRead != targetInteractionId else { return } let threadId: String = self.threadData.threadId let trySendReadReceipt: Bool = (self.threadData.threadIsMessageRequest == false) + self.lastInteractionIdMarkedAsRead = targetInteractionId Storage.shared.writeAsync { db in try Interaction.markAsRead( db, - interactionId: lastInteractionId, + interactionId: targetInteractionId, threadId: threadId, includingOlder: true, trySendReadReceipt: trySendReadReceipt diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index b37f2e1c1..caa9722c3 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -1049,51 +1049,52 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { ) // Custom handle links - let links: [String: NSRange] = { - guard - let body: String = cellViewModel.body, - let detector: NSDataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) - else { return [:] } - - var links: [String: NSRange] = [:] - let matches = detector.matches( - in: body, - options: [], - range: NSRange(location: 0, length: body.count) - ) - - for match in matches { - guard let matchURL = match.url else { continue } - - /// If the URL entered didn't have a scheme it will default to 'http', we want to catch this and - /// set the scheme to 'https' instead as we don't load previews for 'http' so this will result - /// in more previews actually getting loaded without forcing the user to enter 'https://' before - /// every URL they enter - let urlString: String = (matchURL.absoluteString == "http://\(body)" ? - "https://\(body)" : - matchURL.absoluteString - ) - - if URL(string: urlString) != nil { - links[urlString] = (body as NSString).range(of: urlString) - } + let links: [URL: NSRange] = { + guard let detector: NSDataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { + return [:] } - return links + return detector + .matches( + in: attributedText.string, + options: [], + range: NSRange(location: 0, length: attributedText.string.count) + ) + .reduce(into: [:]) { result, match in + guard + let matchUrl: URL = match.url, + let originalRange: Range = Range(match.range, in: attributedText.string) + else { return } + + /// If the URL entered didn't have a scheme it will default to 'http', we want to catch this and + /// set the scheme to 'https' instead as we don't load previews for 'http' so this will result + /// in more previews actually getting loaded without forcing the user to enter 'https://' before + /// every URL they enter + let originalString: String = String(attributedText.string[originalRange]) + + guard matchUrl.absoluteString != "http://\(originalString)" else { + guard let httpsUrl: URL = URL(string: "https://\(originalString)") else { + return + } + + result[httpsUrl] = match.range + return + } + + result[matchUrl] = match.range + } }() - for (urlString, range) in links { - guard let url: URL = URL(string: urlString) else { continue } - + for (linkUrl, urlRange) in links { attributedText.addAttributes( [ .font: UIFont.systemFont(ofSize: getFontSize(for: cellViewModel)), .foregroundColor: actualTextColor, .underlineColor: actualTextColor, .underlineStyle: NSUnderlineStyle.single.rawValue, - .attachment: url + .attachment: linkUrl ], - range: range + range: urlRange ) } @@ -1105,7 +1106,8 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate { .map { part -> String in guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part } - return String(part[part.index(after: part.startIndex).. = { + let term: String = String(normalizedBody[range]) + + // If the matched term doesn't actually match the "part" value then it means + // we've matched a term after a non-alphanumeric character so need to shift + // the range over by 1 + guard term.starts(with: part.lowercased()) else { + return (normalizedBody.index(after: range.lowerBound).. String in guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part } - return String(part[part.index(after: part.startIndex).. = { + let term: String = String(normalizedSnippet[range]) + + // If the matched term doesn't actually match the "part" value then it means + // we've matched a term after a non-alphanumeric character so need to shift + // the range over by 1 + guard term.starts(with: part.lowercased()) else { + return (normalizedSnippet.index(after: range.lowerBound).. Int64 { + return (value > UInt64(Int64.max) ? 0 : Int64(value)) + } +} diff --git a/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift b/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift index c9e8b8af3..bf27ef218 100644 --- a/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift +++ b/SessionMessagingKit/Jobs/Types/SendReadReceiptsJob.swift @@ -109,6 +109,7 @@ public extension SendReadReceiptsJob { .filter(interactionIds.contains(Interaction.Columns.id)) // Only `standardIncoming` incoming interactions should have read receipts sent .filter(Interaction.Columns.variant == Interaction.Variant.standardIncoming) + .filter(Interaction.Columns.wasRead == false) // Only send for unread messages .joining( // Don't send read receipts in group threads required: Interaction.thread @@ -119,7 +120,10 @@ public extension SendReadReceiptsJob { ) // If there are no timestamp values then do nothing - guard let timestampMsValues: [Int64] = maybeTimestampMsValues else { return nil } + guard + let timestampMsValues: [Int64] = maybeTimestampMsValues, + !timestampMsValues.isEmpty + else { return nil } // Try to get an existing job (if there is one that's not running) if diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index 88e478424..b311fa9d9 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -940,6 +940,13 @@ public extension SessionThreadViewModel { public extension SessionThreadViewModel { static let searchResultsLimit: Int = 500 + /// FTS will fail or try to process characters outside of `[A-Za-z0-9]` are included directly in a search + /// term, in order to resolve this the term needs to be wrapped in quotation marks so the eventual SQL + /// is `MATCH '"{term}"'` or `MATCH '"{term}"*'` + static func searchSafeTerm(_ term: String) -> String { + return "\"\(term)\"" + } + static func searchTermParts(_ searchTerm: String) -> [String] { /// Process the search term in order to extract the parts of the search pattern we want /// @@ -954,7 +961,7 @@ public extension SessionThreadViewModel { guard index % 2 == 1 else { return String(value) .split(separator: " ") - .map { String($0) } + .map { "\"\(String($0))\"" } } return ["\"\(value)\""] @@ -972,13 +979,14 @@ public extension SessionThreadViewModel { let rawPattern: String = searchTermParts(searchTerm) .joined(separator: " OR ") .appending("*") + let fallbackTerm: String = "\(searchSafeTerm(searchTerm))*" /// There are cases where creating a pattern can fail, we want to try and recover from those cases /// by failling back to simpler patterns if needed let maybePattern: FTS5Pattern? = (try? db.makeFTS5Pattern(rawPattern: rawPattern, forTable: table)) .defaulting( - to: (try? db.makeFTS5Pattern(rawPattern: searchTerm, forTable: table)) - .defaulting(to: FTS5Pattern(matchingAnyTokenIn: searchTerm)) + to: (try? db.makeFTS5Pattern(rawPattern: fallbackTerm, forTable: table)) + .defaulting(to: FTS5Pattern(matchingAnyTokenIn: fallbackTerm)) ) guard let pattern: FTS5Pattern = maybePattern else { throw StorageError.invalidSearchPattern } diff --git a/SessionMessagingKit/Utilities/Preferences.swift b/SessionMessagingKit/Utilities/Preferences.swift index 81408b1bd..14b9b9f61 100644 --- a/SessionMessagingKit/Utilities/Preferences.swift +++ b/SessionMessagingKit/Utilities/Preferences.swift @@ -15,12 +15,6 @@ public extension Setting.EnumKey { } public extension Setting.BoolKey { - /// Controls whether the preview screen in the app switcher should be enabled - /// - /// **Note:** In the legacy setting this flag controlled whether the preview was "disabled" (and defaulted to - /// true), by inverting this flag we can default it to false as is standard for Bool values - static let appSwitcherPreviewEnabled: Setting.BoolKey = "appSwitcherPreviewEnabled" - /// Controls whether typing indicators are enabled /// /// **Note:** Only works if both participants in a "contact" thread have this setting enabled diff --git a/SessionUIKit/Components/Modal.swift b/SessionUIKit/Components/Modal.swift index 436f04242..25c77d1ec 100644 --- a/SessionUIKit/Components/Modal.swift +++ b/SessionUIKit/Components/Modal.swift @@ -116,8 +116,8 @@ open class Modal: UIViewController, UIGestureRecognizerDelegate { } public static func createButton(title: String, titleColor: ThemeValue) -> UIButton { - let result: UIButton = UIButton() // TODO: NEED to fix the font (looks bad) - result.titleLabel?.font = .systemFont(ofSize: Values.mediumFontSize, weight: UIFont.Weight(600)) + let result: UIButton = UIButton() + result.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize) result.setTitle(title, for: .normal) result.setThemeTitleColor(titleColor, for: .normal) result.setThemeBackgroundColor(.alert_buttonBackground, for: .normal) diff --git a/SessionUtilitiesKit/Database/Storage.swift b/SessionUtilitiesKit/Database/Storage.swift index 56fde9e6c..ad4941d98 100644 --- a/SessionUtilitiesKit/Database/Storage.swift +++ b/SessionUtilitiesKit/Database/Storage.swift @@ -360,14 +360,26 @@ public final class Storage { guard isValid, let dbWriter: DatabaseWriter = dbWriter else { return } guard let observer: TransactionObserver = observer else { return } - dbWriter.add(transactionObserver: observer) + // Note: This actually triggers a write to the database so can be blocked by other + // writes, since it's usually called on the main thread when creating a view controller + // this can result in the UI hanging - to avoid this we dispatch (and hope there isn't + // negative impact) + DispatchQueue.global(qos: .default).async { + dbWriter.add(transactionObserver: observer) + } } public func removeObserver(_ observer: TransactionObserver?) { guard isValid, let dbWriter: DatabaseWriter = dbWriter else { return } guard let observer: TransactionObserver = observer else { return } - dbWriter.remove(transactionObserver: observer) + // Note: This actually triggers a write to the database so can be blocked by other + // writes, since it's usually called on the main thread when creating a view controller + // this can result in the UI hanging - to avoid this we dispatch (and hope there isn't + // negative impact) + DispatchQueue.global(qos: .default).async { + dbWriter.remove(transactionObserver: observer) + } } } diff --git a/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentApprovalViewController.swift b/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentApprovalViewController.swift index 0d2bafdec..e5e0362ad 100644 --- a/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentApprovalViewController.swift +++ b/SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentApprovalViewController.swift @@ -5,10 +5,11 @@ import Foundation import AVFoundation import MediaPlayer +import CoreServices import PromiseKit import SessionUIKit -import CoreServices import SessionMessagingKit +import SignalCoreKit public protocol AttachmentApprovalViewControllerDelegate: AnyObject { func attachmentApproval( @@ -538,7 +539,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC private func setCurrentItem(_ item: SignalAttachmentItem?, direction: UIPageViewController.NavigationDirection, animated isAnimated: Bool) { guard let item: SignalAttachmentItem = item, let page = self.buildPage(item: item) else { - owsFailDebug("unexpectedly unable to build new page") + Logger.error("unexpectedly unable to build new page") return } @@ -550,7 +551,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC func updateMediaRail() { guard let currentItem = self.currentItem else { - owsFailDebug("currentItem was unexpectedly nil") + Logger.error("currentItem was unexpectedly nil") return } @@ -565,7 +566,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC return cell default: - owsFailDebug("unexpted rail item type: \(railItem)") + Logger.error("unexpted rail item type: \(railItem)") return GalleryRailCellView() } } diff --git a/SignalUtilitiesKit/Screen Lock/ScreenLock.swift b/SignalUtilitiesKit/Screen Lock/ScreenLock.swift index ca9896bf2..a4158d358 100644 --- a/SignalUtilitiesKit/Screen Lock/ScreenLock.swift +++ b/SignalUtilitiesKit/Screen Lock/ScreenLock.swift @@ -105,7 +105,7 @@ public class ScreenLock { defaultErrorDescription: defaultErrorDescription) switch outcome { case .success: - owsFailDebug("local authentication unexpected success") + Logger.error("local authentication unexpected success") completion(.failure(error: defaultErrorDescription)) case .cancel, .failure, .unexpectedFailure: @@ -129,8 +129,8 @@ public class ScreenLock { switch outcome { case .success: - owsFailDebug("local authentication unexpected success") - completion(.failure(error:defaultErrorDescription)) + Logger.error("local authentication unexpected success") + completion(.failure(error: defaultErrorDescription)) case .cancel, .failure, .unexpectedFailure: completion(outcome) @@ -190,11 +190,11 @@ public class ScreenLock { return .failure(error: "SCREEN_LOCK_ERROR_LOCAL_AUTHENTICATION_LOCKOUT".localized()) case .invalidContext: - owsFailDebug("context not valid.") + Logger.error("context not valid.") return .unexpectedFailure(error: defaultErrorDescription) case .notInteractive: - owsFailDebug("context not interactive.") + Logger.error("context not interactive.") return .unexpectedFailure(error: defaultErrorDescription) @unknown default: