From 3699f3d47ca6649d2f9885c982b68de7f571797d Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Wed, 26 Feb 2020 08:13:51 -0500 Subject: [PATCH 1/7] Updated project to Xcode 11.3.1 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 ReSwift-Todo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ReSwift-Todo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ReSwift-Todo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ReSwift-Todo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 31db7cd6ede597c20d877761597eada4676d3007 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Wed, 26 Feb 2020 15:49:42 -0500 Subject: [PATCH 2/7] Separated-out ToDoSerializer from ToDoListSerializer --- ReSwift-Todo.xcodeproj/project.pbxproj | 4 +++ ReSwift-Todo/ToDoListSerializer.swift | 27 +++---------------- ReSwift-Todo/ToDoSerializer.swift | 37 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 ReSwift-Todo/ToDoSerializer.swift diff --git a/ReSwift-Todo.xcodeproj/project.pbxproj b/ReSwift-Todo.xcodeproj/project.pbxproj index b4fc293..cffb363 100644 --- a/ReSwift-Todo.xcodeproj/project.pbxproj +++ b/ReSwift-Todo.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ 507347901D7FFE8B00ACFD0D /* StreamReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073478F1D7FFE8B00ACFD0D /* StreamReader.swift */; }; 507347921D7FFFBD00ACFD0D /* ErrorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507347911D7FFFBD00ACFD0D /* ErrorHelpers.swift */; }; 507347941D8001A200ACFD0D /* String+ReSwiftTodo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */; }; + 6972332C24070EDE00E91FBA /* ToDoSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -164,6 +165,7 @@ 5073478F1D7FFE8B00ACFD0D /* StreamReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamReader.swift; sourceTree = ""; }; 507347911D7FFFBD00ACFD0D /* ErrorHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorHelpers.swift; sourceTree = ""; }; 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "String+ReSwiftTodo.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToDoSerializer.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -408,6 +410,7 @@ 502C04841D8850D00032B7F3 /* ToDoLineTokenizer.swift */, 5073478F1D7FFE8B00ACFD0D /* StreamReader.swift */, 502C046E1D87D9580032B7F3 /* ToDoListSerializer.swift */, + 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */, ); name = Persistence; sourceTree = ""; @@ -561,6 +564,7 @@ 502C04851D8850D00032B7F3 /* ToDoLineTokenizer.swift in Sources */, 50703B0D1D7EAD09001DAF45 /* ToDoID.swift in Sources */, 504CDFE31D8A6F2D00D16314 /* UndoCommand.swift in Sources */, + 6972332C24070EDE00E91FBA /* ToDoSerializer.swift in Sources */, 50703B4E1D7F1407001DAF45 /* ToDoListImporter.swift in Sources */, 504CDFE11D8A6E7300D16314 /* NotUndoable.swift in Sources */, 504CDFF71D8ADB3D00D16314 /* ToDoTableView.swift in Sources */, diff --git a/ReSwift-Todo/ToDoListSerializer.swift b/ReSwift-Todo/ToDoListSerializer.swift index 4145252..02b85ac 100644 --- a/ReSwift-Todo/ToDoListSerializer.swift +++ b/ReSwift-Todo/ToDoListSerializer.swift @@ -34,8 +34,8 @@ enum SerializationError: Error { class ToDoListSerializer { init() { } - - lazy var dateConverter: DateConverter = DateConverter() + + lazy var toDoSerializer = ToDoSerializer() func data(toDoList: ToDoList, encoding: String.Encoding = String.Encoding.utf8) -> Data? { @@ -47,7 +47,7 @@ class ToDoListSerializer { guard !toDoList.isEmpty else { return "" } let title = toDoList.title.map { $0.appended(":") } ?? "" - let items = toDoList.items.map(itemRepresentation) + let items = toDoList.items.map(toDoSerializer.itemRepresentation) let lines = [title] .appendedContentsOf(items) @@ -55,27 +55,6 @@ class ToDoListSerializer { return lines.joined(separator: "\n").appended("\n") } - - fileprivate func itemRepresentation(_ item: ToDo) -> String { - - let body = "- \(item.title)" - let tags = item.tags.sorted().map { "@\($0)" } - let done: String? = { - switch item.completion { - case .unfinished: return nil - case .finished(when: let date): - guard let date = date else { return "@done" } - - let dateString = dateConverter.string(date: date) - return "@done(\(dateString))" - } - }() - - return [body] - .appendedContentsOf(tags) - .appendedContentsOf([done].compactMap(identity)) // remove nil - .joined(separator: " ") - } } func identity(_ value: T?) -> T? { diff --git a/ReSwift-Todo/ToDoSerializer.swift b/ReSwift-Todo/ToDoSerializer.swift new file mode 100644 index 0000000..d65b2e8 --- /dev/null +++ b/ReSwift-Todo/ToDoSerializer.swift @@ -0,0 +1,37 @@ +// +// ToDoSerializer.swift +// ReSwift-Todo +// +// Created by Jay Koutavas on 2/26/20. +// Copyright © 2020 ReSwift. All rights reserved. +// + +import Foundation + +class ToDoSerializer { + +init() { } + + lazy var dateConverter: DateConverter = DateConverter() + + func itemRepresentation(_ item: ToDo) -> String { + + let body = "- \(item.title)" + let tags = item.tags.sorted().map { "@\($0)" } + let done: String? = { + switch item.completion { + case .unfinished: return nil + case .finished(when: let date): + guard let date = date else { return "@done" } + + let dateString = dateConverter.string(date: date) + return "@done(\(dateString))" + } + }() + + return [body] + .appendedContentsOf(tags) + .appendedContentsOf([done].compactMap(identity)) // remove nil + .joined(separator: " ") + } +} From 4d6906b3c221ae4f59fae012f2d8cdf8048e20c9 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Wed, 26 Feb 2020 22:38:31 -0500 Subject: [PATCH 3/7] Implemented drag-n-drop task reordering --- ReSwift-Todo.xcodeproj/project.pbxproj | 8 ++++ ReSwift-Todo/ArrayUtil.swift | 29 ++++++++++++ ReSwift-Todo/ToDoList.swift | 6 +++ ReSwift-Todo/ToDoListActions.swift | 23 ++++++++++ ReSwift-Todo/ToDoListWindowController.swift | 9 ++++ ReSwift-Todo/ToDoPasteboardWriter.swift | 51 +++++++++++++++++++++ ReSwift-Todo/ToDoTableDataSource.swift | 48 +++++++++++++++++++ 7 files changed, 174 insertions(+) create mode 100644 ReSwift-Todo/ArrayUtil.swift create mode 100644 ReSwift-Todo/ToDoPasteboardWriter.swift diff --git a/ReSwift-Todo.xcodeproj/project.pbxproj b/ReSwift-Todo.xcodeproj/project.pbxproj index cffb363..0b90529 100644 --- a/ReSwift-Todo.xcodeproj/project.pbxproj +++ b/ReSwift-Todo.xcodeproj/project.pbxproj @@ -71,7 +71,9 @@ 507347901D7FFE8B00ACFD0D /* StreamReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5073478F1D7FFE8B00ACFD0D /* StreamReader.swift */; }; 507347921D7FFFBD00ACFD0D /* ErrorHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507347911D7FFFBD00ACFD0D /* ErrorHelpers.swift */; }; 507347941D8001A200ACFD0D /* String+ReSwiftTodo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */; }; + 6972332A240708A500E91FBA /* ToDoPasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697233282407084100E91FBA /* ToDoPasteboardWriter.swift */; }; 6972332C24070EDE00E91FBA /* ToDoSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */; }; + 6972332E2407679800E91FBA /* ArrayUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332D2407679800E91FBA /* ArrayUtil.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -165,7 +167,9 @@ 5073478F1D7FFE8B00ACFD0D /* StreamReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamReader.swift; sourceTree = ""; }; 507347911D7FFFBD00ACFD0D /* ErrorHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorHelpers.swift; sourceTree = ""; }; 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "String+ReSwiftTodo.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 697233282407084100E91FBA /* ToDoPasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ToDoPasteboardWriter.swift; path = "ReSwift-Todo/ToDoPasteboardWriter.swift"; sourceTree = SOURCE_ROOT; }; 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToDoSerializer.swift; sourceTree = ""; }; + 6972332D2407679800E91FBA /* ArrayUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayUtil.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -200,6 +204,7 @@ 502C04811D880C310032B7F3 /* Infrastructure */ = { isa = PBXGroup; children = ( + 6972332D2407679800E91FBA /* ArrayUtil.swift */, 504CDFE21D8A6F2D00D16314 /* UndoCommand.swift */, 502C047E1D880C150032B7F3 /* Time */, 50703B4C1D7F13DE001DAF45 /* Persistence */, @@ -352,6 +357,7 @@ 50703B311D7EB736001DAF45 /* ToDoListWindowController.swift */, 50703B441D7EF590001DAF45 /* ToDoTableDataSource.swift */, 50703B3A1D7EE569001DAF45 /* ToDoListViewModel.swift */, + 697233282407084100E91FBA /* ToDoPasteboardWriter.swift */, 504CDFFD1D8ADF3400D16314 /* KeyboardEventHandler.swift */, 50703B3C1D7EE581001DAF45 /* To-Do Item */, 504CDFFC1D8ADF2400D16314 /* Components */, @@ -558,6 +564,7 @@ 50703AE91D7EACB8001DAF45 /* ToDoDocument.swift in Sources */, 502C04801D880C2A0032B7F3 /* DateConverter.swift in Sources */, 50703B0A1D7EAD09001DAF45 /* ToDoList.swift in Sources */, + 6972332E2407679800E91FBA /* ArrayUtil.swift in Sources */, 507347901D7FFE8B00ACFD0D /* StreamReader.swift in Sources */, 50703B371D7EBC76001DAF45 /* ToDoCellView.swift in Sources */, 504CDFE71D8A721D00D16314 /* UndoActionContext.swift in Sources */, @@ -589,6 +596,7 @@ 504CDFEE1D8A8E1300D16314 /* SelectionState.swift in Sources */, 502C046F1D87D9580032B7F3 /* ToDoListSerializer.swift in Sources */, 50703B2C1D7EB2E7001DAF45 /* LoggingMiddleware.swift in Sources */, + 6972332A240708A500E91FBA /* ToDoPasteboardWriter.swift in Sources */, 50703B341D7EB838001DAF45 /* ToDoListPresenter.swift in Sources */, 50703B301D7EB60F001DAF45 /* ToDoListState.swift in Sources */, 502C04731D87DF040032B7F3 /* ErrorHandling.swift in Sources */, diff --git a/ReSwift-Todo/ArrayUtil.swift b/ReSwift-Todo/ArrayUtil.swift new file mode 100644 index 0000000..7172bfd --- /dev/null +++ b/ReSwift-Todo/ArrayUtil.swift @@ -0,0 +1,29 @@ +// +// ArrayUtil.swift +// ReSwift-Todo +// +// Created by Jay Koutavas on 2/26/20. +// Copyright © 2020 ReSwift. All rights reserved. +// + +import Foundation + +extension Array { + // These functions from sooop on GitHub + // https://gist.github.com/sooop/3c964900d429516ba48bd75050d0de0a + mutating func move(from start: Index, to end: Index) { + guard (0.. Int? { return items.firstIndex(where: { $0.toDoID == toDoID }) diff --git a/ReSwift-Todo/ToDoListActions.swift b/ReSwift-Todo/ToDoListActions.swift index 7e916c9..4e4017f 100644 --- a/ReSwift-Todo/ToDoListActions.swift +++ b/ReSwift-Todo/ToDoListActions.swift @@ -104,3 +104,26 @@ struct RemoveTaskAction: UndoableAction, ToDoListAction { return InsertTaskAction(toDo: removingToDo.toDo, index: removingToDo.index) } } + +struct MoveTaskAction: UndoableAction, ToDoListAction { + let from: IndexSet + let to: Int + + init(from: IndexSet, to: Int) { + self.from = from + self.to = to + } + + func apply(oldToDoList: ToDoList) -> ToDoList { + var result = oldToDoList + result.moveItems(from: from, to: to) + return result + } + + var name: String { return "Move Task" } + var isUndoable: Bool { return true } + + func inverse(context: UndoActionContext) -> UndoableAction? { + return nil + } +} diff --git a/ReSwift-Todo/ToDoListWindowController.swift b/ReSwift-Todo/ToDoListWindowController.swift index cbff497..e9de371 100644 --- a/ReSwift-Todo/ToDoListWindowController.swift +++ b/ReSwift-Todo/ToDoListWindowController.swift @@ -23,6 +23,7 @@ protocol ToDoTableDataSourceType { var toDoCount: Int { get } func updateContents(toDoListViewModel viewModel: ToDoListViewModel) + func setStore(toDoListStore: ToDoListStore?) func toDoCellView(tableView: NSTableView, row: Int, owner: AnyObject) -> ToDoCellView? } @@ -64,6 +65,7 @@ class ToDoListWindowController: NSWindowController { didSet { keyboardEventHandler?.store = store + dataSource.setStore(toDoListStore: store) } } @@ -86,6 +88,7 @@ class ToDoListWindowController: NSWindowController { tableView.dataSource = self.dataSource.tableDataSource tableView.delegate = self + tableView.registerForDraggedTypes([.todo, .tableViewIndex]) keyboardEventHandler?.dataSource = self.dataSource keyboardEventHandler?.store = self.store @@ -193,6 +196,12 @@ extension ToDoListWindowController: NSTableViewDelegate { dispatchAction(action) } + + // Due to a bug with NSTableView, this method has to be implemented to get + // the draggingDestinationFeedbackStyle.gap animation to look right. + func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { + return 30 + } } extension ToDoListWindowController: ToDoItemChangeDelegate { diff --git a/ReSwift-Todo/ToDoPasteboardWriter.swift b/ReSwift-Todo/ToDoPasteboardWriter.swift new file mode 100644 index 0000000..428e3d2 --- /dev/null +++ b/ReSwift-Todo/ToDoPasteboardWriter.swift @@ -0,0 +1,51 @@ +// +// ToDoPasteboardWriter.swift +// ReSwift-TodoTests +// +// Created by Jay Koutavas on 2/26/20. +// Copyright © 2020 ReSwift. All rights reserved. +// + +import Cocoa + +class ToDoPasteboardWriter: NSObject, NSPasteboardWriting { + var todoViewModel: ToDoViewModel + var index: Int + lazy var toDoSerializer = ToDoSerializer() + + init(todoViewModel: ToDoViewModel, at index: Int) { + self.todoViewModel = todoViewModel + self.index = index + } + + func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] { + return [.todo, .tableViewIndex] + } + + func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? { + switch type { + case .todo: + return todoViewModel.title + case .tableViewIndex: + return index + default: + return nil + } + } +} + +extension NSPasteboard.PasteboardType { + static let todo = NSPasteboard.PasteboardType("com.heynow.todo") + static let tableViewIndex = NSPasteboard.PasteboardType("com.heynow.tableViewIndex") +} + +extension NSPasteboardItem { + open func integer(forType type: NSPasteboard.PasteboardType) -> Int? { + guard let data = data(forType: type) else { return nil } + let plist = try? PropertyListSerialization.propertyList( + from: data, + options: .mutableContainers, + format: nil) + return plist as? Int + } +} diff --git a/ReSwift-Todo/ToDoTableDataSource.swift b/ReSwift-Todo/ToDoTableDataSource.swift index 93eb006..3ddcb9c 100644 --- a/ReSwift-Todo/ToDoTableDataSource.swift +++ b/ReSwift-Todo/ToDoTableDataSource.swift @@ -11,6 +11,12 @@ import Cocoa class ToDoTableDataSource: NSObject { var viewModel: ToDoListViewModel? + var store: ToDoListStore? + + fileprivate func dispatchAction(_ action: Action) { + + store?.dispatch(action) + } } extension ToDoTableDataSource: NSTableViewDataSource { @@ -19,6 +25,44 @@ extension ToDoTableDataSource: NSTableViewDataSource { return viewModel?.itemCount ?? 0 } + + func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? + { + guard let viewModel = viewModel?.items[safe: row] + else { return nil } + + return ToDoPasteboardWriter(todoViewModel: viewModel, at: row) + } + + func tableView( _ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, + proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation + { + guard dropOperation == .above else { return [] } + + if let source = info.draggingSource as? NSTableView, source === tableView + { + tableView.draggingDestinationFeedbackStyle = .gap + } else { + tableView.draggingDestinationFeedbackStyle = .regular + } + return .move + } + + func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, + dropOperation: NSTableView.DropOperation) -> Bool + { + guard let items = info.draggingPasteboard.pasteboardItems + else { return false } + + let indexes = items.compactMap{ $0.integer(forType: .tableViewIndex) } + if !indexes.isEmpty { + dispatchAction(MoveTaskAction(from: IndexSet(indexes), to: row)) + return true + } + + return true + } + } extension ToDoTableDataSource: ToDoTableDataSourceType { @@ -27,6 +71,10 @@ extension ToDoTableDataSource: ToDoTableDataSourceType { var selectedToDo: ToDoViewModel? { return viewModel?.selectedToDo } var toDoCount: Int { return viewModel?.itemCount ?? 0 } + func setStore(toDoListStore: ToDoListStore?) { + store = toDoListStore + } + func updateContents(toDoListViewModel viewModel: ToDoListViewModel) { self.viewModel = viewModel From 3b6f31609f91b51a705a593737dfaed2d1771b57 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Wed, 26 Feb 2020 22:52:50 -0500 Subject: [PATCH 4/7] Updated ToDoTableDataSourceType unit test --- ReSwift-TodoTests/NullToDoTableDataSource.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ReSwift-TodoTests/NullToDoTableDataSource.swift b/ReSwift-TodoTests/NullToDoTableDataSource.swift index 4cf8a89..c1588da 100644 --- a/ReSwift-TodoTests/NullToDoTableDataSource.swift +++ b/ReSwift-TodoTests/NullToDoTableDataSource.swift @@ -10,7 +10,9 @@ import Cocoa @testable import ReSwiftTodo class NullToDoTableDataSource: ToDoTableDataSourceType { - + func setStore(toDoListStore: ToDoListStore?) { + } + var tableDataSource: NSTableViewDataSource { return NullTableViewDataSource() } var selectedRow: Int? { return nil } From 2a11bd8c2d72214e593c5925bf48bdf5630842e2 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Sat, 29 Feb 2020 23:32:44 -0500 Subject: [PATCH 5/7] Implemented inverse for MoveTaskAction --- ReSwift-Todo/ToDoList.swift | 2 +- ReSwift-Todo/ToDoListActions.swift | 12 +++++++++--- ReSwift-Todo/ToDoTableDataSource.swift | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ReSwift-Todo/ToDoList.swift b/ReSwift-Todo/ToDoList.swift index 2a67a4b..e64a0f7 100644 --- a/ReSwift-Todo/ToDoList.swift +++ b/ReSwift-Todo/ToDoList.swift @@ -41,7 +41,7 @@ struct ToDoList { } } - mutating func moveItems(from: IndexSet, to: Int) { + mutating func moveItems(from: Int, to: Int) { items.move(from: from, to: to) } diff --git a/ReSwift-Todo/ToDoListActions.swift b/ReSwift-Todo/ToDoListActions.swift index 4e4017f..11d4047 100644 --- a/ReSwift-Todo/ToDoListActions.swift +++ b/ReSwift-Todo/ToDoListActions.swift @@ -106,15 +106,16 @@ struct RemoveTaskAction: UndoableAction, ToDoListAction { } struct MoveTaskAction: UndoableAction, ToDoListAction { - let from: IndexSet + let from: Int let to: Int - init(from: IndexSet, to: Int) { + init(from: Int, to: Int) { self.from = from self.to = to } func apply(oldToDoList: ToDoList) -> ToDoList { + var result = oldToDoList result.moveItems(from: from, to: to) return result @@ -124,6 +125,11 @@ struct MoveTaskAction: UndoableAction, ToDoListAction { var isUndoable: Bool { return true } func inverse(context: UndoActionContext) -> UndoableAction? { - return nil + + let movedDown = self.to > self.from + let inversedFrom = movedDown ? self.to-1 : self.to + let inversedTo = movedDown ? self.from : self.from+1 + + return MoveTaskAction(from: inversedFrom, to: inversedTo) } } diff --git a/ReSwift-Todo/ToDoTableDataSource.swift b/ReSwift-Todo/ToDoTableDataSource.swift index 3ddcb9c..d05c470 100644 --- a/ReSwift-Todo/ToDoTableDataSource.swift +++ b/ReSwift-Todo/ToDoTableDataSource.swift @@ -56,13 +56,13 @@ extension ToDoTableDataSource: NSTableViewDataSource { let indexes = items.compactMap{ $0.integer(forType: .tableViewIndex) } if !indexes.isEmpty { - dispatchAction(MoveTaskAction(from: IndexSet(indexes), to: row)) + dispatchAction( + MoveTaskAction(from: indexes[0], to: row)) return true } return true } - } extension ToDoTableDataSource: ToDoTableDataSourceType { From b8e6e0c01c107a18bb4f94d9de7b66014e66b768 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Sun, 1 Mar 2020 11:40:41 -0500 Subject: [PATCH 6/7] Removed unused reference --- ReSwift-Todo/ToDoPasteboardWriter.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/ReSwift-Todo/ToDoPasteboardWriter.swift b/ReSwift-Todo/ToDoPasteboardWriter.swift index 428e3d2..ae1abf7 100644 --- a/ReSwift-Todo/ToDoPasteboardWriter.swift +++ b/ReSwift-Todo/ToDoPasteboardWriter.swift @@ -11,7 +11,6 @@ import Cocoa class ToDoPasteboardWriter: NSObject, NSPasteboardWriting { var todoViewModel: ToDoViewModel var index: Int - lazy var toDoSerializer = ToDoSerializer() init(todoViewModel: ToDoViewModel, at index: Int) { self.todoViewModel = todoViewModel From 6f28677e4b72a64429757388ddd3b7edbd51add8 Mon Sep 17 00:00:00 2001 From: Jay Koutavas Date: Sun, 1 Mar 2020 13:17:02 -0500 Subject: [PATCH 7/7] Renamed "ArrayUtil.swift" to "Array+ReSwiftTodo.swift" in keeping with this project's extension file naming convention --- ReSwift-Todo.xcodeproj/project.pbxproj | 8 ++++---- ReSwift-Todo/{ArrayUtil.swift => Array+ReSwiftTodo.swift} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename ReSwift-Todo/{ArrayUtil.swift => Array+ReSwiftTodo.swift} (96%) diff --git a/ReSwift-Todo.xcodeproj/project.pbxproj b/ReSwift-Todo.xcodeproj/project.pbxproj index 0b90529..3e68f9c 100644 --- a/ReSwift-Todo.xcodeproj/project.pbxproj +++ b/ReSwift-Todo.xcodeproj/project.pbxproj @@ -73,7 +73,7 @@ 507347941D8001A200ACFD0D /* String+ReSwiftTodo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */; }; 6972332A240708A500E91FBA /* ToDoPasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697233282407084100E91FBA /* ToDoPasteboardWriter.swift */; }; 6972332C24070EDE00E91FBA /* ToDoSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */; }; - 6972332E2407679800E91FBA /* ArrayUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332D2407679800E91FBA /* ArrayUtil.swift */; }; + 6972332E2407679800E91FBA /* Array+ReSwiftTodo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6972332D2407679800E91FBA /* Array+ReSwiftTodo.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -169,7 +169,7 @@ 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = "String+ReSwiftTodo.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 697233282407084100E91FBA /* ToDoPasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ToDoPasteboardWriter.swift; path = "ReSwift-Todo/ToDoPasteboardWriter.swift"; sourceTree = SOURCE_ROOT; }; 6972332B24070EDE00E91FBA /* ToDoSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToDoSerializer.swift; sourceTree = ""; }; - 6972332D2407679800E91FBA /* ArrayUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayUtil.swift; sourceTree = ""; }; + 6972332D2407679800E91FBA /* Array+ReSwiftTodo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+ReSwiftTodo.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -204,7 +204,6 @@ 502C04811D880C310032B7F3 /* Infrastructure */ = { isa = PBXGroup; children = ( - 6972332D2407679800E91FBA /* ArrayUtil.swift */, 504CDFE21D8A6F2D00D16314 /* UndoCommand.swift */, 502C047E1D880C150032B7F3 /* Time */, 50703B4C1D7F13DE001DAF45 /* Persistence */, @@ -215,6 +214,7 @@ 504CDFDD1D8A6DA800D16314 /* Util */ = { isa = PBXGroup; children = ( + 6972332D2407679800E91FBA /* Array+ReSwiftTodo.swift */, 50703B461D7EF83D001DAF45 /* CollectionType+ReSwiftTodo.swift */, 507347931D8001A200ACFD0D /* String+ReSwiftTodo.swift */, ); @@ -564,7 +564,7 @@ 50703AE91D7EACB8001DAF45 /* ToDoDocument.swift in Sources */, 502C04801D880C2A0032B7F3 /* DateConverter.swift in Sources */, 50703B0A1D7EAD09001DAF45 /* ToDoList.swift in Sources */, - 6972332E2407679800E91FBA /* ArrayUtil.swift in Sources */, + 6972332E2407679800E91FBA /* Array+ReSwiftTodo.swift in Sources */, 507347901D7FFE8B00ACFD0D /* StreamReader.swift in Sources */, 50703B371D7EBC76001DAF45 /* ToDoCellView.swift in Sources */, 504CDFE71D8A721D00D16314 /* UndoActionContext.swift in Sources */, diff --git a/ReSwift-Todo/ArrayUtil.swift b/ReSwift-Todo/Array+ReSwiftTodo.swift similarity index 96% rename from ReSwift-Todo/ArrayUtil.swift rename to ReSwift-Todo/Array+ReSwiftTodo.swift index 7172bfd..f54f5df 100644 --- a/ReSwift-Todo/ArrayUtil.swift +++ b/ReSwift-Todo/Array+ReSwiftTodo.swift @@ -1,5 +1,5 @@ // -// ArrayUtil.swift +// Array+ReSwiftTodo.swift // ReSwift-Todo // // Created by Jay Koutavas on 2/26/20.