Add PDF loader, add Empty trash button
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
Reference in New Issue
Block a user