From 86bf12b91ee6d2f1857160a30582221a8a9c4ce7 Mon Sep 17 00:00:00 2001 From: Eric Tang Date: Fri, 5 May 2017 14:08:44 -0400 Subject: [PATCH] Added ignoreUntil and simplified slop Summary: Fixed https://github.com/material-motion/material-motion-swift/issues/87 and https://github.com/material-motion/material-motion-swift/issues/86 Reviewers: O2 Material Motion, O4 Material Apple platform reviewers, #material_motion, featherless Reviewed By: O2 Material Motion, O4 Material Apple platform reviewers, #material_motion, featherless Subscribers: featherless Tags: #material_motion Differential Revision: http://codereview.cc/D3170 --- .../project.pbxproj | 4 ++ src/operators/ignoreUntil.swift | 33 ++++++++++++++++ src/operators/slop.swift | 15 +------ tests/unit/operator/ignoreUntilTest.swift | 39 +++++++++++++++++++ 4 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 src/operators/ignoreUntil.swift create mode 100644 tests/unit/operator/ignoreUntilTest.swift diff --git a/examples/apps/Catalog/MaterialMotionCatalog.xcodeproj/project.pbxproj b/examples/apps/Catalog/MaterialMotionCatalog.xcodeproj/project.pbxproj index 1f859f2..872aeaa 100644 --- a/examples/apps/Catalog/MaterialMotionCatalog.xcodeproj/project.pbxproj +++ b/examples/apps/Catalog/MaterialMotionCatalog.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 07EB59021EBCEF8F0045ABAE /* ignoreUntilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EB59001EBCEF3D0045ABAE /* ignoreUntilTest.swift */; }; 19940C71B8C97EDA48552251 /* Pods_MaterialMotionCatalog.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16DDCA39C49FF5C091B2AF6C /* Pods_MaterialMotionCatalog.framework */; }; 6605044E1E83146C009EDB8A /* distanceFromTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6605044D1E83146C009EDB8A /* distanceFromTests.swift */; }; 66090B841E03715F00B1D598 /* PropertyObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66090B831E03715F00B1D598 /* PropertyObservation.swift */; }; @@ -87,6 +88,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 07EB59001EBCEF3D0045ABAE /* ignoreUntilTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ignoreUntilTest.swift; sourceTree = ""; }; 1486CD16AAF554D1E8B5BBB3 /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "../../../Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = ""; }; 16DDCA39C49FF5C091B2AF6C /* Pods_MaterialMotionCatalog.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MaterialMotionCatalog.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4F2DC52F25787C67CDBB6189 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "../../../Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = ""; }; @@ -276,6 +278,7 @@ 669512921E8301D100D8868D /* dedupeTests.swift */, 669512961E8305AC00D8868D /* delayTests.swift */, 6605044D1E83146C009EDB8A /* distanceFromTests.swift */, + 07EB59001EBCEF3D0045ABAE /* ignoreUntilTest.swift */, 66F2C3C81E83245800DD9728 /* invertedTests.swift */, 6695129A1E830AE500D8868D /* lowerBoundTests.swift */, 6613A9DA1E832779004A3699 /* mergeTests.swift */, @@ -653,6 +656,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 07EB59021EBCEF8F0045ABAE /* ignoreUntilTest.swift in Sources */, 6613A9F51E842FF5004A3699 /* yLockedToTests.swift in Sources */, 669512891E82E8CB00D8868D /* _rememberTests.swift in Sources */, 669512741E82E68900D8868D /* SubtractableTests.swift in Sources */, diff --git a/src/operators/ignoreUntil.swift b/src/operators/ignoreUntil.swift new file mode 100644 index 0000000..caf488b --- /dev/null +++ b/src/operators/ignoreUntil.swift @@ -0,0 +1,33 @@ +/* + Copyright 2016-present The Material Motion Authors. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit + +extension MotionObservableConvertible where T: Equatable { + /** + Ignores values from upstream until the expected value is received, at which point it emits + that value and all further values without modification. + */ + public func ignoreUntil(_ expected: T) -> MotionObservable { + var shouldSend = false + return _filter() { value in + if value == expected { + shouldSend = true + } + return shouldSend + } + } +} diff --git a/src/operators/slop.swift b/src/operators/slop.swift index 5e3aa54..6a94f9f 100644 --- a/src/operators/slop.swift +++ b/src/operators/slop.swift @@ -48,28 +48,17 @@ extension MotionObservableConvertible where T == CGFloat { size. */ public func slop(size: CGFloat) -> MotionObservable { - let didLeaveSlopRegion = createProperty("slop.didLeaveSlopRegion", withInitialValue: false) - let size = abs(size) return MotionObservable(self.metadata.createChild(Metadata(#function, type: .constraint, args: [size]))) { observer in let upstreamSubscription = self - .thresholdRange(min: -size, max: size) - .rewrite([.below: true, .above: true]) - .dedupe() - .subscribeToValue { didLeaveSlopRegion.value = $0 } - - let downstreamSubscription = self - .valve(openWhenTrue: didLeaveSlopRegion) .thresholdRange(min: -size, max: size) .rewrite([.below: .onExit, .within: .onReturn, .above: .onExit]) .dedupe() + .ignoreUntil(SlopEvent.onExit) .subscribeAndForward(to: observer) - return { - upstreamSubscription.unsubscribe() - downstreamSubscription.unsubscribe() - } + return upstreamSubscription.unsubscribe } } } diff --git a/tests/unit/operator/ignoreUntilTest.swift b/tests/unit/operator/ignoreUntilTest.swift new file mode 100644 index 0000000..e2b84ec --- /dev/null +++ b/tests/unit/operator/ignoreUntilTest.swift @@ -0,0 +1,39 @@ +/* + Copyright 2017-present The Material Motion Authors. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import XCTest +import IndefiniteObservable +import MaterialMotion + +class ignoreUntilTest: XCTestCase { + func testIgnoreUntil() { + + let input = [20, 10, 60, 50, 10, 20, 80] + let expected = [50, 10, 20, 80] + let observable = MotionObservable { observer in + for i in input { + observer.next(i) + } + return noopDisconnect + } + + var values: [Int] = [] + observable.ignoreUntil(50).subscribeToValue { + values.append($0) + } + XCTAssertEqual(values, expected) + } +}