From fa38f4d025032cd87f45381b2564e9fa29b1cbad Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Fri, 14 Apr 2017 13:58:23 -0400 Subject: [PATCH 01/48] podspec --- Dwifft.podspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index ea12ce4..4a1a1c6 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.5' + s.version = '0.6' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' s.social_media_url = 'http://twitter.com/jflinter' - s.author = "Jack Flintermann" - s.source = { :git => 'https://github.com/jflinter/Dwifft.git', :tag => s.version } + s.author = 'Jack Flintermann' + s.source = { git: 'https://github.com/jflinter/Dwifft.git', tag: s.version } s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' From 8ae1e8f800194804c2636a04ec4ff6224e743b90 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Mon, 17 Apr 2017 12:34:27 -0400 Subject: [PATCH 02/48] update scheme --- Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme index 6f78b41..d35c757 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme @@ -22,10 +22,10 @@ </BuildActionEntry> <BuildActionEntry buildForTesting = "YES" - buildForRunning = "YES" + buildForRunning = "NO" buildForProfiling = "NO" buildForArchiving = "NO" - buildForAnalyzing = "YES"> + buildForAnalyzing = "NO"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "041EBB9C1B89679200E113B3" From d3fa85aedf15e3a10593d11c93771c5657324289 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Mon, 17 Apr 2017 14:44:38 -0400 Subject: [PATCH 03/48] podspec --- Dwifft.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index 4a1a1c6..1faf1b3 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.6' + s.version = '0.6.1' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' From 7f98e3e31e60bce3368c88386cf08b6cae3c47e6 Mon Sep 17 00:00:00 2001 From: Maximus <mxmccann@gmail.com> Date: Mon, 17 Apr 2017 17:02:07 -0500 Subject: [PATCH 04/48] Set SingleSectionTableViewDiffCalculator animations. --- Dwifft/Dwifft+UIKit.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 88fb54a..1af4cb6 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -181,7 +181,17 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { /// You can change insertion/deletion animations like this! Fade works well. /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. - public var insertionAnimation = UITableViewRowAnimation.automatic, deletionAnimation = UITableViewRowAnimation.automatic + public var insertionAnimation = UITableViewRowAnimation.automatic { + didSet { + self.internalDiffCalculator.insertionAnimation = self.insertionAnimation + } + } + + public var deletionAnimation = UITableViewRowAnimation.automatic { + didSet { + self.internalDiffCalculator.deletionAnimation = self.deletionAnimation + } + } /// Set this variable to automatically trigger the correct row insertion/deletions /// on your table view. From bda2e83bda52f804a0afc021fe01b46fdd54aae9 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Thu, 20 Apr 2017 10:59:09 -0700 Subject: [PATCH 05/48] 0.6.2 --- Dwifft.podspec | 2 +- Dwifft/Dwifft+UIKit.swift | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index 1faf1b3..612c9cb 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.6.1' + s.version = '0.6.2' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 1af4cb6..018f016 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -10,7 +10,9 @@ import UIKit -internal class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { + +/// A parent class for all diff calculators. Don't use it directly. +public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { fileprivate init(initialSectionedValues: SectionedValues<Section, Value>) { self._sectionedValues = initialSectionedValues From 5c0095a25921dc9971691c6fa27ca24cc2297f82 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Thu, 4 May 2017 00:58:10 -0400 Subject: [PATCH 06/48] package.swift --- .gitignore | 1 + Package.swift | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 Package.swift diff --git a/.gitignore b/.gitignore index 6749b45..039109e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ ### Swift ### ## Build generated +.build/ build/ DerivedData diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..d0d14aa --- /dev/null +++ b/Package.swift @@ -0,0 +1,14 @@ +import PackageDescription + +let package = Package( + name: "Dwifft", + dependencies : [], + exclude: [ + "Carthage", + "DwifftTests", + "DwifftExample", + "docs", + "Dwifft.xcworkspace", + "scripts", + ] +) From e3e8bf0d2355a23dc0f1af3a0b6465efcb3b6488 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Thu, 4 May 2017 01:14:15 -0400 Subject: [PATCH 07/48] remove unnecessary state update --- Dwifft/Dwifft+UIKit.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 018f016..3498ec3 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -142,7 +142,6 @@ public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equat override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { guard let collectionView = self.collectionView else { return } - self._sectionedValues = newState collectionView.performBatchUpdates({ self._sectionedValues = newState for result in diff { From 92b47cbf134aa2eb47ab932f306dbee3e69f2312 Mon Sep 17 00:00:00 2001 From: Jan Gorman <gorman.jan@gmail.com> Date: Mon, 19 Jun 2017 16:46:56 +0200 Subject: [PATCH 08/48] UIKit extension and travis build matrix --- .travis.yml | 32 ++++++++++++++++++++++++++++---- Dwifft/Dwifft+UIKit.swift | 2 +- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 881e2bd..42a33da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,31 @@ -osx_image: xcode8 -language: objective-c -before_script: carthage bootstrap --platform ios --configuration Debug -script: set -o pipefail && xcodebuild clean build build-for-testing -project Dwifft.xcodeproj -scheme Dwifft -sdk iphonesimulator10.0 -destination 'platform=iOS Simulator,name=iPhone 7' | xcpretty -c && xcodebuild test-without-building -project Dwifft.xcodeproj -scheme Dwifft -sdk iphonesimulator10.0 -destination 'platform=iOS Simulator,name=iPhone 7' | xcpretty -c +matrix: + include: + - os: osx + language: objective-c + osx_image: xcode8 + env: + - PLATFORM=iOS NAME='iPhone 7' + before_install: + export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }"); + before_script: + carthage bootstrap --platform $PLATFORM --configuration Debug + script: + - set -o pipefail; + open -a "simulator" --args -CurrentDeviceUDID "$UUID" + xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty; + - os: osx + language: objective-c + osx_image: xcode8 + env: + - PLATFORM=tvOS NAME='Apple TV 1080p' + before_install: + export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }"); + before_script: + carthage bootstrap --platform $PLATFORM --configuration Debug + script: + - set -o pipefail; + open -a "simulator" --args -CurrentDeviceUDID "$UUID" + xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty; env: global: secure: pUV8Ccwq1FWO8PxTHPQ3qZDUDhjNOisNVRyrziYR8x0ZQYjmVmnaLKaOHFP8co6rhBlFqReKUjoFYgRqP5QK1EkD6lqSZfnkrWqnZuLDNy0sn3/+4sLtvqAhBroAfjmmvb5GpY+Kkqfz8Lhdu6+1Z/a5xPhqNeDO3aDpa2vdBztb2qLIZnf2g8NFLOoNuR+ula868nIm858LCN1sqLp9PhV4CGaMsFx7ZFaX1yEQbwNb8+85+U2HIHqjZ62u9KZ4lA1d58VVDGj2f7ObKkC+pjiuknljy5bvRVvg5pttXggJracFgMqouwwQFFCV3nFYSDS6h7ZIjUvbyMrqBN+u32RmtqVLp1by1JvRXSeemJ3HxtZGLbq7rff4zWXyYbelT6sR6J1tWIubRo5v3sXc8E1kurqKkcPqJdG4jqiUXOau2oSHhf7WCRwa0KNfvaQuMhm0Onnsi9tW2MzGieumscfuFIJsXJdXnac7jQUVb571GfxMrDeJ9v2GOPcbnlM8cttBFAw4IoINV6teKITUW6T8RpeDXzfQyxDDQaV0M1ZTab1Tj/f4EYDAXKfZ+QquWK3bgXJhxKghXIskZLdDhYMyP55T6QxLZY9wD2CxLrEbEhDQCEb+7R2LmIC95Rlku+W92b8eWAqNxf+vV7QRqBb/sV9w2mlxmmezYTP5VAs= diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 3498ec3..8e29769 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 jflinter. All rights reserved. // -#if os(iOS) +#if os(iOS) || os(tvOS) import UIKit From 6d79ad226bcb30bfd71c379f73dc9513267bd834 Mon Sep 17 00:00:00 2001 From: Jan Gorman <gorman.jan@gmail.com> Date: Thu, 22 Jun 2017 09:02:15 +0200 Subject: [PATCH 09/48] Add tvOS target --- Dwifft-tvOS/Dwifft_tvOS.h | 18 +++ Dwifft-tvOS/Info.plist | 24 +++ Dwifft.xcodeproj/project.pbxproj | 146 ++++++++++++++++++ .../xcschemes/Dwifft-tvOS.xcscheme | 80 ++++++++++ 4 files changed, 268 insertions(+) create mode 100644 Dwifft-tvOS/Dwifft_tvOS.h create mode 100644 Dwifft-tvOS/Info.plist create mode 100644 Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme diff --git a/Dwifft-tvOS/Dwifft_tvOS.h b/Dwifft-tvOS/Dwifft_tvOS.h new file mode 100644 index 0000000..026736d --- /dev/null +++ b/Dwifft-tvOS/Dwifft_tvOS.h @@ -0,0 +1,18 @@ +// +// Dwifft_tvOS.h +// Dwifft-tvOS +// +// Copyright © 2017 jflinter. All rights reserved. +// + +#import <UIKit/UIKit.h> + +//! Project version number for Dwifft_tvOS. +FOUNDATION_EXPORT double Dwifft_tvOSVersionNumber; + +//! Project version string for Dwifft_tvOS. +FOUNDATION_EXPORT const unsigned char Dwifft_tvOSVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import <Dwifft_tvOS/PublicHeader.h> + + diff --git a/Dwifft-tvOS/Info.plist b/Dwifft-tvOS/Info.plist new file mode 100644 index 0000000..1007fd9 --- /dev/null +++ b/Dwifft-tvOS/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>$(CURRENT_PROJECT_VERSION)</string> + <key>NSPrincipalClass</key> + <string></string> +</dict> +</plist> diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 0fdec96..ce6961d 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ 0486A2651EA0A5B600D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 0486A2661EA0A64900D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 04AC329F1E88AEB000EF63DD /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */; }; + 94783CB11EFBA21900841579 /* Dwifft_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 94783CB51EFBA25300841579 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; + 94783CB61EFBA25300841579 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; + 94783CB71EFBA25300841579 /* Dwifft+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,6 +44,9 @@ 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dwifft+UIKit.swift"; sourceTree = "<group>"; }; 0486A2641EA0A5B600D8093E /* SectionedValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedValues.swift; sourceTree = "<group>"; }; 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/iOS/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; + 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_tvOS.h; sourceTree = "<group>"; }; + 94783CB01EFBA21900841579 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,6 +66,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94783CA91EFBA21900841579 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -67,6 +81,7 @@ children = ( 041EBB941B89679200E113B3 /* Dwifft */, 041EBBA11B89679200E113B3 /* DwifftTests */, + 94783CAE1EFBA21900841579 /* Dwifft-tvOS */, 041EBB931B89679200E113B3 /* Products */, ); sourceTree = "<group>"; @@ -76,6 +91,7 @@ children = ( 041EBB921B89679200E113B3 /* Dwifft.framework */, 041EBB9D1B89679200E113B3 /* DwifftTests.xctest */, + 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */, ); name = Products; sourceTree = "<group>"; @@ -118,6 +134,15 @@ name = "Supporting Files"; sourceTree = "<group>"; }; + 94783CAE1EFBA21900841579 /* Dwifft-tvOS */ = { + isa = PBXGroup; + children = ( + 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */, + 94783CB01EFBA21900841579 /* Info.plist */, + ); + path = "Dwifft-tvOS"; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -129,6 +154,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94783CAA1EFBA21900841579 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 94783CB11EFBA21900841579 /* Dwifft_tvOS.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -169,6 +202,24 @@ productReference = 041EBB9D1B89679200E113B3 /* DwifftTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 94783CAC1EFBA21900841579 /* Dwifft-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */; + buildPhases = ( + 94783CA81EFBA21900841579 /* Sources */, + 94783CA91EFBA21900841579 /* Frameworks */, + 94783CAA1EFBA21900841579 /* Headers */, + 94783CAB1EFBA21900841579 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Dwifft-tvOS"; + productName = "Dwifft-tvOS"; + productReference = 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -188,6 +239,9 @@ CreatedOnToolsVersion = 6.4; LastSwiftMigration = 0800; }; + 94783CAC1EFBA21900841579 = { + CreatedOnToolsVersion = 9.0; + }; }; }; buildConfigurationList = 041EBB8C1B89679200E113B3 /* Build configuration list for PBXProject "Dwifft" */; @@ -204,6 +258,7 @@ targets = ( 041EBB911B89679200E113B3 /* Dwifft */, 041EBB9C1B89679200E113B3 /* DwifftTests */, + 94783CAC1EFBA21900841579 /* Dwifft-tvOS */, ); }; /* End PBXProject section */ @@ -223,6 +278,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94783CAB1EFBA21900841579 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -264,6 +326,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 94783CA81EFBA21900841579 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 94783CB71EFBA25300841579 /* Dwifft+UIKit.swift in Sources */, + 94783CB61EFBA25300841579 /* SectionedValues.swift in Sources */, + 94783CB51EFBA25300841579 /* Dwifft.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -443,6 +515,71 @@ }; name = Release; }; + 94783CB21EFBA21900841579 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Dwifft-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + }; + name = Debug; + }; + 94783CB31EFBA21900841579 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Dwifft-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -473,6 +610,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 94783CB21EFBA21900841579 /* Debug */, + 94783CB31EFBA21900841579 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 041EBB891B89679200E113B3 /* Project object */; diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme new file mode 100644 index 0000000..7468b85 --- /dev/null +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0900" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "94783CAC1EFBA21900841579" + BuildableName = "Dwifft_tvOS.framework" + BlueprintName = "Dwifft-tvOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "94783CAC1EFBA21900841579" + BuildableName = "Dwifft_tvOS.framework" + BlueprintName = "Dwifft-tvOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "94783CAC1EFBA21900841579" + BuildableName = "Dwifft_tvOS.framework" + BlueprintName = "Dwifft-tvOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> From aaa28dd45562b8bf4cfdfc76d963527136c90c3e Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Fri, 23 Jun 2017 13:24:02 -0400 Subject: [PATCH 10/48] 0.6.3 --- Dwifft.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index 612c9cb..b97fc43 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.6.2' + s.version = '0.6.3' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' From 7f18ec1d0c3783ebc9341c6043e9b87191927471 Mon Sep 17 00:00:00 2001 From: Jesse Squires <jessesquires@users.noreply.github.com> Date: Thu, 27 Jul 2017 10:24:09 -0700 Subject: [PATCH 11/48] Make `Dwifft` an enum, not a struct. Close #67 --- Dwifft/Dwifft.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft/Dwifft.swift b/Dwifft/Dwifft.swift index 865a989..fbccb64 100644 --- a/Dwifft/Dwifft.swift +++ b/Dwifft/Dwifft.swift @@ -76,7 +76,7 @@ public enum SectionedDiffStep<Section, Value>: CustomDebugStringConvertible { } /// Namespace for the `diff` and `apply` functions. -public struct Dwifft { +public enum Dwifft { /// Returns the sequence of `DiffStep`s required to transform one array into another. /// From 3ce020739d7b895bf0a5ce79162ebf1a0f6df399 Mon Sep 17 00:00:00 2001 From: Bryan Irace <bryan@irace.me> Date: Thu, 10 Aug 2017 10:37:30 -0400 Subject: [PATCH 12/48] Swift 4 --- Dwifft.xcodeproj/project.pbxproj | 14 ++++++++- .../xcschemes/Dwifft-tvOS.xcscheme | 2 ++ .../xcshareddata/xcschemes/Dwifft.xcscheme | 4 ++- Dwifft/Dwifft.swift | 2 +- .../DwifftExample.xcodeproj/project.pbxproj | 29 ++++++++++++++++++- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index ce6961d..7336cd0 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -228,7 +228,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = jflinter; TargetAttributes = { 041EBB911B89679200E113B3 = { @@ -355,14 +355,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -407,14 +413,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme index 7468b85..2a096fe 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> </Testables> @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme index d35c757..28b227b 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0810" + LastUpgradeVersion = "0900" version = "1.3"> <BuildAction parallelizeBuildables = "YES" @@ -40,6 +40,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES" codeCoverageEnabled = "YES"> <Testables> @@ -70,6 +71,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Dwifft/Dwifft.swift b/Dwifft/Dwifft.swift index fbccb64..4ed7a4a 100644 --- a/Dwifft/Dwifft.swift +++ b/Dwifft/Dwifft.swift @@ -128,7 +128,7 @@ public enum Dwifft { /// - lhs: a `SectionedValues` /// - rhs: another, uh, `SectionedValues` /// - Returns: the series of transformations that, when applied to `lhs`, will yield `rhs`. - public static func diff<Section: Equatable, Value: Equatable>(lhs: SectionedValues<Section, Value>, rhs: SectionedValues<Section, Value>) -> [SectionedDiffStep<Section, Value>] { + public static func diff<Section, Value>(lhs: SectionedValues<Section, Value>, rhs: SectionedValues<Section, Value>) -> [SectionedDiffStep<Section, Value>] { if lhs.sections == rhs.sections { let allResults: [[SectionedDiffStep<Section, Value>]] = (0..<lhs.sections.count).map { i in let lValues = lhs.sectionsAndValues[i].1 diff --git a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj index 66b3bec..b96656e 100644 --- a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj +++ b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj @@ -48,6 +48,13 @@ remoteGlobalIDString = 041EBB911B89679200E113B3; remoteInfo = Dwifft; }; + 931446A91F3CA6FB00471406 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 045502181B898C5400F5614D /* Dwifft.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 94783CAD1EFBA21900841579; + remoteInfo = "Dwifft-tvOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -136,6 +143,7 @@ children = ( 0455021E1B898C5400F5614D /* Dwifft.framework */, 045502201B898C5400F5614D /* DwifftTests.xctest */, + 931446AA1F3CA6FB00471406 /* Dwifft_tvOS.framework */, ); name = Products; sourceTree = "<group>"; @@ -170,7 +178,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = jflinter; TargetAttributes = { 045501F21B898C3200F5614D = { @@ -218,6 +226,13 @@ remoteRef = 0455021F1B898C5400F5614D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 931446AA1F3CA6FB00471406 /* Dwifft_tvOS.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Dwifft_tvOS.framework; + remoteRef = 931446A91F3CA6FB00471406 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -289,14 +304,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -336,14 +357,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; From 3a7b79b7f753fc6ad109767c7448d865904b4ad3 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sun, 27 Aug 2017 08:24:14 +0100 Subject: [PATCH 13/48] initial macOS support Needs test coverage. --- Dwifft-macOS/Dwifft_macOS.h | 18 ++ Dwifft-macOS/Info.plist | 26 ++ Dwifft.xcodeproj/project.pbxproj | 146 ++++++++++ .../xcschemes/Dwifft-macOS.xcscheme | 102 +++++++ Dwifft/Dwifft+AppKit.swift | 266 ++++++++++++++++++ 5 files changed, 558 insertions(+) create mode 100644 Dwifft-macOS/Dwifft_macOS.h create mode 100644 Dwifft-macOS/Info.plist create mode 100644 Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme create mode 100644 Dwifft/Dwifft+AppKit.swift diff --git a/Dwifft-macOS/Dwifft_macOS.h b/Dwifft-macOS/Dwifft_macOS.h new file mode 100644 index 0000000..3bf8a9c --- /dev/null +++ b/Dwifft-macOS/Dwifft_macOS.h @@ -0,0 +1,18 @@ +// +// Dwifft_macOS.h +// Dwifft-macOS +// +// Copyright © 2017 jflinter. All rights reserved. +// + +#import <Cocoa/Cocoa.h> + +//! Project version number for Dwifft_macOS. +FOUNDATION_EXPORT double Dwifft_macOSVersionNumber; + +//! Project version string for Dwifft_macOS. +FOUNDATION_EXPORT const unsigned char Dwifft_macOSVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import <Dwifft_macOS/PublicHeader.h> + + diff --git a/Dwifft-macOS/Info.plist b/Dwifft-macOS/Info.plist new file mode 100644 index 0000000..58e6a64 --- /dev/null +++ b/Dwifft-macOS/Info.plist @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>$(CURRENT_PROJECT_VERSION)</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2017 jflinter. All rights reserved.</string> + <key>NSPrincipalClass</key> + <string></string> +</dict> +</plist> diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 7336cd0..eefb9f0 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ 0486A2651EA0A5B600D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 0486A2661EA0A64900D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 04AC329F1E88AEB000EF63DD /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */; }; + 382DEF461F487396007A8FD2 /* Dwifft_macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; + 382DEF4C1F48751B007A8FD2 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; + 382DEF4D1F48751C007A8FD2 /* Dwifft+AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */; }; 94783CB11EFBA21900841579 /* Dwifft_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94783CB51EFBA25300841579 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 94783CB61EFBA25300841579 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; @@ -44,6 +48,10 @@ 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dwifft+UIKit.swift"; sourceTree = "<group>"; }; 0486A2641EA0A5B600D8093E /* SectionedValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedValues.swift; sourceTree = "<group>"; }; 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/iOS/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; + 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_macOS.h; sourceTree = "<group>"; }; + 382DEF451F487395007A8FD2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dwifft+AppKit.swift"; sourceTree = "<group>"; }; 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_tvOS.h; sourceTree = "<group>"; }; 94783CB01EFBA21900841579 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; @@ -66,6 +74,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 382DEF3E1F487395007A8FD2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CA91EFBA21900841579 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -82,6 +97,7 @@ 041EBB941B89679200E113B3 /* Dwifft */, 041EBBA11B89679200E113B3 /* DwifftTests */, 94783CAE1EFBA21900841579 /* Dwifft-tvOS */, + 382DEF431F487395007A8FD2 /* Dwifft-macOS */, 041EBB931B89679200E113B3 /* Products */, ); sourceTree = "<group>"; @@ -92,6 +108,7 @@ 041EBB921B89679200E113B3 /* Dwifft.framework */, 041EBB9D1B89679200E113B3 /* DwifftTests.xctest */, 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */, + 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */, ); name = Products; sourceTree = "<group>"; @@ -103,6 +120,7 @@ 041EBBAE1B8967C300E113B3 /* Dwifft.swift */, 0486A2641EA0A5B600D8093E /* SectionedValues.swift */, 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */, + 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */, 041EBB951B89679200E113B3 /* Supporting Files */, ); path = Dwifft; @@ -134,6 +152,15 @@ name = "Supporting Files"; sourceTree = "<group>"; }; + 382DEF431F487395007A8FD2 /* Dwifft-macOS */ = { + isa = PBXGroup; + children = ( + 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */, + 382DEF451F487395007A8FD2 /* Info.plist */, + ); + path = "Dwifft-macOS"; + sourceTree = "<group>"; + }; 94783CAE1EFBA21900841579 /* Dwifft-tvOS */ = { isa = PBXGroup; children = ( @@ -154,6 +181,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 382DEF3F1F487395007A8FD2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 382DEF461F487396007A8FD2 /* Dwifft_macOS.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CAA1EFBA21900841579 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -202,6 +237,24 @@ productReference = 041EBB9D1B89679200E113B3 /* DwifftTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 382DEF411F487395007A8FD2 /* Dwifft-macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 382DEF491F487396007A8FD2 /* Build configuration list for PBXNativeTarget "Dwifft-macOS" */; + buildPhases = ( + 382DEF3D1F487395007A8FD2 /* Sources */, + 382DEF3E1F487395007A8FD2 /* Frameworks */, + 382DEF3F1F487395007A8FD2 /* Headers */, + 382DEF401F487395007A8FD2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Dwifft-macOS"; + productName = "Dwifft-macOS"; + productReference = 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */; + productType = "com.apple.product-type.framework"; + }; 94783CAC1EFBA21900841579 /* Dwifft-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */; @@ -239,6 +292,10 @@ CreatedOnToolsVersion = 6.4; LastSwiftMigration = 0800; }; + 382DEF411F487395007A8FD2 = { + CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 0900; + }; 94783CAC1EFBA21900841579 = { CreatedOnToolsVersion = 9.0; }; @@ -259,6 +316,7 @@ 041EBB911B89679200E113B3 /* Dwifft */, 041EBB9C1B89679200E113B3 /* DwifftTests */, 94783CAC1EFBA21900841579 /* Dwifft-tvOS */, + 382DEF411F487395007A8FD2 /* Dwifft-macOS */, ); }; /* End PBXProject section */ @@ -278,6 +336,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 382DEF401F487395007A8FD2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CAB1EFBA21900841579 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -326,6 +391,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 382DEF3D1F487395007A8FD2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */, + 382DEF4C1F48751B007A8FD2 /* SectionedValues.swift in Sources */, + 382DEF4D1F48751C007A8FD2 /* Dwifft+AppKit.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CA81EFBA21900841579 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -527,6 +602,68 @@ }; name = Release; }; + 382DEF471F487396007A8FD2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 382DEF481F487396007A8FD2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; 94783CB21EFBA21900841579 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -622,6 +759,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 382DEF491F487396007A8FD2 /* Build configuration list for PBXNativeTarget "Dwifft-macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 382DEF471F487396007A8FD2 /* Debug */, + 382DEF481F487396007A8FD2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme new file mode 100644 index 0000000..c31dfbf --- /dev/null +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0900" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "382DEF411F487395007A8FD2" + BuildableName = "Dwifft_macOS.framework" + BlueprintName = "Dwifft-macOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "041EBB9C1B89679200E113B3" + BuildableName = "DwifftTests.xctest" + BlueprintName = "DwifftTests" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "382DEF411F487395007A8FD2" + BuildableName = "Dwifft_macOS.framework" + BlueprintName = "Dwifft-macOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "382DEF411F487395007A8FD2" + BuildableName = "Dwifft_macOS.framework" + BlueprintName = "Dwifft-macOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "382DEF411F487395007A8FD2" + BuildableName = "Dwifft_macOS.framework" + BlueprintName = "Dwifft-macOS" + ReferencedContainer = "container:Dwifft.xcodeproj"> + </BuildableReference> + </MacroExpansion> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/Dwifft/Dwifft+AppKit.swift b/Dwifft/Dwifft+AppKit.swift new file mode 100644 index 0000000..7644108 --- /dev/null +++ b/Dwifft/Dwifft+AppKit.swift @@ -0,0 +1,266 @@ +// +// Dwifft+NSKit.swift +// Dwifft +// +// Created by Jack Flintermann on 3/13/15. +// Copyright (c) 2015 jflinter. All rights reserved. +// + +#if os(OSX) + +import Cocoa + + +/// A parent class for all diff calculators. Don't use it directly. +public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { + + fileprivate init(initialSectionedValues: SectionedValues<Section, Value>) { + self._sectionedValues = initialSectionedValues + } + + /// The number of sections in the diff calculator. Return this inside + /// `numberOfSections(in: tableView)` or `numberOfSections(in: collectionView)`. + /// Don't implement that method any other way (see the docs for `numberOfObjects(inSection:)` + /// for more context). + public final func numberOfSections() -> Int { + return self.sectionedValues.sections.count + } + + /// The section at a given index. If you implement `tableView:titleForHeaderInSection` or + /// `collectionView:viewForSupplementaryElementOfKind:atIndexPath`, you can use this + /// method to get information about that section out of Dwifft. + /// + /// - Parameter forSection: the index of the section you care about. + /// - Returns: the Section at that index. + public final func value(forSection: Int) -> Section { + return self.sectionedValues[forSection].0 + } + + + /// The, uh, number of objects in a given section. Use this to implement + /// `NSTableViewDataSource.numberOfRowsInSection:` or `NSCollectionViewDataSource.numberOfItemsInSection:`. + /// Seriously, don't implement that method any other way - there is some subtle timing stuff + /// around when this value should change in order to satisfy `NSTableView`/`NSCollectionView`'s internal + /// assertions, that Dwifft knows how to handle correctly. Read the source for + /// Dwifft+NSKit.swift if you don't believe me/want to learn more. + /// + /// - Parameter section: a section of your table/collection view + /// - Returns: the number of objects in that section. + public final func numberOfObjects(inSection section: Int) -> Int { + return self.sectionedValues[section].1.count + } + + + /// The value at a given index path. Use this to implement + /// `NSTableViewDataSource.objectValueForRow` or `NSCollectionViewDataSource.itemForRepresentedObjectAtIndexPath`. + /// + /// - Parameter indexPath: the index path you are interested in + /// - Returns: the thing at that index path + public final func value(atIndexPath indexPath: IndexPath) -> Value { + return self.sectionedValues[indexPath.section].1[indexPath.item] + } + + + /// Set this variable to automatically trigger the correct section/row/item insertion/deletions + /// on your table/collection view. + public final var sectionedValues: SectionedValues<Section, Value> { + get { + return _sectionedValues + } + set { + let oldSectionedValues = sectionedValues + let newSectionedValues = newValue + let diff = Dwifft.diff(lhs: oldSectionedValues, rhs: newSectionedValues) + if (diff.count > 0) { + self.processChanges(newState: newSectionedValues, diff: diff) + } + } + } + + // NSTableView and NSCollectionView both perform assertions on the *current* number of rows/items before performing any updates. As such, the `sectionedValues` property must be backed by an internal value that does not change until *after* `beginUpdates`/`performBatchUpdates` has been called. + fileprivate final var _sectionedValues: SectionedValues<Section, Value> + fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]){ + fatalError("override me") + } +} + +/// This class manages a `NSTableView`'s rows and sections. It will make the necessary calls to +/// the table view to ensure that its UI is kept in sync with the contents of the `sectionedValues` property. +public final class TableViewDiffCalculator<Section: Equatable, Value: Equatable>: AbstractDiffCalculator<Section, Value> { + + /// The table view to be managed + public weak var tableView: NSTableView? + + /// Initializes a new diff calculator. + /// + /// - Parameters: + /// - tableView: the table view to be managed + /// - initialSectionedValues: optional - if specified, these will be the initial contents of the diff calculator. + public init(tableView: NSTableView?, initialSectionedValues: SectionedValues<Section, Value> = SectionedValues()) { + self.tableView = tableView + super.init(initialSectionedValues: initialSectionedValues) + } + + /// You can change insertion/deletion animations like this! Fade works well. + /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. + public var insertionAnimation = NSTableView.AnimationOptions.slideUp, deletionAnimation = NSTableView.AnimationOptions.slideUp + + override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { + guard let tableView = self.tableView else { return } + tableView.beginUpdates() + self._sectionedValues = newState + for result in diff { + switch result { + case let .delete(_, row, _): tableView.removeRows(at: [row], withAnimation: self.deletionAnimation) + case let .insert(_, row, _): tableView.insertRows(at: [row], withAnimation: self.insertionAnimation) + default: fatalError("NSTableViews do not have sections") + } + } + tableView.endUpdates() + } +} + +/// This class manages a `NSCollectionView`'s items and sections. It will make the necessary +/// calls to the collection view to ensure that its UI is kept in sync with the contents +/// of the `sectionedValues` property. +public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equatable> : AbstractDiffCalculator<Section, Value> { + + /// The collection view to be managed. + public weak var collectionView: NSCollectionView? + + /// Initializes a new diff calculator. + /// + /// - Parameters: + /// - collectionView: the collection view to be managed. + /// - initialSectionedValues: optional - if specified, these will be the initial contents of the diff calculator. + public init(collectionView: NSCollectionView?, initialSectionedValues: SectionedValues<Section, Value> = SectionedValues()) { + self.collectionView = collectionView + super.init(initialSectionedValues: initialSectionedValues) + } + + override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { + guard let collectionView = self.collectionView else { return } + collectionView.performBatchUpdates({ + self._sectionedValues = newState + for result in diff { + switch result { + case let .delete(section, item, _): collectionView.deleteItems(at: [IndexPath(item: item, section: section)]) + case let .insert(section, item, _): collectionView.insertItems(at: [IndexPath(item: item, section: section)]) + case let .sectionDelete(section, _): collectionView.deleteSections(IndexSet(integer: section)) + case let .sectionInsert(section, _): collectionView.insertSections(IndexSet(integer: section)) + } + } + }, completionHandler: nil) + } +} + +/// Let's say your data model consists of different sections containing different model types. Since +/// `SectionedValues` requires a uniform type for all of its rows, this can be a clunky situation. You +/// can address this in a couple of ways. The first is to define a custom enum that encompasses all of the +/// things that *could* be in your data model - if section 1 has a bunch of `String`s, and section 2 has a bunch +/// of `Int`s, define a `StringOrInt` enum that conforms to `Equatable`, and fill the `SectionedValues` +/// that you use to drive your DiffCalculator up with those. Alternatively, if you are lazy, and your +/// models all conform to `Hashable`, you can use a SimpleTableViewDiffCalculator instead. +typealias SimpleTableViewDiffCalculator = TableViewDiffCalculator<AnyHashable, AnyHashable> + +/// See SimpleTableViewDiffCalculator for explanation +typealias SimpleCollectionViewDiffCalculator = CollectionViewDiffCalculator<AnyHashable, AnyHashable> + +/// If your table view only has a single section, or you only want to power a single section of it with Dwifft, +/// use a `SingleSectionTableViewDiffCalculator`. Note that this approach is not highly recommended, and you should +/// do so only if it *really* doesn't make sense to just power your whole table with a `TableViewDiffCalculator`. +/// You'll be less likely to mess up the index math :P +public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { + + /// The table view to be managed + public weak var tableView: NSTableView? + + /// All insertion/deletion calls will be made on this index. + public let sectionIndex: Int + + /// You can change insertion/deletion animations like this! Fade works well. + /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. + public var insertionAnimation = NSTableView.AnimationOptions.slideUp { + didSet { + self.internalDiffCalculator.insertionAnimation = self.insertionAnimation + } + } + + public var deletionAnimation = NSTableView.AnimationOptions.slideUp { + didSet { + self.internalDiffCalculator.deletionAnimation = self.deletionAnimation + } + } + + /// Set this variable to automatically trigger the correct row insertion/deletions + /// on your table view. + public var rows : [Value] { + get { + return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 + } + set { + self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + } + } + + /// Initializes a new diff calculator. + /// + /// - Parameters: + /// - tableView: the table view to be managed + /// - initialRows: optional - if specified, these will be the initial contents of the diff calculator. + /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. + public init(tableView: NSTableView?, initialRows: [Value] = [], sectionIndex: Int = 0) { + self.tableView = tableView + self.internalDiffCalculator = TableViewDiffCalculator(tableView: tableView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) + self.sectionIndex = sectionIndex + } + + fileprivate static func buildSectionedValues(values: [Value], sectionIndex: Int) -> SectionedValues<Int, Value> { + let firstRows = (0..<sectionIndex).map { ($0, [Value]()) } + return SectionedValues(firstRows + [(sectionIndex, values)]) + } + + private let internalDiffCalculator: TableViewDiffCalculator<Int, Value> + +} + +/// If your collection view only has a single section, or you only want to power a single section of it with Dwifft, +/// use a `SingleSectionCollectionViewDiffCalculator`. Note that this approach is not highly recommended, and you should +/// do so only if it *really* doesn't make sense to just power your whole view with a `CollectionViewDiffCalculator`. +/// You'll be less likely to mess up the index math :P +public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { + + /// The collection view to be managed + public weak var collectionView: NSCollectionView? + + /// All insertion/deletion calls will be made for items at this section. + public let sectionIndex: Int + + /// Set this variable to automatically trigger the correct item insertion/deletions + /// on your collection view. + public var items : [Value] { + get { + return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 + } + set { + self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + } + } + + /// Initializes a new diff calculator. + /// + /// - Parameters: + /// - tableView: the table view to be managed + /// - initialItems: optional - if specified, these will be the initial contents of the diff calculator. + /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. + public init(collectionView: NSCollectionView?, initialItems: [Value] = [], sectionIndex: Int = 0) { + self.collectionView = collectionView + self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) + self.sectionIndex = sectionIndex + } + + private let internalDiffCalculator: CollectionViewDiffCalculator<Int, Value> + +} + +#endif From 77b59a872c411ce2e8d529fbcd19dd24b77922e1 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Tue, 19 Sep 2017 23:00:46 -0400 Subject: [PATCH 14/48] update travis --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42a33da..d2b804e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,9 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode8 + osx_image: xcode9 env: - - PLATFORM=iOS NAME='iPhone 7' + - PLATFORM=iOS NAME='iPhone 8' before_install: export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }"); before_script: @@ -15,7 +15,7 @@ matrix: xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty; - os: osx language: objective-c - osx_image: xcode8 + osx_image: xcode9 env: - PLATFORM=tvOS NAME='Apple TV 1080p' before_install: From afc1cd8b61c860f678df15d408de6b6c0873179d Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Wed, 20 Sep 2017 00:42:27 -0400 Subject: [PATCH 15/48] migrate tests --- Cartfile.private | 2 +- Cartfile.resolved | 2 +- Dwifft.xcodeproj/project.pbxproj | 16 ++++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cartfile.private b/Cartfile.private index f76f5c3..ad6fa14 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1 +1 @@ -github "typelift/SwiftCheck" "0.7.3" \ No newline at end of file +github "jflinter/SwiftCheck" "8cb33343f45bc1b2f621011e096dbdd7e66787d6" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 0ee3ec3..1abd40f 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/SwiftCheck" "0.7.3" +github "jflinter/SwiftCheck" "8cb33343f45bc1b2f621011e096dbdd7e66787d6" diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 7336cd0..92c8733 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -233,11 +233,11 @@ TargetAttributes = { 041EBB911B89679200E113B3 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; }; 041EBB9C1B89679200E113B3 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; }; 94783CAC1EFBA21900841579 = { CreatedOnToolsVersion = 9.0; @@ -469,7 +469,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -488,7 +489,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -507,7 +509,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -523,7 +526,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Release; }; From 709bf28a0173acb93f70ae22eeaf99f9134d5b8d Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Wed, 20 Sep 2017 14:20:54 -0400 Subject: [PATCH 16/48] travis --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2b804e..f4947d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ matrix: carthage bootstrap --platform $PLATFORM --configuration Debug script: - set -o pipefail; - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty; + - open -a "simulator" --args -CurrentDeviceUDID "$UUID" + - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty - os: osx language: objective-c osx_image: xcode9 @@ -24,8 +24,8 @@ matrix: carthage bootstrap --platform $PLATFORM --configuration Debug script: - set -o pipefail; - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty; + - open -a "simulator" --args -CurrentDeviceUDID "$UUID" + - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty env: global: secure: pUV8Ccwq1FWO8PxTHPQ3qZDUDhjNOisNVRyrziYR8x0ZQYjmVmnaLKaOHFP8co6rhBlFqReKUjoFYgRqP5QK1EkD6lqSZfnkrWqnZuLDNy0sn3/+4sLtvqAhBroAfjmmvb5GpY+Kkqfz8Lhdu6+1Z/a5xPhqNeDO3aDpa2vdBztb2qLIZnf2g8NFLOoNuR+ula868nIm858LCN1sqLp9PhV4CGaMsFx7ZFaX1yEQbwNb8+85+U2HIHqjZ62u9KZ4lA1d58VVDGj2f7ObKkC+pjiuknljy5bvRVvg5pttXggJracFgMqouwwQFFCV3nFYSDS6h7ZIjUvbyMrqBN+u32RmtqVLp1by1JvRXSeemJ3HxtZGLbq7rff4zWXyYbelT6sR6J1tWIubRo5v3sXc8E1kurqKkcPqJdG4jqiUXOau2oSHhf7WCRwa0KNfvaQuMhm0Onnsi9tW2MzGieumscfuFIJsXJdXnac7jQUVb571GfxMrDeJ9v2GOPcbnlM8cttBFAw4IoINV6teKITUW6T8RpeDXzfQyxDDQaV0M1ZTab1Tj/f4EYDAXKfZ+QquWK3bgXJhxKghXIskZLdDhYMyP55T6QxLZY9wD2CxLrEbEhDQCEb+7R2LmIC95Rlku+W92b8eWAqNxf+vV7QRqBb/sV9w2mlxmmezYTP5VAs= From f9cfec39a3efb70772f6d18129c34a473ba2b3c8 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Thu, 21 Sep 2017 18:19:35 -0400 Subject: [PATCH 17/48] simplify travis --- .travis.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index f4947d4..79609b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,19 +13,6 @@ matrix: - set -o pipefail; - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty - - os: osx - language: objective-c - osx_image: xcode9 - env: - - PLATFORM=tvOS NAME='Apple TV 1080p' - before_install: - export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }"); - before_script: - carthage bootstrap --platform $PLATFORM --configuration Debug - script: - - set -o pipefail; - - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty env: global: secure: pUV8Ccwq1FWO8PxTHPQ3qZDUDhjNOisNVRyrziYR8x0ZQYjmVmnaLKaOHFP8co6rhBlFqReKUjoFYgRqP5QK1EkD6lqSZfnkrWqnZuLDNy0sn3/+4sLtvqAhBroAfjmmvb5GpY+Kkqfz8Lhdu6+1Z/a5xPhqNeDO3aDpa2vdBztb2qLIZnf2g8NFLOoNuR+ula868nIm858LCN1sqLp9PhV4CGaMsFx7ZFaX1yEQbwNb8+85+U2HIHqjZ62u9KZ4lA1d58VVDGj2f7ObKkC+pjiuknljy5bvRVvg5pttXggJracFgMqouwwQFFCV3nFYSDS6h7ZIjUvbyMrqBN+u32RmtqVLp1by1JvRXSeemJ3HxtZGLbq7rff4zWXyYbelT6sR6J1tWIubRo5v3sXc8E1kurqKkcPqJdG4jqiUXOau2oSHhf7WCRwa0KNfvaQuMhm0Onnsi9tW2MzGieumscfuFIJsXJdXnac7jQUVb571GfxMrDeJ9v2GOPcbnlM8cttBFAw4IoINV6teKITUW6T8RpeDXzfQyxDDQaV0M1ZTab1Tj/f4EYDAXKfZ+QquWK3bgXJhxKghXIskZLdDhYMyP55T6QxLZY9wD2CxLrEbEhDQCEb+7R2LmIC95Rlku+W92b8eWAqNxf+vV7QRqBb/sV9w2mlxmmezYTP5VAs= From f224cce1f9be2263bc6e45cc3725d860504dacd4 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Thu, 21 Sep 2017 18:20:40 -0400 Subject: [PATCH 18/48] podspec --- Dwifft.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index b97fc43..dedf069 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.6.3' + s.version = '0.7' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' From b123166a32c4985749c5363c8b322e255a04e271 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Mon, 25 Sep 2017 13:49:34 -0400 Subject: [PATCH 19/48] .swift-version --- .swift-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..5186d07 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4.0 From 3e246d187692818e54ed63684c172163ea94f8b7 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Wed, 27 Sep 2017 13:49:36 +0100 Subject: [PATCH 20/48] Hide SectionedTableViewDiffCalculator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NSTableView’s only support one section. --- Dwifft/Dwifft+AppKit.swift | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Dwifft/Dwifft+AppKit.swift b/Dwifft/Dwifft+AppKit.swift index 7644108..21d4e34 100644 --- a/Dwifft/Dwifft+AppKit.swift +++ b/Dwifft/Dwifft+AppKit.swift @@ -84,9 +84,8 @@ public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { } } -/// This class manages a `NSTableView`'s rows and sections. It will make the necessary calls to -/// the table view to ensure that its UI is kept in sync with the contents of the `sectionedValues` property. -public final class TableViewDiffCalculator<Section: Equatable, Value: Equatable>: AbstractDiffCalculator<Section, Value> { +/// NSTableView does not support sections so we hide this from users. +private final class SectionedTableViewDiffCalculator<Section: Equatable, Value: Equatable>: AbstractDiffCalculator<Section, Value> { /// The table view to be managed public weak var tableView: NSTableView? @@ -161,16 +160,11 @@ public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equat /// of `Int`s, define a `StringOrInt` enum that conforms to `Equatable`, and fill the `SectionedValues` /// that you use to drive your DiffCalculator up with those. Alternatively, if you are lazy, and your /// models all conform to `Hashable`, you can use a SimpleTableViewDiffCalculator instead. -typealias SimpleTableViewDiffCalculator = TableViewDiffCalculator<AnyHashable, AnyHashable> - -/// See SimpleTableViewDiffCalculator for explanation typealias SimpleCollectionViewDiffCalculator = CollectionViewDiffCalculator<AnyHashable, AnyHashable> -/// If your table view only has a single section, or you only want to power a single section of it with Dwifft, -/// use a `SingleSectionTableViewDiffCalculator`. Note that this approach is not highly recommended, and you should -/// do so only if it *really* doesn't make sense to just power your whole table with a `TableViewDiffCalculator`. -/// You'll be less likely to mess up the index math :P -public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { +/// This class manages a `NSTableView`'s rows. It will make the necessary +/// calls to the table view to ensure that its UI is kept in sync with the contents of the `rows` property. +public final class TableViewDiffCalculator<Value: Equatable> { /// The table view to be managed public weak var tableView: NSTableView? @@ -199,7 +193,7 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.internalDiffCalculator.sectionedValues = TableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -211,7 +205,7 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(tableView: NSTableView?, initialRows: [Value] = [], sectionIndex: Int = 0) { self.tableView = tableView - self.internalDiffCalculator = TableViewDiffCalculator(tableView: tableView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) + self.internalDiffCalculator = SectionedTableViewDiffCalculator(tableView: tableView, initialSectionedValues: TableViewDiffCalculator.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) self.sectionIndex = sectionIndex } @@ -220,7 +214,7 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { return SectionedValues(firstRows + [(sectionIndex, values)]) } - private let internalDiffCalculator: TableViewDiffCalculator<Int, Value> + private let internalDiffCalculator: SectionedTableViewDiffCalculator<Int, Value> } @@ -243,7 +237,7 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.internalDiffCalculator.sectionedValues = TableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -255,7 +249,7 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(collectionView: NSCollectionView?, initialItems: [Value] = [], sectionIndex: Int = 0) { self.collectionView = collectionView - self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) + self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: TableViewDiffCalculator.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) self.sectionIndex = sectionIndex } From eea1913e497e34e1e4452388d3e503ad3d87c2b0 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Wed, 27 Sep 2017 17:16:59 +0100 Subject: [PATCH 21/48] Add macOS tests, rename macOS framework The macOS framework now builds as Dwifft.framework --- Cartfile.private | 2 +- Cartfile.resolved | 2 +- Dwifft.xcodeproj/project.pbxproj | 159 ++++++- .../xcschemes/Dwifft-macOS.xcscheme | 17 +- DwifftTests/DwifftTests-macOS.swift | 416 ++++++++++++++++++ 5 files changed, 580 insertions(+), 16 deletions(-) create mode 100644 DwifftTests/DwifftTests-macOS.swift diff --git a/Cartfile.private b/Cartfile.private index ad6fa14..7fc4ebf 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1 +1 @@ -github "jflinter/SwiftCheck" "8cb33343f45bc1b2f621011e096dbdd7e66787d6" \ No newline at end of file +github "typelift/SwiftCheck" diff --git a/Cartfile.resolved b/Cartfile.resolved index 1abd40f..97fb7bd 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "jflinter/SwiftCheck" "8cb33343f45bc1b2f621011e096dbdd7e66787d6" +github "typelift/SwiftCheck" "0.8.1" diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index e6aee10..d522ff0 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -17,10 +17,16 @@ 0486A2651EA0A5B600D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 0486A2661EA0A64900D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 04AC329F1E88AEB000EF63DD /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */; }; + 380FFA411F7BF2E000AEF983 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */; }; 382DEF461F487396007A8FD2 /* Dwifft_macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 382DEF4C1F48751B007A8FD2 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 382DEF4D1F48751C007A8FD2 /* Dwifft+AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */; }; + 38E5B5D61F7BDB5400F33285 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; + 38E5B5D71F7BDB5400F33285 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; + 38E5B5E91F7BDBA500F33285 /* Dwifft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 382DEF421F487395007A8FD2 /* Dwifft.framework */; }; + 38E5B5EA1F7BDBBB00F33285 /* Dwifft+AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */; }; + 38E5B5EB1F7BDBC700F33285 /* DwifftTests-macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E5B5E61F7BDB9800F33285 /* DwifftTests-macOS.swift */; }; 94783CB11EFBA21900841579 /* Dwifft_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94783CB51EFBA25300841579 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 94783CB61EFBA25300841579 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; @@ -35,6 +41,13 @@ remoteGlobalIDString = 041EBB911B89679200E113B3; remoteInfo = Dwifft; }; + 38E5B5E41F7BDB7300F33285 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 041EBB891B89679200E113B3 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 382DEF411F487395007A8FD2; + remoteInfo = "Dwifft-macOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -48,10 +61,13 @@ 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dwifft+UIKit.swift"; sourceTree = "<group>"; }; 0486A2641EA0A5B600D8093E /* SectionedValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedValues.swift; sourceTree = "<group>"; }; 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/iOS/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; - 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 382DEF421F487395007A8FD2 /* Dwifft.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_macOS.h; sourceTree = "<group>"; }; 382DEF451F487395007A8FD2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dwifft+AppKit.swift"; sourceTree = "<group>"; }; + 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/Mac/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; + 38E5B5E21F7BDB5400F33285 /* DwifftTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DwifftTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 38E5B5E61F7BDB9800F33285 /* DwifftTests-macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DwifftTests-macOS.swift"; sourceTree = "<group>"; }; 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 94783CAF1EFBA21900841579 /* Dwifft_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_tvOS.h; sourceTree = "<group>"; }; 94783CB01EFBA21900841579 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; @@ -81,6 +97,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 38E5B5DA1F7BDB5400F33285 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 38E5B5E91F7BDBA500F33285 /* Dwifft.framework in Frameworks */, + 380FFA411F7BF2E000AEF983 /* SwiftCheck.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CA91EFBA21900841579 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -99,6 +124,7 @@ 94783CAE1EFBA21900841579 /* Dwifft-tvOS */, 382DEF431F487395007A8FD2 /* Dwifft-macOS */, 041EBB931B89679200E113B3 /* Products */, + 38E5B5E81F7BDBA500F33285 /* Frameworks */, ); sourceTree = "<group>"; }; @@ -108,7 +134,8 @@ 041EBB921B89679200E113B3 /* Dwifft.framework */, 041EBB9D1B89679200E113B3 /* DwifftTests.xctest */, 94783CAD1EFBA21900841579 /* Dwifft_tvOS.framework */, - 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */, + 382DEF421F487395007A8FD2 /* Dwifft.framework */, + 38E5B5E21F7BDB5400F33285 /* DwifftTests-macOS.xctest */, ); name = Products; sourceTree = "<group>"; @@ -137,6 +164,7 @@ 041EBBA11B89679200E113B3 /* DwifftTests */ = { isa = PBXGroup; children = ( + 38D317751F7BF21000A15CD7 /* macOS */, 041EBBA41B89679200E113B3 /* DwifftTests.swift */, 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */, 041EBBA21B89679200E113B3 /* Supporting Files */, @@ -161,6 +189,22 @@ path = "Dwifft-macOS"; sourceTree = "<group>"; }; + 38D317751F7BF21000A15CD7 /* macOS */ = { + isa = PBXGroup; + children = ( + 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */, + 38E5B5E61F7BDB9800F33285 /* DwifftTests-macOS.swift */, + ); + name = macOS; + sourceTree = "<group>"; + }; + 38E5B5E81F7BDBA500F33285 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = "<group>"; + }; 94783CAE1EFBA21900841579 /* Dwifft-tvOS */ = { isa = PBXGroup; children = ( @@ -252,9 +296,28 @@ ); name = "Dwifft-macOS"; productName = "Dwifft-macOS"; - productReference = 382DEF421F487395007A8FD2 /* Dwifft_macOS.framework */; + productReference = 382DEF421F487395007A8FD2 /* Dwifft.framework */; productType = "com.apple.product-type.framework"; }; + 38E5B5D21F7BDB5400F33285 /* DwifftTests-macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 38E5B5DF1F7BDB5400F33285 /* Build configuration list for PBXNativeTarget "DwifftTests-macOS" */; + buildPhases = ( + 38E5B5D51F7BDB5400F33285 /* Sources */, + 38E5B5DA1F7BDB5400F33285 /* Frameworks */, + 38E5B5DD1F7BDB5400F33285 /* Resources */, + 38E5B5DE1F7BDB5400F33285 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 38E5B5E51F7BDB7300F33285 /* PBXTargetDependency */, + ); + name = "DwifftTests-macOS"; + productName = DwifftTests; + productReference = 38E5B5E21F7BDB5400F33285 /* DwifftTests-macOS.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 94783CAC1EFBA21900841579 /* Dwifft-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */; @@ -317,6 +380,7 @@ 041EBB9C1B89679200E113B3 /* DwifftTests */, 94783CAC1EFBA21900841579 /* Dwifft-tvOS */, 382DEF411F487395007A8FD2 /* Dwifft-macOS */, + 38E5B5D21F7BDB5400F33285 /* DwifftTests-macOS */, ); }; /* End PBXProject section */ @@ -343,6 +407,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 38E5B5DD1F7BDB5400F33285 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CAB1EFBA21900841579 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -367,6 +438,20 @@ shellPath = /bin/sh; shellScript = "/usr/local/bin/carthage copy-frameworks"; }; + 38E5B5DE1F7BDB5400F33285 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/Mac/SwiftCheck.framework", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -401,6 +486,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 38E5B5D51F7BDB5400F33285 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 38E5B5EB1F7BDBC700F33285 /* DwifftTests-macOS.swift in Sources */, + 38E5B5EA1F7BDBBB00F33285 /* Dwifft+AppKit.swift in Sources */, + 38E5B5D61F7BDB5400F33285 /* SectionedValues.swift in Sources */, + 38E5B5D71F7BDB5400F33285 /* Dwifft.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 94783CA81EFBA21900841579 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -419,6 +515,11 @@ target = 041EBB911B89679200E113B3 /* Dwifft */; targetProxy = 041EBB9F1B89679200E113B3 /* PBXContainerItemProxy */; }; + 38E5B5E51F7BDB7300F33285 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 382DEF411F487395007A8FD2 /* Dwifft-macOS */; + targetProxy = 38E5B5E41F7BDB7300F33285 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -629,7 +730,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = Dwifft; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -660,7 +761,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = Dwifft; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -668,6 +769,45 @@ }; name = Release; }; + 38E5B5E01F7BDB5400F33285 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = "DwifftTests copy-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.13; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 38E5B5E11F7BDB5400F33285 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + INFOPLIST_FILE = "DwifftTests copy-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx10.13; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; 94783CB21EFBA21900841579 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -772,6 +912,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 38E5B5DF1F7BDB5400F33285 /* Build configuration list for PBXNativeTarget "DwifftTests-macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 38E5B5E01F7BDB5400F33285 /* Debug */, + 38E5B5E11F7BDB5400F33285 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 94783CB41EFBA21900841579 /* Build configuration list for PBXNativeTarget "Dwifft-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme index c31dfbf..f1717bf 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme @@ -15,7 +15,7 @@ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "382DEF411F487395007A8FD2" - BuildableName = "Dwifft_macOS.framework" + BuildableName = "Dwifft.framework" BlueprintName = "Dwifft-macOS" ReferencedContainer = "container:Dwifft.xcodeproj"> </BuildableReference> @@ -27,16 +27,15 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> <TestableReference skipped = "NO"> <BuildableReference BuildableIdentifier = "primary" - BlueprintIdentifier = "041EBB9C1B89679200E113B3" - BuildableName = "DwifftTests.xctest" - BlueprintName = "DwifftTests" + BlueprintIdentifier = "38E5B5D21F7BDB5400F33285" + BuildableName = "DwifftTests-macOS.xctest" + BlueprintName = "DwifftTests-macOS" ReferencedContainer = "container:Dwifft.xcodeproj"> </BuildableReference> </TestableReference> @@ -45,7 +44,7 @@ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "382DEF411F487395007A8FD2" - BuildableName = "Dwifft_macOS.framework" + BuildableName = "Dwifft.framework" BlueprintName = "Dwifft-macOS" ReferencedContainer = "container:Dwifft.xcodeproj"> </BuildableReference> @@ -68,7 +67,7 @@ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "382DEF411F487395007A8FD2" - BuildableName = "Dwifft_macOS.framework" + BuildableName = "Dwifft.framework" BlueprintName = "Dwifft-macOS" ReferencedContainer = "container:Dwifft.xcodeproj"> </BuildableReference> @@ -86,7 +85,7 @@ <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "382DEF411F487395007A8FD2" - BuildableName = "Dwifft_macOS.framework" + BuildableName = "Dwifft.framework" BlueprintName = "Dwifft-macOS" ReferencedContainer = "container:Dwifft.xcodeproj"> </BuildableReference> diff --git a/DwifftTests/DwifftTests-macOS.swift b/DwifftTests/DwifftTests-macOS.swift new file mode 100644 index 0000000..71ea1c3 --- /dev/null +++ b/DwifftTests/DwifftTests-macOS.swift @@ -0,0 +1,416 @@ +// +// DwifftTests-macOS.swift +// DwifftTests +// +// Created by Rik Chilvers on 27/09/2017. +// Copyright © 2017 jflinter. All rights reserved. +// + +import Cocoa +import XCTest +import SwiftCheck + +struct SectionedValuesWrapper: Arbitrary { + let values: SectionedValues<Int, Int> + + public static var arbitrary: Gen<SectionedValuesWrapper> { + let arrayOfNumbers = Gen<Int>.fromElements(in: 0...10).proliferate.suchThat({ $0.count <= 100 }) + return arrayOfNumbers.map { array in + return array.map { i in + return (i, arrayOfNumbers.generate) + } + }.map { val in + return SectionedValuesWrapper(values: SectionedValues<Int, Int>(val)) + } + } +} + +class DwifftSwiftCheckTests: XCTestCase { + + func testDiff() { + property("Diffing two arrays, then applying the diff to the first, yields the second") <- forAll { (a1 : ArrayOf<Int>, a2 : ArrayOf<Int>) in + let diff = Dwifft.diff(a1.getArray, a2.getArray) + return (Dwifft.apply(diff: diff, toArray: a1.getArray) == a2.getArray) <?> "diff applies" + } + } + + func test2DDiff() { + property("Diffing two 2D arrays, then applying the diff to the first, yields the second") <- forAll { (lhs : SectionedValuesWrapper, rhs: SectionedValuesWrapper) in + let diff = Dwifft.diff(lhs: lhs.values, rhs: rhs.values) + return (Dwifft.apply(diff: diff, toSectionedValues: lhs.values) == rhs.values) <?> "2d diff applies" + } + } + + func testAppKit2D() { + + class DataSource: NSObject, NSTableViewDataSource { + let diffCalculator: TableViewDiffCalculator<Int> + + init(_ diffCalculator: TableViewDiffCalculator<Int>) { + self.diffCalculator = diffCalculator + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return self.diffCalculator.rows.count + } + + func tableView(_ tableView: NSTableView, cellForRowAt indexPath: IndexPath) -> NSTableCellView { + return NSTableCellView() + } + } + + property("Updating a TableViewDiffCalculator never raises an exception") <- forAll { (lhs : SectionedValuesWrapper, rhs: SectionedValuesWrapper) in + let tableView = NSTableView() + let diffCalculator = TableViewDiffCalculator(tableView: tableView, + initialRows: lhs.values.sectionsAndValues.first?.1 ?? []) + let dataSource = DataSource(diffCalculator) + tableView.dataSource = dataSource + tableView.reloadData() + diffCalculator.rows = rhs.values.sectionsAndValues.first?.1 ?? [] + + return true <?> "no exception was raised" + } + } +} + +class DwifftTests: XCTestCase { + + struct TestCase { + let array1: [Character] + let array2: [Character] + let expectedDiff: String + init(_ a: String, _ b: String, _ expectedDiff: String) { + self.array1 = Array(a.characters) + self.array2 = Array(b.characters) + self.expectedDiff = expectedDiff + } + } + + func testDiff() { + let tests: [TestCase] = [ + TestCase("1234", "23", "-4@3-1@0"), + TestCase("0125890", "4598310", "-8@4-2@2-1@1-0@0+4@0+8@3+3@4+1@5"), + TestCase("BANANA", "KATANA", "-N@2-B@0+K@0+T@2"), + TestCase("1234", "1224533324", "+2@2+4@3+5@4+3@6+3@7+2@8"), + TestCase("thisisatest", "testing123testing", "-a@6-s@5-i@2-h@1+e@1+t@3+n@5+g@6+1@7+2@8+3@9+i@14+n@15+g@16"), + TestCase("HUMAN", "CHIMPANZEE", "-U@1+C@0+I@2+P@4+Z@7+E@8+E@9"), + ] + + for test in tests { + let diff = Dwifft.diff(test.array1, test.array2) + let printableDiff = diff.map({ $0.debugDescription }).joined(separator: "") + XCTAssertEqual(printableDiff, test.expectedDiff, "incorrect diff") + } + } + + func testDiffBenchmark() { + let a: [Int] = (0...1000).map({ _ in Int(arc4random_uniform(100)) }).filter({ _ in arc4random_uniform(2) == 0}) + let b: [Int] = (0...1000).map({ _ in Int(arc4random_uniform(100)) }).filter({ _ in arc4random_uniform(2) == 0}) + measure { + let _ = Dwifft.diff(a, b) + } + } + + func test2D() { + let testCases: [([(String, [Int])], [(String, [Int])], String)] = [ + ( + [("a", [0, 1]), ("b", [2, 3, 4])], + [("b", [2])], + "[d(1 2), d(1 1), ds(0)]" + ), + ( + [("a", []), ("b", [])], + [], + "[ds(1), ds(0)]" + ), + ( + [], + [("a", []), ("b", [])], + "[is(0), is(1)]" + ), + ( + [], + [("a", [1, 2]), ("b", [3, 4, 5])], + "[is(0), is(1), i(0 0), i(0 1), i(1 0), i(1 1), i(1 2)]" + ), + ( + [], + [], + "[]" + ), + ( + [("a", [1]), ("b", []), ("c", [])], + [("a", [1])], + "[ds(2), ds(1)]" + ), + ( + [("a", []), ("b", [1]), ("c", [])], + [("a", []), ("b", [2]), ("c", [])], + "[d(1 0), i(1 0)]" + ), + ( + [("a", [1]), ("b", []), ("c", [])], + [("a", []), ("b", [1]), ("c", [])], + "[d(0 0), i(1 0)]" + ), + ( + [("a", [1]), ("b", []), ("c", [])], + [("q", []), ("a", [1])], + "[ds(2), ds(1), is(0)]" + ), + ( + [("a", [1]), ("b", []), ("c", [])], + [("q", []), ("a", [1, 2])], + "[ds(2), ds(1), is(0), i(1 1)]" + ), + ( + [("a", [1])], + [("q", []), ("a", [1])], + "[is(0)]" + ), + ( + [("a", [1, 2]), ("b", [3, 4])], + [("a", [1, 2, 3, 4])], + "[ds(1), i(0 2), i(0 3)]" + ), + ( + [("a", [1, 2, 3]), ("b", [4, 5]), ("c", [])], + [("q", []), ("a", [1, 2]), ("b", [3, 4])], + "[d(0 2), d(1 1), ds(2), is(0), i(2 0)]" + ), + ] + for (lhs, rhs, expected) in testCases { + let mappedLhs = SectionedValues(lhs.map { ($0, $1) }) + let mappedRhs = SectionedValues(rhs.map { ($0, $1) }) + XCTAssertEqual(Dwifft.diff(lhs: mappedLhs, rhs: mappedRhs).debugDescription, expected) + } + } + + func test2DBenchmark() { + let n: Int = 70 + let a: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + guard arc4random_uniform(2) == 0 else { return nil } + let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } + return (i, value) + } + let b: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + guard arc4random_uniform(2) == 0 else { return nil } + let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } + return (i, value) + } + let lhs = SectionedValues(a) + let rhs = SectionedValues(b) + measure { + let _ = Dwifft.diff(lhs: lhs, rhs: rhs) + } + } + + func testSectionedValues() { + XCTAssertEqual(SectionedValues(values: [1,2,3,11,12,13,21,22,23], valueToSection: { i in + return i % 10 + }, sortSections: {a, b in + return a < b + }, sortValues: {a, b in + return a < b + }), SectionedValues([(1, [1, 11, 21]), (2, [2, 12, 22]), (3, [3, 13, 23])])) + + XCTAssertEqual(SectionedValues(values: [1,2,3,11,12,13,21,22,23], valueToSection: { i in + return i % 10 + }, sortSections: {a, b in + return b < a + }, sortValues: {a, b in + return a < b + }), SectionedValues([(3, [3, 13, 23]), (2, [2, 12, 22]), (1, [1, 11, 21])])) + + XCTAssertEqual(SectionedValues(values: [1,2,3,11,12,13,21,22,23], valueToSection: { i in + return i % 10 + }, sortSections: {a, b in + return a < b + }, sortValues: {a, b in + return b < a + }), SectionedValues([(1, [21, 11, 1]), (2, [22, 12, 2]), (3, [23, 13, 3])])) + + XCTAssertEqual(SectionedValues(values: [1,2,3,11,12,13,21,22,23], valueToSection: { i in + return i % 10 + }, sortSections: {a, b in + return b < a + }, sortValues: {a, b in + return b < a + }), SectionedValues([(3, [23, 13, 3]), (2, [22, 12, 2]), (1, [21, 11, 1])])) + } + + func testTableViewDiffCalculator() { + + class TestTableView: NSTableView { + + let insertionExpectations: [Int: XCTestExpectation] + let deletionExpectations: [Int: XCTestExpectation] + + init(insertionExpectations: [Int: XCTestExpectation], deletionExpectations: [Int: XCTestExpectation]) { + self.insertionExpectations = insertionExpectations + self.deletionExpectations = deletionExpectations + super.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("not implemented") + } + + override func insertRows(at indexes: IndexSet, withAnimation animation: NSTableView.AnimationOptions) { + XCTAssertEqual(animation, NSTableView.AnimationOptions.slideLeft, "incorrect insertion animation") + for index in indexes { + self.insertionExpectations[index]!.fulfill() + } + } + + override func removeRows(at indexes: IndexSet, withAnimation animation: NSTableView.AnimationOptions) { + XCTAssertEqual(animation, NSTableView.AnimationOptions.slideRight, "incorrect insertion animation") + for index in indexes { + self.deletionExpectations[index]!.fulfill() + } + } + + } + + class TestViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate { + + let tableView: TestTableView + let diffCalculator: TableViewDiffCalculator<Int> + var rows: [Int] { + didSet { + self.diffCalculator.rows = rows + } + } + + init(tableView: TestTableView, rows: [Int]) { + self.tableView = tableView + self.diffCalculator = TableViewDiffCalculator<Int>(tableView: tableView, initialRows: rows) + self.diffCalculator.insertionAnimation = .slideLeft + self.diffCalculator.deletionAnimation = .slideRight + self.rows = rows + super.init(nibName: nil, bundle: nil) + self.tableView.dataSource = self + self.tableView.delegate = self + } + + required init?(coder aDecoder: NSCoder) { + fatalError("not implemented") + } + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + return NSTableCellView() + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return self.diffCalculator.rows.count + } + + } + + var insertionExpectations: [Int: XCTestExpectation] = [:] + for i in [0, 3, 4, 5] { + let x: XCTestExpectation = expectation(description: "+\(i)") + insertionExpectations[i] = x + } + + var deletionExpectations: [Int: XCTestExpectation] = [:] + for i in [0, 1, 2, 4] { + let x: XCTestExpectation = expectation(description: "+\(i)") + deletionExpectations[i] = x + } + + let tableView = TestTableView(insertionExpectations: insertionExpectations, deletionExpectations: deletionExpectations) + let viewController = TestViewController(tableView: tableView, rows: [0, 1, 2, 5, 8, 9, 0]) + viewController.rows = [4, 5, 9, 8, 3, 1, 0] + waitForExpectations(timeout: 1.0, handler: nil) + } + + func testCollectionViewDiffCalculator() { + + class TestCollectionView: NSCollectionView { + + let insertionExpectations: [Int: XCTestExpectation] + let deletionExpectations: [Int: XCTestExpectation] + + init(insertionExpectations: [Int: XCTestExpectation], deletionExpectations: [Int: XCTestExpectation]) { + self.insertionExpectations = insertionExpectations + self.deletionExpectations = deletionExpectations + super.init(frame: CGRect.zero) + self.collectionViewLayout = NSCollectionViewFlowLayout() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("not implemented") + } + + override func insertItems(at indexPaths: Set<IndexPath>) { + super.insertItems(at: indexPaths) + for indexPath in indexPaths { + self.insertionExpectations[(indexPath as NSIndexPath).item]!.fulfill() + } + } + + override func deleteItems(at indexPaths: Set<IndexPath>) { + super.deleteItems(at: indexPaths) + for indexPath in indexPaths { + self.deletionExpectations[(indexPath as NSIndexPath).item]!.fulfill() + } + } + + } + + class TestViewController: NSViewController, NSCollectionViewDataSource { + let itemIdentifier = NSUserInterfaceItemIdentifier("TestItem") + let testCollectionView: TestCollectionView + let diffCalculator: CollectionViewDiffCalculator<Int, Int> + var rows: [Int] { + didSet { + self.diffCalculator.sectionedValues = SectionedValues([(0, rows)]) + } + } + + init(collectionView: TestCollectionView, rows: [Int]) { + self.testCollectionView = collectionView + self.diffCalculator = CollectionViewDiffCalculator<Int, Int>(collectionView: self.testCollectionView, initialSectionedValues: SectionedValues([(0, rows)])) + self.rows = rows + super.init(nibName: nil, bundle: nil) + + collectionView.register(NSCollectionViewItem.self, forItemWithIdentifier: self.itemIdentifier) + collectionView.dataSource = self + } + + required init?(coder aDecoder: NSCoder) { + fatalError("not implemented") + } + + func numberOfSections(in collectionView: NSCollectionView) -> Int { + return diffCalculator.numberOfSections() + } + + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { + return diffCalculator.numberOfObjects(inSection: section) + } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + return collectionView.makeItem(withIdentifier: self.itemIdentifier, for: indexPath) + } + } + + var insertionExpectations: [Int: XCTestExpectation] = [:] + for i in [0, 3, 4, 5] { + let x: XCTestExpectation = expectation(description: "+\(i)") + insertionExpectations[i] = x + } + + var deletionExpectations: [Int: XCTestExpectation] = [:] + for i in [0, 1, 2, 4] { + let x: XCTestExpectation = expectation(description: "+\(i)") + deletionExpectations[i] = x + } + + let collectionView = TestCollectionView(insertionExpectations: insertionExpectations, deletionExpectations: deletionExpectations) + let viewController = TestViewController(collectionView: collectionView, rows: [0, 1, 2, 5, 8, 9, 0]) + viewController.rows = [4, 5, 9, 8, 3, 1, 0] + waitForExpectations(timeout: 1.0, handler: nil) + } +} From 3e0ba7b2ca5d1437f7b429e8e68749e047a22922 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Wed, 27 Sep 2017 17:23:10 +0100 Subject: [PATCH 22/48] add missing info.plist --- Dwifft.xcodeproj/project.pbxproj | 6 ++++-- DwifftTests/macOS Info.plist | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 DwifftTests/macOS Info.plist diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index d522ff0..7f909a7 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dwifft+UIKit.swift"; sourceTree = "<group>"; }; 0486A2641EA0A5B600D8093E /* SectionedValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedValues.swift; sourceTree = "<group>"; }; 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/iOS/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; + 380FFA421F7C072D00AEF983 /* macOS Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "macOS Info.plist"; sourceTree = "<group>"; }; 382DEF421F487395007A8FD2 /* Dwifft.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dwifft_macOS.h; sourceTree = "<group>"; }; 382DEF451F487395007A8FD2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; @@ -194,6 +195,7 @@ children = ( 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */, 38E5B5E61F7BDB9800F33285 /* DwifftTests-macOS.swift */, + 380FFA421F7C072D00AEF983 /* macOS Info.plist */, ); name = macOS; sourceTree = "<group>"; @@ -780,7 +782,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = "DwifftTests copy-Info.plist"; + INFOPLIST_FILE = "DwifftTests/macOS Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -797,7 +799,7 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", ); - INFOPLIST_FILE = "DwifftTests copy-Info.plist"; + INFOPLIST_FILE = "DwifftTests/macOS Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/DwifftTests/macOS Info.plist b/DwifftTests/macOS Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/DwifftTests/macOS Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> +</dict> +</plist> From bd39fa308404f32bb76684dbafa3aa3ba748bd1a Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Fri, 3 Nov 2017 18:34:02 +0000 Subject: [PATCH 23/48] pin macOS deployment target --- Dwifft.podspec | 1 + Dwifft.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index dedf069..fe336b6 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -10,6 +10,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' + s.osx.deployment_target = '10.11' s.source_files = 'Dwifft/*.swift' diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 7f909a7..25740a3 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -730,10 +730,10 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx; + SDKROOT = macosx10.13; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -761,10 +761,10 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx; + SDKROOT = macosx10.13; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; From 85915a39eb4b4465043fb208465abeebab31249b Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sat, 4 Nov 2017 09:52:52 +0000 Subject: [PATCH 24/48] =?UTF-8?q?update=20for=20Swift=204=E2=80=99s=20Stri?= =?UTF-8?q?ng=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DwifftTests/DwifftTests-macOS.swift | 4 ++-- DwifftTests/DwifftTests.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DwifftTests/DwifftTests-macOS.swift b/DwifftTests/DwifftTests-macOS.swift index 71ea1c3..2267a5b 100644 --- a/DwifftTests/DwifftTests-macOS.swift +++ b/DwifftTests/DwifftTests-macOS.swift @@ -80,8 +80,8 @@ class DwifftTests: XCTestCase { let array2: [Character] let expectedDiff: String init(_ a: String, _ b: String, _ expectedDiff: String) { - self.array1 = Array(a.characters) - self.array2 = Array(b.characters) + self.array1 = a.map { $0 } + self.array2 = b.map { $0 } self.expectedDiff = expectedDiff } } diff --git a/DwifftTests/DwifftTests.swift b/DwifftTests/DwifftTests.swift index ec22da5..c758332 100644 --- a/DwifftTests/DwifftTests.swift +++ b/DwifftTests/DwifftTests.swift @@ -101,8 +101,8 @@ class DwifftTests: XCTestCase { let array2: [Character] let expectedDiff: String init(_ a: String, _ b: String, _ expectedDiff: String) { - self.array1 = Array(a.characters) - self.array2 = Array(b.characters) + self.array1 = a.map { $0 } + self.array2 = b.map { $0 } self.expectedDiff = expectedDiff } } From 8c8b0f0df873c02dde8404c7321e023f9138e977 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sat, 4 Nov 2017 10:12:30 +0000 Subject: [PATCH 25/48] disable swift3 objc inference --- Dwifft.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 25740a3..ae8bcc6 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -647,7 +647,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Debug; @@ -667,7 +667,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Release; @@ -687,7 +687,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Debug; @@ -704,7 +704,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Release; @@ -787,7 +787,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx10.13; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Debug; @@ -805,7 +805,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx10.13; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Release; From 2ac80df7208b09ac93a578ae2c0a5a3a3749af9c Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sat, 4 Nov 2017 10:14:13 +0000 Subject: [PATCH 26/48] update tvOS scheme to swift 4 --- Dwifft.xcodeproj/project.pbxproj | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index ae8bcc6..35a5c60 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -363,6 +363,7 @@ }; 94783CAC1EFBA21900841579 = { CreatedOnToolsVersion = 9.0; + LastSwiftMigration = 0910; }; }; }; @@ -837,7 +838,8 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -869,7 +871,8 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; From f9d665902410e2bc8ee3972e6c406d581e51d167 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sat, 4 Nov 2017 10:31:17 +0000 Subject: [PATCH 27/48] remove unnecessary build stages --- Dwifft.xcodeproj/project.pbxproj | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 35a5c60..3fb299a 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -290,7 +290,6 @@ 382DEF3D1F487395007A8FD2 /* Sources */, 382DEF3E1F487395007A8FD2 /* Frameworks */, 382DEF3F1F487395007A8FD2 /* Headers */, - 382DEF401F487395007A8FD2 /* Resources */, ); buildRules = ( ); @@ -308,7 +307,6 @@ 38E5B5D51F7BDB5400F33285 /* Sources */, 38E5B5DA1F7BDB5400F33285 /* Frameworks */, 38E5B5DD1F7BDB5400F33285 /* Resources */, - 38E5B5DE1F7BDB5400F33285 /* ShellScript */, ); buildRules = ( ); @@ -403,13 +401,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 382DEF401F487395007A8FD2 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 38E5B5DD1F7BDB5400F33285 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -441,20 +432,6 @@ shellPath = /bin/sh; shellScript = "/usr/local/bin/carthage copy-frameworks"; }; - 38E5B5DE1F7BDB5400F33285 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/Mac/SwiftCheck.framework", - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ From c0e249badf57b2dd6f732e3033cb00e53fd34341 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sat, 4 Nov 2017 11:02:00 +0000 Subject: [PATCH 28/48] prep for macOS example app --- .../AppDelegate.swift | 0 .../Base.lproj/LaunchScreen.xib | 0 .../Base.lproj/Main.storyboard | 0 .../EventsTableViewController.swift | 0 .../Stuff.swift | 0 .../StuffCollectionViewController.swift | 0 .../StuffTableViewController.swift | 0 .../AppIcon.appiconset/Contents.json | 15 + .../LaunchImage.launchimage/Contents.json | 9 + .../Supporting Files}/Info.plist | 0 .../DwifftExample.xcodeproj/project.pbxproj | 248 +++++- .../DwifftExamples-macOS/AppDelegate.swift | 20 + .../Base.lproj/Main.storyboard | 717 ++++++++++++++++++ .../AppIcon.appiconset/Contents.json | 58 ++ .../DwifftExamples_macOS.entitlements | 10 + .../Supporting Files/Info.plist | 32 + .../DwifftExamples-macOS/ViewController.swift | 21 + 17 files changed, 1111 insertions(+), 19 deletions(-) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/AppDelegate.swift (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/Base.lproj/LaunchScreen.xib (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/Base.lproj/Main.storyboard (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/EventsTableViewController.swift (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/Stuff.swift (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/StuffCollectionViewController.swift (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS}/StuffTableViewController.swift (100%) rename DwifftExample/{DwifftExample => DwifftExample-iOS/Supporting Files}/Images.xcassets/AppIcon.appiconset/Contents.json (68%) create mode 100644 DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/LaunchImage.launchimage/Contents.json rename DwifftExample/{DwifftExample => DwifftExample-iOS/Supporting Files}/Info.plist (100%) create mode 100644 DwifftExample/DwifftExamples-macOS/AppDelegate.swift create mode 100644 DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard create mode 100644 DwifftExample/DwifftExamples-macOS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 DwifftExample/DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements create mode 100644 DwifftExample/DwifftExamples-macOS/Supporting Files/Info.plist create mode 100644 DwifftExample/DwifftExamples-macOS/ViewController.swift diff --git a/DwifftExample/DwifftExample/AppDelegate.swift b/DwifftExample/DwifftExample-iOS/AppDelegate.swift similarity index 100% rename from DwifftExample/DwifftExample/AppDelegate.swift rename to DwifftExample/DwifftExample-iOS/AppDelegate.swift diff --git a/DwifftExample/DwifftExample/Base.lproj/LaunchScreen.xib b/DwifftExample/DwifftExample-iOS/Base.lproj/LaunchScreen.xib similarity index 100% rename from DwifftExample/DwifftExample/Base.lproj/LaunchScreen.xib rename to DwifftExample/DwifftExample-iOS/Base.lproj/LaunchScreen.xib diff --git a/DwifftExample/DwifftExample/Base.lproj/Main.storyboard b/DwifftExample/DwifftExample-iOS/Base.lproj/Main.storyboard similarity index 100% rename from DwifftExample/DwifftExample/Base.lproj/Main.storyboard rename to DwifftExample/DwifftExample-iOS/Base.lproj/Main.storyboard diff --git a/DwifftExample/DwifftExample/EventsTableViewController.swift b/DwifftExample/DwifftExample-iOS/EventsTableViewController.swift similarity index 100% rename from DwifftExample/DwifftExample/EventsTableViewController.swift rename to DwifftExample/DwifftExample-iOS/EventsTableViewController.swift diff --git a/DwifftExample/DwifftExample/Stuff.swift b/DwifftExample/DwifftExample-iOS/Stuff.swift similarity index 100% rename from DwifftExample/DwifftExample/Stuff.swift rename to DwifftExample/DwifftExample-iOS/Stuff.swift diff --git a/DwifftExample/DwifftExample/StuffCollectionViewController.swift b/DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift similarity index 100% rename from DwifftExample/DwifftExample/StuffCollectionViewController.swift rename to DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift diff --git a/DwifftExample/DwifftExample/StuffTableViewController.swift b/DwifftExample/DwifftExample-iOS/StuffTableViewController.swift similarity index 100% rename from DwifftExample/DwifftExample/StuffTableViewController.swift rename to DwifftExample/DwifftExample-iOS/StuffTableViewController.swift diff --git a/DwifftExample/DwifftExample/Images.xcassets/AppIcon.appiconset/Contents.json b/DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 68% rename from DwifftExample/DwifftExample/Images.xcassets/AppIcon.appiconset/Contents.json rename to DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json index 118c98f..19882d5 100644 --- a/DwifftExample/DwifftExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,5 +1,15 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", @@ -29,6 +39,11 @@ "idiom" : "iphone", "size" : "60x60", "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/LaunchImage.launchimage/Contents.json b/DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..c5fda8e --- /dev/null +++ b/DwifftExample/DwifftExample-iOS/Supporting Files/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,9 @@ +{ + "images" : [ + + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DwifftExample/DwifftExample/Info.plist b/DwifftExample/DwifftExample-iOS/Supporting Files/Info.plist similarity index 100% rename from DwifftExample/DwifftExample/Info.plist rename to DwifftExample/DwifftExample-iOS/Supporting Files/Info.plist diff --git a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj index b96656e..f92eb73 100644 --- a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj +++ b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj @@ -17,6 +17,12 @@ 0455022B1B898CF000F5614D /* StuffTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0455022A1B898CF000F5614D /* StuffTableViewController.swift */; }; 046EA8A01E8CB1AA00FBD07D /* StuffCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046EA89F1E8CB1AA00FBD07D /* StuffCollectionViewController.swift */; }; 046EA8A31E8CBB9400FBD07D /* Stuff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046EA8A21E8CBB9400FBD07D /* Stuff.swift */; }; + 383AE64D1FADD1AA002B6725 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */; }; + 383AE64F1FADD1AA002B6725 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383AE64E1FADD1AA002B6725 /* ViewController.swift */; }; + 383AE6511FADD1AA002B6725 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 383AE6501FADD1AA002B6725 /* Assets.xcassets */; }; + 383AE6541FADD1AA002B6725 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 383AE6521FADD1AA002B6725 /* Main.storyboard */; }; + 3869E24B1FADD34400D85AA5 /* Dwifft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 383AE65E1FADD1AA002B6725 /* Dwifft.framework */; }; + 3869E24C1FADD34400D85AA5 /* Dwifft.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 383AE65E1FADD1AA002B6725 /* Dwifft.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -48,6 +54,27 @@ remoteGlobalIDString = 041EBB911B89679200E113B3; remoteInfo = Dwifft; }; + 383AE65D1FADD1AA002B6725 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 045502181B898C5400F5614D /* Dwifft.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 382DEF421F487395007A8FD2; + remoteInfo = "Dwifft-macOS"; + }; + 383AE65F1FADD1AA002B6725 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 045502181B898C5400F5614D /* Dwifft.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 38E5B5E21F7BDB5400F33285; + remoteInfo = "DwifftTests-macOS"; + }; + 3869E24D1FADD34400D85AA5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 045502181B898C5400F5614D /* Dwifft.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 382DEF411F487395007A8FD2; + remoteInfo = "Dwifft-macOS"; + }; 931446A91F3CA6FB00471406 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 045502181B898C5400F5614D /* Dwifft.xcodeproj */; @@ -69,11 +96,22 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + 3869E24F1FADD34400D85AA5 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3869E24C1FADD34400D85AA5 /* Dwifft.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0401A2081EA08151003C82E5 /* EventsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsTableViewController.swift; sourceTree = "<group>"; }; - 045501F31B898C3200F5614D /* DwifftExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DwifftExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 045501F31B898C3200F5614D /* DwifftExample-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DwifftExample-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 045501F71B898C3200F5614D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 045501F81B898C3200F5614D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 045501FD1B898C3200F5614D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; @@ -83,6 +121,13 @@ 0455022A1B898CF000F5614D /* StuffTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StuffTableViewController.swift; sourceTree = "<group>"; }; 046EA89F1E8CB1AA00FBD07D /* StuffCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StuffCollectionViewController.swift; sourceTree = "<group>"; }; 046EA8A21E8CBB9400FBD07D /* Stuff.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stuff.swift; sourceTree = "<group>"; }; + 383AE64A1FADD1AA002B6725 /* DwifftExample-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DwifftExample-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; + 383AE64E1FADD1AA002B6725 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; + 383AE6501FADD1AA002B6725 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 383AE6531FADD1AA002B6725 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 383AE6551FADD1AA002B6725 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 383AE6561FADD1AA002B6725 /* DwifftExamples_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DwifftExamples_macOS.entitlements; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -94,6 +139,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 383AE6471FADD1AA002B6725 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3869E24B1FADD34400D85AA5 /* Dwifft.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -101,7 +154,8 @@ isa = PBXGroup; children = ( 045502181B898C5400F5614D /* Dwifft.xcodeproj */, - 045501F51B898C3200F5614D /* DwifftExample */, + 045501F51B898C3200F5614D /* DwifftExample-iOS */, + 383AE64B1FADD1AA002B6725 /* DwifftExamples-macOS */, 045501F41B898C3200F5614D /* Products */, ); sourceTree = "<group>"; @@ -109,12 +163,13 @@ 045501F41B898C3200F5614D /* Products */ = { isa = PBXGroup; children = ( - 045501F31B898C3200F5614D /* DwifftExample.app */, + 045501F31B898C3200F5614D /* DwifftExample-iOS.app */, + 383AE64A1FADD1AA002B6725 /* DwifftExample-macOS.app */, ); name = Products; sourceTree = "<group>"; }; - 045501F51B898C3200F5614D /* DwifftExample */ = { + 045501F51B898C3200F5614D /* DwifftExample-iOS */ = { isa = PBXGroup; children = ( 045501F81B898C3200F5614D /* AppDelegate.swift */, @@ -123,19 +178,19 @@ 0401A2081EA08151003C82E5 /* EventsTableViewController.swift */, 046EA8A21E8CBB9400FBD07D /* Stuff.swift */, 045501FC1B898C3200F5614D /* Main.storyboard */, - 045501FF1B898C3200F5614D /* Images.xcassets */, 045502011B898C3200F5614D /* LaunchScreen.xib */, 045501F61B898C3200F5614D /* Supporting Files */, ); - path = DwifftExample; + path = "DwifftExample-iOS"; sourceTree = "<group>"; }; 045501F61B898C3200F5614D /* Supporting Files */ = { isa = PBXGroup; children = ( + 045501FF1B898C3200F5614D /* Images.xcassets */, 045501F71B898C3200F5614D /* Info.plist */, ); - name = "Supporting Files"; + path = "Supporting Files"; sourceTree = "<group>"; }; 045502191B898C5400F5614D /* Products */ = { @@ -144,16 +199,39 @@ 0455021E1B898C5400F5614D /* Dwifft.framework */, 045502201B898C5400F5614D /* DwifftTests.xctest */, 931446AA1F3CA6FB00471406 /* Dwifft_tvOS.framework */, + 383AE65E1FADD1AA002B6725 /* Dwifft.framework */, + 383AE6601FADD1AA002B6725 /* DwifftTests-macOS.xctest */, ); name = Products; sourceTree = "<group>"; }; + 383AE64B1FADD1AA002B6725 /* DwifftExamples-macOS */ = { + isa = PBXGroup; + children = ( + 383AE6621FADD237002B6725 /* Supporting Files */, + 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */, + 383AE64E1FADD1AA002B6725 /* ViewController.swift */, + 383AE6521FADD1AA002B6725 /* Main.storyboard */, + ); + path = "DwifftExamples-macOS"; + sourceTree = "<group>"; + }; + 383AE6621FADD237002B6725 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 383AE6551FADD1AA002B6725 /* Info.plist */, + 383AE6561FADD1AA002B6725 /* DwifftExamples_macOS.entitlements */, + 383AE6501FADD1AA002B6725 /* Assets.xcassets */, + ); + path = "Supporting Files"; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 045501F21B898C3200F5614D /* DwifftExample */ = { + 045501F21B898C3200F5614D /* DwifftExample-iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 045502121B898C3200F5614D /* Build configuration list for PBXNativeTarget "DwifftExample" */; + buildConfigurationList = 045502121B898C3200F5614D /* Build configuration list for PBXNativeTarget "DwifftExample-iOS" */; buildPhases = ( 045501EF1B898C3200F5614D /* Sources */, 045501F01B898C3200F5614D /* Frameworks */, @@ -166,9 +244,28 @@ 045502221B898C5E00F5614D /* PBXTargetDependency */, 045502261B898C6600F5614D /* PBXTargetDependency */, ); - name = DwifftExample; + name = "DwifftExample-iOS"; productName = DwifftExample; - productReference = 045501F31B898C3200F5614D /* DwifftExample.app */; + productReference = 045501F31B898C3200F5614D /* DwifftExample-iOS.app */; + productType = "com.apple.product-type.application"; + }; + 383AE6491FADD1AA002B6725 /* DwifftExample-macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 383AE6611FADD1AA002B6725 /* Build configuration list for PBXNativeTarget "DwifftExample-macOS" */; + buildPhases = ( + 383AE6461FADD1AA002B6725 /* Sources */, + 383AE6471FADD1AA002B6725 /* Frameworks */, + 383AE6481FADD1AA002B6725 /* Resources */, + 3869E24F1FADD34400D85AA5 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 3869E24E1FADD34400D85AA5 /* PBXTargetDependency */, + ); + name = "DwifftExample-macOS"; + productName = "DwifftExamples-macOS"; + productReference = 383AE64A1FADD1AA002B6725 /* DwifftExample-macOS.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -177,13 +274,17 @@ 045501EB1B898C3200F5614D /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0700; + LastSwiftUpdateCheck = 0910; LastUpgradeCheck = 0900; ORGANIZATIONNAME = jflinter; TargetAttributes = { 045501F21B898C3200F5614D = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; + LastSwiftMigration = 0910; + }; + 383AE6491FADD1AA002B6725 = { + CreatedOnToolsVersion = 9.1; + ProvisioningStyle = Automatic; }; }; }; @@ -206,7 +307,8 @@ ); projectRoot = ""; targets = ( - 045501F21B898C3200F5614D /* DwifftExample */, + 045501F21B898C3200F5614D /* DwifftExample-iOS */, + 383AE6491FADD1AA002B6725 /* DwifftExample-macOS */, ); }; /* End PBXProject section */ @@ -226,6 +328,20 @@ remoteRef = 0455021F1B898C5400F5614D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 383AE65E1FADD1AA002B6725 /* Dwifft.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = Dwifft.framework; + remoteRef = 383AE65D1FADD1AA002B6725 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 383AE6601FADD1AA002B6725 /* DwifftTests-macOS.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "DwifftTests-macOS.xctest"; + remoteRef = 383AE65F1FADD1AA002B6725 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 931446AA1F3CA6FB00471406 /* Dwifft_tvOS.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; @@ -246,6 +362,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 383AE6481FADD1AA002B6725 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 383AE6511FADD1AA002B6725 /* Assets.xcassets in Resources */, + 383AE6541FADD1AA002B6725 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -261,6 +386,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 383AE6461FADD1AA002B6725 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 383AE64F1FADD1AA002B6725 /* ViewController.swift in Sources */, + 383AE64D1FADD1AA002B6725 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -274,6 +408,11 @@ name = Dwifft; targetProxy = 045502251B898C6600F5614D /* PBXContainerItemProxy */; }; + 3869E24E1FADD34400D85AA5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Dwifft-macOS"; + targetProxy = 3869E24D1FADD34400D85AA5 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -293,6 +432,14 @@ name = LaunchScreen.xib; sourceTree = "<group>"; }; + 383AE6521FADD1AA002B6725 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 383AE6531FADD1AA002B6725 /* Base */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -403,12 +550,13 @@ IBC_WARNINGS = NO; IBSC_NOTICES = NO; IBSC_WARNINGS = NO; - INFOPLIST_FILE = DwifftExample/Info.plist; + INFOPLIST_FILE = "DwifftExample-iOS/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -420,12 +568,65 @@ IBC_WARNINGS = NO; IBSC_NOTICES = NO; IBSC_WARNINGS = NO; - INFOPLIST_FILE = DwifftExample/Info.plist; + INFOPLIST_FILE = "DwifftExample-iOS/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 383AE6571FADD1AA002B6725 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = "DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "DwifftExamples-macOS/Supporting Files/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.DwifftExamples-macOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 383AE6581FADD1AA002B6725 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = "DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "DwifftExamples-macOS/Supporting Files/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.DwifftExamples-macOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -441,7 +642,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 045502121B898C3200F5614D /* Build configuration list for PBXNativeTarget "DwifftExample" */ = { + 045502121B898C3200F5614D /* Build configuration list for PBXNativeTarget "DwifftExample-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 045502131B898C3200F5614D /* Debug */, @@ -450,6 +651,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 383AE6611FADD1AA002B6725 /* Build configuration list for PBXNativeTarget "DwifftExample-macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 383AE6571FADD1AA002B6725 /* Debug */, + 383AE6581FADD1AA002B6725 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 045501EB1B898C3200F5614D /* Project object */; diff --git a/DwifftExample/DwifftExamples-macOS/AppDelegate.swift b/DwifftExample/DwifftExamples-macOS/AppDelegate.swift new file mode 100644 index 0000000..1147aa7 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/AppDelegate.swift @@ -0,0 +1,20 @@ +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + +} + diff --git a/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard b/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard new file mode 100644 index 0000000..786bd90 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard @@ -0,0 +1,717 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/> + </dependencies> + <scenes> + <!--Application--> + <scene sceneID="JPo-4y-FX3"> + <objects> + <application id="hnw-xV-0zn" sceneMemberID="viewController"> + <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> + <items> + <menuItem title="DwifftExamples-macOS" id="1Xt-HY-uBw"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="DwifftExamples-macOS" systemMenu="apple" id="uQy-DD-JDr"> + <items> + <menuItem title="About DwifftExamples-macOS" id="5kV-Vb-QxS"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> + <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/> + <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> + <menuItem title="Services" id="NMo-om-nkz"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> + </menuItem> + <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> + <menuItem title="Hide DwifftExamples-macOS" keyEquivalent="h" id="Olw-nP-bQN"> + <connections> + <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/> + </connections> + </menuItem> + <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/> + </connections> + </menuItem> + <menuItem title="Show All" id="Kd2-mp-pUS"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> + <menuItem title="Quit DwifftExamples-macOS" keyEquivalent="q" id="4sb-4s-VLi"> + <connections> + <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="File" id="dMs-cI-mzQ"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="File" id="bib-Uj-vzu"> + <items> + <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"> + <connections> + <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/> + </connections> + </menuItem> + <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9"> + <connections> + <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/> + </connections> + </menuItem> + <menuItem title="Open Recent" id="tXI-mr-wws"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ"> + <items> + <menuItem title="Clear Menu" id="vNY-rz-j42"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/> + <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"> + <connections> + <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/> + </connections> + </menuItem> + <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV"> + <connections> + <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/> + </connections> + </menuItem> + <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A"> + <connections> + <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/> + </connections> + </menuItem> + <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H"> + <connections> + <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/> + <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK"> + <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/> + <connections> + <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/> + </connections> + </menuItem> + <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS"> + <connections> + <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Edit" id="5QF-Oa-p0T"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Edit" id="W48-6f-4Dl"> + <items> + <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> + <connections> + <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/> + </connections> + </menuItem> + <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> + <connections> + <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> + <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> + <connections> + <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/> + </connections> + </menuItem> + <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> + <connections> + <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/> + </connections> + </menuItem> + <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> + <connections> + <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/> + </connections> + </menuItem> + <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/> + </connections> + </menuItem> + <menuItem title="Delete" id="pa3-QI-u2k"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/> + </connections> + </menuItem> + <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> + <connections> + <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> + <menuItem title="Find" id="4EN-yA-p0u"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Find" id="1b7-l0-nxx"> + <items> + <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> + <connections> + <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/> + </connections> + </menuItem> + <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/> + </connections> + </menuItem> + <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> + <connections> + <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/> + </connections> + </menuItem> + <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> + <connections> + <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/> + </connections> + </menuItem> + <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> + <connections> + <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/> + </connections> + </menuItem> + <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> + <connections> + <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> + <items> + <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> + <connections> + <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/> + </connections> + </menuItem> + <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> + <connections> + <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> + <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/> + </connections> + </menuItem> + <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/> + </connections> + </menuItem> + <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Substitutions" id="9ic-FL-obx"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> + <items> + <menuItem title="Show Substitutions" id="z6F-FW-3nz"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> + <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/> + </connections> + </menuItem> + <menuItem title="Smart Quotes" id="hQb-2v-fYv"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/> + </connections> + </menuItem> + <menuItem title="Smart Dashes" id="rgM-f4-ycn"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/> + </connections> + </menuItem> + <menuItem title="Smart Links" id="cwL-P1-jid"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/> + </connections> + </menuItem> + <menuItem title="Data Detectors" id="tRr-pd-1PS"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/> + </connections> + </menuItem> + <menuItem title="Text Replacement" id="HFQ-gK-NFA"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Transformations" id="2oI-Rn-ZJC"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Transformations" id="c8a-y6-VQd"> + <items> + <menuItem title="Make Upper Case" id="vmV-6d-7jI"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/> + </connections> + </menuItem> + <menuItem title="Make Lower Case" id="d9M-CD-aMd"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/> + </connections> + </menuItem> + <menuItem title="Capitalize" id="UEZ-Bs-lqG"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Speech" id="xrE-MZ-jX0"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Speech" id="3rS-ZA-NoH"> + <items> + <menuItem title="Start Speaking" id="Ynk-f8-cLZ"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/> + </connections> + </menuItem> + <menuItem title="Stop Speaking" id="Oyz-dy-DGm"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Format" id="jxT-CU-nIS"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Format" id="GEO-Iw-cKr"> + <items> + <menuItem title="Font" id="Gi5-1S-RQB"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq"> + <items> + <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"> + <connections> + <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/> + </connections> + </menuItem> + <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"> + <connections> + <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/> + </connections> + </menuItem> + <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"> + <connections> + <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/> + </connections> + </menuItem> + <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S"> + <connections> + <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/> + <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"> + <connections> + <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/> + </connections> + </menuItem> + <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"> + <connections> + <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/> + <menuItem title="Kern" id="jBQ-r6-VK2"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Kern" id="tlD-Oa-oAM"> + <items> + <menuItem title="Use Default" id="GUa-eO-cwY"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/> + </connections> + </menuItem> + <menuItem title="Use None" id="cDB-IK-hbR"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/> + </connections> + </menuItem> + <menuItem title="Tighten" id="46P-cB-AYj"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/> + </connections> + </menuItem> + <menuItem title="Loosen" id="ogc-rX-tC1"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Ligatures" id="o6e-r0-MWq"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Ligatures" id="w0m-vy-SC9"> + <items> + <menuItem title="Use Default" id="agt-UL-0e3"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/> + </connections> + </menuItem> + <menuItem title="Use None" id="J7y-lM-qPV"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/> + </connections> + </menuItem> + <menuItem title="Use All" id="xQD-1f-W4t"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Baseline" id="OaQ-X3-Vso"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Baseline" id="ijk-EB-dga"> + <items> + <menuItem title="Use Default" id="3Om-Ey-2VK"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/> + </connections> + </menuItem> + <menuItem title="Superscript" id="Rqc-34-cIF"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/> + </connections> + </menuItem> + <menuItem title="Subscript" id="I0S-gh-46l"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/> + </connections> + </menuItem> + <menuItem title="Raise" id="2h7-ER-AoG"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/> + </connections> + </menuItem> + <menuItem title="Lower" id="1tx-W0-xDw"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/> + <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk"> + <connections> + <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/> + <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/> + </connections> + </menuItem> + <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Text" id="Fal-I4-PZk"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Text" id="d9c-me-L2H"> + <items> + <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1"> + <connections> + <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/> + </connections> + </menuItem> + <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb"> + <connections> + <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/> + </connections> + </menuItem> + <menuItem title="Justify" id="J5U-5w-g23"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/> + </connections> + </menuItem> + <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4"> + <connections> + <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/> + <menuItem title="Writing Direction" id="H1b-Si-o9J"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd"> + <items> + <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH"> + <modifierMask key="keyEquivalentModifierMask"/> + </menuItem> + <menuItem id="YGs-j5-SAR"> + <string key="title"> Default</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/> + </connections> + </menuItem> + <menuItem id="Lbh-J2-qVU"> + <string key="title"> Left to Right</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/> + </connections> + </menuItem> + <menuItem id="jFq-tB-4Kx"> + <string key="title"> Right to Left</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="swp-gr-a21"/> + <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA"> + <modifierMask key="keyEquivalentModifierMask"/> + </menuItem> + <menuItem id="Nop-cj-93Q"> + <string key="title"> Default</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/> + </connections> + </menuItem> + <menuItem id="BgM-ve-c93"> + <string key="title"> Left to Right</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/> + </connections> + </menuItem> + <menuItem id="RB4-Sm-HuC"> + <string key="title"> Right to Left</string> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/> + <menuItem title="Show Ruler" id="vLm-3I-IUL"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/> + </connections> + </menuItem> + <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5"> + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> + <connections> + <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/> + </connections> + </menuItem> + <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI"> + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> + <connections> + <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="View" id="H8h-7b-M4v"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="View" id="HyV-fh-RgO"> + <items> + <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/> + </connections> + </menuItem> + <menuItem title="Customize Toolbar…" id="1UK-8n-QPP"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/> + <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE"> + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> + <connections> + <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/> + </connections> + </menuItem> + <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> + <connections> + <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Window" id="aUF-d1-5bR"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> + <items> + <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> + <connections> + <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/> + </connections> + </menuItem> + <menuItem title="Zoom" id="R4o-n2-Eq4"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> + <menuItem title="Bring All to Front" id="LE2-aR-0XJ"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Help" id="wpr-3q-Mcd"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> + <items> + <menuItem title="DwifftExamples-macOS Help" keyEquivalent="?" id="FKE-Sm-Kum"> + <connections> + <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + </items> + </menu> + <connections> + <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/> + </connections> + </application> + <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target"/> + <customObject id="YLy-65-1bz" customClass="NSFontManager"/> + <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="75" y="0.0"/> + </scene> + <!--Window Controller--> + <scene sceneID="R2V-B0-nI4"> + <objects> + <windowController id="B8D-0N-5wS" sceneMemberID="viewController"> + <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> + <rect key="contentRect" x="196" y="240" width="480" height="270"/> + <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> + <connections> + <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> + </connections> + </window> + <connections> + <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/> + </connections> + </windowController> + <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="75" y="250"/> + </scene> + <!--View Controller--> + <scene sceneID="hIz-AP-VOD"> + <objects> + <viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController"> + <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> + <rect key="frame" x="0.0" y="0.0" width="480" height="270"/> + <autoresizingMask key="autoresizingMask"/> + </view> + </viewController> + <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="75" y="655"/> + </scene> + </scenes> +</document> diff --git a/DwifftExample/DwifftExamples-macOS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json b/DwifftExample/DwifftExamples-macOS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DwifftExample/DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements b/DwifftExample/DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements new file mode 100644 index 0000000..f2ef3ae --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/Supporting Files/DwifftExamples_macOS.entitlements @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.app-sandbox</key> + <true/> + <key>com.apple.security.files.user-selected.read-only</key> + <true/> +</dict> +</plist> diff --git a/DwifftExample/DwifftExamples-macOS/Supporting Files/Info.plist b/DwifftExample/DwifftExamples-macOS/Supporting Files/Info.plist new file mode 100644 index 0000000..44e2f49 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/Supporting Files/Info.plist @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSMinimumSystemVersion</key> + <string>$(MACOSX_DEPLOYMENT_TARGET)</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2017 jflinter. All rights reserved.</string> + <key>NSMainStoryboardFile</key> + <string>Main</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> +</dict> +</plist> diff --git a/DwifftExample/DwifftExamples-macOS/ViewController.swift b/DwifftExample/DwifftExamples-macOS/ViewController.swift new file mode 100644 index 0000000..b99a9d0 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/ViewController.swift @@ -0,0 +1,21 @@ +// + +import Cocoa + +class ViewController: NSViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. + } + } + + +} + From 7c8b0aa7250f0a91c84f5f768617445c203be650 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sun, 5 Nov 2017 13:24:13 +0000 Subject: [PATCH 29/48] adjust section index when inserting beyond collectionView.numberOfSections --- Dwifft/Dwifft+AppKit.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Dwifft/Dwifft+AppKit.swift b/Dwifft/Dwifft+AppKit.swift index 21d4e34..27f76c5 100644 --- a/Dwifft/Dwifft+AppKit.swift +++ b/Dwifft/Dwifft+AppKit.swift @@ -146,7 +146,14 @@ public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equat case let .delete(section, item, _): collectionView.deleteItems(at: [IndexPath(item: item, section: section)]) case let .insert(section, item, _): collectionView.insertItems(at: [IndexPath(item: item, section: section)]) case let .sectionDelete(section, _): collectionView.deleteSections(IndexSet(integer: section)) - case let .sectionInsert(section, _): collectionView.insertSections(IndexSet(integer: section)) + case let .sectionInsert(section, _): + // NSCollectionViews don't seem to like it when inserting sections beyond numberOfSections + // so adjust for that + if section > collectionView.numberOfSections { + collectionView.insertSections(IndexSet(integer: collectionView.numberOfSections)) + } else { + collectionView.insertSections(IndexSet(integer: section)) + } } } }, completionHandler: nil) From 784f7de213f6d945743db7bb5548e04118dd65ca Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sun, 5 Nov 2017 13:24:57 +0000 Subject: [PATCH 30/48] macOS example --- .../DwifftExample.xcodeproj/project.pbxproj | 36 ++- .../Base.lproj/Main.storyboard | 205 ++++++++++++++++-- .../StuffCollectionHeaderView.xib | 39 ++++ .../StuffCollectionViewController.swift | 69 ++++++ .../StuffCollectionViewItem.swift | 3 + .../StuffCollectionViewItem.xib | 39 ++++ .../StuffTableViewController.swift | 46 ++++ .../DwifftExamples-macOS/ViewController.swift | 21 -- .../{DwifftExample-iOS => Shared}/Stuff.swift | 6 + 9 files changed, 423 insertions(+), 41 deletions(-) create mode 100644 DwifftExample/DwifftExamples-macOS/StuffCollectionHeaderView.xib create mode 100644 DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift create mode 100644 DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.swift create mode 100644 DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.xib create mode 100644 DwifftExample/DwifftExamples-macOS/StuffTableViewController.swift delete mode 100644 DwifftExample/DwifftExamples-macOS/ViewController.swift rename DwifftExample/{DwifftExample-iOS => Shared}/Stuff.swift (93%) diff --git a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj index f92eb73..a1c0d9f 100644 --- a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj +++ b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj @@ -18,11 +18,16 @@ 046EA8A01E8CB1AA00FBD07D /* StuffCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046EA89F1E8CB1AA00FBD07D /* StuffCollectionViewController.swift */; }; 046EA8A31E8CBB9400FBD07D /* Stuff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046EA8A21E8CBB9400FBD07D /* Stuff.swift */; }; 383AE64D1FADD1AA002B6725 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */; }; - 383AE64F1FADD1AA002B6725 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383AE64E1FADD1AA002B6725 /* ViewController.swift */; }; + 383AE64F1FADD1AA002B6725 /* StuffTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383AE64E1FADD1AA002B6725 /* StuffTableViewController.swift */; }; 383AE6511FADD1AA002B6725 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 383AE6501FADD1AA002B6725 /* Assets.xcassets */; }; 383AE6541FADD1AA002B6725 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 383AE6521FADD1AA002B6725 /* Main.storyboard */; }; 3869E24B1FADD34400D85AA5 /* Dwifft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 383AE65E1FADD1AA002B6725 /* Dwifft.framework */; }; 3869E24C1FADD34400D85AA5 /* Dwifft.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 383AE65E1FADD1AA002B6725 /* Dwifft.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 3869E2561FADD5E000D85AA5 /* Stuff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 046EA8A21E8CBB9400FBD07D /* Stuff.swift */; }; + 388BB5361FAE0C2200F2952D /* StuffCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388BB5351FAE0C2200F2952D /* StuffCollectionViewController.swift */; }; + 38B70D321FAF328C0049AEA1 /* StuffCollectionViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 38B70D311FAF328C0049AEA1 /* StuffCollectionViewItem.xib */; }; + 38B70D371FAF32DB0049AEA1 /* StuffCollectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 38B70D361FAF32DB0049AEA1 /* StuffCollectionHeaderView.xib */; }; + 38B70D391FAF33E70049AEA1 /* StuffCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38B70D381FAF33E70049AEA1 /* StuffCollectionViewItem.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -123,11 +128,15 @@ 046EA8A21E8CBB9400FBD07D /* Stuff.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stuff.swift; sourceTree = "<group>"; }; 383AE64A1FADD1AA002B6725 /* DwifftExample-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DwifftExample-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; - 383AE64E1FADD1AA002B6725 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; + 383AE64E1FADD1AA002B6725 /* StuffTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StuffTableViewController.swift; sourceTree = "<group>"; }; 383AE6501FADD1AA002B6725 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 383AE6531FADD1AA002B6725 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; 383AE6551FADD1AA002B6725 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 383AE6561FADD1AA002B6725 /* DwifftExamples_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DwifftExamples_macOS.entitlements; sourceTree = "<group>"; }; + 388BB5351FAE0C2200F2952D /* StuffCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StuffCollectionViewController.swift; sourceTree = "<group>"; }; + 38B70D311FAF328C0049AEA1 /* StuffCollectionViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StuffCollectionViewItem.xib; sourceTree = "<group>"; }; + 38B70D361FAF32DB0049AEA1 /* StuffCollectionHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StuffCollectionHeaderView.xib; sourceTree = "<group>"; }; + 38B70D381FAF33E70049AEA1 /* StuffCollectionViewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StuffCollectionViewItem.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -154,6 +163,7 @@ isa = PBXGroup; children = ( 045502181B898C5400F5614D /* Dwifft.xcodeproj */, + 3869E2551FADD5B600D85AA5 /* Shared */, 045501F51B898C3200F5614D /* DwifftExample-iOS */, 383AE64B1FADD1AA002B6725 /* DwifftExamples-macOS */, 045501F41B898C3200F5614D /* Products */, @@ -176,7 +186,6 @@ 0455022A1B898CF000F5614D /* StuffTableViewController.swift */, 046EA89F1E8CB1AA00FBD07D /* StuffCollectionViewController.swift */, 0401A2081EA08151003C82E5 /* EventsTableViewController.swift */, - 046EA8A21E8CBB9400FBD07D /* Stuff.swift */, 045501FC1B898C3200F5614D /* Main.storyboard */, 045502011B898C3200F5614D /* LaunchScreen.xib */, 045501F61B898C3200F5614D /* Supporting Files */, @@ -210,8 +219,12 @@ children = ( 383AE6621FADD237002B6725 /* Supporting Files */, 383AE64C1FADD1AA002B6725 /* AppDelegate.swift */, - 383AE64E1FADD1AA002B6725 /* ViewController.swift */, + 383AE64E1FADD1AA002B6725 /* StuffTableViewController.swift */, + 388BB5351FAE0C2200F2952D /* StuffCollectionViewController.swift */, 383AE6521FADD1AA002B6725 /* Main.storyboard */, + 38B70D311FAF328C0049AEA1 /* StuffCollectionViewItem.xib */, + 38B70D361FAF32DB0049AEA1 /* StuffCollectionHeaderView.xib */, + 38B70D381FAF33E70049AEA1 /* StuffCollectionViewItem.swift */, ); path = "DwifftExamples-macOS"; sourceTree = "<group>"; @@ -226,6 +239,14 @@ path = "Supporting Files"; sourceTree = "<group>"; }; + 3869E2551FADD5B600D85AA5 /* Shared */ = { + isa = PBXGroup; + children = ( + 046EA8A21E8CBB9400FBD07D /* Stuff.swift */, + ); + path = Shared; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -368,6 +389,8 @@ files = ( 383AE6511FADD1AA002B6725 /* Assets.xcassets in Resources */, 383AE6541FADD1AA002B6725 /* Main.storyboard in Resources */, + 38B70D321FAF328C0049AEA1 /* StuffCollectionViewItem.xib in Resources */, + 38B70D371FAF32DB0049AEA1 /* StuffCollectionHeaderView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -390,8 +413,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 383AE64F1FADD1AA002B6725 /* ViewController.swift in Sources */, + 383AE64F1FADD1AA002B6725 /* StuffTableViewController.swift in Sources */, + 38B70D391FAF33E70049AEA1 /* StuffCollectionViewItem.swift in Sources */, + 388BB5361FAE0C2200F2952D /* StuffCollectionViewController.swift in Sources */, 383AE64D1FADD1AA002B6725 /* AppDelegate.swift in Sources */, + 3869E2561FADD5E000D85AA5 /* Stuff.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard b/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard index 786bd90..e5f6978 100644 --- a/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard +++ b/DwifftExample/DwifftExamples-macOS/Base.lproj/Main.storyboard @@ -1,7 +1,9 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/> + <deployment identifier="macosx"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> <!--Application--> @@ -673,7 +675,7 @@ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/> </connections> </application> - <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target"/> + <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="DwifftExample_macOS" customModuleProvider="target"/> <customObject id="YLy-65-1bz" customClass="NSFontManager"/> <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> </objects> @@ -683,35 +685,208 @@ <scene sceneID="R2V-B0-nI4"> <objects> <windowController id="B8D-0N-5wS" sceneMemberID="viewController"> - <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> + <window key="window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" titlebarAppearsTransparent="YES" titleVisibility="hidden" id="IQv-IB-iLA"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> - <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <rect key="contentRect" x="196" y="240" width="480" height="270"/> <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> - <connections> + <connections> <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> </connections> </window> <connections> - <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/> + <segue destination="1vE-e5-vPF" kind="relationship" relationship="window.shadowedContentViewController" id="QpG-rW-KO9"/> </connections> </windowController> <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="75" y="250"/> </scene> - <!--View Controller--> - <scene sceneID="hIz-AP-VOD"> + <!--Tab View Controller--> + <scene sceneID="C9Y-hy-t4v"> <objects> - <viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController"> - <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> - <rect key="frame" x="0.0" y="0.0" width="480" height="270"/> + <tabViewController selectedTabViewItemIndex="1" id="1vE-e5-vPF" sceneMemberID="viewController"> + <tabViewItems> + <tabViewItem label="Table" identifier="" id="BEc-Vo-WXE"/> + <tabViewItem label="Collection" identifier="" id="mpK-w8-Zbh"/> + </tabViewItems> + <tabView key="tabView" type="noTabsNoBorder" id="uPM-IG-FJw"> + <rect key="frame" x="1" y="0.0" width="479" height="300"/> <autoresizingMask key="autoresizingMask"/> + <font key="font" metaFont="message"/> + <tabViewItems/> + <connections> + <outlet property="delegate" destination="1vE-e5-vPF" id="WyC-Z8-NqD"/> + </connections> + </tabView> + <connections> + <outlet property="tabView" destination="uPM-IG-FJw" id="Y4H-FZ-7d9"/> + <segue destination="NO0-Lb-Myr" kind="relationship" relationship="tabItems" id="9V5-Z9-Fcl"/> + <segue destination="D4b-NX-Tgs" kind="relationship" relationship="tabItems" id="k2n-Po-Mig"/> + </connections> + </tabViewController> + <customObject id="FK4-eL-cge" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="76" y="731"/> + </scene> + <!--Stuff Table View Controller--> + <scene sceneID="Zcc-mP-2lQ"> + <objects> + <viewController id="NO0-Lb-Myr" customClass="StuffTableViewController" customModule="DwifftExample_macOS" customModuleProvider="target" sceneMemberID="viewController"> + <view key="view" id="4GF-HL-GiL"> + <rect key="frame" x="0.0" y="0.0" width="452" height="300"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="148-Wq-1BV"> + <rect key="frame" x="20" y="61" width="412" height="219"/> + <clipView key="contentView" id="laV-7c-1ce"> + <rect key="frame" x="1" y="1" width="410" height="217"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" id="GQD-JO-4SI"> + <rect key="frame" x="0.0" y="0.0" width="410" height="217"/> + <autoresizingMask key="autoresizingMask"/> + <size key="intercellSpacing" width="3" height="2"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> + <tableColumns> + <tableColumn identifier="" width="407" minWidth="40" maxWidth="1000" id="cqv-5U-hYF"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Item"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="xYB-Ls-7J8"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + <prototypeCellViews> + <tableCellView identifier="itemCell" id="NW6-Oe-6lP"> + <rect key="frame" x="1" y="1" width="407" height="17"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oox-rg-dVZ"> + <rect key="frame" x="0.0" y="0.0" width="407" height="17"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="WPD-3O-dyV"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <connections> + <outlet property="textField" destination="oox-rg-dVZ" id="Qm4-IV-qeV"/> + </connections> + </tableCellView> + </prototypeCellViews> + </tableColumn> + </tableColumns> + </tableView> + </subviews> + </clipView> + <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="NmN-wb-aEl"> + <rect key="frame" x="1" y="202" width="408" height="16"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="efU-OM-CWa"> + <rect key="frame" x="224" y="17" width="15" height="102"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + </scrollView> + <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ieA-Rb-fol"> + <rect key="frame" x="354" y="13" width="84" height="32"/> + <buttonCell key="cell" type="push" title="Shuffle" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XFi-bw-0AY"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="shuffle:" target="NO0-Lb-Myr" id="Y9Y-84-VLz"/> + </connections> + </button> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="ieA-Rb-fol" secondAttribute="bottom" constant="20" id="0t3-87-QTG"/> + <constraint firstItem="148-Wq-1BV" firstAttribute="leading" secondItem="4GF-HL-GiL" secondAttribute="leading" constant="20" id="6J6-Lf-WjB"/> + <constraint firstAttribute="bottom" secondItem="148-Wq-1BV" secondAttribute="bottom" constant="61" id="IKB-5D-Ncd"/> + <constraint firstAttribute="trailing" secondItem="ieA-Rb-fol" secondAttribute="trailing" constant="20" id="drS-U1-GQx"/> + <constraint firstItem="ieA-Rb-fol" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="4GF-HL-GiL" secondAttribute="leading" constant="20" symbolic="YES" id="i6t-3p-WrW"/> + <constraint firstItem="148-Wq-1BV" firstAttribute="top" secondItem="4GF-HL-GiL" secondAttribute="top" constant="20" id="jX9-td-fXH"/> + <constraint firstAttribute="trailing" secondItem="148-Wq-1BV" secondAttribute="trailing" constant="20" id="sN1-cA-JdP"/> + </constraints> </view> + <connections> + <outlet property="tableView" destination="GQD-JO-4SI" id="2ee-YP-rdv"/> + </connections> + </viewController> + <customObject id="eBl-L0-ols" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="730" y="543"/> + </scene> + <!--Stuff Collection View Controller--> + <scene sceneID="Lwg-Tq-ZqY"> + <objects> + <viewController id="D4b-NX-Tgs" customClass="StuffCollectionViewController" customModule="DwifftExample_macOS" customModuleProvider="target" sceneMemberID="viewController"> + <view key="view" id="jFT-PR-U1p"> + <rect key="frame" x="0.0" y="0.0" width="450" height="300"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <scrollView wantsLayer="YES" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vap-vo-g3h"> + <rect key="frame" x="20" y="61" width="410" height="219"/> + <clipView key="contentView" drawsBackground="NO" id="egF-wW-jbh"> + <rect key="frame" x="1" y="1" width="408" height="217"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <collectionView id="zFa-bq-fRd"> + <rect key="frame" x="0.0" y="0.0" width="408" height="158"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES"/> + <collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="10" minimumLineSpacing="10" id="INc-yc-TRN"> + <size key="itemSize" width="60" height="60"/> + <size key="headerReferenceSize" width="50" height="50"/> + </collectionViewFlowLayout> + <color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </collectionView> + </subviews> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </clipView> + <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Mki-xa-dNm"> + <rect key="frame" x="1" y="144" width="233" height="15"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="qY5-WD-sTp"> + <rect key="frame" x="234" y="1" width="15" height="143"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + </scrollView> + <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="16r-of-nPT"> + <rect key="frame" x="352" y="13" width="84" height="32"/> + <buttonCell key="cell" type="push" title="Shuffle" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WVI-bb-vEo"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="shuffle:" target="D4b-NX-Tgs" id="r2H-PH-ItM"/> + </connections> + </button> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="Vap-vo-g3h" secondAttribute="bottom" constant="61" id="1fE-Ac-wTQ"/> + <constraint firstAttribute="bottom" secondItem="16r-of-nPT" secondAttribute="bottom" constant="20" id="2gu-c0-krn"/> + <constraint firstItem="Vap-vo-g3h" firstAttribute="leading" secondItem="jFT-PR-U1p" secondAttribute="leading" constant="20" id="5l3-GI-vHU"/> + <constraint firstItem="16r-of-nPT" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="jFT-PR-U1p" secondAttribute="leading" constant="20" symbolic="YES" id="aAR-zP-Zrj"/> + <constraint firstAttribute="trailing" secondItem="Vap-vo-g3h" secondAttribute="trailing" constant="20" id="aKp-4z-2mV"/> + <constraint firstAttribute="trailing" secondItem="16r-of-nPT" secondAttribute="trailing" constant="20" id="jna-g3-rQG"/> + <constraint firstItem="Vap-vo-g3h" firstAttribute="top" secondItem="jFT-PR-U1p" secondAttribute="top" constant="20" id="pQ1-PA-KAD"/> + </constraints> + </view> + <connections> + <outlet property="collectionView" destination="zFa-bq-fRd" id="ODf-gD-YEa"/> + </connections> </viewController> - <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> + <customObject id="BTX-cg-Lsx" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> </objects> - <point key="canvasLocation" x="75" y="655"/> + <point key="canvasLocation" x="730" y="918"/> </scene> </scenes> </document> diff --git a/DwifftExample/DwifftExamples-macOS/StuffCollectionHeaderView.xib b/DwifftExample/DwifftExamples-macOS/StuffCollectionHeaderView.xib new file mode 100644 index 0000000..9c82bdc --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/StuffCollectionHeaderView.xib @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> + <dependencies> + <deployment identifier="macosx"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + <capability name="system font weights other than Regular or Bold" minToolsVersion="7.0"/> + </dependencies> + <objects> + <customObject id="-2" userLabel="File's Owner"/> + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> + <customObject id="-3" userLabel="Application" customClass="NSObject"/> + <customView id="c22-O7-iKe" customClass="StuffCollectionHeaderView" customModule="DwifftExample_macOS" customModuleProvider="target"> + <rect key="frame" x="0.0" y="0.0" width="480" height="34"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <subviews> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ehT-LL-UG8"> + <rect key="frame" x="220" y="8" width="40" height="18"/> + <constraints> + <constraint firstAttribute="height" constant="18" id="viC-5X-w9G"/> + </constraints> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="bBz-Tm-jfv"> + <font key="font" metaFont="systemMedium" size="14"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <constraints> + <constraint firstItem="ehT-LL-UG8" firstAttribute="centerY" secondItem="c22-O7-iKe" secondAttribute="centerY" id="IPY-GS-NE6"/> + <constraint firstItem="ehT-LL-UG8" firstAttribute="centerX" secondItem="c22-O7-iKe" secondAttribute="centerX" id="SKR-Qj-9U9"/> + </constraints> + <connections> + <outlet property="title" destination="ehT-LL-UG8" id="fTw-ZX-hqG"/> + </connections> + <point key="canvasLocation" x="139" y="211"/> + </customView> + </objects> +</document> diff --git a/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift new file mode 100644 index 0000000..49ab94d --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift @@ -0,0 +1,69 @@ +import Cocoa +import Dwifft + +final class StuffCollectionViewController: NSViewController { + + @IBOutlet weak var collectionView: NSCollectionView! + + let itemIdentifier: NSUserInterfaceItemIdentifier = NSUserInterfaceItemIdentifier("emojiItem") + let headerIdentifier: NSUserInterfaceItemIdentifier = NSUserInterfaceItemIdentifier("sectionHeader") + var diffCalculator: CollectionViewDiffCalculator<String, String>? + var stuff: SectionedValues<String, String> = Stuff.emojiStuff() { + // So, whenever your datasource's array of things changes, just let the diffCalculator know and it'll do the rest. + didSet { + self.diffCalculator?.sectionedValues = stuff + } + } + + override func viewDidLoad() { + super.viewDidLoad() + collectionView.dataSource = self + diffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: stuff) + + let itemNib = NSNib(nibNamed: NSNib.Name(rawValue: "StuffCollectionViewItem"), bundle: nil) + collectionView.register(itemNib, forItemWithIdentifier: itemIdentifier) + + let headerNib = NSNib(nibNamed: NSNib.Name(rawValue: "StuffCollectionHeaderView"), bundle: nil) + collectionView.register(headerNib, forSupplementaryViewOfKind: .sectionHeader, withIdentifier: headerIdentifier) + } + + @IBAction func shuffle(_ sender: NSButton) { + self.stuff = Stuff.emojiStuff() + } +} + +extension StuffCollectionViewController: NSCollectionViewDataSource { + func numberOfSections(in collectionView: NSCollectionView) -> Int { + return diffCalculator?.numberOfSections() ?? 0 + } + + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { + return diffCalculator?.numberOfObjects(inSection: section) ?? 0 + } + + func collectionView(_ collectionView: NSCollectionView, + viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, + at indexPath: IndexPath) -> NSView { + let header = collectionView.makeSupplementaryView(ofKind: .sectionHeader, withIdentifier: headerIdentifier, for: indexPath) + + if let dc = diffCalculator, let stuffHeader = header as? StuffCollectionHeaderView { + stuffHeader.title.stringValue = dc.value(forSection: indexPath.section) + } + + return header + } + + func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { + let item = collectionView.makeItem(withIdentifier: itemIdentifier, for: indexPath) + + if let dc = diffCalculator, let emojiItem = item as? StuffCollectionViewItem { + emojiItem.textField?.stringValue = dc.value(atIndexPath: indexPath) + } + + return item + } +} + +final class StuffCollectionHeaderView: NSView { + @IBOutlet weak var title: NSTextField! +} diff --git a/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.swift b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.swift new file mode 100644 index 0000000..c1e9998 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.swift @@ -0,0 +1,3 @@ +import Cocoa + +final class StuffCollectionViewItem: NSCollectionViewItem { } diff --git a/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.xib b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.xib new file mode 100644 index 0000000..6b8aa93 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewItem.xib @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> + <dependencies> + <deployment identifier="macosx"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13529"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <objects> + <customObject id="-2" userLabel="File's Owner"/> + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> + <customObject id="-3" userLabel="Application" customClass="NSObject"/> + <customView id="c22-O7-iKe"> + <rect key="frame" x="0.0" y="0.0" width="480" height="61"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <subviews> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aMz-N2-Abt"> + <rect key="frame" x="3" y="5" width="474" height="51"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Label" id="xaJ-Dv-YOV"> + <font key="font" metaFont="system" size="42"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <constraints> + <constraint firstAttribute="bottom" secondItem="aMz-N2-Abt" secondAttribute="bottom" constant="5" id="31x-s3-cuB"/> + <constraint firstAttribute="trailing" secondItem="aMz-N2-Abt" secondAttribute="trailing" constant="5" id="Dqo-8T-Le8"/> + <constraint firstItem="aMz-N2-Abt" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" constant="5" id="k8O-oW-Bfb"/> + <constraint firstItem="aMz-N2-Abt" firstAttribute="top" secondItem="c22-O7-iKe" secondAttribute="top" constant="5" id="qip-ih-g1a"/> + </constraints> + </customView> + <collectionViewItem id="U4V-H6-ESQ" customClass="StuffCollectionViewItem" customModule="DwifftExample_macOS" customModuleProvider="target"> + <connections> + <outlet property="textField" destination="aMz-N2-Abt" id="83J-A6-7Bp"/> + <outlet property="view" destination="c22-O7-iKe" id="tA2-J5-gac"/> + </connections> + </collectionViewItem> + </objects> +</document> diff --git a/DwifftExample/DwifftExamples-macOS/StuffTableViewController.swift b/DwifftExample/DwifftExamples-macOS/StuffTableViewController.swift new file mode 100644 index 0000000..ef60278 --- /dev/null +++ b/DwifftExample/DwifftExamples-macOS/StuffTableViewController.swift @@ -0,0 +1,46 @@ +import Cocoa +import Dwifft + +final class StuffTableViewController: NSViewController { + + @IBOutlet weak var tableView: NSTableView! + + let itemIdentifier: NSUserInterfaceItemIdentifier = NSUserInterfaceItemIdentifier("itemCell") + var diffCalculator: TableViewDiffCalculator<String>? + var stuff: [String] = Stuff.onlyWordItems() { + // So, whenever your datasource's array of things changes, just let the diffCalculator know and it'll do the rest. + didSet { + self.diffCalculator?.rows = stuff + } + } + + @IBAction func shuffle(_ sender: NSButton) { + self.stuff = Stuff.onlyWordItems() + } + + override func viewDidLoad() { + super.viewDidLoad() + diffCalculator = TableViewDiffCalculator(tableView: tableView, initialRows: stuff, sectionIndex: 1) + tableView.delegate = self + tableView.dataSource = self + } +} + +extension StuffTableViewController: NSTableViewDataSource { + func numberOfRows(in tableView: NSTableView) -> Int { + return diffCalculator?.rows.count ?? 0 + } +} + +extension StuffTableViewController: NSTableViewDelegate { + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + guard + let item = tableView.makeView(withIdentifier: itemIdentifier, owner: nil) as? NSTableCellView, + let word = diffCalculator?.rows[row] + else { + return nil + } + item.textField?.stringValue = word + return item + } +} diff --git a/DwifftExample/DwifftExamples-macOS/ViewController.swift b/DwifftExample/DwifftExamples-macOS/ViewController.swift deleted file mode 100644 index b99a9d0..0000000 --- a/DwifftExample/DwifftExamples-macOS/ViewController.swift +++ /dev/null @@ -1,21 +0,0 @@ -// - -import Cocoa - -class ViewController: NSViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - } - - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } - } - - -} - diff --git a/DwifftExample/DwifftExample-iOS/Stuff.swift b/DwifftExample/Shared/Stuff.swift similarity index 93% rename from DwifftExample/DwifftExample-iOS/Stuff.swift rename to DwifftExample/Shared/Stuff.swift index 4b106b3..78646b3 100644 --- a/DwifftExample/DwifftExample-iOS/Stuff.swift +++ b/DwifftExample/Shared/Stuff.swift @@ -6,6 +6,7 @@ // Copyright © 2017 jflinter. All rights reserved. // +import Foundation import Dwifft struct Stuff { @@ -40,6 +41,10 @@ struct Stuff { return SectionedValues(mutable) } + static func onlyWordItems() -> [String] { + return Stuff.wordStuff().sectionsAndValues.flatMap() { $0.1 } + } + static func emojiStuff() -> SectionedValues<String, String> { let possibleStuff = [ ("foods", [ @@ -69,4 +74,5 @@ struct Stuff { } return SectionedValues(mutable) } + } From 34c232ab7e609512f8967b2f1506888a464546a1 Mon Sep 17 00:00:00 2001 From: Rik Chilvers <rikchilvers@fastmail.com> Date: Sun, 5 Nov 2017 13:55:28 +0000 Subject: [PATCH 31/48] reinstate test dependencies --- Cartfile.resolved | 3 ++- Dwifft.xcodeproj/project.pbxproj | 33 ++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 97fb7bd..6b0a63e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1,2 @@ -github "typelift/SwiftCheck" "0.8.1" +github "trill-lang/FileCheck" "0.0.4" +github "typelift/SwiftCheck" "0.9.1" diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 3fb299a..be2fcf6 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 382DEF4C1F48751B007A8FD2 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 382DEF4D1F48751C007A8FD2 /* Dwifft+AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */; }; + 38B70D3E1FAF4F800049AEA1 /* SwiftCheck.framework in Resources */ = {isa = PBXBuildFile; fileRef = 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */; }; + 38B70D3F1FAF4F930049AEA1 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 38E5B5D61F7BDB5400F33285 /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 38E5B5D71F7BDB5400F33285 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 38E5B5E91F7BDBA500F33285 /* Dwifft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 382DEF421F487395007A8FD2 /* Dwifft.framework */; }; @@ -50,6 +52,19 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 38B70D3D1FAF4F790049AEA1 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 38B70D3F1FAF4F930049AEA1 /* SwiftCheck.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 041EBB921B89679200E113B3 /* Dwifft.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Dwifft.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 041EBB961B89679200E113B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; @@ -91,13 +106,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 382DEF3E1F487395007A8FD2 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 38E5B5DA1F7BDB5400F33285 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -288,7 +296,6 @@ buildConfigurationList = 382DEF491F487396007A8FD2 /* Build configuration list for PBXNativeTarget "Dwifft-macOS" */; buildPhases = ( 382DEF3D1F487395007A8FD2 /* Sources */, - 382DEF3E1F487395007A8FD2 /* Frameworks */, 382DEF3F1F487395007A8FD2 /* Headers */, ); buildRules = ( @@ -307,6 +314,7 @@ 38E5B5D51F7BDB5400F33285 /* Sources */, 38E5B5DA1F7BDB5400F33285 /* Frameworks */, 38E5B5DD1F7BDB5400F33285 /* Resources */, + 38B70D3D1FAF4F790049AEA1 /* CopyFiles */, ); buildRules = ( ); @@ -405,6 +413,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 38B70D3E1FAF4F800049AEA1 /* SwiftCheck.framework in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -703,6 +712,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); FRAMEWORK_VERSION = A; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; @@ -734,6 +747,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); FRAMEWORK_VERSION = A; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; From b7a804b113a8c77cd3233f51f400f85a2e5a1c91 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Mon, 11 Dec 2017 17:55:11 -0800 Subject: [PATCH 32/48] tweaks --- Dwifft.podspec | 2 -- Dwifft.xcodeproj/project.pbxproj | 4 ---- Dwifft/Dwifft.swift | 5 +++-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index dedf069..eb007a2 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -14,6 +14,4 @@ Pod::Spec.new do |s| s.source_files = 'Dwifft/*.swift' s.requires_arc = true - - s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0.1' } end diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 92c8733..8389f28 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -469,7 +469,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Debug; @@ -489,7 +488,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Release; @@ -509,7 +507,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Debug; @@ -526,7 +523,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Release; diff --git a/Dwifft/Dwifft.swift b/Dwifft/Dwifft.swift index 4ed7a4a..188d037 100644 --- a/Dwifft/Dwifft.swift +++ b/Dwifft/Dwifft.swift @@ -91,7 +91,7 @@ public enum Dwifft { return lhs.enumerated().map(DiffStep.delete).reversed() } - let table = MemoizedSequenceComparison.buildTable(lhs, rhs, lhs.count, rhs.count) + let table = MemoizedSequenceComparison.buildTable(lhs, rhs) var result = diffInternal(table, lhs, rhs, lhs.count, rhs.count, ([], [])) while case let .call(f) = result { result = f() @@ -279,7 +279,8 @@ fileprivate enum Result<T>{ } fileprivate struct MemoizedSequenceComparison<T: Equatable> { - static func buildTable(_ x: [T], _ y: [T], _ n: Int, _ m: Int) -> [[Int]] { + static func buildTable(_ x: [T], _ y: [T]) -> [[Int]] { + let n = x.count, m = y.count var table = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1) // using unsafe pointers lets us avoid swift array bounds-checking, which results in a considerable speed boost. table.withUnsafeMutableBufferPointer { unsafeTable in From 6e16ae3b85504a4fa4f0da39f3a7275377af8fd2 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Mon, 11 Dec 2017 19:21:12 -0800 Subject: [PATCH 33/48] cleanup & test fixes --- .travis.yml | 2 + Dwifft-macOS/Dwifft_macOS.h | 4 - Dwifft.xcodeproj/project.pbxproj | 12 ++ Dwifft/AbstractDiffCalculator.swift | 93 ++++++++++ Dwifft/Dwifft+AppKit.swift | 256 ++++++++-------------------- Dwifft/Dwifft+UIKit.swift | 96 +---------- DwifftTests/DwifftTests-macOS.swift | 8 +- 7 files changed, 196 insertions(+), 275 deletions(-) create mode 100644 Dwifft/AbstractDiffCalculator.swift diff --git a/.travis.yml b/.travis.yml index 79609b4..e5098ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: - set -o pipefail; - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty + - xcodebuild -scheme Dwifft-macOS test | xcpretty + env: global: secure: pUV8Ccwq1FWO8PxTHPQ3qZDUDhjNOisNVRyrziYR8x0ZQYjmVmnaLKaOHFP8co6rhBlFqReKUjoFYgRqP5QK1EkD6lqSZfnkrWqnZuLDNy0sn3/+4sLtvqAhBroAfjmmvb5GpY+Kkqfz8Lhdu6+1Z/a5xPhqNeDO3aDpa2vdBztb2qLIZnf2g8NFLOoNuR+ula868nIm858LCN1sqLp9PhV4CGaMsFx7ZFaX1yEQbwNb8+85+U2HIHqjZ62u9KZ4lA1d58VVDGj2f7ObKkC+pjiuknljy5bvRVvg5pttXggJracFgMqouwwQFFCV3nFYSDS6h7ZIjUvbyMrqBN+u32RmtqVLp1by1JvRXSeemJ3HxtZGLbq7rff4zWXyYbelT6sR6J1tWIubRo5v3sXc8E1kurqKkcPqJdG4jqiUXOau2oSHhf7WCRwa0KNfvaQuMhm0Onnsi9tW2MzGieumscfuFIJsXJdXnac7jQUVb571GfxMrDeJ9v2GOPcbnlM8cttBFAw4IoINV6teKITUW6T8RpeDXzfQyxDDQaV0M1ZTab1Tj/f4EYDAXKfZ+QquWK3bgXJhxKghXIskZLdDhYMyP55T6QxLZY9wD2CxLrEbEhDQCEb+7R2LmIC95Rlku+W92b8eWAqNxf+vV7QRqBb/sV9w2mlxmmezYTP5VAs= diff --git a/Dwifft-macOS/Dwifft_macOS.h b/Dwifft-macOS/Dwifft_macOS.h index 3bf8a9c..e4ddce0 100644 --- a/Dwifft-macOS/Dwifft_macOS.h +++ b/Dwifft-macOS/Dwifft_macOS.h @@ -12,7 +12,3 @@ FOUNDATION_EXPORT double Dwifft_macOSVersionNumber; //! Project version string for Dwifft_macOS. FOUNDATION_EXPORT const unsigned char Dwifft_macOSVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import <Dwifft_macOS/PublicHeader.h> - - diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index e4d0222..6542a34 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -14,9 +14,14 @@ 041EBBB11B8967C300E113B3 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; 041EBBB21B8967C300E113B3 /* Dwifft+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */; }; 041EBBB31B8967C300E113B3 /* Dwifft+UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */; }; + 044079181FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */; }; + 044079191FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */; }; + 0440791A1FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */; }; 0486A2651EA0A5B600D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 0486A2661EA0A64900D8093E /* SectionedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0486A2641EA0A5B600D8093E /* SectionedValues.swift */; }; 04AC329F1E88AEB000EF63DD /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */; }; + 04CEEB8F1FDF787B00C17562 /* AbstractDiffCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */; }; + 04CEEB901FDF787D00C17562 /* AbstractDiffCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */; }; 380FFA411F7BF2E000AEF983 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38D317731F7BF1E400A15CD7 /* SwiftCheck.framework */; }; 382DEF461F487396007A8FD2 /* Dwifft_macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 382DEF441F487395007A8FD2 /* Dwifft_macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041EBBAE1B8967C300E113B3 /* Dwifft.swift */; }; @@ -74,6 +79,7 @@ 041EBBA41B89679200E113B3 /* DwifftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DwifftTests.swift; sourceTree = "<group>"; }; 041EBBAE1B8967C300E113B3 /* Dwifft.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dwifft.swift; sourceTree = "<group>"; }; 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dwifft+UIKit.swift"; sourceTree = "<group>"; }; + 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractDiffCalculator.swift; sourceTree = "<group>"; }; 0486A2641EA0A5B600D8093E /* SectionedValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionedValues.swift; sourceTree = "<group>"; }; 04AC329E1E88AEB000EF63DD /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCheck.framework; path = Carthage/Build/iOS/SwiftCheck.framework; sourceTree = SOURCE_ROOT; }; 380FFA421F7C072D00AEF983 /* macOS Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "macOS Info.plist"; sourceTree = "<group>"; }; @@ -155,6 +161,7 @@ 041EBB971B89679200E113B3 /* Dwifft.h */, 041EBBAE1B8967C300E113B3 /* Dwifft.swift */, 0486A2641EA0A5B600D8093E /* SectionedValues.swift */, + 044079171FDF75FF00DDB952 /* AbstractDiffCalculator.swift */, 041EBBAF1B8967C300E113B3 /* Dwifft+UIKit.swift */, 382DEF4A1F4873F9007A8FD2 /* Dwifft+AppKit.swift */, 041EBB951B89679200E113B3 /* Supporting Files */, @@ -451,6 +458,7 @@ 041EBBB01B8967C300E113B3 /* Dwifft.swift in Sources */, 0486A2651EA0A5B600D8093E /* SectionedValues.swift in Sources */, 041EBBB21B8967C300E113B3 /* Dwifft+UIKit.swift in Sources */, + 044079181FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -459,6 +467,7 @@ buildActionMask = 2147483647; files = ( 0486A2661EA0A64900D8093E /* SectionedValues.swift in Sources */, + 04CEEB8F1FDF787B00C17562 /* AbstractDiffCalculator.swift in Sources */, 041EBBB11B8967C300E113B3 /* Dwifft.swift in Sources */, 041EBBA51B89679200E113B3 /* DwifftTests.swift in Sources */, 041EBBB31B8967C300E113B3 /* Dwifft+UIKit.swift in Sources */, @@ -472,6 +481,7 @@ 382DEF4B1F487519007A8FD2 /* Dwifft.swift in Sources */, 382DEF4C1F48751B007A8FD2 /* SectionedValues.swift in Sources */, 382DEF4D1F48751C007A8FD2 /* Dwifft+AppKit.swift in Sources */, + 0440791A1FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -480,6 +490,7 @@ buildActionMask = 2147483647; files = ( 38E5B5EB1F7BDBC700F33285 /* DwifftTests-macOS.swift in Sources */, + 04CEEB901FDF787D00C17562 /* AbstractDiffCalculator.swift in Sources */, 38E5B5EA1F7BDBBB00F33285 /* Dwifft+AppKit.swift in Sources */, 38E5B5D61F7BDB5400F33285 /* SectionedValues.swift in Sources */, 38E5B5D71F7BDB5400F33285 /* Dwifft.swift in Sources */, @@ -493,6 +504,7 @@ 94783CB71EFBA25300841579 /* Dwifft+UIKit.swift in Sources */, 94783CB61EFBA25300841579 /* SectionedValues.swift in Sources */, 94783CB51EFBA25300841579 /* Dwifft.swift in Sources */, + 044079191FDF75FF00DDB952 /* AbstractDiffCalculator.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Dwifft/AbstractDiffCalculator.swift b/Dwifft/AbstractDiffCalculator.swift new file mode 100644 index 0000000..9db51ca --- /dev/null +++ b/Dwifft/AbstractDiffCalculator.swift @@ -0,0 +1,93 @@ +// +// AbstractDiffCalculator.swift +// Dwifft +// +// Created by Jack Flintermann on 12/11/17. +// Copyright © 2017 jflinter. All rights reserved. +// + +import Foundation + +/// A parent class for all diff calculators. Don't use it directly. +public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { + + internal init(initialSectionedValues: SectionedValues<Section, Value>) { + self._sectionedValues = initialSectionedValues + } + + /// The number of sections in the diff calculator. Return this inside + /// `numberOfSections(in: tableView)` or `numberOfSections(in: collectionView)`. + /// Don't implement that method any other way (see the docs for `numberOfObjects(inSection:)` + /// for more context). + public final func numberOfSections() -> Int { + return self.sectionedValues.sections.count + } + + /// The section at a given index. If you implement `tableView:titleForHeaderInSection` or + /// `collectionView:viewForSupplementaryElementOfKind:atIndexPath`, you can use this + /// method to get information about that section out of Dwifft. + /// + /// - Parameter forSection: the index of the section you care about. + /// - Returns: the Section at that index. + public final func value(forSection: Int) -> Section { + return self.sectionedValues[forSection].0 + } + + + /// The, uh, number of objects in a given section. Use this to implement + /// `UITableViewDataSource.numberOfRowsInSection:` or `UICollectionViewDataSource.numberOfItemsInSection:`. + /// Seriously, don't implement that method any other way - there is some subtle timing stuff + /// around when this value should change in order to satisfy `UITableView`/`UICollectionView`'s internal + /// assertions, that Dwifft knows how to handle correctly. Read the source for + /// Dwifft+UIKit.swift if you don't believe me/want to learn more. + /// + /// - Parameter section: a section of your table/collection view + /// - Returns: the number of objects in that section. + public final func numberOfObjects(inSection section: Int) -> Int { + return self.sectionedValues[section].1.count + } + + + /// The value at a given index path. Use this to implement + /// `UITableViewDataSource.cellForRowAtIndexPath` or `UICollectionViewDataSource.cellForItemAtIndexPath`. + /// + /// - Parameter indexPath: the index path you are interested in + /// - Returns: the thing at that index path + public final func value(atIndexPath indexPath: IndexPath) -> Value { + #if os(iOS) || os(tvOS) + let row = indexPath.row + #endif + #if os(macOS) + let row = indexPath.item + #endif + return self.sectionedValues[indexPath.section].1[row] + } + + + /// Set this variable to automatically trigger the correct section/row/item insertion/deletions + /// on your table/collection view. + public final var sectionedValues: SectionedValues<Section, Value> { + get { + return _sectionedValues + } + set { + let oldSectionedValues = sectionedValues + let newSectionedValues = newValue + let diff = Dwifft.diff(lhs: oldSectionedValues, rhs: newSectionedValues) + if (diff.count > 0) { + self.processChanges(newState: newSectionedValues, diff: diff) + } + } + } + + internal static func buildSectionedValues(values: [Value], sectionIndex: Int) -> SectionedValues<Int, Value> { + let firstRows = (0..<sectionIndex).map { ($0, [Value]()) } + return SectionedValues(firstRows + [(sectionIndex, values)]) + } + + // UITableView and UICollectionView both perform assertions on the *current* number of rows/items before performing any updates. As such, the `sectionedValues` property must be backed by an internal value that does not change until *after* `beginUpdates`/`performBatchUpdates` has been called. + internal final var _sectionedValues: SectionedValues<Section, Value> + internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]){ + fatalError("override me") + } +} diff --git a/Dwifft/Dwifft+AppKit.swift b/Dwifft/Dwifft+AppKit.swift index 27f76c5..fde751b 100644 --- a/Dwifft/Dwifft+AppKit.swift +++ b/Dwifft/Dwifft+AppKit.swift @@ -9,169 +9,10 @@ #if os(OSX) import Cocoa - - -/// A parent class for all diff calculators. Don't use it directly. -public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { - - fileprivate init(initialSectionedValues: SectionedValues<Section, Value>) { - self._sectionedValues = initialSectionedValues - } - - /// The number of sections in the diff calculator. Return this inside - /// `numberOfSections(in: tableView)` or `numberOfSections(in: collectionView)`. - /// Don't implement that method any other way (see the docs for `numberOfObjects(inSection:)` - /// for more context). - public final func numberOfSections() -> Int { - return self.sectionedValues.sections.count - } - - /// The section at a given index. If you implement `tableView:titleForHeaderInSection` or - /// `collectionView:viewForSupplementaryElementOfKind:atIndexPath`, you can use this - /// method to get information about that section out of Dwifft. - /// - /// - Parameter forSection: the index of the section you care about. - /// - Returns: the Section at that index. - public final func value(forSection: Int) -> Section { - return self.sectionedValues[forSection].0 - } - - - /// The, uh, number of objects in a given section. Use this to implement - /// `NSTableViewDataSource.numberOfRowsInSection:` or `NSCollectionViewDataSource.numberOfItemsInSection:`. - /// Seriously, don't implement that method any other way - there is some subtle timing stuff - /// around when this value should change in order to satisfy `NSTableView`/`NSCollectionView`'s internal - /// assertions, that Dwifft knows how to handle correctly. Read the source for - /// Dwifft+NSKit.swift if you don't believe me/want to learn more. - /// - /// - Parameter section: a section of your table/collection view - /// - Returns: the number of objects in that section. - public final func numberOfObjects(inSection section: Int) -> Int { - return self.sectionedValues[section].1.count - } - - - /// The value at a given index path. Use this to implement - /// `NSTableViewDataSource.objectValueForRow` or `NSCollectionViewDataSource.itemForRepresentedObjectAtIndexPath`. - /// - /// - Parameter indexPath: the index path you are interested in - /// - Returns: the thing at that index path - public final func value(atIndexPath indexPath: IndexPath) -> Value { - return self.sectionedValues[indexPath.section].1[indexPath.item] - } - - - /// Set this variable to automatically trigger the correct section/row/item insertion/deletions - /// on your table/collection view. - public final var sectionedValues: SectionedValues<Section, Value> { - get { - return _sectionedValues - } - set { - let oldSectionedValues = sectionedValues - let newSectionedValues = newValue - let diff = Dwifft.diff(lhs: oldSectionedValues, rhs: newSectionedValues) - if (diff.count > 0) { - self.processChanges(newState: newSectionedValues, diff: diff) - } - } - } - - // NSTableView and NSCollectionView both perform assertions on the *current* number of rows/items before performing any updates. As such, the `sectionedValues` property must be backed by an internal value that does not change until *after* `beginUpdates`/`performBatchUpdates` has been called. - fileprivate final var _sectionedValues: SectionedValues<Section, Value> - fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]){ - fatalError("override me") - } -} - -/// NSTableView does not support sections so we hide this from users. -private final class SectionedTableViewDiffCalculator<Section: Equatable, Value: Equatable>: AbstractDiffCalculator<Section, Value> { - - /// The table view to be managed - public weak var tableView: NSTableView? - - /// Initializes a new diff calculator. - /// - /// - Parameters: - /// - tableView: the table view to be managed - /// - initialSectionedValues: optional - if specified, these will be the initial contents of the diff calculator. - public init(tableView: NSTableView?, initialSectionedValues: SectionedValues<Section, Value> = SectionedValues()) { - self.tableView = tableView - super.init(initialSectionedValues: initialSectionedValues) - } - - /// You can change insertion/deletion animations like this! Fade works well. - /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. - public var insertionAnimation = NSTableView.AnimationOptions.slideUp, deletionAnimation = NSTableView.AnimationOptions.slideUp - - override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { - guard let tableView = self.tableView else { return } - tableView.beginUpdates() - self._sectionedValues = newState - for result in diff { - switch result { - case let .delete(_, row, _): tableView.removeRows(at: [row], withAnimation: self.deletionAnimation) - case let .insert(_, row, _): tableView.insertRows(at: [row], withAnimation: self.insertionAnimation) - default: fatalError("NSTableViews do not have sections") - } - } - tableView.endUpdates() - } -} - -/// This class manages a `NSCollectionView`'s items and sections. It will make the necessary -/// calls to the collection view to ensure that its UI is kept in sync with the contents -/// of the `sectionedValues` property. -public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equatable> : AbstractDiffCalculator<Section, Value> { - - /// The collection view to be managed. - public weak var collectionView: NSCollectionView? - - /// Initializes a new diff calculator. - /// - /// - Parameters: - /// - collectionView: the collection view to be managed. - /// - initialSectionedValues: optional - if specified, these will be the initial contents of the diff calculator. - public init(collectionView: NSCollectionView?, initialSectionedValues: SectionedValues<Section, Value> = SectionedValues()) { - self.collectionView = collectionView - super.init(initialSectionedValues: initialSectionedValues) - } - - override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { - guard let collectionView = self.collectionView else { return } - collectionView.performBatchUpdates({ - self._sectionedValues = newState - for result in diff { - switch result { - case let .delete(section, item, _): collectionView.deleteItems(at: [IndexPath(item: item, section: section)]) - case let .insert(section, item, _): collectionView.insertItems(at: [IndexPath(item: item, section: section)]) - case let .sectionDelete(section, _): collectionView.deleteSections(IndexSet(integer: section)) - case let .sectionInsert(section, _): - // NSCollectionViews don't seem to like it when inserting sections beyond numberOfSections - // so adjust for that - if section > collectionView.numberOfSections { - collectionView.insertSections(IndexSet(integer: collectionView.numberOfSections)) - } else { - collectionView.insertSections(IndexSet(integer: section)) - } - } - } - }, completionHandler: nil) - } -} - -/// Let's say your data model consists of different sections containing different model types. Since -/// `SectionedValues` requires a uniform type for all of its rows, this can be a clunky situation. You -/// can address this in a couple of ways. The first is to define a custom enum that encompasses all of the -/// things that *could* be in your data model - if section 1 has a bunch of `String`s, and section 2 has a bunch -/// of `Int`s, define a `StringOrInt` enum that conforms to `Equatable`, and fill the `SectionedValues` -/// that you use to drive your DiffCalculator up with those. Alternatively, if you are lazy, and your -/// models all conform to `Hashable`, you can use a SimpleTableViewDiffCalculator instead. -typealias SimpleCollectionViewDiffCalculator = CollectionViewDiffCalculator<AnyHashable, AnyHashable> - + /// This class manages a `NSTableView`'s rows. It will make the necessary /// calls to the table view to ensure that its UI is kept in sync with the contents of the `rows` property. -public final class TableViewDiffCalculator<Value: Equatable> { +public final class TableViewDiffCalculator<Value: Equatable>: AbstractDiffCalculator<Int, Value> { /// The table view to be managed public weak var tableView: NSTableView? @@ -181,26 +22,18 @@ public final class TableViewDiffCalculator<Value: Equatable> { /// You can change insertion/deletion animations like this! Fade works well. /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. - public var insertionAnimation = NSTableView.AnimationOptions.slideUp { - didSet { - self.internalDiffCalculator.insertionAnimation = self.insertionAnimation - } - } + public var insertionAnimation = NSTableView.AnimationOptions.slideUp - public var deletionAnimation = NSTableView.AnimationOptions.slideUp { - didSet { - self.internalDiffCalculator.deletionAnimation = self.deletionAnimation - } - } + public var deletionAnimation = NSTableView.AnimationOptions.slideUp /// Set this variable to automatically trigger the correct row insertion/deletions /// on your table view. public var rows : [Value] { get { - return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 + return self._sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = TableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.sectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -212,17 +45,24 @@ public final class TableViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(tableView: NSTableView?, initialRows: [Value] = [], sectionIndex: Int = 0) { self.tableView = tableView - self.internalDiffCalculator = SectionedTableViewDiffCalculator(tableView: tableView, initialSectionedValues: TableViewDiffCalculator.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) self.sectionIndex = sectionIndex + super.init(initialSectionedValues: AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) } - - fileprivate static func buildSectionedValues(values: [Value], sectionIndex: Int) -> SectionedValues<Int, Value> { - let firstRows = (0..<sectionIndex).map { ($0, [Value]()) } - return SectionedValues(firstRows + [(sectionIndex, values)]) + + override internal func processChanges(newState: SectionedValues<Int, Value>, diff: [SectionedDiffStep<Int, Value>]) { + guard let tableView = self.tableView else { return } + tableView.beginUpdates() + self._sectionedValues = newState + for result in diff { + switch result { + case let .delete(_, row, _): tableView.removeRows(at: [row], withAnimation: self.deletionAnimation) + case let .insert(_, row, _): tableView.insertRows(at: [row], withAnimation: self.insertionAnimation) + default: fatalError("NSTableViews do not have sections") + } + } + tableView.endUpdates() } - private let internalDiffCalculator: SectionedTableViewDiffCalculator<Int, Value> - } /// If your collection view only has a single section, or you only want to power a single section of it with Dwifft, @@ -244,7 +84,7 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = TableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.internalDiffCalculator.sectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -256,12 +96,64 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(collectionView: NSCollectionView?, initialItems: [Value] = [], sectionIndex: Int = 0) { self.collectionView = collectionView - self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: TableViewDiffCalculator.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) + let initialSectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex) + self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: initialSectionedValues) self.sectionIndex = sectionIndex } private let internalDiffCalculator: CollectionViewDiffCalculator<Int, Value> } + + +/// This class manages a `NSCollectionView`'s items and sections. It will make the necessary +/// calls to the collection view to ensure that its UI is kept in sync with the contents +/// of the `sectionedValues` property. +public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equatable> : AbstractDiffCalculator<Section, Value> { + + /// The collection view to be managed. + public weak var collectionView: NSCollectionView? + + /// Initializes a new diff calculator. + /// + /// - Parameters: + /// - collectionView: the collection view to be managed. + /// - initialSectionedValues: optional - if specified, these will be the initial contents of the diff calculator. + public init(collectionView: NSCollectionView?, initialSectionedValues: SectionedValues<Section, Value> = SectionedValues()) { + self.collectionView = collectionView + super.init(initialSectionedValues: initialSectionedValues) + } + + override internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { + guard let collectionView = self.collectionView else { return } + collectionView.performBatchUpdates({ + self._sectionedValues = newState + for result in diff { + switch result { + case let .delete(section, item, _): collectionView.deleteItems(at: [IndexPath(item: item, section: section)]) + case let .insert(section, item, _): collectionView.insertItems(at: [IndexPath(item: item, section: section)]) + case let .sectionDelete(section, _): collectionView.deleteSections(IndexSet(integer: section)) + case let .sectionInsert(section, _): + // NSCollectionViews don't seem to like it when inserting sections beyond numberOfSections + // so adjust for that + if section > collectionView.numberOfSections { + collectionView.insertSections(IndexSet(integer: collectionView.numberOfSections)) + } else { + collectionView.insertSections(IndexSet(integer: section)) + } + } + } + }, completionHandler: nil) + } +} + +/// Let's say your data model consists of different sections containing different model types. Since +/// `SectionedValues` requires a uniform type for all of its rows, this can be a clunky situation. You +/// can address this in a couple of ways. The first is to define a custom enum that encompasses all of the +/// things that *could* be in your data model - if section 1 has a bunch of `String`s, and section 2 has a bunch +/// of `Int`s, define a `StringOrInt` enum that conforms to `Equatable`, and fill the `SectionedValues` +/// that you use to drive your DiffCalculator up with those. Alternatively, if you are lazy, and your +/// models all conform to `Hashable`, you can use a SimpleTableViewDiffCalculator instead. +typealias SimpleCollectionViewDiffCalculator = CollectionViewDiffCalculator<AnyHashable, AnyHashable> #endif diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 8e29769..752c528 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -9,83 +9,7 @@ #if os(iOS) || os(tvOS) import UIKit - - -/// A parent class for all diff calculators. Don't use it directly. -public class AbstractDiffCalculator<Section: Equatable, Value: Equatable> { - - fileprivate init(initialSectionedValues: SectionedValues<Section, Value>) { - self._sectionedValues = initialSectionedValues - } - - /// The number of sections in the diff calculator. Return this inside - /// `numberOfSections(in: tableView)` or `numberOfSections(in: collectionView)`. - /// Don't implement that method any other way (see the docs for `numberOfObjects(inSection:)` - /// for more context). - public final func numberOfSections() -> Int { - return self.sectionedValues.sections.count - } - - /// The section at a given index. If you implement `tableView:titleForHeaderInSection` or - /// `collectionView:viewForSupplementaryElementOfKind:atIndexPath`, you can use this - /// method to get information about that section out of Dwifft. - /// - /// - Parameter forSection: the index of the section you care about. - /// - Returns: the Section at that index. - public final func value(forSection: Int) -> Section { - return self.sectionedValues[forSection].0 - } - - - /// The, uh, number of objects in a given section. Use this to implement - /// `UITableViewDataSource.numberOfRowsInSection:` or `UICollectionViewDataSource.numberOfItemsInSection:`. - /// Seriously, don't implement that method any other way - there is some subtle timing stuff - /// around when this value should change in order to satisfy `UITableView`/`UICollectionView`'s internal - /// assertions, that Dwifft knows how to handle correctly. Read the source for - /// Dwifft+UIKit.swift if you don't believe me/want to learn more. - /// - /// - Parameter section: a section of your table/collection view - /// - Returns: the number of objects in that section. - public final func numberOfObjects(inSection section: Int) -> Int { - return self.sectionedValues[section].1.count - } - - - /// The value at a given index path. Use this to implement - /// `UITableViewDataSource.cellForRowAtIndexPath` or `UICollectionViewDataSource.cellForItemAtIndexPath`. - /// - /// - Parameter indexPath: the index path you are interested in - /// - Returns: the thing at that index path - public final func value(atIndexPath indexPath: IndexPath) -> Value { - return self.sectionedValues[indexPath.section].1[indexPath.row] - } - - - /// Set this variable to automatically trigger the correct section/row/item insertion/deletions - /// on your table/collection view. - public final var sectionedValues: SectionedValues<Section, Value> { - get { - return _sectionedValues - } - set { - let oldSectionedValues = sectionedValues - let newSectionedValues = newValue - let diff = Dwifft.diff(lhs: oldSectionedValues, rhs: newSectionedValues) - if (diff.count > 0) { - self.processChanges(newState: newSectionedValues, diff: diff) - } - } - } - - // UITableView and UICollectionView both perform assertions on the *current* number of rows/items before performing any updates. As such, the `sectionedValues` property must be backed by an internal value that does not change until *after* `beginUpdates`/`performBatchUpdates` has been called. - fileprivate final var _sectionedValues: SectionedValues<Section, Value> - fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]){ - fatalError("override me") - } -} - - -/// This class manages a `UITableView`'s rows and sections. It will make the necessary calls to + /// This class manages a `UITableView`'s rows and sections. It will make the necessary calls to /// the table view to ensure that its UI is kept in sync with the contents of the `sectionedValues` property. public final class TableViewDiffCalculator<Section: Equatable, Value: Equatable>: AbstractDiffCalculator<Section, Value> { @@ -106,7 +30,7 @@ public final class TableViewDiffCalculator<Section: Equatable, Value: Equatable> /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. public var insertionAnimation = UITableViewRowAnimation.automatic, deletionAnimation = UITableViewRowAnimation.automatic - override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { + override internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { guard let tableView = self.tableView else { return } tableView.beginUpdates() self._sectionedValues = newState @@ -140,7 +64,7 @@ public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equat super.init(initialSectionedValues: initialSectionedValues) } - override fileprivate func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { + override internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { guard let collectionView = self.collectionView else { return } collectionView.performBatchUpdates({ self._sectionedValues = newState @@ -201,7 +125,7 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.internalDiffCalculator.sectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -213,15 +137,11 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(tableView: UITableView?, initialRows: [Value] = [], sectionIndex: Int = 0) { self.tableView = tableView - self.internalDiffCalculator = TableViewDiffCalculator(tableView: tableView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex)) + let initialSectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: initialRows, sectionIndex: sectionIndex) + self.internalDiffCalculator = TableViewDiffCalculator(tableView: tableView, initialSectionedValues: initialSectionedValues) self.sectionIndex = sectionIndex } - fileprivate static func buildSectionedValues(values: [Value], sectionIndex: Int) -> SectionedValues<Int, Value> { - let firstRows = (0..<sectionIndex).map { ($0, [Value]()) } - return SectionedValues(firstRows + [(sectionIndex, values)]) - } - private let internalDiffCalculator: TableViewDiffCalculator<Int, Value> } @@ -245,7 +165,7 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { return self.internalDiffCalculator.sectionedValues[self.sectionIndex].1 } set { - self.internalDiffCalculator.sectionedValues = SingleSectionTableViewDiffCalculator.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) + self.internalDiffCalculator.sectionedValues = AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: newValue, sectionIndex: self.sectionIndex) } } @@ -257,7 +177,7 @@ public final class SingleSectionCollectionViewDiffCalculator<Value: Equatable> { /// - sectionIndex: optional - all insertion/deletion calls will be made on this index. public init(collectionView: UICollectionView?, initialItems: [Value] = [], sectionIndex: Int = 0) { self.collectionView = collectionView - self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: SingleSectionTableViewDiffCalculator.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) + self.internalDiffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: AbstractDiffCalculator<Int, Value>.buildSectionedValues(values: initialItems, sectionIndex: sectionIndex)) self.sectionIndex = sectionIndex } diff --git a/DwifftTests/DwifftTests-macOS.swift b/DwifftTests/DwifftTests-macOS.swift index 2267a5b..1709c55 100644 --- a/DwifftTests/DwifftTests-macOS.swift +++ b/DwifftTests/DwifftTests-macOS.swift @@ -327,6 +327,12 @@ class DwifftTests: XCTestCase { func testCollectionViewDiffCalculator() { + class TestCollectionViewItem: NSCollectionViewItem { + override func loadView() { + self.view = NSView() + } + } + class TestCollectionView: NSCollectionView { let insertionExpectations: [Int: XCTestExpectation] @@ -375,7 +381,7 @@ class DwifftTests: XCTestCase { self.rows = rows super.init(nibName: nil, bundle: nil) - collectionView.register(NSCollectionViewItem.self, forItemWithIdentifier: self.itemIdentifier) + collectionView.register(TestCollectionViewItem.self, forItemWithIdentifier: self.itemIdentifier) collectionView.dataSource = self } From 41d81bfe2e344a27fe5b4fba113b6034a78c7635 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jack@stripe.com> Date: Mon, 11 Dec 2017 19:52:59 -0800 Subject: [PATCH 34/48] fix travis carthage --- .travis.yml | 2 +- Cartfile.resolved | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5098ab..95ee467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ matrix: before_install: export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }"); before_script: - carthage bootstrap --platform $PLATFORM --configuration Debug + carthage bootstrap --configuration Debug script: - set -o pipefail; - open -a "simulator" --args -CurrentDeviceUDID "$UUID" diff --git a/Cartfile.resolved b/Cartfile.resolved index 6b0a63e..36f72fa 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,2 @@ -github "trill-lang/FileCheck" "0.0.4" +github "trill-lang/FileCheck" "0.0.5" github "typelift/SwiftCheck" "0.9.1" From d18a3961116071688ebba2f641a76043b6e41265 Mon Sep 17 00:00:00 2001 From: Dennis Oberhoff <dennis@obrhoff.de> Date: Sat, 16 Dec 2017 10:17:00 +0100 Subject: [PATCH 35/48] Use Animator to animate NSCollectionView changes --- Dwifft/Dwifft+AppKit.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft/Dwifft+AppKit.swift b/Dwifft/Dwifft+AppKit.swift index fde751b..a3831a1 100644 --- a/Dwifft/Dwifft+AppKit.swift +++ b/Dwifft/Dwifft+AppKit.swift @@ -126,7 +126,7 @@ public final class CollectionViewDiffCalculator<Section: Equatable, Value: Equat override internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { guard let collectionView = self.collectionView else { return } - collectionView.performBatchUpdates({ + collectionView.animator().performBatchUpdates({ self._sectionedValues = newState for result in diff { switch result { From f67bb83c70702fb2238fbaf47afdbcc913fa5d64 Mon Sep 17 00:00:00 2001 From: Alex Leeds <alexleeds@hotmail.com> Date: Fri, 14 Sep 2018 12:13:11 -0400 Subject: [PATCH 36/48] Update to Swift 4.2 --- Dwifft.xcodeproj/project.pbxproj | 48 ++++++++++--------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../xcschemes/Dwifft-macOS.xcscheme | 4 +- .../xcschemes/Dwifft-tvOS.xcscheme | 4 +- .../xcshareddata/xcschemes/Dwifft.xcscheme | 8 ++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ Dwifft/Dwifft+UIKit.swift | 6 +-- .../DwifftExample-iOS/AppDelegate.swift | 2 +- .../StuffCollectionViewController.swift | 2 +- .../DwifftExample.xcodeproj/project.pbxproj | 12 +++-- .../StuffCollectionViewController.swift | 8 ++-- DwifftTests/DwifftTests-macOS.swift | 4 +- DwifftTests/DwifftTests.swift | 14 +++--- 13 files changed, 72 insertions(+), 56 deletions(-) create mode 100644 Dwifft.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Dwifft.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 6542a34..1229f53 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -359,20 +359,24 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = jflinter; TargetAttributes = { 041EBB911B89679200E113B3 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0900; + LastSwiftMigration = 1000; }; 041EBB9C1B89679200E113B3 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0900; + LastSwiftMigration = 1000; + ProvisioningStyle = Automatic; }; 382DEF411F487395007A8FD2 = { CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 0900; + LastSwiftMigration = 1000; + }; + 38E5B5D21F7BDB5400F33285 = { + LastSwiftMigration = 1000; }; 94783CAC1EFBA21900841579 = { CreatedOnToolsVersion = 9.0; @@ -536,12 +540,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -575,7 +581,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0.1; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -594,12 +600,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -624,7 +632,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_VERSION = 3.0.1; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -646,7 +654,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -665,13 +672,15 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; }; name = Release; }; 041EBBAC1B89679200E113B3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -684,13 +693,16 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; 041EBBAD1B89679200E113B3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", @@ -699,8 +711,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; }; name = Release; }; @@ -732,11 +744,10 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx10.13; + SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -767,10 +778,9 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx10.13; + SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; }; name = Release; }; @@ -789,9 +799,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx10.13; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SDKROOT = macosx; }; name = Debug; }; @@ -806,10 +814,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx10.13; + SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; }; name = Release; }; @@ -841,7 +847,6 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -874,7 +879,6 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; diff --git a/Dwifft.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dwifft.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Dwifft.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEDidComputeMac32BitWarning</key> + <true/> +</dict> +</plist> diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme index f1717bf..6de1915 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-macOS.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0900" + LastUpgradeVersion = "1000" version = "1.3"> <BuildAction parallelizeBuildables = "YES" @@ -26,7 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> <TestableReference @@ -56,7 +55,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme index 2a096fe..a2dc107 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft-tvOS.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0900" + LastUpgradeVersion = "1000" version = "1.3"> <BuildAction parallelizeBuildables = "YES" @@ -26,7 +26,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> </Testables> @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme index 28b227b..62b4488 100644 --- a/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme +++ b/Dwifft.xcodeproj/xcshareddata/xcschemes/Dwifft.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0900" + LastUpgradeVersion = "1000" version = "1.3"> <BuildAction parallelizeBuildables = "YES" @@ -40,9 +40,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> <TestableReference skipped = "NO"> @@ -71,7 +70,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Dwifft.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dwifft.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Dwifft.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEDidComputeMac32BitWarning</key> + <true/> +</dict> +</plist> diff --git a/Dwifft/Dwifft+UIKit.swift b/Dwifft/Dwifft+UIKit.swift index 752c528..96c4beb 100644 --- a/Dwifft/Dwifft+UIKit.swift +++ b/Dwifft/Dwifft+UIKit.swift @@ -28,7 +28,7 @@ public final class TableViewDiffCalculator<Section: Equatable, Value: Equatable> /// You can change insertion/deletion animations like this! Fade works well. /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. - public var insertionAnimation = UITableViewRowAnimation.automatic, deletionAnimation = UITableViewRowAnimation.automatic + public var insertionAnimation = UITableView.RowAnimation.automatic, deletionAnimation = UITableView.RowAnimation.automatic override internal func processChanges(newState: SectionedValues<Section, Value>, diff: [SectionedDiffStep<Section, Value>]) { guard let tableView = self.tableView else { return } @@ -106,13 +106,13 @@ public final class SingleSectionTableViewDiffCalculator<Value: Equatable> { /// You can change insertion/deletion animations like this! Fade works well. /// So does Top/Bottom. Left/Right/Middle are a little weird, but hey, do your thing. - public var insertionAnimation = UITableViewRowAnimation.automatic { + public var insertionAnimation = UITableView.RowAnimation.automatic { didSet { self.internalDiffCalculator.insertionAnimation = self.insertionAnimation } } - public var deletionAnimation = UITableViewRowAnimation.automatic { + public var deletionAnimation = UITableView.RowAnimation.automatic { didSet { self.internalDiffCalculator.deletionAnimation = self.deletionAnimation } diff --git a/DwifftExample/DwifftExample-iOS/AppDelegate.swift b/DwifftExample/DwifftExample-iOS/AppDelegate.swift index 88ee714..b4f985e 100644 --- a/DwifftExample/DwifftExample-iOS/AppDelegate.swift +++ b/DwifftExample/DwifftExample-iOS/AppDelegate.swift @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } diff --git a/DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift b/DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift index 14ef669..9f95696 100644 --- a/DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift +++ b/DwifftExample/DwifftExample-iOS/StuffCollectionViewController.swift @@ -80,7 +80,7 @@ final class StuffCollectionViewController: UICollectionViewController { collectionView.register(StuffCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier) collectionView.register( StuffSectionHeaderView.self, - forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, + forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerReuseIdentifier ) } diff --git a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj index a1c0d9f..04cbdb4 100644 --- a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj +++ b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj @@ -296,7 +296,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0910; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = jflinter; TargetAttributes = { 045501F21B898C3200F5614D = { @@ -481,12 +481,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -519,6 +521,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -534,12 +537,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -564,6 +569,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; VALIDATE_PRODUCT = YES; }; name = Release; @@ -582,7 +588,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -600,7 +605,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; }; name = Release; }; @@ -627,7 +631,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -652,7 +655,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.DwifftExamples-macOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; - SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift index 49ab94d..9b49030 100644 --- a/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift +++ b/DwifftExample/DwifftExamples-macOS/StuffCollectionViewController.swift @@ -20,11 +20,11 @@ final class StuffCollectionViewController: NSViewController { collectionView.dataSource = self diffCalculator = CollectionViewDiffCalculator(collectionView: collectionView, initialSectionedValues: stuff) - let itemNib = NSNib(nibNamed: NSNib.Name(rawValue: "StuffCollectionViewItem"), bundle: nil) + let itemNib = NSNib(nibNamed: NSNib.Name("StuffCollectionViewItem"), bundle: nil) collectionView.register(itemNib, forItemWithIdentifier: itemIdentifier) - let headerNib = NSNib(nibNamed: NSNib.Name(rawValue: "StuffCollectionHeaderView"), bundle: nil) - collectionView.register(headerNib, forSupplementaryViewOfKind: .sectionHeader, withIdentifier: headerIdentifier) + let headerNib = NSNib(nibNamed: NSNib.Name("StuffCollectionHeaderView"), bundle: nil) + collectionView.register(headerNib, forSupplementaryViewOfKind: NSCollectionView.elementKindSectionHeader, withIdentifier: headerIdentifier) } @IBAction func shuffle(_ sender: NSButton) { @@ -44,7 +44,7 @@ extension StuffCollectionViewController: NSCollectionViewDataSource { func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView { - let header = collectionView.makeSupplementaryView(ofKind: .sectionHeader, withIdentifier: headerIdentifier, for: indexPath) + let header = collectionView.makeSupplementaryView(ofKind: NSCollectionView.elementKindSectionHeader, withIdentifier: headerIdentifier, for: indexPath) if let dc = diffCalculator, let stuffHeader = header as? StuffCollectionHeaderView { stuffHeader.title.stringValue = dc.value(forSection: indexPath.section) diff --git a/DwifftTests/DwifftTests-macOS.swift b/DwifftTests/DwifftTests-macOS.swift index 1709c55..a9ddd18 100644 --- a/DwifftTests/DwifftTests-macOS.swift +++ b/DwifftTests/DwifftTests-macOS.swift @@ -188,12 +188,12 @@ class DwifftTests: XCTestCase { func test2DBenchmark() { let n: Int = 70 - let a: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + let a: [(Int, [Int])] = (0...n).compactMap { (i: Int) -> (Int, [Int])? in guard arc4random_uniform(2) == 0 else { return nil } let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } return (i, value) } - let b: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + let b: [(Int, [Int])] = (0...n).compactMap { (i: Int) -> (Int, [Int])? in guard arc4random_uniform(2) == 0 else { return nil } let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } return (i, value) diff --git a/DwifftTests/DwifftTests.swift b/DwifftTests/DwifftTests.swift index c758332..7f55220 100644 --- a/DwifftTests/DwifftTests.swift +++ b/DwifftTests/DwifftTests.swift @@ -211,12 +211,12 @@ class DwifftTests: XCTestCase { func test2DBenchmark() { let n: Int = 70 - let a: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + let a: [(Int, [Int])] = (0...n).compactMap { (i: Int) -> (Int, [Int])? in guard arc4random_uniform(2) == 0 else { return nil } let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } return (i, value) } - let b: [(Int, [Int])] = (0...n).flatMap { (i: Int) -> (Int, [Int])? in + let b: [(Int, [Int])] = (0...n).compactMap { (i: Int) -> (Int, [Int])? in guard arc4random_uniform(2) == 0 else { return nil } let value: [Int] = (0...arc4random_uniform(UInt32(n))).map { _ in Int(arc4random_uniform(100)) } return (i, value) @@ -272,22 +272,22 @@ class DwifftTests: XCTestCase { init(insertionExpectations: [Int: XCTestExpectation], deletionExpectations: [Int: XCTestExpectation]) { self.insertionExpectations = insertionExpectations self.deletionExpectations = deletionExpectations - super.init(frame: CGRect.zero, style: UITableViewStyle.plain) + super.init(frame: CGRect.zero, style: UITableView.Style.plain) } required init?(coder aDecoder: NSCoder) { fatalError("not implemented") } - override func insertRows(at indexPaths: [IndexPath], with animation: UITableViewRowAnimation) { - XCTAssertEqual(animation, UITableViewRowAnimation.left, "incorrect insertion animation") + override func insertRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) { + XCTAssertEqual(animation, UITableView.RowAnimation.left, "incorrect insertion animation") for indexPath in indexPaths { self.insertionExpectations[(indexPath as NSIndexPath).row]!.fulfill() } } - override func deleteRows(at indexPaths: [IndexPath], with animation: UITableViewRowAnimation) { - XCTAssertEqual(animation, UITableViewRowAnimation.right, "incorrect insertion animation") + override func deleteRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) { + XCTAssertEqual(animation, UITableView.RowAnimation.right, "incorrect insertion animation") for indexPath in indexPaths { self.deletionExpectations[(indexPath as NSIndexPath).row]!.fulfill() } From afa1dcbb028dfac1aa23d569bd127cb8cd96df92 Mon Sep 17 00:00:00 2001 From: Alex Leeds <alexleeds@hotmail.com> Date: Fri, 14 Sep 2018 18:38:59 -0400 Subject: [PATCH 37/48] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95ee467..a9b73ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode9 + osx_image: xcode10 env: - PLATFORM=iOS NAME='iPhone 8' before_install: From 78117cd1f3b73242600e68ef0853dccf78a30cd8 Mon Sep 17 00:00:00 2001 From: Jack Flintermann <jflinter11@gmail.com> Date: Fri, 14 Sep 2018 19:45:29 -0400 Subject: [PATCH 38/48] Update .travis.yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95ee467..a791402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode9 + osx_image: xcode10 env: - PLATFORM=iOS NAME='iPhone 8' before_install: @@ -11,7 +11,6 @@ matrix: carthage bootstrap --configuration Debug script: - set -o pipefail; - - open -a "simulator" --args -CurrentDeviceUDID "$UUID" - xcodebuild -scheme Dwifft -destination "id=$UUID" test | xcpretty - xcodebuild -scheme Dwifft-macOS test | xcpretty From 97826d17dc1bb2afa733a76ccad2773082577f03 Mon Sep 17 00:00:00 2001 From: Ilya Laryionau <larryonoff@gmail.com> Date: Sun, 16 Sep 2018 14:00:51 +0300 Subject: [PATCH 39/48] Add into --- Dwifft.podspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dwifft.podspec b/Dwifft.podspec index d7c02be..ff3070d 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -8,6 +8,8 @@ Pod::Spec.new do |s| s.author = 'Jack Flintermann' s.source = { git: 'https://github.com/jflinter/Dwifft.git', tag: s.version } + s.swift_version = '4.0' + s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' s.osx.deployment_target = '10.11' From 9c86830677bd423a8bb5e3cd386188250439291f Mon Sep 17 00:00:00 2001 From: jflinter <jflinter11@gmail.com> Date: Tue, 18 Sep 2018 01:13:21 -0400 Subject: [PATCH 40/48] update to macos 10.13 --- Dwifft.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 6542a34..c469317 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -729,10 +729,10 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx10.13; + SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -764,10 +764,10 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; - SDKROOT = macosx10.13; + SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.0; From 9406b784722fe6c61b215baf0a89991cd19fa3e2 Mon Sep 17 00:00:00 2001 From: jflinter <jflinter11@gmail.com> Date: Tue, 18 Sep 2018 01:14:05 -0400 Subject: [PATCH 41/48] fix macos test target --- Dwifft.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index c469317..e496903 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -789,7 +789,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx10.13; + SDKROOT = macosx; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; @@ -806,7 +806,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx10.13; + SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; From 4aa4e1dd3af51ab6ac0ca5464f6655d9fd17683e Mon Sep 17 00:00:00 2001 From: jflinter <jflinter11@gmail.com> Date: Tue, 18 Sep 2018 01:34:41 -0400 Subject: [PATCH 42/48] 0.9 --- .swift-version | 2 +- Dwifft.podspec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.swift-version b/.swift-version index 5186d07..bf77d54 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.0 +4.2 diff --git a/Dwifft.podspec b/Dwifft.podspec index ff3070d..3320fff 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.7' + s.version = '0.8' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.author = 'Jack Flintermann' s.source = { git: 'https://github.com/jflinter/Dwifft.git', tag: s.version } - s.swift_version = '4.0' + s.swift_version = '4.2' s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' From a006cd099779f835e1a357247a8de02031195a4e Mon Sep 17 00:00:00 2001 From: jflinter <jflinter11@gmail.com> Date: Tue, 18 Sep 2018 01:35:51 -0400 Subject: [PATCH 43/48] 0.9 --- Dwifft.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index 3320fff..3b54116 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Dwifft' - s.version = '0.8' + s.version = '0.9' s.license = 'MIT' s.summary = 'Swift Diff' s.homepage = 'https://github.com/jflinter/Dwifft' From 361e65492a2a181d747836f7d8b0c5f3f9afd0e6 Mon Sep 17 00:00:00 2001 From: jflinter <jflinter11@gmail.com> Date: Thu, 27 Sep 2018 22:56:49 -0400 Subject: [PATCH 44/48] fix osx deployment target --- Dwifft.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dwifft.xcodeproj/project.pbxproj b/Dwifft.xcodeproj/project.pbxproj index 07d3310..1229f53 100644 --- a/Dwifft.xcodeproj/project.pbxproj +++ b/Dwifft.xcodeproj/project.pbxproj @@ -741,7 +741,7 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; SDKROOT = macosx; @@ -775,7 +775,7 @@ INFOPLIST_FILE = "Dwifft-macOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = "com.jflinter.Dwifft-macOS"; PRODUCT_NAME = Dwifft; SDKROOT = macosx; From 9db2dc1bb6e9702b1e426d19bd3043c60eb2e1db Mon Sep 17 00:00:00 2001 From: Wolf McNally <wolf@wolfmcnally.com> Date: Tue, 26 Mar 2019 16:44:39 -0700 Subject: [PATCH 45/48] Updated for Swift 5. --- Dwifft.podspec | 2 +- Dwifft/Dwifft.swift | 4 ++-- Dwifft/SectionedValues.swift | 2 +- DwifftExample/DwifftExample.xcodeproj/project.pbxproj | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Dwifft.podspec b/Dwifft.podspec index 3b54116..fbab4a9 100644 --- a/Dwifft.podspec +++ b/Dwifft.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.author = 'Jack Flintermann' s.source = { git: 'https://github.com/jflinter/Dwifft.git', tag: s.version } - s.swift_version = '4.2' + s.swift_version = '5.0' s.ios.deployment_target = '8.0' s.tvos.deployment_target = '9.0' diff --git a/Dwifft/Dwifft.swift b/Dwifft/Dwifft.swift index 188d037..5efe041 100644 --- a/Dwifft/Dwifft.swift +++ b/Dwifft/Dwifft.swift @@ -309,13 +309,13 @@ public extension Array where Element: Equatable { /// Deprecated in favor of `Dwifft.diff`. @available(*, deprecated) - public func diff(_ other: [Element]) -> [DiffStep<Element>] { + func diff(_ other: [Element]) -> [DiffStep<Element>] { return Dwifft.diff(self, other) } /// Deprecated in favor of `Dwifft.apply`. @available(*, deprecated) - public func apply(_ diff: [DiffStep<Element>]) -> [Element] { + func apply(_ diff: [DiffStep<Element>]) -> [Element] { return Dwifft.apply(diff: diff, toArray: self) } diff --git a/Dwifft/SectionedValues.swift b/Dwifft/SectionedValues.swift index d87eac0..0556d90 100644 --- a/Dwifft/SectionedValues.swift +++ b/Dwifft/SectionedValues.swift @@ -72,7 +72,7 @@ public extension SectionedValues where Section: Hashable { /// should be sorted before the second. Used to sort the sections in the returned `SectionedValues`. /// - sortValues: A function that compares two values, and returns true if the first /// should be sorted before the second. Used to sort the values in each section of the returned `SectionedValues`. - public init( + init( values: [Value], valueToSection: ((Value) -> Section), sortSections: ((Section, Section) -> Bool), diff --git a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj index 04cbdb4..5ad9c23 100644 --- a/DwifftExample/DwifftExample.xcodeproj/project.pbxproj +++ b/DwifftExample/DwifftExample.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -521,7 +522,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -569,7 +570,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; From 434d4d2a179a234ddd0645e193cf61cfb3791066 Mon Sep 17 00:00:00 2001 From: Wolf McNally <wolf@wolfmcnally.com> Date: Sun, 9 Jun 2019 17:20:53 -0700 Subject: [PATCH 46/48] Updated .gitignore. --- .gitignore | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 039109e..f14113e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ ### Swift ### ## Build generated -.build/ build/ DerivedData @@ -29,4 +28,9 @@ xcuserdata *.hmap *.ipa -Carthage/ \ No newline at end of file +# Swift Package Manager +.build +.swiftpm +Package.resolved + +Carthage/ From 4fcb62b0a96780606589beac00f74f317be5e0e0 Mon Sep 17 00:00:00 2001 From: Denys Telezhkin <strangervir@gmail.com> Date: Tue, 9 Jul 2019 12:12:10 +0300 Subject: [PATCH 47/48] Add support fro Swift Package Manager in Xcode 11. --- Package.swift | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/Package.swift b/Package.swift index d0d14aa..2416eb0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,14 +1,43 @@ +// swift-tools-version:5.1 +// +// Package.swift +// Dwifft +// +// Created by Denys Telezhkin on 09.07.2019. +// Copyright © 2019 Denys Telezhkin. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + import PackageDescription let package = Package( name: "Dwifft", - dependencies : [], - exclude: [ - "Carthage", - "DwifftTests", - "DwifftExample", - "docs", - "Dwifft.xcworkspace", - "scripts", - ] + platforms: [ + .iOS(.v8), + .tvOS(.v9), + .macOS(.v10_11) + ], + products: [ + .library(name: "Dwifft", targets: ["Dwifft"]) + ], + targets: [ + .target(name: "Dwifft", path: "Dwifft") + ], + swiftLanguageVersions: [.v5] ) From f405eaa651be188c42b7cf0bf7b8a4df01179f59 Mon Sep 17 00:00:00 2001 From: Denys Telezhkin <strangervir@gmail.com> Date: Wed, 10 Jul 2019 09:57:56 +0300 Subject: [PATCH 48/48] Remove copyright header. --- Package.swift | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/Package.swift b/Package.swift index 2416eb0..df9459e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,28 +1,5 @@ // swift-tools-version:5.1 // -// Package.swift -// Dwifft -// -// Created by Denys Telezhkin on 09.07.2019. -// Copyright © 2019 Denys Telezhkin. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. import PackageDescription