mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Update view models
This commit is contained in:
parent
92b2f9112b
commit
fa82917f55
10 changed files with 279 additions and 290 deletions
|
|
@ -3,11 +3,17 @@ import Utils
|
|||
import Views
|
||||
|
||||
public extension PlatformViewController {
|
||||
static func makeShareExtensionController(extensionContext: NSExtensionContext?) -> PlatformViewController {
|
||||
static func makeShareExtensionController(
|
||||
viewModel: ShareExtensionViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
extensionContext: NSExtensionContext?
|
||||
) -> PlatformViewController {
|
||||
registerFonts()
|
||||
|
||||
let hostingController = PlatformHostingController(
|
||||
rootView: ShareExtensionView(extensionContext: extensionContext)
|
||||
rootView: ShareExtensionView(viewModel: viewModel,
|
||||
labelsViewModel: labelsViewModel,
|
||||
extensionContext: extensionContext)
|
||||
)
|
||||
#if os(iOS)
|
||||
hostingController.view.layer.cornerRadius = 12
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@ public class ShareExtensionViewModel: ObservableObject {
|
|||
@Published public var linkedItem: LinkedItem?
|
||||
@Published public var requestId = UUID().uuidString.lowercased()
|
||||
@Published var debugText: String?
|
||||
@Published var noteText: String = ""
|
||||
|
||||
let services = Services()
|
||||
let queue = OperationQueue()
|
||||
|
||||
public init() {}
|
||||
|
||||
func handleReadNowAction(extensionContext: NSExtensionContext?) {
|
||||
#if os(iOS)
|
||||
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ import Utils
|
|||
import Views
|
||||
|
||||
public struct AddNoteSheet: View {
|
||||
@State var text = ""
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@StateObject var viewModel: ShareExtensionViewModel
|
||||
let highlightId = UUID().uuidString.lowercased()
|
||||
let shortId = NanoID.generate(alphabet: NanoID.Alphabet.urlSafe.rawValue, size: 8)
|
||||
|
||||
enum FocusField: Hashable {
|
||||
case noteEditor
|
||||
|
|
@ -20,13 +24,25 @@ public struct AddNoteSheet: View {
|
|||
|
||||
@FocusState private var focusedField: FocusField?
|
||||
|
||||
public init() {
|
||||
UITextView.appearance().textContainerInset = UIEdgeInsets(top: 5, left: 2, bottom: 5, right: 2)
|
||||
public init(viewModel: ShareExtensionViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
UITextView.appearance().textContainerInset = UIEdgeInsets(top: 8, left: 4, bottom: 10, right: 4)
|
||||
}
|
||||
|
||||
func saveNote() {
|
||||
if let linkedItem = viewModel.linkedItem {
|
||||
_ = viewModel.services.dataService.createNote(shortId: shortId,
|
||||
highlightID: highlightId,
|
||||
articleId: linkedItem.unwrappedID,
|
||||
annotation: viewModel.noteText)
|
||||
} else {
|
||||
// Maybe we shouldn't even allow this UI without linkeditem existing
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
NavigationView {
|
||||
TextEditor(text: $text)
|
||||
TextEditor(text: $viewModel.noteText)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.focused($focusedField, equals: .noteEditor)
|
||||
.task {
|
||||
|
|
@ -35,10 +51,15 @@ public struct AddNoteSheet: View {
|
|||
.background(Color.extensionPanelBackground)
|
||||
.navigationTitle("Add Note")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(leading: Button(action: {}, label: {
|
||||
.navigationBarItems(leading: Button(action: {
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("Cancel")
|
||||
}))
|
||||
.navigationBarItems(trailing: Button(action: {}, label: {
|
||||
.navigationBarItems(trailing: Button(action: {
|
||||
saveNote()
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("Save").bold()
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// EditLabelsSheet.swift
|
||||
//
|
||||
//
|
||||
// Created by Jackson Harper on 10/27/23.
|
||||
//
|
||||
|
||||
import Models
|
||||
import Services
|
||||
import SwiftUI
|
||||
import Utils
|
||||
import Views
|
||||
|
||||
@MainActor
|
||||
public struct EditLabelsSheet: View {
|
||||
@State var text = ""
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@EnvironmentObject var dataService: DataService
|
||||
|
||||
@StateObject var labelsViewModel: LabelsViewModel
|
||||
@StateObject var viewModel: ShareExtensionViewModel
|
||||
|
||||
enum FocusField: Hashable {
|
||||
case noteEditor
|
||||
}
|
||||
|
||||
@FocusState private var focusedField: FocusField?
|
||||
|
||||
public init(viewModel: ShareExtensionViewModel, labelsViewModel: LabelsViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
_labelsViewModel = StateObject(wrappedValue: labelsViewModel)
|
||||
|
||||
UITextView.appearance().textContainerInset = UIEdgeInsets(top: 5, left: 2, bottom: 5, right: 2)
|
||||
}
|
||||
|
||||
func onLabelTap(label: LinkedItemLabel, textChip _: TextChip) {
|
||||
if labelsViewModel.selectedLabels.contains(label) {
|
||||
labelsViewModel.selectedLabels.remove(label)
|
||||
} else {
|
||||
labelsViewModel.selectedLabels.insert(label)
|
||||
}
|
||||
|
||||
if let linkedItem = viewModel.linkedItem {
|
||||
labelsViewModel.saveItemLabelChanges(itemID: linkedItem.unwrappedID, dataService: viewModel.services.dataService)
|
||||
}
|
||||
}
|
||||
|
||||
var content: some View {
|
||||
VStack(spacing: 15) {
|
||||
SearchBar(searchTerm: $labelsViewModel.labelSearchFilter)
|
||||
|
||||
// swiftlint:disable line_length
|
||||
ScrollView {
|
||||
LabelsMasonaryView(labels: labelsViewModel.labels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
selectedLabels: labelsViewModel.selectedLabels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
onLabelTap: onLabelTap)
|
||||
Button(
|
||||
action: { labelsViewModel.showCreateLabelModal = true },
|
||||
label: {
|
||||
HStack {
|
||||
let trimmedLabelName = labelsViewModel.labelSearchFilter.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
Image(systemName: "tag").foregroundColor(.blue)
|
||||
Text(
|
||||
labelsViewModel.labelSearchFilter.count > 0 ?
|
||||
"Create: \"\(trimmedLabelName)\" label" :
|
||||
LocalText.createLabelMessage
|
||||
).foregroundColor(.blue)
|
||||
.font(Font.system(size: 14))
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.padding(10)
|
||||
}
|
||||
}
|
||||
.background(Color.clear)
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
NavigationView {
|
||||
content
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(Color.extensionBackground)
|
||||
.navigationTitle("Set Labels")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(trailing: Button(action: {
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("Done").bold()
|
||||
}))
|
||||
}
|
||||
.task {
|
||||
await labelsViewModel.loadLabelsFromStore(dataService: viewModel.services.dataService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ import Views
|
|||
// swiftlint:disable file_length type_body_length
|
||||
public struct ShareExtensionView: View {
|
||||
let extensionContext: NSExtensionContext?
|
||||
@StateObject var labelsViewModel = LabelsViewModel()
|
||||
@StateObject private var viewModel = ShareExtensionViewModel()
|
||||
@StateObject var viewModel: ShareExtensionViewModel
|
||||
@StateObject var labelsViewModel: LabelsViewModel
|
||||
|
||||
@State var previousLabels: [LinkedItemLabel]?
|
||||
@State var messageText: String?
|
||||
|
|
@ -32,6 +32,15 @@ public struct ShareExtensionView: View {
|
|||
|
||||
@FocusState private var focusedField: FocusField?
|
||||
|
||||
public init(viewModel: ShareExtensionViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
extensionContext: NSExtensionContext?)
|
||||
{
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
_labelsViewModel = StateObject(wrappedValue: labelsViewModel)
|
||||
self.extensionContext = extensionContext
|
||||
}
|
||||
|
||||
private var titleText: String {
|
||||
switch viewModel.status {
|
||||
case .saved, .synced, .syncFailed(error: _):
|
||||
|
|
@ -132,76 +141,76 @@ public struct ShareExtensionView: View {
|
|||
}
|
||||
}
|
||||
|
||||
var labelsSection: some View {
|
||||
HStack {
|
||||
if viewState != .editingLabels {
|
||||
ZStack {
|
||||
Circle()
|
||||
.foregroundColor(Color.blue)
|
||||
.frame(width: 34, height: 34)
|
||||
|
||||
Image(systemName: "tag")
|
||||
.font(.appCallout)
|
||||
.frame(width: 34, height: 34)
|
||||
}
|
||||
.padding(.trailing, 8)
|
||||
|
||||
VStack {
|
||||
Text(LocalText.labelsGeneric)
|
||||
.font(.appSubheadline)
|
||||
.foregroundColor(Color.appGrayTextContrast)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
let labelCount = labelsViewModel.selectedLabels.count
|
||||
Text(labelCount > 0 ?
|
||||
"\(labelCount) label\(labelCount > 1 ? "s" : "") selected"
|
||||
: "Add labels to your saved link")
|
||||
.font(.appFootnote)
|
||||
.foregroundColor(Color.appGrayText)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.appCallout)
|
||||
} else {
|
||||
VStack(spacing: 15) {
|
||||
SearchBar(searchTerm: $labelsViewModel.labelSearchFilter)
|
||||
|
||||
// swiftlint:disable line_length
|
||||
ScrollView {
|
||||
LabelsMasonaryView(labels: labelsViewModel.labels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
selectedLabels: labelsViewModel.selectedLabels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
onLabelTap: onLabelTap)
|
||||
Button(
|
||||
action: { labelsViewModel.showCreateLabelModal = true },
|
||||
label: {
|
||||
HStack {
|
||||
let trimmedLabelName = labelsViewModel.labelSearchFilter.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
Image(systemName: "tag").foregroundColor(.blue)
|
||||
Text(
|
||||
labelsViewModel.labelSearchFilter.count > 0 ?
|
||||
"Create: \"\(trimmedLabelName)\" label" :
|
||||
LocalText.createLabelMessage
|
||||
).foregroundColor(.blue)
|
||||
.font(Font.system(size: 14))
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.padding(10)
|
||||
}.background(Color.appButtonBackground)
|
||||
// swiftlint:enable line_length
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(viewState == .editingLabels ? 0 : 16)
|
||||
.background(Color.extensionBackground)
|
||||
.frame(maxWidth: .infinity, maxHeight: viewState == .editingLabels ? .infinity : 60)
|
||||
.cornerRadius(8)
|
||||
}
|
||||
// var labelsSection: some View {
|
||||
// HStack {
|
||||
// if viewState != .editingLabels {
|
||||
// ZStack {
|
||||
// Circle()
|
||||
// .foregroundColor(Color.blue)
|
||||
// .frame(width: 34, height: 34)
|
||||
//
|
||||
// Image(systemName: "tag")
|
||||
// .font(.appCallout)
|
||||
// .frame(width: 34, height: 34)
|
||||
// }
|
||||
// .padding(.trailing, 8)
|
||||
//
|
||||
// VStack {
|
||||
// Text(LocalText.labelsGeneric)
|
||||
// .font(.appSubheadline)
|
||||
// .foregroundColor(Color.appGrayTextContrast)
|
||||
// .frame(maxWidth: .infinity, alignment: .leading)
|
||||
//
|
||||
// let labelCount = labelsViewModel.selectedLabels.count
|
||||
// Text(labelCount > 0 ?
|
||||
// "\(labelCount) label\(labelCount > 1 ? "s" : "") selected"
|
||||
// : "Add labels to your saved link")
|
||||
// .font(.appFootnote)
|
||||
// .foregroundColor(Color.appGrayText)
|
||||
// .frame(maxWidth: .infinity, alignment: .leading)
|
||||
// }
|
||||
//
|
||||
// Spacer()
|
||||
//
|
||||
// Image(systemName: "chevron.right")
|
||||
// .font(.appCallout)
|
||||
// } else {
|
||||
// VStack(spacing: 15) {
|
||||
// SearchBar(searchTerm: $labelsViewModel.labelSearchFilter)
|
||||
//
|
||||
// // swiftlint:disable line_length
|
||||
// ScrollView {
|
||||
// LabelsMasonaryView(labels: labelsViewModel.labels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
// selectedLabels: labelsViewModel.selectedLabels.applySearchFilter(labelsViewModel.labelSearchFilter),
|
||||
// onLabelTap: onLabelTap)
|
||||
// Button(
|
||||
// action: { labelsViewModel.showCreateLabelModal = true },
|
||||
// label: {
|
||||
// HStack {
|
||||
// let trimmedLabelName = labelsViewModel.labelSearchFilter.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
// Image(systemName: "tag").foregroundColor(.blue)
|
||||
// Text(
|
||||
// labelsViewModel.labelSearchFilter.count > 0 ?
|
||||
// "Create: \"\(trimmedLabelName)\" label" :
|
||||
// LocalText.createLabelMessage
|
||||
// ).foregroundColor(.blue)
|
||||
// .font(Font.system(size: 14))
|
||||
// Spacer()
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
// .buttonStyle(PlainButtonStyle())
|
||||
// .padding(10)
|
||||
// }.background(Color.appButtonBackground)
|
||||
// // swiftlint:enable line_length
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding(viewState == .editingLabels ? 0 : 16)
|
||||
// .background(Color.extensionBackground)
|
||||
// .frame(maxWidth: .infinity, maxHeight: viewState == .editingLabels ? .infinity : 60)
|
||||
// .cornerRadius(8)
|
||||
// }
|
||||
|
||||
var highlightSection: some View {
|
||||
HStack {
|
||||
|
|
@ -249,52 +258,6 @@ public struct ShareExtensionView: View {
|
|||
.cornerRadius(8)
|
||||
}
|
||||
|
||||
func onLabelTap(label: LinkedItemLabel, textChip _: TextChip) {
|
||||
if labelsViewModel.selectedLabels.contains(label) {
|
||||
labelsViewModel.selectedLabels.remove(label)
|
||||
} else {
|
||||
labelsViewModel.selectedLabels.insert(label)
|
||||
}
|
||||
|
||||
if let linkedItem = viewModel.linkedItem {
|
||||
labelsViewModel.saveItemLabelChanges(itemID: linkedItem.unwrappedID, dataService: viewModel.services.dataService)
|
||||
}
|
||||
}
|
||||
|
||||
var primaryButtons: some View {
|
||||
HStack {
|
||||
Button(
|
||||
action: { viewModel.handleReadNowAction(extensionContext: extensionContext) },
|
||||
label: {
|
||||
Label("Read Now", systemImage: "book")
|
||||
.padding(16)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.background(Color.appButtonBackground)
|
||||
.frame(height: 52)
|
||||
.cornerRadius(8)
|
||||
|
||||
Spacer(minLength: 8)
|
||||
|
||||
Button(
|
||||
action: {
|
||||
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
|
||||
},
|
||||
label: {
|
||||
Label(LocalText.readLaterGeneric, systemImage: "text.book.closed.fill")
|
||||
.padding(16)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
)
|
||||
.foregroundColor(.black)
|
||||
.background(Color.appBackground)
|
||||
.frame(height: 52)
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
|
||||
var moreActionsMenu: some View {
|
||||
Menu {
|
||||
Button(action: {}, label: {
|
||||
|
|
@ -370,11 +333,21 @@ public struct ShareExtensionView: View {
|
|||
|
||||
var articleInfoBox: some View {
|
||||
HStack(alignment: .top, spacing: 15) {
|
||||
AsyncImage(url: self.viewModel.iconURL)
|
||||
.frame(width: 56, height: 56).overlay(
|
||||
RoundedRectangle(cornerRadius: 14)
|
||||
.stroke(.white, lineWidth: 1)
|
||||
).cornerRadius(14)
|
||||
AsyncImage(url: self.viewModel.iconURL) { phase in
|
||||
if let image = phase.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 56, height: 56)
|
||||
} else {
|
||||
Color.appButtonBackground
|
||||
.frame(width: 56, height: 56)
|
||||
}
|
||||
}
|
||||
.frame(width: 56, height: 56).overlay(
|
||||
RoundedRectangle(cornerRadius: 14)
|
||||
.stroke(.white, lineWidth: 1)
|
||||
).cornerRadius(14)
|
||||
VStack(alignment: .leading) {
|
||||
Text(self.viewModel.url ?? "")
|
||||
.font(Font.system(size: 12))
|
||||
|
|
@ -399,19 +372,31 @@ public struct ShareExtensionView: View {
|
|||
}
|
||||
}
|
||||
|
||||
var hasNoteText: Bool {
|
||||
!viewModel.noteText.isEmpty
|
||||
}
|
||||
|
||||
var noteBox: some View {
|
||||
Button(action: {
|
||||
NotificationCenter.default.post(name: Notification.Name("ExpandForm"), object: nil)
|
||||
// showAddNoteModal = true
|
||||
}, label: { Text("Add note...") })
|
||||
.foregroundColor(Color.extensionTextSubtle)
|
||||
NotificationCenter.default.post(name: Notification.Name("ShowAddNoteSheet"), object: nil)
|
||||
}, label: {
|
||||
Text(hasNoteText ? viewModel.noteText : "Add note...")
|
||||
.frame(height: 50, alignment: .top)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
})
|
||||
.foregroundColor(hasNoteText ?
|
||||
Color.appGrayTextContrast : Color.extensionTextSubtle
|
||||
)
|
||||
.font(Font.system(size: 13, weight: .semibold))
|
||||
.frame(height: 50, alignment: .top)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
var labelsBox: some View {
|
||||
Button(action: {}, label: {
|
||||
Button(action: {
|
||||
NotificationCenter.default.post(name: Notification.Name("ShowEditLabelsSheet"), object: nil)
|
||||
}, label: {
|
||||
Label {
|
||||
Text("Add Labels").font(Font.system(size: 12, weight: .medium)).tint(Color.white)
|
||||
} icon: {
|
||||
|
|
@ -546,7 +531,7 @@ public struct ShareExtensionView: View {
|
|||
.frame(height: 50)
|
||||
.background(Color.blue)
|
||||
.cornerRadius(24)
|
||||
.padding(15)
|
||||
.padding(.bottom, 15)
|
||||
}.frame(maxWidth: .infinity)
|
||||
}.padding(.horizontal, 15)
|
||||
.background(Color.extensionBackground)
|
||||
|
|
@ -554,128 +539,4 @@ public struct ShareExtensionView: View {
|
|||
viewModel.savePage(extensionContext: extensionContext)
|
||||
}
|
||||
}
|
||||
|
||||
public var oldbody: some View {
|
||||
VStack(alignment: .center) {
|
||||
Capsule()
|
||||
.fill(.gray)
|
||||
.frame(width: 60, height: 4)
|
||||
.padding(.top, 10)
|
||||
|
||||
if viewState == .mainView {
|
||||
titleBar
|
||||
.padding(.top, 10)
|
||||
.padding(.bottom, 12)
|
||||
} else {
|
||||
ZStack {
|
||||
Text(editingViewTitle).bold()
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
submitEditTitle()
|
||||
}
|
||||
}, label: { Text(LocalText.doneGeneric).bold() })
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
}
|
||||
.padding(8)
|
||||
.padding(.bottom, 4)
|
||||
}
|
||||
|
||||
if viewState == .mainView {
|
||||
titleBox
|
||||
}
|
||||
|
||||
if viewState == .editingTitle {
|
||||
ScrollView(showsIndicators: false) {
|
||||
VStack(alignment: .center, spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
TextEditor(text: $viewModel.title)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.lineSpacing(6)
|
||||
.submitLabel(.done)
|
||||
.accentColor(.appGraySolid)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.font(.appSubheadline)
|
||||
.padding(8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.strokeBorder(Color.appGrayBorder, lineWidth: 1)
|
||||
.background(RoundedRectangle(cornerRadius: 8).fill(Color.systemBackground))
|
||||
)
|
||||
.frame(height: 100)
|
||||
.focused($focusedField, equals: .titleEditor)
|
||||
.task {
|
||||
self.focusedField = .titleEditor
|
||||
}
|
||||
.onChange(of: viewModel.title) { text in
|
||||
if text.last?.isNewline == .some(true) {
|
||||
viewModel.title.removeLast()
|
||||
submitEditTitle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(8)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
if viewState != .editingTitle {
|
||||
if viewState != .viewingHighlight {
|
||||
labelsSection
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
previousLabels = Array(self.labelsViewModel.selectedLabels)
|
||||
viewState = .editingLabels
|
||||
}
|
||||
}
|
||||
}
|
||||
if viewState != .editingLabels {
|
||||
highlightSection
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
if viewModel.highlightData != nil {
|
||||
viewState = .viewingHighlight
|
||||
} else {
|
||||
showHighlightInstructionAlert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if viewState == .mainView {
|
||||
Divider()
|
||||
.padding(.bottom, 20)
|
||||
|
||||
primaryButtons
|
||||
|
||||
moreActionsMenu
|
||||
}
|
||||
}
|
||||
.frame(
|
||||
maxWidth: .infinity,
|
||||
maxHeight: .infinity,
|
||||
alignment: .topLeading
|
||||
)
|
||||
.padding(.horizontal, 16)
|
||||
.onAppear {
|
||||
viewModel.savePage(extensionContext: extensionContext)
|
||||
}
|
||||
.sheet(isPresented: $labelsViewModel.showCreateLabelModal) {
|
||||
CreateLabelView(viewModel: labelsViewModel, newLabelName: labelsViewModel.labelSearchFilter)
|
||||
}
|
||||
.alert("Before saving an article select text in Safari to create a highlight on save.",
|
||||
isPresented: $showHighlightInstructionAlert) {
|
||||
Button(LocalText.genericOk, role: .cancel) { showHighlightInstructionAlert = false }
|
||||
}
|
||||
.task {
|
||||
await labelsViewModel.loadLabelsFromStore(dataService: viewModel.services.dataService)
|
||||
}.environmentObject(viewModel.services.dataService)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import SwiftUI
|
|||
import Models
|
||||
import Views
|
||||
|
||||
@MainActor
|
||||
struct LabelsMasonaryView: View {
|
||||
var onLabelTap: (LinkedItemLabel, TextChip) -> Void
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Services
|
|||
import SwiftUI
|
||||
import Views
|
||||
|
||||
@MainActor final class LabelsViewModel: ObservableObject {
|
||||
@MainActor public final class LabelsViewModel: ObservableObject {
|
||||
let labelNameMaxLength = 64
|
||||
|
||||
@Published var isLoading = false
|
||||
|
|
@ -14,6 +14,8 @@ import Views
|
|||
@Published var showCreateLabelModal = false
|
||||
@Published var labelSearchFilter = ""
|
||||
|
||||
public init() {}
|
||||
|
||||
func setLabels(_ labels: [LinkedItemLabel]) {
|
||||
self.labels = labels.sorted { left, right in
|
||||
let aTrimmed = left.unwrappedName.trimmingCharacters(in: .whitespaces)
|
||||
|
|
|
|||
|
|
@ -48,23 +48,6 @@
|
|||
|
||||
child.didMove(toParent: self)
|
||||
}
|
||||
//
|
||||
// @objc func keyboardWillShow(notification: Notification) {
|
||||
// if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
|
||||
// if self.view.frame.origin.y == 0{
|
||||
// self.view.frame.origin.y -= keyboardSize.height
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @objc func keyboardWillHide(notification: Notification) {
|
||||
// if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
|
||||
// if self.view.frame.origin.y != 0 {
|
||||
// self.view.frame.origin.y += keyboardSize.height
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public struct SearchBar: View {
|
|||
|
||||
public var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
TextField("Search", text: $searchTerm)
|
||||
TextField("Add Labels", text: $searchTerm)
|
||||
.frame(height: 36)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.leading, 28)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import App
|
||||
import Services
|
||||
import SwiftUI
|
||||
import Utils
|
||||
import Views
|
||||
|
|
@ -6,32 +7,45 @@ import Views
|
|||
#if os(iOS)
|
||||
import UIKit
|
||||
|
||||
final class SheetViewController: UIViewController {}
|
||||
|
||||
@objc(ShareExtensionViewController)
|
||||
final class ShareExtensionViewController: UIViewController {
|
||||
let labelsViewModel = LabelsViewModel()
|
||||
let viewModel = ShareExtensionViewModel()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .clear
|
||||
|
||||
NotificationCenter.default.addObserver(forName: Notification.Name("ExpandForm"), object: nil, queue: OperationQueue.main) { _ in
|
||||
NotificationCenter.default.addObserver(
|
||||
forName: Notification.Name("ShowAddNoteSheet"),
|
||||
object: nil,
|
||||
queue: OperationQueue.main
|
||||
) { _ in
|
||||
self.openSheet(AnyView(AddNoteSheet(viewModel: self.viewModel)))
|
||||
}
|
||||
|
||||
self.openSheet()
|
||||
NotificationCenter.default.addObserver(
|
||||
forName: Notification.Name("ShowEditLabelsSheet"),
|
||||
object: nil,
|
||||
queue: OperationQueue.main
|
||||
) { _ in
|
||||
self.openSheet(AnyView(EditLabelsSheet(viewModel: self.viewModel, labelsViewModel: self.labelsViewModel)))
|
||||
}
|
||||
|
||||
embed(
|
||||
childViewController: UIViewController.makeShareExtensionController(extensionContext: extensionContext),
|
||||
childViewController: UIViewController.makeShareExtensionController(
|
||||
viewModel: viewModel,
|
||||
labelsViewModel: labelsViewModel,
|
||||
extensionContext: extensionContext
|
||||
),
|
||||
heightRatio: 0.60
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction func openSheet() {
|
||||
let hostingController = UIHostingController(rootView: AddNoteSheet())
|
||||
func openSheet(_ rootView: AnyView) {
|
||||
let hostingController = UIHostingController(rootView: rootView)
|
||||
|
||||
present(hostingController, animated: true, completion: nil)
|
||||
|
||||
// Present it w/o any adjustments so it uses the default sheet presentation.
|
||||
// present(sheetViewController., animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue