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.
This commit is contained in:
Jackson Harper
2023-12-22 20:11:33 +08:00
parent f7105c1350
commit e4850311f4
8 changed files with 116 additions and 62 deletions

View File

@ -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
}
}
}

View File

@ -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)
}
)
}

View File

@ -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

View File

@ -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)

View File

@ -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()
}

View File

@ -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)

View File

@ -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,

View File

@ -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)
}