Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Canvas related logics #89

Merged
merged 16 commits into from
Dec 19, 2021
2 changes: 1 addition & 1 deletion PiecesOfPaper/Model/NotificationName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ import Foundation

public extension Notification.Name {
static let addedNewNote = Notification.Name("addedNewNote")
static let channgedTagToNote = Notification.Name("channgedTagToNote")
static let changedTagToNote = Notification.Name("changedTagToNote")
}
10 changes: 10 additions & 0 deletions PiecesOfPaper/Model/UserPreference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Foundation
struct UserPreference {
private let iCloudDisabledKey = "iCloud_disabled"
private let autoSaveDisabledKey = "autosave_disabled"
private let infiniteScrollKey = "infinite_scroll_disabled"

var enablediCloud: Bool {
get {
Expand All @@ -29,4 +30,13 @@ struct UserPreference {
UserDefaults.standard.set(!newValue, forKey: autoSaveDisabledKey)
}
}

var enabledInfiniteScroll: Bool {
get {
!UserDefaults.standard.bool(forKey: infiniteScrollKey)
}
set {
UserDefaults.standard.set(!newValue, forKey: infiniteScrollKey)
}
}
}
7 changes: 3 additions & 4 deletions PiecesOfPaper/PiecesOfPaperApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct PiecesOfPaperApp: App {
@State var isAppLaunch = true
@State var isShowCanvas = false
@State var isShowTagList = false
@State var noteDocument: NoteDocument?
@StateObject var canvasViewModel = CanvasViewModel()

var body: some Scene {
WindowGroup {
Expand All @@ -23,7 +23,7 @@ struct PiecesOfPaperApp: App {
}
.fullScreenCover(isPresented: $isShowCanvas) {
NavigationView {
Canvas(noteDocument: noteDocument)
Canvas(viewModel: canvasViewModel)
}
}
.sheet(isPresented: $isShowTagList, onDismiss: {
Expand All @@ -33,14 +33,13 @@ struct PiecesOfPaperApp: App {
}
.onAppear {
guard isAppLaunch else { return }
CanvasRouter.shared.bind(isShowCanvas: $isShowCanvas, noteDocument: $noteDocument)
CanvasRouter.shared.bind(isShowCanvas: $isShowCanvas, noteDocument: $canvasViewModel.document)
CanvasRouter.shared.openNewCanvas()
// I thought this can work, but SwiftUI cannot pass the document data...
TagListRouter.shared.bind(isShowTagList: $isShowTagList)
DrawingsPlistConverter.convert()
isAppLaunch = false
}
}
// }
}
}
10 changes: 7 additions & 3 deletions PiecesOfPaper/SideBarList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ import SwiftUI

struct SideBarList: View {
@Binding var isAppLaunch: Bool
@StateObject var inboxNoteViewModel = NotesViewModel(targetDirectory: .inbox)
@StateObject var allNoteViewModel = NotesViewModel(targetDirectory: .all)
@StateObject var archivedNoteViewModel = NotesViewModel(targetDirectory: .archived)

var body: some View {
List {
Section(header: Text("Folder")) {
NavigationLink(destination: Notes(targetDirectory: .inbox), isActive: $isAppLaunch) {
NavigationLink(destination: Notes(viewModel: inboxNoteViewModel),
isActive: $isAppLaunch) {
Label("Inbox", systemImage: "tray")
}
NavigationLink(destination: Notes(targetDirectory: .all)) {
NavigationLink(destination: Notes(viewModel: allNoteViewModel)) {
Label("All", systemImage: "note.text")
}
NavigationLink(destination: Notes(targetDirectory: .archived)) {
NavigationLink(destination: Notes(viewModel: archivedNoteViewModel)) {
Label("Archived", systemImage: "archivebox")
}
}
Expand Down
78 changes: 23 additions & 55 deletions PiecesOfPaper/View/Canvas/Canvas.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,17 @@ import StoreKit
import LinkPresentation

struct Canvas: View {
@ObservedObject var viewModel = CanvasViewModel()
@State private var canvasView = PKCanvasView()
@State var isShowActivityView = false {
didSet {
if isShowActivityView == true {
toolPicker.setVisible(false, forFirstResponder: canvasView)
}
}
}
@ObservedObject var viewModel: CanvasViewModel

@Environment(\.presentationMode) var presentationMode
@AppStorage("review_requested") var reviewRequested = false

var delegateBridge: CanvasDelegateBridgeObject
var toolPicker = PKToolPicker()
var activityViewController: UIActivityViewControllerWrapper {
let drawing = canvasView.drawing
var image = UIImage()
let trait = UITraitCollection(userInterfaceStyle: .light)
trait.performAsCurrent {
image = drawing.image(from: drawing.bounds, scale: UIScreen.main.scale)
}

return UIActivityViewControllerWrapper(activityItems: [image, delegateBridge])
}

var tap: some Gesture {
TapGesture(count: 1)
.onEnded { _ in
viewModel.hideExceptPaper.toggle()
toolPicker.addObserver(canvasView)
toolPicker.setVisible(!viewModel.hideExceptPaper, forFirstResponder: canvasView)
canvasView.becomeFirstResponder()
viewModel.setVisibleToolPicker(!viewModel.hideExceptPaper)
viewModel.canvasView.becomeFirstResponder()
}
}

Expand All @@ -55,26 +33,8 @@ struct Canvas: View {
}
var cancelButton: Alert.Button { .default(Text("Cancel")) }

init(noteDocument: NoteDocument?) {
delegateBridge = CanvasDelegateBridgeObject(toolPicker: toolPicker)
if let noteDocument = noteDocument {
viewModel.document = noteDocument
canvasView.drawing = noteDocument.entity.drawing
}

delegateBridge.canvas = self
canvasView.delegate = delegateBridge
addPencilInteraction()
}

private func addPencilInteraction() {
let pencilInteraction = UIPencilInteraction()
pencilInteraction.delegate = delegateBridge
canvasView.addInteraction(pencilInteraction)
}

var body: some View {
PKCanvasViewWrapper(canvasView: $canvasView)
PKCanvasViewWrapper(canvasView: $viewModel.canvasView)
.gesture(tap)
.navigationBarTitleDisplayMode(.inline)
.statusBar(hidden: viewModel.hideExceptPaper)
Expand All @@ -89,7 +49,7 @@ struct Canvas: View {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if viewModel.document != nil {
Button(action: {
toolPicker.setVisible(false, forFirstResponder: canvasView)
viewModel.setVisibleToolPicker(false)
viewModel.showTagList.toggle()
}) {
Image(systemName: "tag.circle")
Expand All @@ -101,49 +61,57 @@ struct Canvas: View {
.popover(isPresented: $viewModel.showDrawingInformation) {
NoteInformation(document: viewModel.document)
}
Button(action: { isShowActivityView.toggle() }) {
Button(action: { viewModel.isShowActivityView.toggle() }) {
Image(systemName: "square.and.arrow.up")
}
Button(action: close) {
Image(systemName: "tray.full")
}
}
}
.sheet(isPresented: $isShowActivityView,
onDismiss: { toolPicker.setVisible(true, forFirstResponder: canvasView) }) {
activityViewController
.sheet(isPresented: $viewModel.isShowActivityView,
onDismiss: { viewModel.setVisibleToolPicker(true) }) {
viewModel.activityViewController
}
.sheet(isPresented: $viewModel.showTagList) {
.sheet(isPresented: $viewModel.showTagList,
onDismiss: { viewModel.setVisibleToolPicker(true) }) {
TagListToNote(viewModel: TagListToNoteViewModel(noteDocument: viewModel.document))
}
.alert(isPresented: $viewModel.showUnsavedAlert) { () -> Alert in
Alert(title: Text("Are you sure you want to discard the changes you made?"),
primaryButton: discardButton,
secondaryButton: cancelButton)
}
.onAppear {
viewModel.hideExceptPaper = true
}
}

private func archive() {
if !UserPreference().enabledAutoSave {
guard !canvasView.drawing.strokes.isEmpty else {
guard !viewModel.canvasView.drawing.strokes.isEmpty else {
presentationMode.wrappedValue.dismiss()
return
}
toolPicker.setVisible(false, forFirstResponder: canvasView)
viewModel.setVisibleToolPicker(false)
viewModel.showUnsavedAlert.toggle()
return
}
viewModel.archive()
NotificationCenter.default.post(name: .addedNewNote, object: viewModel.document)
// do not send notification

presentationMode.wrappedValue.dismiss()
reviewRequest()
}

private func close() {
if !UserPreference().enabledAutoSave {
viewModel.save(drawing: canvasView.drawing)
viewModel.save(drawing: viewModel.canvasView.drawing)
}

if viewModel.hasSavedDocument {
NotificationCenter.default.post(name: .addedNewNote, object: viewModel.document)
}
NotificationCenter.default.post(name: .addedNewNote, object: viewModel.document)
presentationMode.wrappedValue.dismiss()
reviewRequest()
}
Expand Down
36 changes: 29 additions & 7 deletions PiecesOfPaper/View/Canvas/CanvasDelegateBridgeObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ import SwiftUI
import PencilKit
import LinkPresentation

protocol CanvasDelegateBridgeObjectDelegate: AnyObject {
var hideExceptPaper: Bool { get set }
func save(drawing: PKDrawing)
}

// MARK: - PKToolPickerObserver
/// This class conform some protocol, because SwiftUI Views cannot conform PencilKit delegates
class CanvasDelegateBridgeObject: NSObject, PKToolPickerObserver {
let toolPicker: PKToolPicker
final class CanvasDelegateBridgeObject: NSObject, PKToolPickerObserver {
let toolPicker = PKToolPicker()
private let defaultTool = PKInkingTool(.pen, color: .black, width: 1)
private var previousTool: PKTool!
private var currentTool: PKTool!
var canvas: Canvas!
weak var delegate: CanvasDelegateBridgeObjectDelegate?

init(toolPicker: PKToolPicker) {
self.toolPicker = toolPicker
override init() {
super.init()

toolPicker.addObserver(self)
toolPicker.selectedTool = defaultTool
previousTool = defaultTool
currentTool = defaultTool
toolPicker.showsDrawingPolicyControls = false
}

func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
Expand All @@ -44,7 +49,7 @@ extension CanvasDelegateBridgeObject: UIPencilInteractionDelegate {
switch action {
case .switchPrevious: switchPreviousTool()
case .switchEraser: switchEraser()
case .showColorPalette: canvas.viewModel.hideExceptPaper.toggle()
case .showColorPalette: delegate?.hideExceptPaper.toggle()
case .ignore: return
default: return
}
Expand All @@ -66,8 +71,25 @@ extension CanvasDelegateBridgeObject: UIPencilInteractionDelegate {
// MARK: - PKCanvasViewDelegate
extension CanvasDelegateBridgeObject: PKCanvasViewDelegate {
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
updateContentSizeIfNeeded(canvasView)

guard UserPreference().enabledAutoSave else { return }
canvas.viewModel.save(drawing: canvasView.drawing)
delegate?.save(drawing: canvasView.drawing)
}

private func updateContentSizeIfNeeded(_ canvasView: PKCanvasView) {
guard !canvasView.drawing.bounds.isNull,
UserPreference().enabledInfiniteScroll else { return }
let drawingWidth = canvasView.drawing.bounds.maxX
if canvasView.contentSize.width < drawingWidth * 2 {
canvasView.contentSize.width += canvasView.frame.width
}

let drawingHeight = canvasView.drawing.bounds.maxY
if canvasView.contentSize.height < drawingHeight * 2 {
canvasView.contentSize.height += canvasView.frame.height
}

}
}

Expand Down
2 changes: 1 addition & 1 deletion PiecesOfPaper/View/NoteList/NoteImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import SwiftUI

struct NoteImage: View {
var noteDocument: NoteDocument
@Binding var noteDocument: NoteDocument

var body: some View {
Button(action: { open(noteDocument: noteDocument) },
Expand Down
9 changes: 2 additions & 7 deletions PiecesOfPaper/View/NoteList/Notes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ struct Notes: View {
}
var cancelButton: Alert.Button { .default(Text("Cancel")) }

init(targetDirectory: NotesViewModel.TargetDirectory) {
self.viewModel = NotesViewModel(targetDirectory: targetDirectory)
}

var body: some View {
Group {
if !viewModel.isLoaded {
Expand All @@ -36,8 +32,7 @@ struct Notes: View {
Text("No Data")
.font(.largeTitle)
} else {
NotesScrollViewReader()
.environmentObject(viewModel)
NotesScrollViewReader(viewModel: viewModel)
}
}

Expand Down Expand Up @@ -74,6 +69,6 @@ struct Notes: View {

struct Notes_Previews: PreviewProvider {
static var previews: some View {
Notes(targetDirectory: .inbox)
Notes(viewModel: NotesViewModel(targetDirectory: .inbox))
}
}
Loading