From 40c9b019508d4059fdc1fecbf1eb59769370e3b6 Mon Sep 17 00:00:00 2001 From: Mohamed Afifi Date: Sat, 9 Dec 2023 15:19:59 -0500 Subject: [PATCH 1/2] Add some extra logging to debug download and word pointer issues --- .../DownloadBatchDataController.swift | 10 +++++----- .../Sources/Downloader/DownloadManager.swift | 11 ++++++++--- .../AudioBannerViewModel.swift | 4 ++++ .../WordPointerViewController.swift | 16 ++++++++++------ .../WordPointerViewModel.swift | 18 ++++++++++++------ 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/Data/BatchDownloader/Sources/Downloader/DownloadBatchDataController.swift b/Data/BatchDownloader/Sources/Downloader/DownloadBatchDataController.swift index d5419b32..63342b01 100644 --- a/Data/BatchDownloader/Sources/Downloader/DownloadBatchDataController.swift +++ b/Data/BatchDownloader/Sources/Downloader/DownloadBatchDataController.swift @@ -175,20 +175,24 @@ actor DownloadBatchDataController { private func startPendingTasksIfNeeded() async { if !initialRunningTasks.initialized { + logger.warning("startPendingTasksIfNeeded not initialized") return } // if we have a session guard let session else { + logger.warning("startPendingTasksIfNeeded no session") return } // and there are empty slots to use for downloading let runningTasks = await runningTasks guard runningTasks < maxSimultaneousDownloads else { + logger.info("startPendingTasksIfNeeded no empty slots for download") return } // and there are things to download guard !batches.isEmpty else { + logger.info("startPendingTasksIfNeeded no batches to download") return } @@ -215,11 +219,7 @@ actor DownloadBatchDataController { } } - if downloadTasks.isEmpty { - return - } - - logger.info("Enqueuing \(downloadTasks.count) to download on empty channels.") + logger.info("startDownloadTasks \(downloadTasks.count) to download on empty channels.") // start the tasks for download in downloadTasks { diff --git a/Data/BatchDownloader/Sources/Downloader/DownloadManager.swift b/Data/BatchDownloader/Sources/Downloader/DownloadManager.swift index 2a0f28ea..7e6f2c55 100644 --- a/Data/BatchDownloader/Sources/Downloader/DownloadManager.swift +++ b/Data/BatchDownloader/Sources/Downloader/DownloadManager.swift @@ -69,7 +69,7 @@ public final class DownloadManager: Sendable { logger.info("Starting download manager") let session = createSession() await dataController.start(with: session) - logger.info("Download manager start completed") + logger.info("Download manager started") } @MainActor @@ -78,11 +78,16 @@ public final class DownloadManager: Sendable { } public func getOnGoingDownloads() async -> [DownloadBatchResponse] { - await dataController.getOnGoingDownloads() + logger.info("getOnGoingDownloads requested") + let downloads = await dataController.getOnGoingDownloads() + logger.debug("Found \(downloads.count) ongoing downloads") + return downloads } public func download(_ batch: DownloadBatchRequest) async throws -> DownloadBatchResponse { - try await dataController.download(batch) + logger.debug("Requested to download \(batch.requests.map(\.url.absoluteString))") + let result = try await dataController.download(batch) + return result } // MARK: Private diff --git a/Features/AudioBannerFeature/AudioBannerViewModel.swift b/Features/AudioBannerFeature/AudioBannerViewModel.swift index 8ccae0e5..55e6fc8a 100644 --- a/Features/AudioBannerFeature/AudioBannerViewModel.swift +++ b/Features/AudioBannerFeature/AudioBannerViewModel.swift @@ -293,16 +293,20 @@ public final class AudioBannerViewModel: RemoteCommandsHandlerDelegate { cancellableTasks.task { [weak self] in do { let downloaded = await self?.downloader.downloaded(reciter: selectedReciter, from: from, to: end) ?? true + logger.info("AudioBanner: reciter downloaded? \(downloaded)") if !downloaded { self?.startDownloading() let download = try await self?.downloader.download(from: from, to: end, reciter: selectedReciter) guard let download else { + logger.info("AudioBanner: couldn't create a download request") return } await self?.observe([download]) for try await _ in download.progress { } + + logger.info("AudioBanner: download completed") } try await self?.audioPlayer.play( diff --git a/Features/WordPointerFeature/WordPointerViewController.swift b/Features/WordPointerFeature/WordPointerViewController.swift index 1159c424..a233ef6f 100644 --- a/Features/WordPointerFeature/WordPointerViewController.swift +++ b/Features/WordPointerFeature/WordPointerViewController.swift @@ -10,8 +10,15 @@ import NoorUI import Popover_OC import UIKit import UIx +import VLogging public final class WordPointerViewController: UIViewController { + private enum GestureState { + case began + case changed(translation: CGPoint) + case ended(velocity: CGPoint) + } + // MARK: Lifecycle init(viewModel: WordPointerViewModel) { @@ -119,12 +126,6 @@ public final class WordPointerViewController: UIViewController { // MARK: Private - private enum GestureState { - case began - case changed(translation: CGPoint) - case ended(velocity: CGPoint) - } - private let viewModel: WordPointerViewModel // For word translation @@ -180,11 +181,14 @@ public final class WordPointerViewController: UIViewController { private func makeGestureState(_ gesture: UIPanGestureRecognizer) -> GestureState? { switch gesture.state { case .began: + logger.debug("Started pointer dragging") return .began case .changed: let translation = gesture.translation(in: container) + logger.debug("Pointer dragged to new position \(translation)") return .changed(translation: translation) case .ended, .cancelled, .failed: + logger.debug("Ended pointer dragging \(gesture.state.rawValue)") let velocity = gesture.velocity(in: container) return .ended(velocity: velocity) case .possible: diff --git a/Features/WordPointerFeature/WordPointerViewModel.swift b/Features/WordPointerFeature/WordPointerViewModel.swift index 0ea5fa4a..9f42fa89 100644 --- a/Features/WordPointerFeature/WordPointerViewModel.swift +++ b/Features/WordPointerFeature/WordPointerViewModel.swift @@ -10,6 +10,7 @@ import Crashing import QuranKit import UIKit import Utilities +import VLogging import WordTextService @MainActor @@ -21,6 +22,12 @@ public protocol WordPointerListener: AnyObject { @MainActor final class WordPointerViewModel { + enum PanResult { + case none + case hidePopover + case showPopover(text: String) + } + // MARK: Lifecycle init(service: WordTextService) { @@ -29,12 +36,6 @@ final class WordPointerViewModel { // MARK: Internal - enum PanResult { - case none - case hidePopover - case showPopover(text: String) - } - weak var listener: WordPointerListener? func viewPanBegan() { @@ -43,19 +44,24 @@ final class WordPointerViewModel { func viewPanned(to point: CGPoint, in view: UIView) async -> PanResult { guard let word = listener?.word(at: point, in: view) else { + logger.debug("No word found at position \(point)") unhighlightWord() return .hidePopover } + logger.debug("Highlighting word \(word) at position: \(point)") listener?.highlightWord(word) if selectedWord == word { + logger.debug("Same word selected before") return .none } do { if let text = try await service.textForWord(word) { + logger.debug("Found text '\(text)' for word \(word)") selectedWord = word return .showPopover(text: text) } else { + logger.debug("No text found for word \(word)") return .hidePopover } } catch { From a7bbed948c5f5c9e46ea36f5b4a2ba74b1d542f4 Mon Sep 17 00:00:00 2001 From: Mohamed Afifi Date: Sat, 9 Dec 2023 15:24:37 -0500 Subject: [PATCH 2/2] Select first reciter if no match found with the stored reciter id This fixes the issue when audio banner not in a functioning state. --- Features/AudioBannerFeature/AudioBannerViewModel.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Features/AudioBannerFeature/AudioBannerViewModel.swift b/Features/AudioBannerFeature/AudioBannerViewModel.swift index 55e6fc8a..4a929942 100644 --- a/Features/AudioBannerFeature/AudioBannerViewModel.swift +++ b/Features/AudioBannerFeature/AudioBannerViewModel.swift @@ -113,7 +113,14 @@ public final class AudioBannerViewModel: RemoteCommandsHandlerDelegate { } var selectedReciter: Reciter? { - reciters.first { $0.id == preferences.lastSelectedReciterId } + let storedSelectedReciterId = preferences.lastSelectedReciterId + let selectedReciter = reciters.first { $0.id == storedSelectedReciterId } + if selectedReciter == nil { + let firstReciter = reciters.first + logger.error("AudioBanner: couldn't find reciter \(storedSelectedReciterId) using \(String(describing: firstReciter?.id)) instead") + return firstReciter + } + return selectedReciter } func start() async {