Move download audio option, clean up menus

This commit is contained in:
Jackson Harper 2022-11-14 10:35:17 +08:00
parent fa99af3f6a
commit 6eab360da3
7 changed files with 175 additions and 155 deletions

View file

@ -215,56 +215,118 @@ import Views
@ObservedObject var viewModel: HomeFeedViewModel
var filtersHeader: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
if viewModel.searchTerm.count > 0 {
TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) {
viewModel.searchTerm = ""
GeometryReader { reader in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
if viewModel.searchTerm.count > 0 {
TextChipButton.makeSearchFilterButton(title: viewModel.searchTerm) {
viewModel.searchTerm = ""
}.frame(maxWidth: reader.size.width * 0.66)
} else {
Menu(
content: {
ForEach(LinkedItemFilter.allCases, id: \.self) { filter in
Button(filter.displayName, action: { viewModel.appliedFilter = filter.rawValue })
}
},
label: {
TextChipButton.makeMenuButton(
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter"
)
}
)
}
} else {
Menu(
content: {
ForEach(LinkedItemFilter.allCases, id: \.self) { filter in
Button(filter.displayName, action: { viewModel.appliedFilter = filter.rawValue })
ForEach(LinkedItemSort.allCases, id: \.self) { sort in
Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue })
}
},
label: {
TextChipButton.makeMenuButton(
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter"
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort"
)
}
)
}
Menu(
content: {
ForEach(LinkedItemSort.allCases, id: \.self) { sort in
Button(sort.displayName, action: { viewModel.appliedSort = sort.rawValue })
TextChipButton.makeAddLabelButton {
viewModel.showLabelsSheet = true
}
ForEach(viewModel.selectedLabels, id: \.self) { label in
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
viewModel.selectedLabels.removeAll { $0.id == label.id }
}
}
ForEach(viewModel.negatedLabels, id: \.self) { label in
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) {
viewModel.negatedLabels.removeAll { $0.id == label.id }
}
}
Spacer()
}
.padding(0)
}
.listRowSeparator(.hidden)
}
}
func menuItems(for item: LinkedItem) -> some View {
Group {
if (item.highlights?.count ?? 0) > 0 {
Button(
action: { viewModel.itemForHighlightsView = item },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
}
Button(
action: { viewModel.itemUnderTitleEdit = item },
label: { Label("Edit Title/Description", systemImage: "textbox") }
)
Button(
action: { viewModel.itemUnderLabelEdit = item },
label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") }
)
Button(action: {
withAnimation(.linear(duration: 0.4)) {
viewModel.setLinkArchived(
dataService: dataService,
objectID: item.objectID,
archived: !item.isArchived
)
}
}, label: {
Label(
item.isArchived ? "Unarchive" : "Archive",
systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox"
)
})
Button(
action: {
itemToRemove = item
confirmationShown = true
},
label: {
Label("Remove Item", systemImage: "trash")
}
).tint(.red)
if FeatureFlag.enableSnooze {
Button {
viewModel.itemToSnoozeID = item.id
viewModel.snoozePresented = true
} label: {
Label { Text("Snooze") } icon: { Image.moon }
}
}
if let author = item.author {
Button(
action: {
viewModel.searchTerm = "author:\"\(author)\""
},
label: {
TextChipButton.makeMenuButton(
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort"
)
Label(String("More by \(author)"), systemImage: "person")
}
)
TextChipButton.makeAddLabelButton {
viewModel.showLabelsSheet = true
}
ForEach(viewModel.selectedLabels, id: \.self) { label in
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
viewModel.selectedLabels.removeAll { $0.id == label.id }
}
}
ForEach(viewModel.negatedLabels, id: \.self) { label in
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: true) {
viewModel.negatedLabels.removeAll { $0.id == label.id }
}
}
Spacer()
}
.padding(0)
}
.listRowSeparator(.hidden)
}
var body: some View {
@ -292,59 +354,7 @@ import Views
viewModel: viewModel
)
.contextMenu {
Button(
action: { viewModel.itemForHighlightsView = item },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
Button(
action: { viewModel.itemUnderTitleEdit = item },
label: { Label("Edit Title/Description", systemImage: "textbox") }
)
Button(
action: { viewModel.itemUnderLabelEdit = item },
label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") }
)
Button(action: {
withAnimation(.linear(duration: 0.4)) {
viewModel.setLinkArchived(
dataService: dataService,
objectID: item.objectID,
archived: !item.isArchived
)
}
}, label: {
Label(
item.isArchived ? "Unarchive" : "Archive",
systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox"
)
})
Button(
action: {
itemToRemove = item
confirmationShown = true
},
label: {
Label("Remove Item", systemImage: "trash")
}
).tint(.red)
if FeatureFlag.enableSnooze {
Button {
viewModel.itemToSnoozeID = item.id
viewModel.snoozePresented = true
} label: {
Label { Text("Snooze") } icon: { Image.moon }
}
}
if let author = item.author {
Button(
action: {
viewModel.searchTerm = "author:\"\(author)\""
},
label: {
Label(String("More by \(author)"), systemImage: "person")
}
)
}
menuItems(for: item)
}
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
if !item.isArchived {
@ -428,8 +438,6 @@ import Views
viewModel.itemUnderLabelEdit = item
case .editTitle:
viewModel.itemUnderTitleEdit = item
case .downloadAudio:
viewModel.downloadAudio(audioController: audioController, item: item)
}
}

View file

@ -50,7 +50,7 @@ import Views
)
Button(
action: { viewModel.itemUnderLabelEdit = item },
label: { Label("Edit Labels", systemImage: "tag") }
label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") }
)
Button(action: {
withAnimation(.linear(duration: 0.4)) {

View file

@ -175,14 +175,6 @@ import Views
showLoadingBar = false
}
func downloadAudio(audioController: AudioController, item: LinkedItem) {
Snackbar.show(message: "Downloading Offline Audio")
Task {
let downloaded = await audioController.downloadForOffline(itemID: item.unwrappedID)
Snackbar.show(message: downloaded ? "Audio file downloaded" : "Error downloading audio")
}
}
private var fetchRequest: NSFetchRequest<Models.LinkedItem> {
let fetchRequest: NSFetchRequest<Models.LinkedItem> = LinkedItem.fetchRequest()

View file

@ -153,6 +153,60 @@ struct WebReaderContainerView: View {
}.foregroundColor(.appGrayTextContrast)
}
func menuItems(for item: LinkedItem) -> some View {
let hasLabels = item.labels?.count == 0
let hasHighlights = (item.highlights?.count ?? 0) > 0
return Group {
if hasHighlights {
Button(
action: { showHighlightsView = true },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
}
Button(
action: { showTitleEdit = true },
label: { Label("Edit Title/Description", systemImage: "textbox") }
)
Button(
action: editLabels,
label: { Label(hasLabels ? "Edit Labels" : "Add Labels", systemImage: "tag") }
)
Button(
action: {
archive()
},
label: {
Label(
item.isArchived ? "Unarchive" : "Archive",
systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox"
)
}
)
Button(
action: {
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0)
},
label: { Label("Reset Read Location", systemImage: "arrow.counterclockwise.circle") }
)
Button(
action: {
viewModel.downloadAudio(audioController: audioController, item: item)
},
label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") }
)
if viewModel.hasOriginalUrl(item) {
Button(
action: share,
label: { Label("Share Original", systemImage: "square.and.arrow.up") }
)
}
Button(
action: delete,
label: { Label("Delete", systemImage: "trash") }
)
}
}
var navBar: some View {
HStack(alignment: .center) {
#if os(iOS)
@ -183,55 +237,7 @@ struct WebReaderContainerView: View {
#endif
Menu(
content: {
Group {
Button(
action: { showHighlightsView = true },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
Button(
action: { showTitleEdit = true },
label: { Label("Edit Title/Description", systemImage: "textbox") }
)
Button(
action: editLabels,
label: { Label("Edit Labels", systemImage: "tag") }
)
Button(
action: {
archive()
},
label: {
Label(
item.isArchived ? "Unarchive" : "Archive",
systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox"
)
}
)
Button(
action: {
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0)
},
label: { Label("Reset Read Location", systemImage: "arrow.counterclockwise.circle") }
)
Button(
action: { /* viewModel.downloadAudio(audioController: audioController, item: item) */ },
label: { Label("Download Audio", systemImage: "icloud.and.arrow.down") }
)
Button(
action: share,
label: { Label("Share Original", systemImage: "square.and.arrow.up") }
)
if viewModel.hasOriginalUrl(item) {
Button(
action: share,
label: { Label("Share Original", systemImage: "square.and.arrow.up") }
)
}
Button(
action: delete,
label: { Label("Delete", systemImage: "trash") }
)
}
menuItems(for: item)
},
label: {
#if os(iOS)

View file

@ -1,6 +1,7 @@
import Models
import Services
import SwiftUI
import Views
import WebKit
struct SafariWebLink: Identifiable {
@ -22,6 +23,14 @@ struct SafariWebLink: Identifiable {
return false
}
func downloadAudio(audioController: AudioController, item: LinkedItem) {
Snackbar.show(message: "Downloading Offline Audio")
Task {
let downloaded = await audioController.downloadForOffline(itemID: item.unwrappedID)
Snackbar.show(message: downloaded ? "Audio file downloaded" : "Error downloading audio")
}
}
func loadContent(dataService: DataService, username: String, itemID: String, retryCount: Int = 0) async {
errorMessage = nil

View file

@ -7,7 +7,6 @@ public enum GridCardAction {
case delete
case editLabels
case editTitle
case downloadAudio
case viewHighlights
}
@ -46,17 +45,19 @@ public struct GridCard: View {
var contextMenuView: some View {
Group {
Button(
action: { menuActionHandler(.viewHighlights) },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
if (item.highlights?.count ?? 0) > 0 {
Button(
action: { menuActionHandler(.viewHighlights) },
label: { Label("View Highlights & Notes", systemImage: "highlighter") }
)
}
Button(
action: { menuActionHandler(.editTitle) },
label: { Label("Edit Title/Description", systemImage: "textbox") }
)
Button(
action: { menuActionHandler(.editLabels) },
label: { Label("Edit Labels", systemImage: "tag") }
label: { Label(item.labels?.count == 0 ? "Add Labels" : "Edit Labels", systemImage: "tag") }
)
Button(
action: { menuActionHandler(.toggleArchiveStatus) },

View file

@ -110,7 +110,7 @@ public struct TextChipButton: View {
}
public static func makeSearchFilterButton(title: String, onTap: @escaping () -> Void) -> TextChipButton {
TextChipButton(title: "Search: \(title)", color: .appCtaYellow, actionType: .clear, negated: false, onTap: onTap)
TextChipButton(title: title, color: .appCtaYellow, actionType: .filter, negated: false, onTap: onTap)
}
public static func makeShowOptionsButton(title: String, onTap: @escaping () -> Void) -> TextChipButton {
@ -135,11 +135,11 @@ public struct TextChipButton: View {
case remove
case add
case show
case clear
case filter
var systemIconName: String {
switch self {
case .clear, .remove:
case .filter, .remove:
return "xmark"
case .add:
return "plus"
@ -173,6 +173,10 @@ public struct TextChipButton: View {
public var body: some View {
VStack(spacing: 0) {
HStack {
if actionType == .filter {
Image(systemName: "line.3.horizontal.decrease")
}
Text(text)
.strikethrough(color: negated ? foregroundColor : .clear)
.padding(.leading, 3)