From d4ef6aad83936e79a43f120658a1b35e531c26cd Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:15:15 +0200 Subject: [PATCH 1/9] Adopted latest SKStoreReviewController API changes in ReviewActions --- 4champ/Utils/ReviewActions.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/4champ/Utils/ReviewActions.swift b/4champ/Utils/ReviewActions.swift index 7f0b1d4..f891605 100644 --- a/4champ/Utils/ReviewActions.swift +++ b/4champ/Utils/ReviewActions.swift @@ -8,6 +8,16 @@ import Foundation import StoreKit +extension SKStoreReviewController { + public static func requestReviewInCurrentScene() { + if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { + DispatchQueue.main.async { + requestReview(in: scene) + } + } + } +} + /// Enumeration used to trigger AppStore review requests enum ReviewActions: String { @@ -46,7 +56,7 @@ enum ReviewActions: String { return } - SKStoreReviewController.requestReview() + SKStoreReviewController.requestReviewInCurrentScene() // Reset the defaults defaults.set(0, forKey: ReviewActions.noteworthyActionCount.rawValue) From 68ab0013b071a1e08df17550b11f758b8e4f7bad Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:25:35 +0200 Subject: [PATCH 2/9] Use UIApplication::connectedScenes API for getting the topmost controller --- 4champ/Utils/ModuleSharing.swift | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/4champ/Utils/ModuleSharing.swift b/4champ/Utils/ModuleSharing.swift index d7e0527..6391575 100644 --- a/4champ/Utils/ModuleSharing.swift +++ b/4champ/Utils/ModuleSharing.swift @@ -39,7 +39,8 @@ class ShareUtility: NSObject, UIActivityItemSource { } var sourceView: UIView? - if let mainVC = UIApplication.shared.windows[0].rootViewController as? MainViewController { + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first, let mainVC = window.rootViewController as? MainViewController { sourceView = mainVC.tabBar } @@ -64,17 +65,21 @@ class ShareUtility: NSObject, UIActivityItemSource { } static func topMostController() -> UIViewController? { - let window = UIApplication.shared.windows[0] - guard let rootViewController = window.rootViewController else { - return nil - } + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first else { + return nil + } + + guard let rootViewController = window.rootViewController else { + return nil + } - var topController = rootViewController + var topController = rootViewController - while let newTopController = topController.presentedViewController { - topController = newTopController - } + while let newTopController = topController.presentedViewController { + topController = newTopController + } - return topController + return topController } } From 39a0ebbdfd861c852fda0d669830d3b3de3b9aba Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:27:18 +0200 Subject: [PATCH 3/9] Execute radio/playlist view updates in main thread only --- 4champ/AppDelegate.swift | 19 ++++++++++++------- .../Scenes/Playlists/PlaylistPresenter.swift | 8 ++++++-- 4champ/Scenes/Radio/RadioPresenter.swift | 4 +++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/4champ/AppDelegate.swift b/4champ/AppDelegate.swift index 21a58c7..cae6d05 100644 --- a/4champ/AppDelegate.swift +++ b/4champ/AppDelegate.swift @@ -100,20 +100,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } if components.path == "/mod", let idString = components.queryItems?.first?.value, let modId = Int(idString) { - dlController.rootViewController = UIApplication.shared.windows[0].rootViewController + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first else { + return false + } + dlController.rootViewController = window.rootViewController dlController.show(modId: modId) } - return true } func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { - if url.scheme == "fourchamp" && url.host == "modules" { - if let idString = url.path.split(separator: "/").first, let modId = Int(idString) { - dlController.show(modId: modId) + DispatchQueue.main.async { + if url.scheme == "fourchamp" && url.host == "modules" { + if let idString = url.path.split(separator: "/").first, let modId = Int(idString) { + self.dlController.show(modId: modId) + } + } else { + self.dlController.showImport(for: [url]) } - } else { - dlController.showImport(for: [url]) } return true } diff --git a/4champ/Scenes/Playlists/PlaylistPresenter.swift b/4champ/Scenes/Playlists/PlaylistPresenter.swift index 0acb4c8..ffde867 100644 --- a/4champ/Scenes/Playlists/PlaylistPresenter.swift +++ b/4champ/Scenes/Playlists/PlaylistPresenter.swift @@ -39,10 +39,14 @@ class PlaylistPresenter: PlaylistPresentationLogic { } let vm = Playlists.Select.ViewModel(playlistName: name, shuffle: shuffle, modules: mods) - viewController?.displayPlaylist(viewModel: vm) + DispatchQueue.main.async { + self.viewController?.displayPlaylist(viewModel: vm) + } } func presentModeChange(shuffled: Bool) { - viewController?.displayModeChange(shuffled: shuffled) + DispatchQueue.main.async { + self.viewController?.displayModeChange(shuffled: shuffled) + } } } diff --git a/4champ/Scenes/Radio/RadioPresenter.swift b/4champ/Scenes/Radio/RadioPresenter.swift index 8daec59..c01dcd3 100644 --- a/4champ/Scenes/Radio/RadioPresenter.swift +++ b/4champ/Scenes/Radio/RadioPresenter.swift @@ -56,7 +56,9 @@ class RadioPresenter: RadioPresentationLogic { } func presentSessionHistoryInsert() { - self.viewController?.displaySessionHistoryInsert() + DispatchQueue.main.async { + self.viewController?.displaySessionHistoryInsert() + } } func presentPlaybackTime(length: Int, elapsed: Int) { From 13906fbd828780ff9be147cee3b0c853334259ac Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:28:53 +0200 Subject: [PATCH 4/9] Migrate to latest UNUserNotificationCenter API for displaying notifications --- 4champ/Scenes/MainViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4champ/Scenes/MainViewController.swift b/4champ/Scenes/MainViewController.swift index d5240cd..cd68aa0 100644 --- a/4champ/Scenes/MainViewController.swift +++ b/4champ/Scenes/MainViewController.swift @@ -230,7 +230,7 @@ extension MainViewController: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - completionHandler([.alert, .badge, .sound]) + completionHandler([.badge, .sound]) } func userNotificationCenter(_ center: UNUserNotificationCenter, From 675ddc0140398d5a2ead3cac79eb72c02ff9e833 Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:32:09 +0200 Subject: [PATCH 5/9] Only update view constraints when the view has been added to the view hierarchy in AboutViewController --- 4champ/Scenes/About/AboutViewController.swift | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/4champ/Scenes/About/AboutViewController.swift b/4champ/Scenes/About/AboutViewController.swift index b205930..91b1657 100644 --- a/4champ/Scenes/About/AboutViewController.swift +++ b/4champ/Scenes/About/AboutViewController.swift @@ -71,13 +71,16 @@ class AboutViewController: UIViewController, AboutDisplayLogic { UIUtils.roundCornersInView(tableView) navigationItem.title = "AboutView_Title".l13n().uppercased() - toggleNowPlaying(modulePlayer.status.rawValue > PlayerStatus.stopped.rawValue) - let img = UIImage(named: "favestar-grey")?.withRenderingMode(.alwaysTemplate) let buttonItem = UIBarButtonItem.init(image: img, landscapeImagePhone: img, style: .plain, target: self, action: #selector(reviewNow)) self.navigationItem.leftBarButtonItem = buttonItem } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + toggleNowPlaying(modulePlayer.status.rawValue > PlayerStatus.stopped.rawValue) + } + // MARK: Display Logic func displayNowPlaying(_ viewModel: About.Status.ViewModel) { } @@ -88,12 +91,14 @@ class AboutViewController: UIViewController, AboutDisplayLogic { } extension AboutViewController: NowPlayingContainer { + func toggleNowPlaying(_ value: Bool) { + guard view.window != nil else { return } log.debug("") - if value { - bottomAnchor?.constant = -(50.0 + 10.0) - } else { - bottomAnchor?.constant = -10.0 + if value { + bottomAnchor?.constant = -(50.0 + 10.0) + } else { + bottomAnchor?.constant = -10.0 } view.layoutIfNeeded() } From a7416da9eee7ccd4a616a2202b23cf0a2f1daee0 Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:34:19 +0200 Subject: [PATCH 6/9] Get UADE replayer song length from info struct It is not coming for any known module though :D --- 4champ/Replay/UADE/UADEReplayer.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4champ/Replay/UADE/UADEReplayer.m b/4champ/Replay/UADE/UADEReplayer.m index 8a46484..0c06acd 100644 --- a/4champ/Replay/UADE/UADEReplayer.m +++ b/4champ/Replay/UADE/UADEReplayer.m @@ -355,7 +355,7 @@ - (int)currentPosition { - (int)moduleLength { if(ustate) { const struct uade_song_info *info = uade_get_song_info(ustate); - return ustate->song.info.duration; + return info->duration; } return 0; } From 0391381e20bb6371da7629ac200008064e44cf8c Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:45:48 +0200 Subject: [PATCH 7/9] SwiftUI frame animation API deprecation fix --- 4champ/Scenes/DownloadView/DownloadView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4champ/Scenes/DownloadView/DownloadView.swift b/4champ/Scenes/DownloadView/DownloadView.swift index 2e62644..b253978 100644 --- a/4champ/Scenes/DownloadView/DownloadView.swift +++ b/4champ/Scenes/DownloadView/DownloadView.swift @@ -20,7 +20,7 @@ struct ProgressBar: View { Rectangle().frame(width: min(CGFloat(self.value)*geometry.size.width, geometry.size.width), height: geometry.size.height) .foregroundColor(Color(UIColor.systemBlue)) - .animation(.linear) + .animation(value > 0.01 ? .linear : nil, value: value) }.cornerRadius(2) } } From 516f92a480a7915ef76cb4068002036996ffe664 Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Tue, 13 Feb 2024 21:53:47 +0200 Subject: [PATCH 8/9] Migrate to latest UIDocumentPickerViewController API --- .../DownloadView/DownloadHostingController.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/4champ/Scenes/DownloadView/DownloadHostingController.swift b/4champ/Scenes/DownloadView/DownloadHostingController.swift index b98e2bf..8baf03e 100644 --- a/4champ/Scenes/DownloadView/DownloadHostingController.swift +++ b/4champ/Scenes/DownloadView/DownloadHostingController.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import UniformTypeIdentifiers enum ImportResultType { case importSuccess @@ -55,7 +56,14 @@ class DownloadController: NSObject, ObservableObject { func selectImportModules(addToPlaylist: Bool = false) { self.addToCurrentPlaylist = addToPlaylist if documentPickerVC == nil { - documentPickerVC = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .import) + + if #available(iOS 14, *) { + let supportedTypes: [UTType] = [UTType.item] + documentPickerVC = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes) + } else { + let supportedTypes: [String] = ["public.item"] + documentPickerVC = UIDocumentPickerViewController(documentTypes: supportedTypes, in: .import) + } documentPickerVC?.delegate = self documentPickerVC?.modalPresentationStyle = .formSheet documentPickerVC?.allowsMultipleSelection = true From adf3f701d8a32d620b56f14c885ffafcc97bddcb Mon Sep 17 00:00:00 2001 From: Aleksi Sitomaniemi Date: Wed, 14 Feb 2024 09:43:25 +0200 Subject: [PATCH 9/9] Replay/MTPReplayer warnings elimination --- 4champ/Replay/OpenMPT/MPTReplayer.m | 2 +- 4champ/Replay/Replay.m | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/4champ/Replay/OpenMPT/MPTReplayer.m b/4champ/Replay/OpenMPT/MPTReplayer.m index 5562be3..213c9c2 100644 --- a/4champ/Replay/OpenMPT/MPTReplayer.m +++ b/4champ/Replay/OpenMPT/MPTReplayer.m @@ -147,7 +147,7 @@ - (NSArray*) getSamples } return sampleArray; } - + - (NSArray*) getInstruments { if (!currentOMPTFile) { diff --git a/4champ/Replay/Replay.m b/4champ/Replay/Replay.m index d36d506..c8daa35 100644 --- a/4champ/Replay/Replay.m +++ b/4champ/Replay/Replay.m @@ -60,9 +60,9 @@ -(id)init -(void) initAudio { //set up audio buffers for rendering - bufLeft = malloc(maxFrameSize * 2 * sizeof(UInt16)); - bufRight = malloc(maxFrameSize * 2 * sizeof(UInt16)); - + bufLeft = malloc(maxFrameSize * 2 * sizeof(SInt16)); + bufRight = malloc(maxFrameSize * 2 * sizeof(SInt16)); + OSStatus status; // Describe audio component @@ -78,7 +78,7 @@ -(void) initAudio // Get audio units status = AudioComponentInstanceNew(inputComponent, &audioUnit); - //checkStatus(status); + checkStatus(status); UInt32 flag = 1; const int kOutputBus = 0;