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:
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user