From 4689a9d20fdf7fdad42a76ec8b3b5cfc8e599933 Mon Sep 17 00:00:00 2001 From: Felix Mau Date: Sun, 3 Oct 2021 22:35:46 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20::=20Add=20iPhone=20specific=20conf?= =?UTF-8?q?igurations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj | 4 + Example/Pods/Pods.xcodeproj/project.pbxproj | 35 ++++---- .../GradientLoadingBarViewModelTestCase.swift | 2 +- ...hGradientLoadingBarViewModelTestCase.swift | 76 +++++++++++++++++ .../NotchGradientLoadingBarController.swift | 79 +++++++++--------- .../NotchGradientLoadingBarViewModel.swift | 82 +++++++++++++++++++ 6 files changed, 219 insertions(+), 59 deletions(-) create mode 100644 Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift create mode 100644 GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift diff --git a/Example/GradientLoadingBar.xcodeproj/project.pbxproj b/Example/GradientLoadingBar.xcodeproj/project.pbxproj index c342234..8209003 100644 --- a/Example/GradientLoadingBar.xcodeproj/project.pbxproj +++ b/Example/GradientLoadingBar.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 97B6F5FF2143F31F008CFEA5 /* BlueFilledButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B6F5FC2143F31F008CFEA5 /* BlueFilledButton.swift */; }; 97B6F6002143F31F008CFEA5 /* BlueBorderedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B6F5FD2143F31F008CFEA5 /* BlueBorderedButton.swift */; }; DC190F622496A25A0069E2B0 /* NotchGradientLoadingBarControllerTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC190F602496A24F0069E2B0 /* NotchGradientLoadingBarControllerTestCase.swift */; }; + DC9FF938270A470D0065B5B9 /* NotchGradientLoadingBarViewModelTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9FF937270A470D0065B5B9 /* NotchGradientLoadingBarViewModelTestCase.swift */; }; DCE3AB13249761B300889FFA /* Snapshotting+WindowedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE3AB11249761AB00889FFA /* Snapshotting+WindowedImage.swift */; }; DCE3AB16249764BB00889FFA /* GradientLoadingBarControllerTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE3AB14249764A000889FFA /* GradientLoadingBarControllerTestCase.swift */; }; /* End PBXBuildFile section */ @@ -83,6 +84,7 @@ ABA9B1EF5F3928BA6E31D3EA /* Pods_GradientLoadingBar_SnapshotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GradientLoadingBar_SnapshotTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C06CA4DFA1DCB931095ABD3D /* GradientLoadingBar.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = GradientLoadingBar.podspec; path = ../GradientLoadingBar.podspec; sourceTree = ""; }; DC190F602496A24F0069E2B0 /* NotchGradientLoadingBarControllerTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchGradientLoadingBarControllerTestCase.swift; sourceTree = ""; }; + DC9FF937270A470D0065B5B9 /* NotchGradientLoadingBarViewModelTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchGradientLoadingBarViewModelTestCase.swift; sourceTree = ""; }; DCE3AB11249761AB00889FFA /* Snapshotting+WindowedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Snapshotting+WindowedImage.swift"; sourceTree = ""; }; DCE3AB14249764A000889FFA /* GradientLoadingBarControllerTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientLoadingBarControllerTestCase.swift; sourceTree = ""; }; DCE3AB172497670400889FFA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -214,6 +216,7 @@ children = ( 64E0F5BB2211B7D20066D00D /* GradientLoadingBarViewModelTestCase.swift */, 640E8ABF231457620008C5A6 /* GradientActivityIndicatorViewModelTestCase.swift */, + DC9FF937270A470D0065B5B9 /* NotchGradientLoadingBarViewModelTestCase.swift */, ); path = ViewModel; sourceTree = ""; @@ -579,6 +582,7 @@ files = ( 640E8AC0231457620008C5A6 /* GradientActivityIndicatorViewModelTestCase.swift in Sources */, 64E0F5BF2211B7D20066D00D /* GradientLoadingBarViewModelTestCase.swift in Sources */, + DC9FF938270A470D0065B5B9 /* NotchGradientLoadingBarViewModelTestCase.swift in Sources */, 64E7F4252293E16B00BE5095 /* GradientActivityIndicatorView+AnimateIsHiddenTestCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index 31423e0..9526e48 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ dependencies = ( ); name = SwiftFormat; + productName = SwiftFormat; }; 52B60EC2A583F24ACBB69C113F5488B9 /* SwiftLint */ = { isa = PBXAggregateTarget; @@ -24,6 +25,7 @@ dependencies = ( ); name = SwiftLint; + productName = SwiftLint; }; B951B6FCD3E55AF969FBA9F7B476B877 /* SwiftConfigurationFiles */ = { isa = PBXAggregateTarget; @@ -33,6 +35,7 @@ dependencies = ( ); name = SwiftConfigurationFiles; + productName = SwiftConfigurationFiles; }; /* End PBXAggregateTarget section */ @@ -95,6 +98,7 @@ D03D6CE2236A23EFA2AEF55B1C3612FB /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DCA8C4CBB512E220B4470D94AF8BE7D /* Observable.swift */; }; D5CF78CD0117EBB47C0F4CF5B69F021A /* XCTAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C95B2FA66AB0EFC760FE3BC82E183D /* XCTAttachment.swift */; }; D858C353CC2F564E42446D4E6E360668 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A501BC0324C0925814D79A81451E58C /* SwiftUIView.swift */; }; + DC9FF936270A3FA10065B5B9 /* NotchGradientLoadingBarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9FF935270A3FA10065B5B9 /* NotchGradientLoadingBarViewModel.swift */; }; DDDE93984B4D723CB07EC2F755E8DE2F /* GradientLoadingBar-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ED406C1723EE2AB785C72BF3A291751 /* GradientLoadingBar-dummy.m */; }; E76A36AD50421F378F37CE67D2C1F920 /* Pods-GradientLoadingBar_Example-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A900E1CFF1D76CF61DDF7358F5C8863 /* Pods-GradientLoadingBar_Example-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; E817F6368413D42837C5F1A6CCDDD834 /* Pods-GradientLoadingBar_Example-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8194C4CB9E683FC366F48513ED1B1A9A /* Pods-GradientLoadingBar_Example-dummy.m */; }; @@ -179,9 +183,9 @@ 108AACC96F7DBC089B0840E09F19C698 /* Pods-GradientLoadingBar_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-GradientLoadingBar_Example.release.xcconfig"; sourceTree = ""; }; 12241E9306298FD7BD30DD97B2F2F585 /* Description.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Description.swift; path = Sources/SnapshotTesting/Snapshotting/Description.swift; sourceTree = ""; }; 132C18988D60EF85736C043D43C19E57 /* Pods-GradientLoadingBar_Tests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-GradientLoadingBar_Tests-umbrella.h"; sourceTree = ""; }; - 13520AB8B3790CE3CEDCBBEEE1EF237A /* Pods_GradientLoadingBar_SnapshotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_GradientLoadingBar_SnapshotTests.framework; path = "Pods-GradientLoadingBar_SnapshotTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 13520AB8B3790CE3CEDCBBEEE1EF237A /* Pods_GradientLoadingBar_SnapshotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GradientLoadingBar_SnapshotTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1679A4CF92D4ADFB15F8200201EC3AE5 /* Pods-GradientLoadingBar_SnapshotTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-GradientLoadingBar_SnapshotTests-frameworks.sh"; sourceTree = ""; }; - 1711FC18263D47D46851F0433A93F110 /* Pods_GradientLoadingBar_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_GradientLoadingBar_Tests.framework; path = "Pods-GradientLoadingBar_Tests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1711FC18263D47D46851F0433A93F110 /* Pods_GradientLoadingBar_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GradientLoadingBar_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 172DF8516EF6D5757C3FBEF1C0CB52DC /* Pods-GradientLoadingBar_SnapshotTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-GradientLoadingBar_SnapshotTests-dummy.m"; sourceTree = ""; }; 1A9107CAA27BA0679345F24910903133 /* Pods-GradientLoadingBar_Tests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-GradientLoadingBar_Tests-dummy.m"; sourceTree = ""; }; 1B664F0A7F5E59140F761C16069995E9 /* Pods-GradientLoadingBar_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-GradientLoadingBar_Tests.release.xcconfig"; sourceTree = ""; }; @@ -202,11 +206,11 @@ 3745B9ADEFD5EB502DDDCA38C54C0469 /* SpriteKit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpriteKit.swift; path = Sources/SnapshotTesting/Snapshotting/SpriteKit.swift; sourceTree = ""; }; 388DBB0163B3768EC43AB87FFED8A19D /* URLRequest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLRequest.swift; path = Sources/SnapshotTesting/Snapshotting/URLRequest.swift; sourceTree = ""; }; 3A900E1CFF1D76CF61DDF7358F5C8863 /* Pods-GradientLoadingBar_Example-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-GradientLoadingBar_Example-umbrella.h"; sourceTree = ""; }; - 3C6A379C135C84644F189B8056CCBA04 /* Pods_GradientLoadingBar_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_GradientLoadingBar_Example.framework; path = "Pods-GradientLoadingBar_Example.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3C6A379C135C84644F189B8056CCBA04 /* Pods_GradientLoadingBar_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GradientLoadingBar_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3D1546F727E84C17FB03D49A501AEBF3 /* LightweightObservable.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = LightweightObservable.modulemap; sourceTree = ""; }; 3D25A3B900085A32A5C7D3F385452EF0 /* GradientActivityIndicatorViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GradientActivityIndicatorViewModel.swift; sourceTree = ""; }; 4077B2112D2B1D73DE188E8058E85FA1 /* View.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = View.swift; path = Sources/SnapshotTesting/Common/View.swift; sourceTree = ""; }; - 42D87AB9459267458201EBFBB68848C1 /* readme.md */ = {isa = PBXFileReference; includeInIndex = 1; path = readme.md; sourceTree = ""; }; + 42D87AB9459267458201EBFBB68848C1 /* readme.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = readme.md; sourceTree = ""; }; 4371A74F9A6D74628527A30E755EFF25 /* Pods-GradientLoadingBar_SnapshotTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-GradientLoadingBar_SnapshotTests-umbrella.h"; sourceTree = ""; }; 44FC5949DA58E53329E8837F44618093 /* SwiftLint.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftLint.debug.xcconfig; sourceTree = ""; }; 4F9247405B237F2F2FC8E7A4256E26CE /* SnapshotTesting-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SnapshotTesting-Info.plist"; sourceTree = ""; }; @@ -219,7 +223,7 @@ 60F741339642A8D8B19A4EF0EDE2B528 /* LightweightObservable-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "LightweightObservable-dummy.m"; sourceTree = ""; }; 652D9AA358DBDB2DBA1CFB02CCBA8DC4 /* Pods-GradientLoadingBar_Tests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-GradientLoadingBar_Tests-Info.plist"; sourceTree = ""; }; 675C8FED0CA649F447020502AC40DA94 /* Diffing.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Diffing.swift; path = Sources/SnapshotTesting/Diffing.swift; sourceTree = ""; }; - 67873E92210DD4E777C49C6E8AEDC108 /* GradientLoadingBar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GradientLoadingBar.framework; path = GradientLoadingBar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 67873E92210DD4E777C49C6E8AEDC108 /* GradientLoadingBar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GradientLoadingBar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 69838A921E83418B945E72EB342809F5 /* Pods-GradientLoadingBar_SnapshotTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-GradientLoadingBar_SnapshotTests.debug.xcconfig"; sourceTree = ""; }; 6B8C3644CAA8A93B3901127A7B8DE26E /* UIView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIView.swift; path = Sources/SnapshotTesting/Snapshotting/UIView.swift; sourceTree = ""; }; 6BA6CC273DB1F3DF8863CA959253A9E1 /* LightweightObservable.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = LightweightObservable.debug.xcconfig; sourceTree = ""; }; @@ -242,14 +246,14 @@ 8B7AAA3C809414A46F196C6DE5F6CFB4 /* Observable+KeyPath.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+KeyPath.swift"; path = "LightweightObservable/Classes/Extensions/Observable+KeyPath.swift"; sourceTree = ""; }; 8DD33C2202B004A8B452184DCFAB4DEC /* SnapshotTesting-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SnapshotTesting-prefix.pch"; sourceTree = ""; }; 8F17E189033503650D8A495ADF1F369D /* Constants.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 95A4CD5CAEDCA57994965B76430C1FBE /* GradientLoadingBar.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = GradientLoadingBar.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 95A4CD5CAEDCA57994965B76430C1FBE /* GradientLoadingBar.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = GradientLoadingBar.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 9C2EEFBFFAE6AD15C903A20EE7BF57D7 /* Any.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Any.swift; path = Sources/SnapshotTesting/Snapshotting/Any.swift; sourceTree = ""; }; - 9D184645A643B40E94DA5BC70B5C6F2B /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE; sourceTree = ""; }; + 9D184645A643B40E94DA5BC70B5C6F2B /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 9D21ADE128CE03553F0F1D720F4F967D /* UIViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIViewController.swift; path = Sources/SnapshotTesting/Snapshotting/UIViewController.swift; sourceTree = ""; }; - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 9DCA8C4CBB512E220B4470D94AF8BE7D /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = LightweightObservable/Classes/Observable.swift; sourceTree = ""; }; 9DD32929B122D2561D1E99468EECDBF7 /* Pods-GradientLoadingBar_SnapshotTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-GradientLoadingBar_SnapshotTests.release.xcconfig"; sourceTree = ""; }; - A037DBBCCACBFACB5C39A80B1C273043 /* SnapshotTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SnapshotTesting.framework; path = SnapshotTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A037DBBCCACBFACB5C39A80B1C273043 /* SnapshotTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapshotTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A652F20CE7EE44E64565C2120B651665 /* Pods-GradientLoadingBar_SnapshotTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-GradientLoadingBar_SnapshotTests.modulemap"; sourceTree = ""; }; A6F9A1BAFFBBC246C94565120C2B671A /* GradientLoadingBar.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GradientLoadingBar.modulemap; sourceTree = ""; }; A85AAD62B88A5A61ED41F15941BCF50E /* UIBezierPath.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIBezierPath.swift; path = Sources/SnapshotTesting/Snapshotting/UIBezierPath.swift; sourceTree = ""; }; @@ -270,12 +274,13 @@ D2F1D5D4FE8EB1B511317314725F9D54 /* SwiftConfigurationFiles.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftConfigurationFiles.release.xcconfig; sourceTree = ""; }; D997502F7A2A3F2E07DE43BA6C33DEF8 /* SwiftFormat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftFormat.release.xcconfig; sourceTree = ""; }; D9EECF497600BB53CEDDACB2CE8A2B9D /* LightweightObservable.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = LightweightObservable.release.xcconfig; sourceTree = ""; }; + DC9FF935270A3FA10065B5B9 /* NotchGradientLoadingBarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotchGradientLoadingBarViewModel.swift; sourceTree = ""; }; E0AE401171F66B5A704B064F6007059B /* Observable+Equatable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Equatable.swift"; path = "LightweightObservable/Classes/Extensions/Observable+Equatable.swift"; sourceTree = ""; }; E0D90990792D653F523A884442305989 /* Pods-GradientLoadingBar_Example.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-GradientLoadingBar_Example.modulemap"; sourceTree = ""; }; E475B473BD1D9805A199E083205DD153 /* CaseIterable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CaseIterable.swift; path = Sources/SnapshotTesting/Snapshotting/CaseIterable.swift; sourceTree = ""; }; ED333E2FD9F83C466E13C6A69C917345 /* String+SpecialCharacters.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+SpecialCharacters.swift"; path = "Sources/SnapshotTesting/Common/String+SpecialCharacters.swift"; sourceTree = ""; }; ED5073BA8E5F040F45B737BBC7393222 /* Async.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Async.swift; path = Sources/SnapshotTesting/Async.swift; sourceTree = ""; }; - F196AAA163469B17170E99B82C7C4C0A /* LightweightObservable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = LightweightObservable.framework; path = LightweightObservable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F196AAA163469B17170E99B82C7C4C0A /* LightweightObservable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LightweightObservable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F7B1750DE470F045803DE2094D5F7264 /* Pods-GradientLoadingBar_SnapshotTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-GradientLoadingBar_SnapshotTests-Info.plist"; sourceTree = ""; }; FBAEAE91BB9B77006558E537894C33C5 /* Pods-GradientLoadingBar_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-GradientLoadingBar_Tests.debug.xcconfig"; sourceTree = ""; }; FF135E1D23F08BE7F1D7FFC86260EF9B /* Pods-GradientLoadingBar_SnapshotTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-GradientLoadingBar_SnapshotTests-acknowledgements.markdown"; sourceTree = ""; }; @@ -391,7 +396,6 @@ 8B7AAA3C809414A46F196C6DE5F6CFB4 /* Observable+KeyPath.swift */, 9CF614E301B83EC4DD18CF37D095ED73 /* Support Files */, ); - name = LightweightObservable; path = LightweightObservable; sourceTree = ""; }; @@ -400,7 +404,6 @@ children = ( D849F6B1672F929753FBCBD372FABBFA /* Support Files */, ); - name = SwiftLint; path = SwiftLint; sourceTree = ""; }; @@ -418,7 +421,6 @@ children = ( 73893CCD044DB8B8BFF17C6C86A52345 /* Support Files */, ); - name = SwiftFormat; path = SwiftFormat; sourceTree = ""; }; @@ -473,7 +475,6 @@ C4C95B2FA66AB0EFC760FE3BC82E183D /* XCTAttachment.swift */, 0E360A9F9862C6DCC0C9EF8C5DF2BF51 /* Support Files */, ); - name = SnapshotTesting; path = SnapshotTesting; sourceTree = ""; }; @@ -519,6 +520,7 @@ children = ( 3D25A3B900085A32A5C7D3F385452EF0 /* GradientActivityIndicatorViewModel.swift */, 8224E37407CEAAEBC6A6BF5B09960E84 /* GradientLoadingBarViewModel.swift */, + DC9FF935270A3FA10065B5B9 /* NotchGradientLoadingBarViewModel.swift */, ); name = ViewModel; path = GradientLoadingBar/Classes/ViewModel; @@ -541,7 +543,6 @@ children = ( 9F500AA9EDCC9F77CF819939A745BC17 /* Support Files */, ); - name = SwiftConfigurationFiles; path = SwiftConfigurationFiles; sourceTree = ""; }; @@ -941,6 +942,7 @@ DDDE93984B4D723CB07EC2F755E8DE2F /* GradientLoadingBar-dummy.m in Sources */, 9ADB23CA3DF64D1CF47513040AA579E1 /* GradientLoadingBarController.swift in Sources */, 081ACC777E7889B6D4A7F968C34DE894 /* GradientLoadingBarViewModel.swift in Sources */, + DC9FF936270A3FA10065B5B9 /* NotchGradientLoadingBarViewModel.swift in Sources */, AA10687BD2EC0D7EC6131EFB66CA1132 /* NotchGradientLoadingBarController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1532,8 +1534,7 @@ MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; diff --git a/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift b/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift index 028e35f..dc8061b 100644 --- a/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift +++ b/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift @@ -116,6 +116,6 @@ class GradientLoadingBarViewModelTestCase: XCTestCase { // MARK: - Mocks -class SharedApplicationMock: UIApplicationProtocol { +private class SharedApplicationMock: UIApplicationProtocol { var windows = [UIWindow]() } diff --git a/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift b/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift new file mode 100644 index 0000000..dfb6a02 --- /dev/null +++ b/Example/Tests/ViewModel/NotchGradientLoadingBarViewModelTestCase.swift @@ -0,0 +1,76 @@ +// +// NotchGradientLoadingBarViewModelTestCase.swift +// GradientLoadingBar_Tests +// +// Created by Felix Mau on 26.12.17. +// Copyright © 2017 Felix Mau. All rights reserved. +// + +import XCTest + +@testable import GradientLoadingBar + +class NotchGradientLoadingBarViewModelTestCase: XCTestCase { + func testInitializerShouldSetSafeAreaDeviceToIPhoneX() { + // Given + let deviceIdentifiers = ["iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6", "iPhone11,8"] + deviceIdentifiers.forEach { deviceIdentifier in + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .iPhoneX) + } + } + + func testInitializerShouldSetSafeAreaDeviceToIPhone11() { + // Given + let deviceIdentifiers = ["iPhone12,1", "iPhone12,3", "iPhone12,5"] + deviceIdentifiers.forEach { deviceIdentifier in + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .iPhone11) + } + } + + func testInitializerShouldSetSafeAreaDeviceToIPhone12() { + // Given + let deviceIdentifiers = ["iPhone13,1", "iPhone13,2", "iPhone13,3", "iPhone13,4"] + deviceIdentifiers.forEach { deviceIdentifier in + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .iPhone12) + } + } + + func testInitializerShouldSetSafeAreaDeviceToIPhone13() { + // Given + let deviceIdentifiers = ["iPhone14,4", "iPhone14,5", "iPhone14,2", "iPhone14,3"] + deviceIdentifiers.forEach { deviceIdentifier in + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .iPhone13) + } + } + + func testInitializerShouldSetSafeAreaDeviceToUnknown() { + // Given + let deviceIdentifier = "Foo-Bar-🤡" + + // When + let viewModel = NotchGradientLoadingBarViewModel(deviceIdentifier: deviceIdentifier) + + // Then + XCTAssertEqual(viewModel.safeAreaDevice, .unknown) + } +} diff --git a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift index 9d2d575..0717978 100644 --- a/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/NotchGradientLoadingBarController.swift @@ -15,17 +15,25 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // MARK: - Config private struct Config { - /// The default configuration for the iPhone X, 11 and 12. + /// The default configuration for the iPhone X and 11. /// Values are based on . - static let `default` = Config(notchWidth: 209.5, - largeCircleRadius: 21, - verticalOffsetForLargeCircle: -1.75) + static let `default` = Config(notchWidth: 208, + largeCircleRadius: 22.5, + verticalOffsetForLargeCircle: -4.5, + transform: CGAffineTransform(translationX: 0.33, y: 0)) + + /// The iPhone 12 specific configuration. + static let iPhone12Device = Config(notchWidth: 209.5, + largeCircleRadius: 21, + verticalOffsetForLargeCircle: -1.75, + transform: .identity) // The iPhone 13 specific configuration: ‟iPhone 13 notch is 20% smaller in width, but it is also a little taller in height‟. // Source: . static let iPhone13Device = Config(notchWidth: 161, largeCircleRadius: 22, - verticalOffsetForLargeCircle: -1) + verticalOffsetForLargeCircle: -1, + transform: .identity) /// The width of the iPhone notch. let notchWidth: CGFloat @@ -36,12 +44,19 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { /// The radius of the large circle on the inside of the notch. let largeCircleRadius: CGFloat - // We're moving the the large-circles a bit up. - // This prevents having a straight line between the circles. - // See + /// We're moving the the large-circles a bit up. + /// This prevents having a straight line between the circles. + /// See let verticalOffsetForLargeCircle: CGFloat + + /// The transform to be applied to the bezier path. + let transform: CGAffineTransform } + // MARK: - Private properties + + private let viewModel = NotchGradientLoadingBarViewModel() + // MARK: - Public methods override open func setupConstraints(superview: UIView) { @@ -67,8 +82,20 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // As we currently only support portrait mode (and no device rotation), we can safely use `bounds.size.width` here. let screenWidth = superview.bounds.size.width - let notchBezierPath = self.notchBezierPath(for: screenWidth, - config: UIDevice.isAnyIPhone13Device ? .iPhone13Device : .default) + + let config: Config + switch viewModel.safeAreaDevice { + case .unknown, .iPhoneX, .iPhone11: + config = .default + + case .iPhone12: + config = .iPhone12Device + + case .iPhone13: + config = .iPhone13Device + } + + let notchBezierPath = self.notchBezierPath(for: screenWidth, config: config) // Setting the `lineWidth` draws a line, where the actual path is exactly in the middle of the drawn line. // To get the correct height (including the path) we have to add the `height` here to the given bounds (half height for top, half for bottom). @@ -146,6 +173,7 @@ open class NotchGradientLoadingBarController: GradientLoadingBarController { // Draw line to the end of the screen. bezierPath.addLineTo(x: screenWidth, y: halfStrokeSize) + bezierPath.apply(config.transform) return bezierPath } @@ -180,34 +208,3 @@ private extension UIBezierPath { addLine(to: CGPoint(x: x, y: y)) } } - -private extension UIDevice { - private enum Config { - static let iPhone13Identifiers = ["iPhone14,5", "iPhone14,2", "iPhone14,3"] - } - - /// Starting from the iPhone 13 the notch is smaller, but a little bit higher. - /// Therefore we explicitly need to detect any iPhone 13 device for an adapted notch calculation. - /// - /// Based on: - /// Adapted for Simulator usage based on - static var isAnyIPhone13Device: Bool { - #if targetEnvironment(simulator) - let identifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "" - #else - var systemInfo = utsname() - uname(&systemInfo) - - let machineMirror = Mirror(reflecting: systemInfo.machine) - let identifier = machineMirror.children.reduce("") { identifier, element in - guard let value = element.value as? Int8, value != 0 else { - return identifier - } - - return identifier + String(UnicodeScalar(UInt8(value))) - } - #endif - - return Config.iPhone13Identifiers.contains(identifier) - } -} diff --git a/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift b/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift new file mode 100644 index 0000000..a8b583c --- /dev/null +++ b/GradientLoadingBar/Classes/ViewModel/NotchGradientLoadingBarViewModel.swift @@ -0,0 +1,82 @@ +// +// NotchGradientLoadingBarViewModel.swift +// GradientLoadingBar +// +// Created by Felix Mau on 03.10.21. +// Copyright © 2021 Felix Mau. All rights reserved. +// + +import Foundation + +final class NotchGradientLoadingBarViewModel { + // MARK: - Types + + enum SafeAreaDevice { + case unknown + case iPhoneX + case iPhone11 + case iPhone12 + case iPhone13 + } + + // MARK: - Public properties + + /// The current safe area device. + let safeAreaDevice: SafeAreaDevice + + // MARK: - Initializer + + init(deviceIdentifier: String = UIDevice.identifier) { + safeAreaDevice = SafeAreaDevice(deviceIdentifier: deviceIdentifier) + } +} + +// MARK: - Helpers + +private extension NotchGradientLoadingBarViewModel.SafeAreaDevice { + /// Creates a new instance from a given `deviceIdentifier` (value returned by `UIDevice.identifier`). + /// + /// Taken from + init(deviceIdentifier: String) { + switch deviceIdentifier { + case "iPhone10,3", "iPhone10,6", "iPhone11,2", "iPhone11,4", "iPhone11,6", "iPhone11,8": + self = .iPhoneX + + case "iPhone12,1", "iPhone12,3", "iPhone12,5": + self = .iPhone11 + + case "iPhone13,1", "iPhone13,2", "iPhone13,3", "iPhone13,4": + self = .iPhone12 + + case "iPhone14,4", "iPhone14,5", "iPhone14,2", "iPhone14,3": + self = .iPhone13 + + default: + self = .unknown + } + } +} + +private extension UIDevice { + /// Returns the device identifier. + /// + /// Based on: + /// Adapted for Simulator usage on + static var identifier: String { + #if targetEnvironment(simulator) + return ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "" + #else + var systemInfo = utsname() + uname(&systemInfo) + + let machineMirror = Mirror(reflecting: systemInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { + return identifier + } + + return identifier + String(UnicodeScalar(UInt8(value))) + } + #endif + } +}