diff --git a/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/Contents.json b/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/Contents.json index 069cdf4d..90b58dbe 100644 --- a/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/Contents.json +++ b/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "audiobookshelf-icon.png", + "filename" : "abs.svg", "idiom" : "universal" } ], diff --git a/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/abs.svg b/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/abs.svg new file mode 100644 index 00000000..54cb1849 --- /dev/null +++ b/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/abs.svg @@ -0,0 +1,31 @@ + + +bgAsset 6 + + + + + + + + + + + + \ No newline at end of file diff --git a/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/audiobookshelf-icon.png b/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/audiobookshelf-icon.png deleted file mode 100644 index 87fcee04..00000000 Binary files a/BookPlayer/Assets.xcassets/audiobookshelf-icon.imageset/audiobookshelf-icon.png and /dev/null differ diff --git a/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/Contents.json b/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/Contents.json index da19810b..7385abcb 100644 --- a/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/Contents.json +++ b/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "icon-transparent.png", + "filename" : "jellyfin.svg", "idiom" : "universal" } ], diff --git a/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/icon-transparent.png b/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/icon-transparent.png deleted file mode 100644 index 50c881b3..00000000 Binary files a/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/icon-transparent.png and /dev/null differ diff --git a/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/jellyfin.svg b/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/jellyfin.svg new file mode 100644 index 00000000..5c75f1c0 --- /dev/null +++ b/BookPlayer/Assets.xcassets/jellyfin-icon.imageset/jellyfin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BookPlayer/Library/ItemList/ItemListViewModel.swift b/BookPlayer/Library/ItemList/ItemListViewModel.swift index bfe5316f..9e5bfe50 100644 --- a/BookPlayer/Library/ItemList/ItemListViewModel.swift +++ b/BookPlayer/Library/ItemList/ItemListViewModel.swift @@ -375,8 +375,14 @@ extension ItemListViewModel { func createFolder(with title: String, items: [String]? = nil, type: SimpleItemType) { Task { @MainActor in do { + let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines) + + guard !trimmedTitle.isEmpty else { + return + } + let folder = try libraryService.createFolder( - with: title, + with: trimmedTitle, inside: libraryNode.folderRelativePath ) await syncService.scheduleUpload(items: [folder]) diff --git a/BookPlayer/Player/PlayerManager.swift b/BookPlayer/Player/PlayerManager.swift index 0fb6e32b..207d4724 100755 --- a/BookPlayer/Player/PlayerManager.swift +++ b/BookPlayer/Player/PlayerManager.swift @@ -590,7 +590,7 @@ final class PlayerManager: NSObject, PlayerManagerProtocol, ObservableObject { self.nowPlayingInfo[MPMediaItemPropertyTitle] = chapter.title /// If the chapter title is the same as the current item, show the author instead - if chapter.title == currentItem.title { + if currentItem.isBoundBook || chapter.title == currentItem.title { self.nowPlayingInfo[MPMediaItemPropertyArtist] = currentItem.author } else { self.nowPlayingInfo[MPMediaItemPropertyArtist] = currentItem.title diff --git a/BookPlayer/Settings/Sections/SettingsTipView.swift b/BookPlayer/Settings/Sections/SettingsTipView.swift index 48ee17d1..61d7c4df 100644 --- a/BookPlayer/Settings/Sections/SettingsTipView.swift +++ b/BookPlayer/Settings/Sections/SettingsTipView.swift @@ -19,9 +19,26 @@ struct SettingsTipView: View { @State private var loadProductTask: Task<(), Error>? @EnvironmentObject private var theme: ThemeViewModel @Environment(\.loadingState) var loadingState + @Environment(\.accountService) var accountService let purchaseCompleted: () -> Void + /// Whether this is the user's first donation (uses non-consumable) or a repeat donation (uses consumable) + private var isFirstDonation: Bool { + return accountService.getAccount()?.donationMade != true + } + + /// Returns the appropriate product ID based on donation history + private var productId: String { + if isFirstDonation { + // First time donation uses non-consumable + return tipOption.rawValue + } else { + // Subsequent donations use consumable + return tipOption.rawValue + ".consumable" + } + } + var buttonBackgroundColor: Color { switch tipOption { case .kind: @@ -93,7 +110,8 @@ struct SettingsTipView: View { func loadProduct() { loadProductTask = Task { self.isLoading = true - let products = await Purchases.shared.products([tipOption.rawValue]) + // Use non-consumable for first donation, consumable for repeat donations + let products = await Purchases.shared.products([productId]) self.product = products.first self.buttonTitle = self.product?.localizedPriceString ?? "" self.isLoading = false @@ -104,7 +122,7 @@ struct SettingsTipView: View { guard AppEnvironment.isPurchaseEnabled else { throw PurchaseError.testFlightPurchasesDisabled } - + _ = await loadProductTask?.result guard let product else { diff --git a/Shared/Services/PlaybackService.swift b/Shared/Services/PlaybackService.swift index 17d91f36..e368b9c0 100644 --- a/Shared/Services/PlaybackService.swift +++ b/Shared/Services/PlaybackService.swift @@ -260,7 +260,7 @@ public final class PlaybackService: PlaybackServiceProtocol { return PlayableItem( title: folder.title, - author: chapters.first?.author ?? "voiceover_unknown_author".localized, + author: chapters.first?.author ?? folder.details, chapters: chapters, currentTime: folder.currentTime, duration: duration ?? folder.duration,