diff --git a/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookView.swift b/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookView.swift index 76904f3e3..42c894f8c 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookView.swift @@ -1,5 +1,6 @@ #if os(iOS) import CoreData + import MarkdownUI import Models import Services import SwiftUI @@ -10,6 +11,11 @@ @Environment(\.presentationMode) private var presentationMode @StateObject var viewModel = NotebookViewModel() + @State var showAnnotationModal = false + @State var errorAlertMessage: String? + @State var showErrorAlertMessage = false + @State var noteAnnotation = "" + let itemObjectID: NSManagedObjectID @Binding var hasHighlightMutations: Bool @State var setLabelsHighlight: Highlight? @@ -17,12 +23,12 @@ var emptyView: some View { Text(LocalText.highlightCardNoHighlightsOnPage) - .multilineTextAlignment(.center) + .multilineTextAlignment(.leading) .padding(16) } var innerBody: some View { - (viewModel.highlightItems.count > 0 ? AnyView(listView) : AnyView(emptyView)) + listView .navigationTitle("Notebook") .listStyle(PlainListStyle()) #if os(iOS) @@ -46,35 +52,80 @@ #endif } + var noteSection: some View { + HStack { + // let isEmpty = viewModel.noteItem.annotation.isEmpty + Spacer(minLength: 6) + + if let note = viewModel.noteItem, let annotation = note.annotation, !annotation.isEmpty { + Markdown(annotation) + .lineSpacing(6) + .accentColor(.appGraySolid) + .foregroundColor(.appGrayTextContrast) + .font(.appSubheadline) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color.appButtonBackground) + .cornerRadius(8) + + } else { + Text("Add Notes...") + .lineSpacing(6) + .accentColor(.appGraySolid) + .foregroundColor(.appGrayText) + .font(.appSubheadline) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color.appButtonBackground) + .cornerRadius(8) + } + } + .onTapGesture { + // annotation = highlightParams.annotation + showAnnotationModal = true + } + } + var listView: some View { List { - Section { - ForEach(viewModel.highlightItems) { highlightParams in - HighlightsListCard( - viewModel: self.viewModel, - highlightParams: highlightParams, - hasHighlightMutations: $hasHighlightMutations, - onSaveAnnotation: { - viewModel.updateAnnotation( - highlightID: highlightParams.highlightID, - annotation: $0, - dataService: dataService - ) - }, - onDeleteHighlight: { - hasHighlightMutations = true - viewModel.deleteHighlight( - highlightID: highlightParams.highlightID, - dataService: dataService - ) - }, - onSetLabels: { highlightID in - setLabelsHighlight = Highlight.lookup(byID: highlightID, inContext: dataService.viewContext) - } - ) - .listRowSeparator(.hidden) + Section("Article Notes") { + noteSection + .listRowSeparator(.hidden, edges: .bottom) + } + Section("Highlights") { + if viewModel.highlightItems.count > 0 { + ForEach(Array(viewModel.highlightItems.enumerated()), id: \.offset) { idx, highlightParams in + HighlightsListCard( + viewModel: self.viewModel, + highlightParams: highlightParams, + hasHighlightMutations: $hasHighlightMutations, + onSaveAnnotation: { + viewModel.updateAnnotation( + highlightID: highlightParams.highlightID, + annotation: $0, + dataService: dataService + ) + }, + onDeleteHighlight: { + hasHighlightMutations = true + viewModel.deleteHighlight( + highlightID: highlightParams.highlightID, + dataService: dataService + ) + }, + onSetLabels: { highlightID in + setLabelsHighlight = Highlight.lookup(byID: highlightID, inContext: dataService.viewContext) + } + ) + .listRowSeparator(.hidden, edges: idx == 0 ? .bottom : .all) + } + } else { + emptyView + .listRowSeparator(.hidden, edges: .bottom) } } + Spacer(minLength: 120) + .listRowSeparator(.hidden, edges: .all) }.sheet(item: $setLabelsHighlight) { highlight in ApplyLabelsView(mode: .highlight(highlight), isSearchFocused: false, onSave: { selectedLabels in hasHighlightMutations = true @@ -83,6 +134,20 @@ labels: selectedLabels, dataService: dataService) }) + }.sheet(isPresented: $showAnnotationModal) { + HighlightAnnotationSheet( + annotation: $noteAnnotation, + onSave: { + // onSaveAnnotation(annotation) + showAnnotationModal = false + hasHighlightMutations = true + }, + onCancel: { + showAnnotationModal = false + }, + errorAlertMessage: $errorAlertMessage, + showErrorAlertMessage: $showErrorAlertMessage + ) } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookViewModel.swift index a20b4eb9f..4c0ff7dd5 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Highlights/NotebookViewModel.swift @@ -17,7 +17,7 @@ struct HighlightListItemParams: Identifiable { struct NoteItemParams: Identifiable { let id = UUID() let highlightID: String - let annotation: String + let annotation: String? } @MainActor final class NotebookViewModel: ObservableObject { @@ -79,7 +79,6 @@ struct NoteItemParams: Identifiable { } private func loadHighlights(item: LinkedItem) { - let notes = item.highlights.asArray(of: Highlight.self).filter { $0.type == "NOTE" } let unsortedHighlights = item.highlights.asArray(of: Highlight.self) .filter { $0.type == "HIGHLIGHT" && $0.serverSyncStatus != ServerSyncStatus.needsDeletion.rawValue } @@ -100,5 +99,10 @@ struct NoteItemParams: Identifiable { createdBy: $0.createdByMe ? nil : InternalUserProfile.makeSingle($0.createdBy) ) } + + noteItem = item.highlights.asArray(of: Highlight.self) + .filter { $0.type == "NOTE" && $0.serverSyncStatus != ServerSyncStatus.needsDeletion.rawValue } + .first + .map { NoteItemParams(highlightID: $0.unwrappedID, annotation: $0.annotation) } } } diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Contents.json b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Contents.json b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Contents.json new file mode 100644 index 000000000..f27546ced --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Hotpot.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Hotpot.png b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Hotpot.png new file mode 100644 index 000000000..db6f271c4 Binary files /dev/null and b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/Hotpot.imageset/Hotpot.png differ diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/Contents.json b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/Contents.json new file mode 100644 index 000000000..f1bc63759 --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "notebook.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/notebook.svg b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/notebook.svg new file mode 100644 index 000000000..a9a6bb068 --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/Media.xcassets/notebook.imageset/notebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift index 44f4b27e6..698fba525 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift @@ -14,7 +14,7 @@ struct WebReaderContainerView: View { @State private var showLabelsModal = false @State private var showHighlightLabelsModal = false @State private var showTitleEdit = false - @State private var showHighlightsView = false + @State private var showNotebookView = false @State private var hasPerformedHighlightMutations = false @State var showHighlightAnnotationModal = false @State private var navBarVisibilityRatio = 1.0 @@ -61,7 +61,7 @@ struct WebReaderContainerView: View { lastScrollPercentage = percent } - func onHighlightListViewDismissal() { + func onNotebookViewDismissal() { // Reload the web view if mutation happened in highlights list modal guard hasPerformedHighlightMutations else { return } @@ -205,7 +205,7 @@ struct WebReaderContainerView: View { let hasLabels = item.labels?.count != 0 return Group { Button( - action: { showHighlightsView = true }, + action: { showNotebookView = true }, label: { Label("Notebook", systemImage: "highlighter") } ) Button( @@ -261,14 +261,13 @@ struct WebReaderContainerView: View { } var navBar: some View { - HStack(alignment: .center) { + HStack(alignment: .center, spacing: 15) { #if os(iOS) Button( action: { self.presentationMode.wrappedValue.dismiss() }, label: { Image(systemName: "chevron.backward") .font(.appNavbarIcon) - // .foregroundColor(.appGrayTextContrast) .padding() } ) @@ -285,6 +284,14 @@ struct WebReaderContainerView: View { ) .padding(.horizontal) .scaleEffect(navBarVisibilityRatio) + Button( + action: { showNotebookView.toggle() }, + label: { + Image("notebook", bundle: Bundle.module) + } + ) + .padding(.horizontal) + .scaleEffect(navBarVisibilityRatio) #if os(macOS) Spacer() #endif @@ -297,7 +304,6 @@ struct WebReaderContainerView: View { Image(systemName: "ellipsis") .resizable(resizingMode: Image.ResizingMode.stretch) .aspectRatio(contentMode: .fit) - // .foregroundColor(.appGrayTextContrast) .frame(width: 20, height: 20) .scaleEffect(navBarVisibilityRatio) .padding() @@ -344,7 +350,7 @@ struct WebReaderContainerView: View { }) } #if os(iOS) - .sheet(isPresented: $showHighlightsView, onDismiss: onHighlightListViewDismissal) { + .sheet(isPresented: $showNotebookView, onDismiss: onNotebookViewDismissal) { NotebookView( itemObjectID: item.objectID, hasHighlightMutations: $hasPerformedHighlightMutations diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/Contents.json b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/Contents.json new file mode 100644 index 000000000..f1bc63759 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "notebook.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/notebook.svg b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/notebook.svg new file mode 100644 index 000000000..a9a6bb068 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/notebook.imageset/notebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apple/OmnivoreKit/Sources/Views/Resources/en.lproj/Localizable.strings b/apple/OmnivoreKit/Sources/Views/Resources/en.lproj/Localizable.strings index a99810b74..08503bd95 100644 --- a/apple/OmnivoreKit/Sources/Views/Resources/en.lproj/Localizable.strings +++ b/apple/OmnivoreKit/Sources/Views/Resources/en.lproj/Localizable.strings @@ -13,7 +13,7 @@ // Highlights List Card "highlightCardHighlightByOther" = "Highlight by "; -"highlightCardNoHighlightsOnPage" = "You have not added any highlights or notes to this page."; +"highlightCardNoHighlightsOnPage" = "You have not added any highlights to this page."; // Labels View "labelsViewAssignNameColor" = "Assign a name and color.";