From ccf2909d0cdf36907990b5a44a0b6254ecd95cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rasmus=20Kr=C3=A4mer?= Date: Wed, 13 Mar 2024 18:48:21 +0100 Subject: [PATCH] Small improvements --- ShelfPlayer.xcodeproj/project.pbxproj | 4 + iOS/CarPlay/CarPlay+Offline.swift | 95 +++++++++++++++++++++++ iOS/CarPlay/CarPlay+Playback.swift | 21 ++--- iOS/CarPlay/CarPlayDelegate.swift | 88 --------------------- iOS/Offline/OfflineView.swift | 1 - iOS/Reusable/Buttons/DownloadButton.swift | 12 +-- 6 files changed, 118 insertions(+), 103 deletions(-) create mode 100644 iOS/CarPlay/CarPlay+Offline.swift diff --git a/ShelfPlayer.xcodeproj/project.pbxproj b/ShelfPlayer.xcodeproj/project.pbxproj index 01e6414a..8710f497 100644 --- a/ShelfPlayer.xcodeproj/project.pbxproj +++ b/ShelfPlayer.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 3A38A1582AD4715100D533F3 /* PlayButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A38A1572AD4715100D533F3 /* PlayButton.swift */; }; 3A48D2512AD0661500991139 /* LibrarySelectorModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A48D2502AD0661500991139 /* LibrarySelectorModifier.swift */; }; 3A48D2542AD074DC00991139 /* PodcastEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A48D2532AD074DC00991139 /* PodcastEntryView.swift */; }; + 3A4E8A192B8E52A700A2586C /* CarPlay+Offline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4E8A182B8E52A700A2586C /* CarPlay+Offline.swift */; }; 3A50AAA52ACC42B400BF5438 /* AudiobookEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A50AAA42ACC42B400BF5438 /* AudiobookEntryView.swift */; }; 3A50AAB62ACC521B00BF5438 /* AudiobookLibraryView+ListenNow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A50AAB52ACC521B00BF5438 /* AudiobookLibraryView+ListenNow.swift */; }; 3A50AAB82ACC522900BF5438 /* AudiobookEntryView+Library.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A50AAB72ACC522900BF5438 /* AudiobookEntryView+Library.swift */; }; @@ -155,6 +156,7 @@ 3A38A1572AD4715100D533F3 /* PlayButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayButton.swift; sourceTree = ""; }; 3A48D2502AD0661500991139 /* LibrarySelectorModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySelectorModifier.swift; sourceTree = ""; }; 3A48D2532AD074DC00991139 /* PodcastEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PodcastEntryView.swift; sourceTree = ""; }; + 3A4E8A182B8E52A700A2586C /* CarPlay+Offline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CarPlay+Offline.swift"; sourceTree = ""; }; 3A50AAA42ACC42B400BF5438 /* AudiobookEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudiobookEntryView.swift; sourceTree = ""; }; 3A50AAB52ACC521B00BF5438 /* AudiobookLibraryView+ListenNow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudiobookLibraryView+ListenNow.swift"; sourceTree = ""; }; 3A50AAB72ACC522900BF5438 /* AudiobookEntryView+Library.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudiobookEntryView+Library.swift"; sourceTree = ""; }; @@ -462,6 +464,7 @@ isa = PBXGroup; children = ( 3A83B8722B8893E000A05957 /* CarPlayDelegate.swift */, + 3A4E8A182B8E52A700A2586C /* CarPlay+Offline.swift */, 3AD6BE862B89066300EEA347 /* CarPlay+Playback.swift */, 3AD6BE842B89060F00EEA347 /* CarPlay+NowPlaying.swift */, ); @@ -787,6 +790,7 @@ 3A77B6FD2ACDE2FA00F22C7F /* AuthorUnavailableView.swift in Sources */, 3A0AE6BA2AB624E700ACCD68 /* LoginView.swift in Sources */, 3AEFA9532B8BB3CA00220CA3 /* String+Random.swift in Sources */, + 3A4E8A192B8E52A700A2586C /* CarPlay+Offline.swift in Sources */, 3A9874292B59A7B500B2704F /* View+ReverseMask.swift in Sources */, 3A1EAB962ACC808A0064C80C /* ItemImage.swift in Sources */, 3A853FAF2AD03FA600FACAF6 /* AuthorView+Header.swift in Sources */, diff --git a/iOS/CarPlay/CarPlay+Offline.swift b/iOS/CarPlay/CarPlay+Offline.swift new file mode 100644 index 00000000..9c37e2c5 --- /dev/null +++ b/iOS/CarPlay/CarPlay+Offline.swift @@ -0,0 +1,95 @@ +// +// CarPlay+Offline.swift +// iOS +// +// Created by Rasmus Krämer on 27.02.24. +// + +import CarPlay +import SPPlayback +import SPOffline +import SPOfflineExtended + +extension CarPlayDelegate { + internal func buildOfflineListTemplate() async throws -> CPListTemplate { + let template = CPListTemplate(title: String(localized: "carPlay.offline.title"), sections: try getOfflineSections(), assistantCellConfiguration: .init(position: .top, visibility: .always, assistantAction: .playMedia)) + + Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in + Task { @MainActor in + template.updateSections(Self.updateSections(template.sections)) + } + } + NotificationCenter.default.addObserver(forName: Self.updateContentNotifications, object: nil, queue: nil) { _ in + Task { @MainActor in + template.updateSections(Self.updateSections(template.sections)) + } + } + + return template + } + + private func getOfflineSections() throws -> [CPListSection] { + let podcasts = try OfflineManager.shared.getPodcasts() + let audiobooks = try OfflineManager.shared.getAudiobooks() + + var sections: [CPListSection] = [ + .init(items: audiobooks.map { @MainActor in + var image: UIImage? + var detailText = "" + + if let imageUrl = $0.image?.url, let data = try? Data(contentsOf: imageUrl) { + image = UIImage(data: data) + } + + if let author = $0.author { + detailText += author + } + if let narrator = $0.narrator { + if !detailText.isEmpty { + detailText += " • " + } + + detailText += narrator + } + + let item = CPListItem(text: $0.name, detailText: detailText.isEmpty ? nil : detailText, image: image, accessoryImage: nil, accessoryType: .none) + + item.isExplicitContent = $0.explicit + + item.playingIndicatorLocation = .trailing + item.isPlaying = AudioPlayer.shared.item == $0 + + item.userInfo = $0 + item.handler = Self.startPlayback + + item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: $0).progress + + return item + }, header: String(localized: "carPlay.offline.sections.audiobooks"), headerSubtitle: nil, headerImage: UIImage(systemName: "bookmark.fill"), headerButton: nil, sectionIndexTitle: nil), + ] + + sections.append(contentsOf: podcasts.map { + CPListSection(items: $0.value.map { @MainActor in + let item = CPListItem(text: $0.name, detailText: $0.descriptionText) + + item.userInfo = $0 + item.handler = Self.startPlayback + + item.playingIndicatorLocation = .trailing + item.isPlaying = AudioPlayer.shared.item == $0 + + item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: $0).progress + + return item + }, header: $0.key.name, headerSubtitle: $0.key.author, headerImage: { + if let imageUrl = $0.image?.url, let data = try? Data(contentsOf: imageUrl) { + return UIImage(data: data) + } + + return nil + }($0.key), headerButton: nil, sectionIndexTitle: nil) + }) + + return sections + } +} diff --git a/iOS/CarPlay/CarPlay+Playback.swift b/iOS/CarPlay/CarPlay+Playback.swift index 1d14d396..f3983799 100644 --- a/iOS/CarPlay/CarPlay+Playback.swift +++ b/iOS/CarPlay/CarPlay+Playback.swift @@ -21,17 +21,20 @@ internal extension CarPlayDelegate { static func updateSections(_ sections: [CPListSection]) -> [CPListSection] { sections.map { CPListSection(items: $0.items.map { - let item = $0 as! CPListItem - let playableItem = $0.userInfo as! PlayableItem - - if AudioPlayer.shared.item == playableItem { - item.isPlaying = true - item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: playableItem).progress - } else { - item.isPlaying = false + if let item = $0 as? CPListItem { + let playableItem = $0.userInfo as! PlayableItem + + if AudioPlayer.shared.item == playableItem { + item.isPlaying = true + item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: playableItem).progress + } else { + item.isPlaying = false + } + + return item } - return item + return $0 }, header: $0.header!, headerSubtitle: $0.headerSubtitle, headerImage: $0.headerImage, headerButton: $0.headerButton, sectionIndexTitle: $0.sectionIndexTitle) } } diff --git a/iOS/CarPlay/CarPlayDelegate.swift b/iOS/CarPlay/CarPlayDelegate.swift index 3dd6e859..25ee0057 100644 --- a/iOS/CarPlay/CarPlayDelegate.swift +++ b/iOS/CarPlay/CarPlayDelegate.swift @@ -6,11 +6,7 @@ // import CarPlay -import Defaults import SPBase -import SPPlayback -import SPOffline -import SPOfflineExtended class CarPlayDelegate: UIResponder, CPTemplateApplicationSceneDelegate { // we need to keep a strong reference to this object @@ -43,87 +39,3 @@ class CarPlayDelegate: UIResponder, CPTemplateApplicationSceneDelegate { nowPlayingObserver = nil } } - -extension CarPlayDelegate { - private func buildOfflineListTemplate() async throws -> CPListTemplate { - let template = CPListTemplate(title: String(localized: "carPlay.offline.title"), sections: try getOfflineSections(), assistantCellConfiguration: .init(position: .top, visibility: .always, assistantAction: .playMedia)) - - Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in - Task { @MainActor in - template.updateSections(Self.updateSections(template.sections)) - } - } - NotificationCenter.default.addObserver(forName: Self.updateContentNotifications, object: nil, queue: nil) { _ in - Task { @MainActor in - template.updateSections(Self.updateSections(template.sections)) - } - } - - return template - } - - private func getOfflineSections() throws -> [CPListSection] { - let podcasts = try OfflineManager.shared.getPodcasts() - let audiobooks = try OfflineManager.shared.getAudiobooks() - - var sections: [CPListSection] = [ - .init(items: audiobooks.map { @MainActor in - var image: UIImage? - var detailText = "" - - if let imageUrl = $0.image?.url, let data = try? Data(contentsOf: imageUrl) { - image = UIImage(data: data) - } - - if let author = $0.author { - detailText += author - } - if let narrator = $0.narrator { - if !detailText.isEmpty { - detailText += " • " - } - - detailText += narrator - } - - let item = CPListItem(text: $0.name, detailText: detailText.isEmpty ? nil : detailText, image: image, accessoryImage: nil, accessoryType: .none) - - item.isExplicitContent = $0.explicit - - item.playingIndicatorLocation = .trailing - item.isPlaying = AudioPlayer.shared.item == $0 - - item.userInfo = $0 - item.handler = Self.startPlayback - - item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: $0).progress - - return item - }, header: String(localized: "carPlay.offline.sections.audiobooks"), headerSubtitle: nil, headerImage: UIImage(systemName: "bookmark.fill"), headerButton: nil, sectionIndexTitle: nil), - ] - - sections.append(contentsOf: podcasts.map { - CPListSection(items: $0.value.map { @MainActor in - let item = CPListItem(text: $0.name, detailText: $0.descriptionText) - - item.userInfo = $0 - item.handler = Self.startPlayback - - item.playingIndicatorLocation = .trailing - item.isPlaying = AudioPlayer.shared.item == $0 - - item.playbackProgress = OfflineManager.shared.requireProgressEntity(item: $0).progress - - return item - }, header: $0.key.name, headerSubtitle: $0.key.author, headerImage: { - if let imageUrl = $0.image?.url, let data = try? Data(contentsOf: imageUrl) { - return UIImage(data: data) - } - - return nil - }($0.key), headerButton: nil, sectionIndexTitle: nil) - }) - - return sections - } -} diff --git a/iOS/Offline/OfflineView.swift b/iOS/Offline/OfflineView.swift index 096d8a65..09e4e4c4 100644 --- a/iOS/Offline/OfflineView.swift +++ b/iOS/Offline/OfflineView.swift @@ -64,7 +64,6 @@ struct OfflineView: View { } extension OfflineView { - @Sendable func loadItems() async throws { (audiobooks, podcasts) = try await (OfflineManager.shared.getAudiobooks(), OfflineManager.shared.getPodcasts()) } diff --git a/iOS/Reusable/Buttons/DownloadButton.swift b/iOS/Reusable/Buttons/DownloadButton.swift index 55b5547c..ae7ef4f7 100644 --- a/iOS/Reusable/Buttons/DownloadButton.swift +++ b/iOS/Reusable/Buttons/DownloadButton.swift @@ -51,12 +51,14 @@ struct DownloadButton: View { Label("download.remove", systemImage: "xmark") } case .working: - HStack { - ProgressView() - - if downloadingLabel { + if downloadingLabel { + HStack { + ProgressView() + Text("downloading") } + } else { + ProgressView() } } } @@ -89,5 +91,5 @@ extension DownloadButton { } #Preview { - DownloadButton(item: Audiobook.fixture, downloadingLabel: true) + DownloadButton(item: Audiobook.fixture, downloadingLabel: false) }