Add PDF loader, add Empty trash button

This commit is contained in:
Jackson Harper
2024-02-05 17:16:12 +08:00
parent 737692214c
commit 5f3a3d4bf3
7 changed files with 27352 additions and 26964 deletions

View File

@ -369,58 +369,74 @@ struct AnimatingCellHeight: AnimatableModifier {
}
ToolbarItemGroup(placement: .barTrailing) {
if isEditMode == .active {
Button(action: { isEditMode = .inactive }, label: { Text("Cancel") })
} else {
if prefersListLayout {
if viewModel.appliedFilter?.name == "Deleted" {
if viewModel.isEmptyingTrash {
ProgressView()
} else {
Button(
action: {
viewModel.emptyTrash(dataService: dataService)
},
label: {
Text("Empty trash").tint(Color.blue)
})
.buttonStyle(.plain)
.foregroundColor(Color.blue)
}
} else {
if isEditMode == .active {
Button(action: { isEditMode = .inactive }, label: { Text("Cancel") })
} else {
if prefersListLayout {
Button(
action: { isEditMode = isEditMode == .active ? .inactive : .active },
label: {
Image
.selectMultiple
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
}
if enableGrid {
Button(
action: { prefersListLayout.toggle() },
label: {
Image(systemName: prefersListLayout ? "square.grid.2x2" : "list.bullet")
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
}
Button(
action: { isEditMode = isEditMode == .active ? .inactive : .active },
action: {
if viewModel.currentFolder == "inbox" {
showAddLinkView = true
} else if viewModel.currentFolder == "following" {
viewModel.showAddFeedView = true
}
},
label: {
Image
.selectMultiple
Image.addLink
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
Button(
action: {
searchPresented = true
isEditMode = .inactive
},
label: {
Image
.magnifyingGlass
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
}
if enableGrid {
Button(
action: { prefersListLayout.toggle() },
label: {
Image(systemName: prefersListLayout ? "square.grid.2x2" : "list.bullet")
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
}
Button(
action: {
if viewModel.currentFolder == "inbox" {
showAddLinkView = true
} else if viewModel.currentFolder == "following" {
viewModel.showAddFeedView = true
}
},
label: {
Image.addLink
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
Button(
action: {
searchPresented = true
isEditMode = .inactive
},
label: {
Image
.magnifyingGlass
.foregroundColor(Color.toolbarItemForeground)
}
).buttonStyle(.plain)
.padding(.horizontal, UIDevice.isIPad ? 5 : 0)
}
}
@ -430,19 +446,17 @@ struct AnimatingCellHeight: AnimatableModifier {
viewModel.bulkAction(dataService: dataService, action: .delete, items: Array(selection))
isEditMode = .inactive
}, label: { Image.toolbarTrash })
.disabled(selection.count < 1)
.padding(.horizontal, UIDevice.isIPad ? 10 : 5)
.disabled(selection.count < 1)
.padding(.horizontal, UIDevice.isIPad ? 10 : 5)
Spacer()
Text("\(selection.count) selected").font(.footnote)
Spacer()
Button(action: {
viewModel.bulkAction(dataService: dataService, action: .archive, items: Array(selection))
isEditMode = .inactive
}, label: { Image.toolbarArchive })
.disabled(selection.count < 1)
.padding(.horizontal, UIDevice.isIPad ? 10 : 5)
.disabled(selection.count < 1)
.padding(.horizontal, UIDevice.isIPad ? 10 : 5)
}
}
}
@ -492,7 +506,11 @@ struct AnimatingCellHeight: AnimatableModifier {
}
PresentationLink(transition: slideTransition, isPresented: $viewModel.linkIsActive) {
if let presentingItem = viewModel.selectedItem {
WebReaderContainerView(item: presentingItem)
if presentingItem.isPDF {
PDFContainerView(item: presentingItem)
} else {
WebReaderContainerView(item: presentingItem)
}
} else {
EmptyView()
}
@ -805,6 +823,15 @@ struct AnimatingCellHeight: AnimatableModifier {
.frame(maxWidth: .infinity)
.padding()
.listRowSeparator(.hidden, edges: .all)
} else if viewModel.isEmptyingTrash {
VStack {
Text("Emptying trash")
ProgressView()
}
.frame(minHeight: 400)
.frame(maxWidth: .infinity)
.padding()
.listRowSeparator(.hidden, edges: .all)
} else if viewModel.fetcher.items.isEmpty {
EmptyState(viewModel: viewModel)
.listRowSeparator(.hidden, edges: .all)
@ -1138,6 +1165,8 @@ struct BottomView: View {
var innerBody: some View {
if viewModel.fetcher.items.count < 3 {
AnyView(Color.clear)
} else if viewModel.appliedFilter?.name == "Deleted" {
AnyView(Color.clear)
} else {
AnyView(HStack {
if let totalCount = viewModel.fetcher.totalCount {

View File

@ -377,4 +377,18 @@ enum LoadingBarStyle {
fetcher.updateFeatureFilter(context: context, filter: filter)
}
}
@Published var isEmptyingTrash = false
func emptyTrash(dataService: DataService) {
self.isEmptyingTrash = true
Task {
if !(await dataService.emptyTrash()) {
snackbar("Error emptying trash")
} else {
snackbar("Trash emptied")
}
isEmptyingTrash = false
}
}
}

View File

@ -73,11 +73,13 @@ struct LibraryTabView: View {
@State var showOperationToast = false
@State var operationStatus: OperationStatus = .none
@State var operationMessage: String?
var body: some View {
VStack(spacing: 0) {
WindowLink(level: .alert, transition: .move(edge: .bottom), isPresented: $showOperationToast) {
OperationToast(operationMessage: $operationMessage, showOperationToast: $showOperationToast, operationStatus: $operationStatus)
OperationToast(operationMessage: $operationMessage,
showOperationToast: $showOperationToast,
operationStatus: $operationStatus)
} label: {
EmptyView()
}.buttonStyle(.plain)

View File

@ -231,6 +231,10 @@ struct WebReaderContainerView: View {
action: copyDeeplink,
label: { Label("Copy Deeplink", systemImage: "link") }
)
// Button(
// action: print,
// label: { Label("Print", systemImage: "printer") }
// )
Button(
action: delete,
label: { Label("Remove", systemImage: "trash") }
@ -399,6 +403,7 @@ struct WebReaderContainerView: View {
Task {
await audioController.preload(itemIDs: [item.unwrappedID])
}
viewModel.trackReadEvent(item: item)
}
.confirmationDialog(linkToOpen?.absoluteString ?? "", isPresented: $displayLinkSheet,
titleVisibility: .visible) {
@ -651,6 +656,10 @@ struct WebReaderContainerView: View {
func share() {
shareActionID = UUID()
}
func print() {
shareActionID = UUID()
}
func copyDeeplink() {
if let deepLink = item.deepLink {

View File

@ -45,11 +45,13 @@ public struct WebReaderLoadingContainer: View {
if let item = viewModel.item {
if let pdfItem = PDFItem.make(item: item) {
#if os(iOS)
NavigationView {
PDFViewer(viewModel: PDFViewerViewModel(pdfItem: pdfItem))
.navigationBarHidden(true)
.navigationViewStyle(.stack)
.accentColor(.appGrayTextContrast)
.onAppear { viewModel.trackReadEvent() }
}
#else
if let pdfURL = pdfItem.pdfURL {
PDFWrapperView(pdfURL: pdfURL)
@ -58,7 +60,7 @@ public struct WebReaderLoadingContainer: View {
} else if item.state == "CONTENT_NOT_FETCHED" {
ProgressView()
} else {
WebReaderContainerView(item: item, pop: { dismiss() })
WebReaderContainerView(item: item)
#if os(iOS)
.navigationViewStyle(.stack)
#endif

View File

@ -3,6 +3,7 @@ import Services
import SwiftUI
import Views
import WebKit
import Utils
struct SafariWebLink: Identifiable {
let id: UUID
@ -229,4 +230,19 @@ struct SafariWebLink: Identifiable {
}
}
}
func trackReadEvent(item: Models.LibraryItem) {
let itemID = item.unwrappedID
let slug = item.unwrappedSlug
let originalArticleURL = item.unwrappedPageURLString
EventTracker.track(
.linkRead(
linkID: itemID,
slug: slug,
reader: "WEB",
originalArticleURL: originalArticleURL
)
)
}
}

File diff suppressed because it is too large Load Diff