From e4850311f4daaa0205ff49ff82304bf2c08dd30e Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 22 Dec 2023 20:11:33 +0800 Subject: [PATCH] archive/delete for tts player, use valet to sync hide system labels property Using valet instead of UserDefaults(suiteName to work around some potential issues with the extension loading. --- .../AudioPlayer/ExpandedAudioPlayer.swift | 124 +++++++++++------- .../App/Views/Home/HomeFeedViewIOS.swift | 16 ++- .../App/Views/Labels/ApplyLabelsView.swift | 2 +- .../Labels/FilterByLabelsViewModel.swift | 2 +- .../Sources/App/Views/Labels/LabelsView.swift | 12 +- .../App/Views/Labels/LabelsViewModel.swift | 2 +- .../Sources/Models/DataModels/FeedItem.swift | 2 + .../Sources/Services/Keychain/ValetKey.swift | 18 +++ 8 files changed, 116 insertions(+), 62 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/ExpandedAudioPlayer.swift b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/ExpandedAudioPlayer.swift index 7ff57855e..39e8b1a8d 100644 --- a/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/ExpandedAudioPlayer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/AudioPlayer/ExpandedAudioPlayer.swift @@ -7,12 +7,16 @@ // swiftlint:disable file_length type_body_length public struct ExpandedAudioPlayer: View { + @EnvironmentObject var dataService: DataService @EnvironmentObject var audioController: AudioController + @Environment(\.colorScheme) private var colorScheme: ColorScheme @Environment(\.dismiss) private var dismiss @State var showVoiceSheet = false @State var tabIndex: Int = 0 + @State var showLabelsModal = false + @State var showNotebookView = false var playPauseButtonImage: String { switch audioController.state { @@ -54,62 +58,51 @@ .aspectRatio(contentMode: .fit) .font(Font.title.weight(.light)) } - )) + ) + .buttonStyle(.plain) + ) } } var closeButton: some View { - Button( - action: { - dismiss() - }, - label: { - ZStack { - Circle() - .foregroundColor(Color.appGrayText) - .frame(width: 36, height: 36) - .opacity(0.1) + ZStack { + Circle() + .foregroundColor(Color.appGrayText) + .frame(width: 36, height: 36) + .opacity(0.1) - Image(systemName: "chevron.down") - .font(.appCallout) - .frame(width: 36, height: 36) - } - } - ) + Image(systemName: "chevron.down") + .font(.appCallout) + .frame(width: 36, height: 36) + } } - var menuButton: some View { - Menu { - Menu(String(format: "Playback Speed (%.1f×)", audioController.playbackRate)) { - playbackRateButton(rate: 0.8, title: "0.8×", selected: audioController.playbackRate == 0.8) - playbackRateButton(rate: 0.9, title: "0.9×", selected: audioController.playbackRate == 0.9) - playbackRateButton(rate: 1.0, title: "1.0×", selected: audioController.playbackRate == 1.0) - playbackRateButton(rate: 1.1, title: "1.1×", selected: audioController.playbackRate == 1.1) - playbackRateButton(rate: 1.2, title: "1.2×", selected: audioController.playbackRate == 1.2) - playbackRateButton(rate: 1.3, title: "1.3×", selected: audioController.playbackRate == 1.3) - playbackRateButton(rate: 1.5, title: "1.5×", selected: audioController.playbackRate == 1.5) - playbackRateButton(rate: 1.7, title: "1.7×", selected: audioController.playbackRate == 1.7) - playbackRateButton(rate: 2.0, title: "2.0×", selected: audioController.playbackRate == 2.0) - playbackRateButton(rate: 2.2, title: "2.2×", selected: audioController.playbackRate == 2.2) - playbackRateButton(rate: 2.5, title: "2.5×", selected: audioController.playbackRate == 2.5) - } - Button(action: { showVoiceSheet = true }, label: { Label("Change Voice", systemImage: "person.wave.2") }) - Button(action: { viewArticle() }, label: { Label("View Article", systemImage: "book") }) - Button(action: { audioController.stop() }, label: { Label("Stop", systemImage: "xmark.circle") }) - Button(action: { dismiss() }, label: { Label(LocalText.dismissButton, systemImage: "arrow.down.to.line") }) - } label: { - ZStack { - Circle() - .foregroundColor(Color.appGrayText) - .frame(width: 36, height: 36) - .opacity(0.1) + var toolbarItems: some ToolbarContent { + ToolbarItemGroup(placement: .barTrailing) { + Button( + action: { delete() }, + label: { + Image + .toolbarTrash + .foregroundColor(ThemeManager.currentTheme.toolbarColor) + } + ).padding(.trailing, 5) - Image(systemName: "ellipsis") - .font(.appCallout) - .frame(width: 36, height: 36) - } + Button( + action: { archive() }, + label: { + if audioController.itemAudioProperties?.isArchived ?? false { + Image + .toolbarUnarchive + .foregroundColor(ThemeManager.currentTheme.toolbarColor) + } else { + Image + .toolbarArchive + .foregroundColor(ThemeManager.currentTheme.toolbarColor) + } + } + ).padding(.trailing, 5) } - .padding(8) } func viewArticle() { @@ -121,6 +114,32 @@ } } + func delete() { + if let objectID = audioController.itemAudioProperties?.objectID { + audioController.stop() + dismiss() + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { + removeLibraryItemAction(dataService: dataService, objectID: objectID) + } + } + } + + func archive() { + if let objectID = audioController.itemAudioProperties?.objectID, + let isArchived = audioController.itemAudioProperties?.isArchived + { + if isArchived { + audioController.stop() + dismiss() + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { + dataService.archiveLink(objectID: objectID, archived: !isArchived) + } + } else { + dataService.archiveLink(objectID: objectID, archived: !isArchived) + } + } + } + struct SpeechCard: View { let id: Int @EnvironmentObject var audioController: AudioController @@ -297,6 +316,7 @@ .resizable() .frame(width: 18, height: 18) }) + .buttonStyle(.plain) .padding(.trailing, 32) Button( @@ -307,6 +327,7 @@ .font(Font.title.weight(.light)) } ) + .buttonStyle(.plain) .frame(width: 16, height: 16) .padding(.trailing, 16) .foregroundColor(.themeAudioPlayerGray) @@ -324,6 +345,7 @@ .font(Font.title.weight(.light)) } ) + .buttonStyle(.plain) .frame(width: 16, height: 16) .padding(.trailing, 32 - 4) // -4 to account for the menu touch padding .foregroundColor(.themeAudioPlayerGray) @@ -343,6 +365,7 @@ Text("\(String(format: "%.1f", audioController.playbackRate))×") .font(.appCaption) }) + .buttonStyle(.plain) .padding(4) Spacer() @@ -416,9 +439,12 @@ NavigationView { innerBody .background(Color.themeDisabledBG) - .navigationTitle(audioController.itemAudioProperties?.title ?? LocalText.textToSpeechGeneric) - .navigationBarItems(trailing: Button(action: { dismiss() }, label: { Text("Hide") })) + .navigationTitle("") + .navigationBarItems(leading: Button(action: { dismiss() }, label: { closeButton })) .navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.inline) + .toolbar { + toolbarItems + } } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 26de7a666..87098ba5b 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -258,15 +258,18 @@ struct AnimatingCellHeight: AnimatableModifier { Button( action: { isEditMode = isEditMode == .active ? .inactive : .active }, label: { - Image.selectMultiple + Image + .selectMultiple + .foregroundColor(ThemeManager.currentTheme.toolbarColor) } - ) + ).foregroundColor(ThemeManager.currentTheme.toolbarColor) } if enableGrid { Button( action: { prefersListLayout.toggle() }, label: { - Label("Toggle Feed Layout", systemImage: prefersListLayout ? "square.grid.2x2" : "list.bullet") + Image(systemName: prefersListLayout ? "square.grid.2x2" : "list.bullet") + .foregroundColor(ThemeManager.currentTheme.toolbarColor) } ) } @@ -280,12 +283,15 @@ struct AnimatingCellHeight: AnimatableModifier { }, label: { Image.addLink + .foregroundColor(ThemeManager.currentTheme.toolbarColor) } - ) + ).tint(Color.appGrayText) Button( action: { searchPresented = true }, label: { - Image.magnifyingGlass + Image + .magnifyingGlass + .foregroundColor(ThemeManager.currentTheme.toolbarColor) } ) } diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift index 829fb3614..4eff7787d 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift @@ -202,7 +202,7 @@ func isSystemLabel(_ label: LinkedItemLabel) -> Bool { extension Sequence where Element == LinkedItemLabel { func applySearchFilter(_ searchFilter: String) -> [LinkedItemLabel] { - let hideSystemLabels = UserDefaults(suiteName: "group.app.omnivoreapp")?.bool(forKey: UserDefaultKey.hideSystemLabels.rawValue) ?? false + let hideSystemLabels = PublicValet.hideLabels if searchFilter.isEmpty || searchFilter == ZWSP { return map { $0 } // return the identity of the sequence diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/FilterByLabelsViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/FilterByLabelsViewModel.swift index 8355db882..b978f3b97 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/FilterByLabelsViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/FilterByLabelsViewModel.swift @@ -15,7 +15,7 @@ import Views @Published var labelSearchFilter = "" func setLabels(_ labels: [LinkedItemLabel]) { - let hideSystemLabels = UserDefaults(suiteName: "group.app.omnivoreapp")?.bool(forKey: UserDefaultKey.hideSystemLabels.rawValue) ?? false + let hideSystemLabels = PublicValet.hideLabels self.labels = labels.filter { !hideSystemLabels || !isSystemLabel($0) }.sorted { left, right in let aTrimmed = left.unwrappedName.trimmingCharacters(in: .whitespaces) diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift index 86c3f4c59..f18fd6335 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift @@ -34,6 +34,8 @@ struct LabelsView: View { } Section("Label settings") { Toggle("Hide system labels", isOn: $hideSystemLabels) + }.onChange(of: hideSystemLabels) { newValue in + PublicValet.hideLabels = newValue } } .navigationTitle(LocalText.labelsGeneric) @@ -52,11 +54,11 @@ struct LabelsView: View { } Button(LocalText.cancelGeneric, role: .cancel) { self.labelToRemove = nil } } - .onChange(of: hideSystemLabels) { _ in - Task { - await viewModel.loadLabels(dataService: dataService, item: nil) - } - } +// .onChange(of: hideSystemLabels) { _ in +// Task { +// await viewModel.loadLabels(dataService: dataService, item: nil) +// } +// } .onReceive(NotificationCenter.default.publisher(for: Notification.Name("ScrollToTop"))) { _ in dismiss() } diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift index 5165e16dd..ee606d417 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift @@ -17,7 +17,7 @@ import Utils public init() {} func setLabels(_ labels: [LinkedItemLabel]) { - let hideSystemLabels = UserDefaults(suiteName: "group.app.omnivoreapp")?.bool(forKey: UserDefaultKey.hideSystemLabels.rawValue) ?? false + let hideSystemLabels = PublicValet.hideLabels self.labels = labels.filter { !hideSystemLabels || !isSystemLabel($0) }.sorted { left, right in let aTrimmed = left.unwrappedName.trimmingCharacters(in: .whitespaces) diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index 7861f8575..874e75010 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -32,6 +32,7 @@ public struct LinkedItemAudioProperties { public let itemID: String public let objectID: NSManagedObjectID public let title: String + public let isArchived: Bool public let byline: String? public let imageURL: URL? public let language: String? @@ -240,6 +241,7 @@ public extension LibraryItem { itemID: unwrappedID, objectID: objectID, title: unwrappedTitle, + isArchived: isArchived, byline: formattedByline, imageURL: imageURL, language: language, diff --git a/apple/OmnivoreKit/Sources/Services/Keychain/ValetKey.swift b/apple/OmnivoreKit/Sources/Services/Keychain/ValetKey.swift index e4daea999..543fc6846 100644 --- a/apple/OmnivoreKit/Sources/Services/Keychain/ValetKey.swift +++ b/apple/OmnivoreKit/Sources/Services/Keychain/ValetKey.swift @@ -10,12 +10,26 @@ public enum PublicValet { public static var authToken: String? { ValetKey.authToken.value() } + + public static var hideLabels: Bool { + get { + ValetKey.hideLabels.exists + } + set { + if newValue { + try? ValetKey.hideLabels.setValue("true") + } else { + ValetKey.hideLabels.clear() + } + } + } } enum ValetKey: String { case authToken = "app.omnivore.valet.auth-token" case authCookieString = "app.omnivore.valet.auth-cookie-raw-string" case appEnvironmentString = "app.omnivore.valet.app-environment" + case hideLabels = "app.omnivore.valet.hide-labels" } extension ValetKey { @@ -23,6 +37,10 @@ extension ValetKey { value() != nil } + func clear() { + try? ValetKey.valet.removeObject(forKey: rawValue) + } + func value() -> String? { try? ValetKey.valet.string(forKey: rawValue) }