From 5a0eadd73fbb485c9be8fce94027b3b4666ec809 Mon Sep 17 00:00:00 2001
From: Vincent Neo <23420208+vincentneo@users.noreply.github.com>
Date: Tue, 31 Jan 2023 00:25:00 +0800
Subject: [PATCH 1/5] watch devices support
---
.../contents.xcworkspacedata | 7 +
UIDeviceComplete.xcodeproj/project.pbxproj | 157 ++++++++++++++++++
WKDeviceComplete/DeviceModel.swift | 73 ++++++++
WKDeviceComplete/Identifier.swift | 152 +++++++++++++++++
WKDeviceComplete/Screen.swift | 60 +++++++
WKDeviceComplete/WKDeviceComplete.h | 19 +++
WKDeviceComplete/WKDeviceComplete.swift | 46 +++++
.../WKInterfaceDeviceExtensions.swift | 54 ++++++
8 files changed, 568 insertions(+)
create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
create mode 100644 WKDeviceComplete/DeviceModel.swift
create mode 100644 WKDeviceComplete/Identifier.swift
create mode 100644 WKDeviceComplete/Screen.swift
create mode 100644 WKDeviceComplete/WKDeviceComplete.h
create mode 100644 WKDeviceComplete/WKDeviceComplete.swift
create mode 100644 WKDeviceComplete/WKInterfaceDeviceExtensions.swift
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/UIDeviceComplete.xcodeproj/project.pbxproj b/UIDeviceComplete.xcodeproj/project.pbxproj
index 009e021..03fb1fd 100644
--- a/UIDeviceComplete.xcodeproj/project.pbxproj
+++ b/UIDeviceComplete.xcodeproj/project.pbxproj
@@ -20,6 +20,13 @@
AA1C21AB1F385C2A0095BFBD /* UIDeviceExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21A71F385C2A0095BFBD /* UIDeviceExtensionsTests.swift */; };
AAB1EF351F13866F003BBCF2 /* UIDeviceComplete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB1EF2B1F13866F003BBCF2 /* UIDeviceComplete.framework */; };
AAB1EF3C1F13866F003BBCF2 /* UIDeviceComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB1EF2E1F13866F003BBCF2 /* UIDeviceComplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ BF72D63129880FAC00B70A2B /* WKDeviceComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ BF72D63629880FCF00B70A2B /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219A1F385BEC0095BFBD /* System.swift */; };
+ BF72D638298810D700B70A2B /* DeviceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D637298810D700B70A2B /* DeviceModel.swift */; };
+ BF72D63A2988115000B70A2B /* Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D6392988115000B70A2B /* Identifier.swift */; };
+ BF72D63C29881D1A00B70A2B /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63B29881D1A00B70A2B /* Screen.swift */; };
+ BF72D63E2988206900B70A2B /* WKInterfaceDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */; };
+ BF72D6402988209C00B70A2B /* WKDeviceComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */; };
BFA9121C215B9881000CD8A8 /* DeviceModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */; };
/* End PBXBuildFile section */
@@ -50,6 +57,13 @@
AAB1EF2F1F13866F003BBCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIDeviceCompleteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AAB1EF3B1F13866F003BBCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WKDeviceComplete.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKDeviceComplete.h; sourceTree = ""; };
+ BF72D637298810D700B70A2B /* DeviceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceModel.swift; sourceTree = ""; };
+ BF72D6392988115000B70A2B /* Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identifier.swift; sourceTree = ""; };
+ BF72D63B29881D1A00B70A2B /* Screen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = ""; };
+ BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKInterfaceDeviceExtensions.swift; sourceTree = ""; };
+ BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKDeviceComplete.swift; sourceTree = ""; };
BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceModelTests.swift; path = Tests/DeviceModelTests.swift; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@@ -69,6 +83,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ BF72D62B29880FAC00B70A2B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -77,6 +98,7 @@
children = (
AAB1EF2D1F13866F003BBCF2 /* UIDeviceComplete */,
AAB1EF381F13866F003BBCF2 /* UIDeviceCompleteTests */,
+ BF72D62F29880FAC00B70A2B /* WKDeviceComplete */,
AAB1EF2C1F13866F003BBCF2 /* Products */,
);
sourceTree = "";
@@ -86,6 +108,7 @@
children = (
AAB1EF2B1F13866F003BBCF2 /* UIDeviceComplete.framework */,
AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */,
+ BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */,
);
name = Products;
sourceTree = "";
@@ -127,6 +150,19 @@
name = Sources;
sourceTree = "";
};
+ BF72D62F29880FAC00B70A2B /* WKDeviceComplete */ = {
+ isa = PBXGroup;
+ children = (
+ BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */,
+ BF72D637298810D700B70A2B /* DeviceModel.swift */,
+ BF72D6392988115000B70A2B /* Identifier.swift */,
+ BF72D63B29881D1A00B70A2B /* Screen.swift */,
+ BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */,
+ BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */,
+ );
+ path = WKDeviceComplete;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -138,6 +174,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ BF72D62929880FAC00B70A2B /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BF72D63129880FAC00B70A2B /* WKDeviceComplete.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@@ -177,6 +221,24 @@
productReference = AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
+ BF72D62D29880FAC00B70A2B /* WKDeviceComplete */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BF72D63429880FAC00B70A2B /* Build configuration list for PBXNativeTarget "WKDeviceComplete" */;
+ buildPhases = (
+ BF72D62929880FAC00B70A2B /* Headers */,
+ BF72D62A29880FAC00B70A2B /* Sources */,
+ BF72D62B29880FAC00B70A2B /* Frameworks */,
+ BF72D62C29880FAC00B70A2B /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = WKDeviceComplete;
+ productName = WKDeviceComplete;
+ productReference = BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */;
+ productType = "com.apple.product-type.framework";
+ };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -197,6 +259,10 @@
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
+ BF72D62D29880FAC00B70A2B = {
+ CreatedOnToolsVersion = 14.2;
+ ProvisioningStyle = Automatic;
+ };
};
};
buildConfigurationList = AAB1EF251F13866F003BBCF2 /* Build configuration list for PBXProject "UIDeviceComplete" */;
@@ -214,6 +280,7 @@
targets = (
AAB1EF2A1F13866F003BBCF2 /* UIDeviceComplete */,
AAB1EF331F13866F003BBCF2 /* UIDeviceCompleteTests */,
+ BF72D62D29880FAC00B70A2B /* WKDeviceComplete */,
);
};
/* End PBXProject section */
@@ -233,6 +300,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ BF72D62C29880FAC00B70A2B /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -262,6 +336,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ BF72D62A29880FAC00B70A2B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BF72D63E2988206900B70A2B /* WKInterfaceDeviceExtensions.swift in Sources */,
+ BF72D63629880FCF00B70A2B /* System.swift in Sources */,
+ BF72D63A2988115000B70A2B /* Identifier.swift in Sources */,
+ BF72D638298810D700B70A2B /* DeviceModel.swift in Sources */,
+ BF72D6402988209C00B70A2B /* WKDeviceComplete.swift in Sources */,
+ BF72D63C29881D1A00B70A2B /* Screen.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -475,6 +562,67 @@
};
name = Release;
};
+ BF72D63229880FAC00B70A2B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nicholas Maccharoli. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.vincent-neo.WKDeviceComplete";
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 4.0;
+ };
+ name = Debug;
+ };
+ BF72D63329880FAC00B70A2B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nicholas Maccharoli. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.vincent-neo.WKDeviceComplete";
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 4.0;
+ };
+ name = Release;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -505,6 +653,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ BF72D63429880FAC00B70A2B /* Build configuration list for PBXNativeTarget "WKDeviceComplete" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BF72D63229880FAC00B70A2B /* Debug */,
+ BF72D63329880FAC00B70A2B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
/* End XCConfigurationList section */
};
rootObject = AAB1EF221F13866F003BBCF2 /* Project object */;
diff --git a/WKDeviceComplete/DeviceModel.swift b/WKDeviceComplete/DeviceModel.swift
new file mode 100644
index 0000000..82500b9
--- /dev/null
+++ b/WKDeviceComplete/DeviceModel.swift
@@ -0,0 +1,73 @@
+//
+// DeviceModel.swift
+//
+// Copyright (c) 2017-2023 Nicholas Maccharoli
+// Copyright (c) 2023 Vincent Neo
+//
+// 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.
+
+public enum DeviceModel: CaseIterable {
+ case firstGen
+ case series1
+ case series2
+ case series3
+ case series4
+ case series5
+ case se
+ case series6
+ case series7
+ case series8
+ case se2
+ case ultra
+
+ case unknown
+}
+
+// MARK: - init
+
+extension DeviceModel {
+ init(identifier: Identifier) {
+ self = DeviceModel.detectWatchModel(with: identifier)
+ }
+}
+
+extension DeviceModel {
+ fileprivate static func detectWatchModel(with identifier: Identifier) -> DeviceModel {
+ guard let major = identifier.version.major,
+ let minor = identifier.version.minor
+ else { return .unknown }
+
+ switch (major, minor) {
+ case (1, _): return .firstGen
+ case (2, 3), (2, 4): return .series2
+ case (2, 6), (2, 7): return .series1
+ case (3, _): return .series3
+ case (4, _): return .series4
+ case (5, 1), (5, 2), (5, 3), (5, 4): return .series5
+ case (5, 9), (5, 10), (5, 11), (5, 12): return .se
+ case (6, 1), (6, 2), (6, 3), (6, 4): return .series6
+ case (6, 6), (6, 7), (6, 8), (6, 9): return .series7
+ case (6, 10), (6, 11), (6, 12), (6, 13): return .se2
+ case (6, 14), (6, 15), (6, 16), (6, 17): return .series8
+ case (6, 18): return .ultra
+
+ default: return .unknown
+ }
+ }
+}
diff --git a/WKDeviceComplete/Identifier.swift b/WKDeviceComplete/Identifier.swift
new file mode 100644
index 0000000..341f961
--- /dev/null
+++ b/WKDeviceComplete/Identifier.swift
@@ -0,0 +1,152 @@
+//
+// Identifier.swift
+//
+// Copyright (c) 2017-2023 Nicholas Maccharoli
+// Copyright (c) 2023 Vincent Neo
+//
+// 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.
+
+struct Identifier {
+ let version: (major: Int?, minor: Int?)
+
+ init(_ identifier: String) {
+ let (major, minor) = Identifier.typeVersionComponents(with: identifier)
+ self.version = (major, minor)
+ }
+}
+
+
+// MARK: - Identifier String parsing
+
+extension Identifier {
+ static func typeVersionComponents(with identifierString: String) -> (major: Int?, minor: Int?) {
+
+ let numericCharacters: [String] = (0...9).map { "\($0)" }
+ let type = identifierString.prefix(while: { !numericCharacters.contains(String($0))})
+
+ let version = identifierString.suffix(from: type.endIndex)
+ .split(separator: ",")
+ .map { Int($0) }
+
+ let major: Int? = !version.isEmpty ? version[0] : nil
+ let minor: Int? = version.count > 1 ? version[1] : nil
+
+ return (major, minor)
+ }
+}
+
+
+// MARK: - String Representation - Watch
+
+extension Identifier: CustomStringConvertible {
+ var description: String {
+
+ guard let major = version.major,
+ let minor = version.minor
+ else { return "unknown" }
+
+ return watchStringRepresentable(major: major, minor: minor)
+ }
+
+ private func watchStringRepresentable(major: Int, minor: Int) -> String {
+ switch (major, minor) {
+ case (1, 1):
+ return "Apple Watch (1st generation), 38mm case"
+ case (1, 2):
+ return "Apple Watch (1st generation), 42mm case"
+ case (2, 3):
+ return "Apple Watch Series 2, 38mm case"
+ case (2, 4):
+ return "Apple Watch Series 2, 42mm case"
+ case (2, 6):
+ return "Apple Watch Series 1, 38mm case"
+ case (2, 7):
+ return "Apple Watch Series 1, 42mm case"
+ case (3, 1):
+ return "Apple Watch Series 3, 38mm case (GPS + Cellular)"
+ case (3, 2):
+ return "Apple Watch Series 3, 42mm case (GPS + Cellular)"
+ case (3, 3):
+ return "Apple Watch Series 3, 38mm case (GPS)"
+ case (3, 4):
+ return "Apple Watch Series 3, 42mm case (GPS)"
+ case (4, 1):
+ return "Apple Watch Series 4, 40mm case (GPS)"
+ case (4, 2):
+ return "Apple Watch Series 4, 44mm case (GPS)"
+ case (4, 3):
+ return "Apple Watch Series 4, 40mm case (GPS + Cellular)"
+ case (4, 4):
+ return "Apple Watch Series 4, 44mm case (GPS + Cellular)"
+ case (5, 1):
+ return "Apple Watch Series 5, 40mm case (GPS)"
+ case (5, 2):
+ return "Apple Watch Series 5, 44mm case (GPS)"
+ case (5, 3):
+ return "Apple Watch Series 5, 40mm case (GPS + Cellular)"
+ case (5, 4):
+ return "Apple Watch Series 5, 44mm case (GPS + Cellular)"
+ case (5, 9):
+ return "Apple Watch SE, 40mm case (GPS)"
+ case (5, 10):
+ return "Apple Watch SE, 44mm case (GPS)"
+ case (5, 11):
+ return "Apple Watch SE, 40mm case (GPS + Cellular)"
+ case (5, 12):
+ return "Apple Watch SE, 44mm case (GPS + Cellular)"
+ case (6, 1):
+ return "Apple Watch Series 6, 40mm case (GPS)"
+ case (6, 2):
+ return "Apple Watch Series 6, 44mm case (GPS)"
+ case (6, 3):
+ return "Apple Watch Series 6, 40mm case (GPS + Cellular)"
+ case (6, 4):
+ return "Apple Watch Series 6, 44mm case (GPS + Cellular)"
+ case (6, 6):
+ return "Apple Watch Series 7, 41mm case (GPS)"
+ case (6, 7):
+ return "Apple Watch Series 7, 45mm case (GPS)"
+ case (6, 8):
+ return "Apple Watch Series 7, 41mm case (GPS + Cellular)"
+ case (6, 9):
+ return "Apple Watch Series 7, 45mm case (GPS + Cellular)"
+ case (6, 10):
+ return "Apple Watch SE (2nd Generation), 40mm case (GPS)"
+ case (6, 11):
+ return "Apple Watch SE (2nd Generation), 44mm case (GPS)"
+ case (6, 12):
+ return "Apple Watch SE (2nd Generation), 40mm case (GPS + Cellular)"
+ case (6, 13):
+ return "Apple Watch SE (2nd Generation), 44mm case (GPS + Cellular)"
+ case (6, 14):
+ return "Apple Watch Series 8, 41mm case (GPS)"
+ case (6, 15):
+ return "Apple Watch Series 8, 45mm case (GPS)"
+ case (6, 16):
+ return "Apple Watch Series 8, 41mm case (GPS + Cellular)"
+ case (6, 17):
+ return "Apple Watch Series 8, 45mm case (GPS + Cellular)"
+ case (6, 18):
+ return "Apple Watch Ultra"
+ default:
+ return "unknown"
+ }
+ }
+
+}
diff --git a/WKDeviceComplete/Screen.swift b/WKDeviceComplete/Screen.swift
new file mode 100644
index 0000000..1634b48
--- /dev/null
+++ b/WKDeviceComplete/Screen.swift
@@ -0,0 +1,60 @@
+//
+// Screen.swift
+//
+// Copyright (c) 2017-2023 Nicholas Maccharoli
+// Copyright (c) 2023 Vincent Neo
+//
+// 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.
+
+public struct Screen {
+ let caseSize: Int?
+}
+
+extension Screen {
+ init(identifier: Identifier) {
+ self.caseSize = Screen.detectCaseSize(with: identifier)
+ }
+}
+
+// MARK: - Detecting Screen size by model, in mm
+
+extension Screen {
+ fileprivate static func detectCaseSize(with identifier: Identifier) -> Int? {
+ guard let major = identifier.version.major,
+ let minor = identifier.version.minor
+ else { return nil }
+
+ switch (major, minor) {
+ case (1, 1), (2, 3), (2, 6), (3, 1), (3, 3): return 38
+ case (1, 2), (2, 4), (2, 7), (3, 2), (3, 4): return 42
+
+ case (4, 1), (4, 3), (5, 1), (5, 3), (5, 9),
+ (5, 11), (6, 1), (6, 3), (6, 10), (6, 12): return 40
+ case (4, 2), (4, 4), (5, 2), (5, 4), (5, 10),
+ (5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return 44
+
+ case (6, 6), (6, 8), (6, 14), (6, 16): return 41
+ case (6, 7), (6, 9), (6, 15), (6, 17): return 45
+
+ case (6, 18): return 49
+
+ default: return nil
+ }
+ }
+}
diff --git a/WKDeviceComplete/WKDeviceComplete.h b/WKDeviceComplete/WKDeviceComplete.h
new file mode 100644
index 0000000..6b75725
--- /dev/null
+++ b/WKDeviceComplete/WKDeviceComplete.h
@@ -0,0 +1,19 @@
+//
+// WKDeviceComplete.h
+// WKDeviceComplete
+//
+// Created by Vincent Neo on 30/1/23.
+// Copyright © 2023 Nicholas Maccharoli. All rights reserved.
+//
+
+#import
+
+//! Project version number for WKDeviceComplete.
+FOUNDATION_EXPORT double WKDeviceCompleteVersionNumber;
+
+//! Project version string for WKDeviceComplete.
+FOUNDATION_EXPORT const unsigned char WKDeviceCompleteVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+
diff --git a/WKDeviceComplete/WKDeviceComplete.swift b/WKDeviceComplete/WKDeviceComplete.swift
new file mode 100644
index 0000000..a4312be
--- /dev/null
+++ b/WKDeviceComplete/WKDeviceComplete.swift
@@ -0,0 +1,46 @@
+//
+// WKDeviceComplete.swift
+//
+// Copyright (c) 2017-2023 Nicholas Maccharoli
+// Copyright (c) 2023 Vincent Neo
+//
+// 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 WatchKit
+
+public final class WKDeviceComplete {
+ let base: Base
+ public init(_ base: Base) {
+ self.base = base
+ }
+}
+
+public protocol WKDeviceCompleteCompatible {
+ associatedtype CompatibleType
+
+ var dc: CompatibleType { get }
+}
+
+public extension WKDeviceCompleteCompatible {
+ var dc: WKDeviceComplete {
+ return WKDeviceComplete(self)
+ }
+}
+
+extension WKInterfaceDevice: WKDeviceCompleteCompatible { }
diff --git a/WKDeviceComplete/WKInterfaceDeviceExtensions.swift b/WKDeviceComplete/WKInterfaceDeviceExtensions.swift
new file mode 100644
index 0000000..cf19473
--- /dev/null
+++ b/WKDeviceComplete/WKInterfaceDeviceExtensions.swift
@@ -0,0 +1,54 @@
+//
+// WKInterfaceDeviceExtensions.swift
+//
+// Copyright (c) 2017-2023 Nicholas Maccharoli
+// Copyright (c) 2023 Vincent Neo
+//
+// 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 WatchKit
+
+public extension WKDeviceComplete where Base == WKInterfaceDevice {
+
+ private var identifier: Identifier? {
+ return System.name.flatMap {
+ return Identifier($0)
+ }
+ }
+
+ /// Specific model i.e iphone7 or iPhone7s
+ var deviceModel: DeviceModel {
+ return identifier.flatMap { DeviceModel(identifier: $0) } ?? .unknown
+ }
+
+ /// Common name for device i.e "iPhone 7 Plus"
+ var commonDeviceName: String {
+ return identifier?.description ?? "unknown"
+ }
+
+}
+
+// MARK: - Screen Size Detection
+
+public extension WKDeviceComplete where Base == WKInterfaceDevice {
+ var screenSize: Screen? {
+ guard let identifier else { return nil }
+ return Screen(identifier: identifier)
+ }
+}
From f9d8a7bab19b66315c2997c1e932baf165bf94c4 Mon Sep 17 00:00:00 2001
From: Vincent Neo <23420208+vincentneo@users.noreply.github.com>
Date: Thu, 14 Sep 2023 12:07:57 +0800
Subject: [PATCH 2/5] Support for Series 9 and Ultra 2 watches
---
WKDeviceComplete/DeviceModel.swift | 4 ++++
WKDeviceComplete/Identifier.swift | 10 ++++++++++
WKDeviceComplete/Screen.swift | 8 +++++---
3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/WKDeviceComplete/DeviceModel.swift b/WKDeviceComplete/DeviceModel.swift
index 82500b9..3d80f1a 100644
--- a/WKDeviceComplete/DeviceModel.swift
+++ b/WKDeviceComplete/DeviceModel.swift
@@ -35,6 +35,8 @@ public enum DeviceModel: CaseIterable {
case series8
case se2
case ultra
+ case series9
+ case ultra2
case unknown
}
@@ -66,6 +68,8 @@ extension DeviceModel {
case (6, 10), (6, 11), (6, 12), (6, 13): return .se2
case (6, 14), (6, 15), (6, 16), (6, 17): return .series8
case (6, 18): return .ultra
+ case (7, 1), (7, 2), (7, 3), (7, 4): return .series9
+ case (7, 5): return .ultra2
default: return .unknown
}
diff --git a/WKDeviceComplete/Identifier.swift b/WKDeviceComplete/Identifier.swift
index 341f961..b282b74 100644
--- a/WKDeviceComplete/Identifier.swift
+++ b/WKDeviceComplete/Identifier.swift
@@ -144,6 +144,16 @@ extension Identifier: CustomStringConvertible {
return "Apple Watch Series 8, 45mm case (GPS + Cellular)"
case (6, 18):
return "Apple Watch Ultra"
+ case (7, 1):
+ return "Apple Watch Series 9, 41mm case (GPS)"
+ case (7, 2):
+ return "Apple Watch Series 9, 45mm case (GPS)"
+ case (7, 3):
+ return "Apple Watch Series 9, 41mm case (GPS + Cellular)"
+ case (7, 4):
+ return "Apple Watch Series 9, 45mm case (GPS + Cellular)"
+ case (7, 5):
+ return "Apple Watch Ultra 2"
default:
return "unknown"
}
diff --git a/WKDeviceComplete/Screen.swift b/WKDeviceComplete/Screen.swift
index 1634b48..c5856de 100644
--- a/WKDeviceComplete/Screen.swift
+++ b/WKDeviceComplete/Screen.swift
@@ -49,10 +49,12 @@ extension Screen {
case (4, 2), (4, 4), (5, 2), (5, 4), (5, 10),
(5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return 44
- case (6, 6), (6, 8), (6, 14), (6, 16): return 41
- case (6, 7), (6, 9), (6, 15), (6, 17): return 45
+ case (6, 6), (6, 8), (6, 14), (6, 16),
+ (7, 1), (7, 3): return 41
+ case (6, 7), (6, 9), (6, 15), (6, 17),
+ (7, 2), (7, 4): return 45
- case (6, 18): return 49
+ case (6, 18), (7, 5): return 49
default: return nil
}
From 8c0cbe4d5c2adc8df4adbc8052feea88abdcc701 Mon Sep 17 00:00:00 2001
From: Vincent Neo <23420208+vincentneo@users.noreply.github.com>
Date: Sat, 16 Sep 2023 16:56:19 +0800
Subject: [PATCH 3/5] merge ios and watchos codebase into one
---
Package.swift | 2 +-
Sources/DeviceFamily.swift | 3 +
Sources/DeviceModel.swift | 66 ++++++-
Sources/Identifier.swift | 97 +++++++++++
Sources/Screen.swift | 42 ++++-
Sources/UIDeviceComplete.swift | 8 +
Sources/UIDeviceExtensions.swift | 19 +-
UIDeviceComplete.xcodeproj/project.pbxproj | 44 ++---
WKDeviceComplete/DeviceModel.swift | 77 ---------
WKDeviceComplete/Identifier.swift | 162 ------------------
WKDeviceComplete/Screen.swift | 62 -------
WKDeviceComplete/WKDeviceComplete.h | 19 --
WKDeviceComplete/WKDeviceComplete.swift | 46 -----
.../WKInterfaceDeviceExtensions.swift | 54 ------
14 files changed, 238 insertions(+), 463 deletions(-)
delete mode 100644 WKDeviceComplete/DeviceModel.swift
delete mode 100644 WKDeviceComplete/Identifier.swift
delete mode 100644 WKDeviceComplete/Screen.swift
delete mode 100644 WKDeviceComplete/WKDeviceComplete.h
delete mode 100644 WKDeviceComplete/WKDeviceComplete.swift
delete mode 100644 WKDeviceComplete/WKInterfaceDeviceExtensions.swift
diff --git a/Package.swift b/Package.swift
index 3ac5ed8..4e31a0b 100644
--- a/Package.swift
+++ b/Package.swift
@@ -25,7 +25,7 @@ import PackageDescription
let package = Package(
name: "UIDeviceComplete",
platforms: [
- .iOS(.v11)
+ .iOS(.v11), .watchOS(.v4)
],
products: [
.library(name: "UIDeviceComplete", targets: ["UIDeviceComplete"])
diff --git a/Sources/DeviceFamily.swift b/Sources/DeviceFamily.swift
index 545ede2..1e353ec 100644
--- a/Sources/DeviceFamily.swift
+++ b/Sources/DeviceFamily.swift
@@ -26,6 +26,7 @@ public enum DeviceFamily: String {
case iPhone
case iPod
case iPad
+ case watch
case unknown
public init(rawValue: String) {
@@ -36,6 +37,8 @@ public enum DeviceFamily: String {
self = .iPod
case "iPad":
self = .iPad
+ case "Watch":
+ self = .watch
default:
self = .unknown
}
diff --git a/Sources/DeviceModel.swift b/Sources/DeviceModel.swift
index c9b5682..96ca16b 100644
--- a/Sources/DeviceModel.swift
+++ b/Sources/DeviceModel.swift
@@ -23,6 +23,7 @@
public enum DeviceModel: CaseIterable {
+ #if os(iOS)
case iPhone4, iPhone4S
case iPhone5, iPhone5C, iPhone5S
case iPhone6, iPhone6Plus
@@ -62,7 +63,24 @@ public enum DeviceModel: CaseIterable {
case iPodTouchFirstGen, iPodTouchSecondGen, iPodTouchThirdGen,
iPodTouchFourthGen, iPodTouchFifthGen, iPodTouchSixthGen, iPodTouchSeventhGen
-
+
+ #elseif os(watchOS)
+ case firstGen
+ case series1
+ case series2
+ case series3
+ case series4
+ case series5
+ case se
+ case series6
+ case series7
+ case series8
+ case se2
+ case ultra
+ case series9
+ case ultra2
+ #endif
+
case unknown
}
@@ -72,19 +90,24 @@ public enum DeviceModel: CaseIterable {
extension DeviceModel {
init(identifier: Identifier) {
switch identifier.type {
+ #if os(iOS)
case .iPhone:
self = DeviceModel.detectIphoneModel(with: identifier)
case .iPad:
self = DeviceModel.detectIpadModel(with: identifier)
case .iPod:
self = DeviceModel.detectIpodModel(with: identifier)
+ #elseif os(watchOS)
+ case .watch:
+ self = DeviceModel.detectWatchModel(with: identifier)
+ #endif
default:
self = .unknown
}
}
}
-
+#if os(iOS)
// MARK: Detecting iPhone Models
extension DeviceModel {
@@ -154,8 +177,9 @@ extension DeviceModel {
}
}
}
+#endif
-
+#if os(iOS)
// MARK: Detecting iPad Models
extension DeviceModel {
@@ -207,8 +231,9 @@ extension DeviceModel {
}
}
}
+#endif
-
+#if os(iOS)
// MARK: Detecting iPod Models
extension DeviceModel {
@@ -230,8 +255,40 @@ extension DeviceModel {
}
}
}
+#endif
+#if os(watchOS)
+// MARK: Detecting Apple Watch Models
+
+extension DeviceModel {
+ fileprivate static func detectWatchModel(with identifier: Identifier) -> DeviceModel {
+ guard let major = identifier.version.major,
+ let minor = identifier.version.minor
+ else { return .unknown }
+
+ switch (major, minor) {
+ case (1, _): return .firstGen
+ case (2, 3), (2, 4): return .series2
+ case (2, 6), (2, 7): return .series1
+ case (3, _): return .series3
+ case (4, _): return .series4
+ case (5, 1), (5, 2), (5, 3), (5, 4): return .series5
+ case (5, 9), (5, 10), (5, 11), (5, 12): return .se
+ case (6, 1), (6, 2), (6, 3), (6, 4): return .series6
+ case (6, 6), (6, 7), (6, 8), (6, 9): return .series7
+ case (6, 10), (6, 11), (6, 12), (6, 13): return .se2
+ case (6, 14), (6, 15), (6, 16), (6, 17): return .series8
+ case (6, 18): return .ultra
+ case (7, 1), (7, 2), (7, 3), (7, 4): return .series9
+ case (7, 5): return .ultra2
+
+ default: return .unknown
+ }
+ }
+}
+#endif
+#if os(iOS)
// MARK: Detecting the Notch
extension DeviceModel {
@@ -266,3 +323,4 @@ extension DeviceModel {
}
}
}
+#endif
diff --git a/Sources/Identifier.swift b/Sources/Identifier.swift
index ff73c67..20e5f84 100644
--- a/Sources/Identifier.swift
+++ b/Sources/Identifier.swift
@@ -69,6 +69,8 @@ extension Identifier: CustomStringConvertible {
return iPadStringRepresentation(major: major, minor: minor)
case .iPod:
return iPodStringRepresentation(major: major, minor: minor)
+ case .watch:
+ return watchStringRepresentable(major: major, minor: minor)
case .unknown:
return "unknown"
}
@@ -384,4 +386,99 @@ extension Identifier: CustomStringConvertible {
return "unknown"
}
}
+
+ private func watchStringRepresentable(major: Int, minor: Int) -> String {
+ switch (major, minor) {
+ case (1, 1):
+ return "Apple Watch (1st generation), 38mm case"
+ case (1, 2):
+ return "Apple Watch (1st generation), 42mm case"
+ case (2, 3):
+ return "Apple Watch Series 2, 38mm case"
+ case (2, 4):
+ return "Apple Watch Series 2, 42mm case"
+ case (2, 6):
+ return "Apple Watch Series 1, 38mm case"
+ case (2, 7):
+ return "Apple Watch Series 1, 42mm case"
+ case (3, 1):
+ return "Apple Watch Series 3, 38mm case (GPS + Cellular)"
+ case (3, 2):
+ return "Apple Watch Series 3, 42mm case (GPS + Cellular)"
+ case (3, 3):
+ return "Apple Watch Series 3, 38mm case (GPS)"
+ case (3, 4):
+ return "Apple Watch Series 3, 42mm case (GPS)"
+ case (4, 1):
+ return "Apple Watch Series 4, 40mm case (GPS)"
+ case (4, 2):
+ return "Apple Watch Series 4, 44mm case (GPS)"
+ case (4, 3):
+ return "Apple Watch Series 4, 40mm case (GPS + Cellular)"
+ case (4, 4):
+ return "Apple Watch Series 4, 44mm case (GPS + Cellular)"
+ case (5, 1):
+ return "Apple Watch Series 5, 40mm case (GPS)"
+ case (5, 2):
+ return "Apple Watch Series 5, 44mm case (GPS)"
+ case (5, 3):
+ return "Apple Watch Series 5, 40mm case (GPS + Cellular)"
+ case (5, 4):
+ return "Apple Watch Series 5, 44mm case (GPS + Cellular)"
+ case (5, 9):
+ return "Apple Watch SE, 40mm case (GPS)"
+ case (5, 10):
+ return "Apple Watch SE, 44mm case (GPS)"
+ case (5, 11):
+ return "Apple Watch SE, 40mm case (GPS + Cellular)"
+ case (5, 12):
+ return "Apple Watch SE, 44mm case (GPS + Cellular)"
+ case (6, 1):
+ return "Apple Watch Series 6, 40mm case (GPS)"
+ case (6, 2):
+ return "Apple Watch Series 6, 44mm case (GPS)"
+ case (6, 3):
+ return "Apple Watch Series 6, 40mm case (GPS + Cellular)"
+ case (6, 4):
+ return "Apple Watch Series 6, 44mm case (GPS + Cellular)"
+ case (6, 6):
+ return "Apple Watch Series 7, 41mm case (GPS)"
+ case (6, 7):
+ return "Apple Watch Series 7, 45mm case (GPS)"
+ case (6, 8):
+ return "Apple Watch Series 7, 41mm case (GPS + Cellular)"
+ case (6, 9):
+ return "Apple Watch Series 7, 45mm case (GPS + Cellular)"
+ case (6, 10):
+ return "Apple Watch SE (2nd Generation), 40mm case (GPS)"
+ case (6, 11):
+ return "Apple Watch SE (2nd Generation), 44mm case (GPS)"
+ case (6, 12):
+ return "Apple Watch SE (2nd Generation), 40mm case (GPS + Cellular)"
+ case (6, 13):
+ return "Apple Watch SE (2nd Generation), 44mm case (GPS + Cellular)"
+ case (6, 14):
+ return "Apple Watch Series 8, 41mm case (GPS)"
+ case (6, 15):
+ return "Apple Watch Series 8, 45mm case (GPS)"
+ case (6, 16):
+ return "Apple Watch Series 8, 41mm case (GPS + Cellular)"
+ case (6, 17):
+ return "Apple Watch Series 8, 45mm case (GPS + Cellular)"
+ case (6, 18):
+ return "Apple Watch Ultra"
+ case (7, 1):
+ return "Apple Watch Series 9, 41mm case (GPS)"
+ case (7, 2):
+ return "Apple Watch Series 9, 45mm case (GPS)"
+ case (7, 3):
+ return "Apple Watch Series 9, 41mm case (GPS + Cellular)"
+ case (7, 4):
+ return "Apple Watch Series 9, 45mm case (GPS + Cellular)"
+ case (7, 5):
+ return "Apple Watch Ultra 2"
+ default:
+ return "unknown"
+ }
+ }
}
diff --git a/Sources/Screen.swift b/Sources/Screen.swift
index 5534a67..f6b9175 100644
--- a/Sources/Screen.swift
+++ b/Sources/Screen.swift
@@ -21,9 +21,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+#if os(iOS)
import UIKit
+#endif
public struct Screen {
+ #if os(iOS)
init(width: Double, height: Double, scale: Double) {
self.width = width
self.height = height
@@ -37,9 +40,16 @@ public struct Screen {
public var adjustedScale: Double {
return 1.0 / scale
}
+ #elseif os(watchOS)
+ init(identifier: Identifier) {
+ self.identifier = identifier
+ }
+
+ let identifier: Identifier
+ #endif
}
-
+#if os(iOS)
// MARK: - Detecting Screen size in Inches
extension Screen {
@@ -89,3 +99,33 @@ extension Screen {
}
}
+#endif
+
+#if os(watchOS)
+extension Screen {
+ public var caseSize: Int? {
+ guard let major = identifier.version.major,
+ let minor = identifier.version.minor
+ else { return nil }
+
+ switch (major, minor) {
+ case (1, 1), (2, 3), (2, 6), (3, 1), (3, 3): return 38
+ case (1, 2), (2, 4), (2, 7), (3, 2), (3, 4): return 42
+
+ case (4, 1), (4, 3), (5, 1), (5, 3), (5, 9),
+ (5, 11), (6, 1), (6, 3), (6, 10), (6, 12): return 40
+ case (4, 2), (4, 4), (5, 2), (5, 4), (5, 10),
+ (5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return 44
+
+ case (6, 6), (6, 8), (6, 14), (6, 16),
+ (7, 1), (7, 3): return 41
+ case (6, 7), (6, 9), (6, 15), (6, 17),
+ (7, 2), (7, 4): return 45
+
+ case (6, 18), (7, 5): return 49
+
+ default: return nil
+ }
+ }
+}
+#endif
diff --git a/Sources/UIDeviceComplete.swift b/Sources/UIDeviceComplete.swift
index c84baa7..f95503f 100644
--- a/Sources/UIDeviceComplete.swift
+++ b/Sources/UIDeviceComplete.swift
@@ -21,7 +21,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+#if os(iOS)
import UIKit
+#elseif os(watchOS)
+import WatchKit
+#endif
public final class UIDeviceComplete {
let base: Base
@@ -42,4 +46,8 @@ public extension UIDeviceCompleteCompatible {
}
}
+#if os(iOS)
extension UIDevice: UIDeviceCompleteCompatible { }
+#elseif os(watchOS)
+extension WKInterfaceDevice: UIDeviceCompleteCompatible { }
+#endif
diff --git a/Sources/UIDeviceExtensions.swift b/Sources/UIDeviceExtensions.swift
index e95c2a5..6142ad7 100644
--- a/Sources/UIDeviceExtensions.swift
+++ b/Sources/UIDeviceExtensions.swift
@@ -21,9 +21,15 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
+#if os(iOS)
import UIKit
+public typealias DCDevice = UIDevice
+#elseif os(watchOS)
+import WatchKit
+public typealias DCDevice = WKInterfaceDevice
+#endif
-public extension UIDeviceComplete where Base == UIDevice {
+public extension UIDeviceComplete where Base == DCDevice {
private var identifier: Identifier? {
return System.name.flatMap {
@@ -45,7 +51,8 @@ public extension UIDeviceComplete where Base == UIDevice {
var commonDeviceName: String {
return identifier?.description ?? "unknown"
}
-
+
+ #if os(iOS)
/// Device family iPhone
var isIphone: Bool {
return deviceFamily == .iPhone
@@ -60,13 +67,14 @@ public extension UIDeviceComplete where Base == UIDevice {
var isIpod: Bool {
return deviceFamily == .iPod
}
-
+ #endif
+
}
-
+#if os(iOS)
// MARK: - Screen Size Detection
-public extension UIDeviceComplete where Base == UIDevice {
+public extension UIDeviceComplete where Base == DCDevice {
var screenSize: Screen {
let scale: Double = Double(UIScreen.main.scale)
let width: Double = Double(UIScreen.main.bounds.width)
@@ -75,3 +83,4 @@ public extension UIDeviceComplete where Base == UIDevice {
return Screen(width: width, height: height, scale: scale)
}
}
+#endif
diff --git a/UIDeviceComplete.xcodeproj/project.pbxproj b/UIDeviceComplete.xcodeproj/project.pbxproj
index 03fb1fd..4b73f4f 100644
--- a/UIDeviceComplete.xcodeproj/project.pbxproj
+++ b/UIDeviceComplete.xcodeproj/project.pbxproj
@@ -20,14 +20,14 @@
AA1C21AB1F385C2A0095BFBD /* UIDeviceExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21A71F385C2A0095BFBD /* UIDeviceExtensionsTests.swift */; };
AAB1EF351F13866F003BBCF2 /* UIDeviceComplete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB1EF2B1F13866F003BBCF2 /* UIDeviceComplete.framework */; };
AAB1EF3C1F13866F003BBCF2 /* UIDeviceComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB1EF2E1F13866F003BBCF2 /* UIDeviceComplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
- BF72D63129880FAC00B70A2B /* WKDeviceComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
BF72D63629880FCF00B70A2B /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219A1F385BEC0095BFBD /* System.swift */; };
- BF72D638298810D700B70A2B /* DeviceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D637298810D700B70A2B /* DeviceModel.swift */; };
- BF72D63A2988115000B70A2B /* Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D6392988115000B70A2B /* Identifier.swift */; };
- BF72D63C29881D1A00B70A2B /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63B29881D1A00B70A2B /* Screen.swift */; };
- BF72D63E2988206900B70A2B /* WKInterfaceDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */; };
- BF72D6402988209C00B70A2B /* WKDeviceComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */; };
BFA9121C215B9881000CD8A8 /* DeviceModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */; };
+ BFE460D02AB5A08700BE39DB /* Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21981F385BEC0095BFBD /* Identifier.swift */; };
+ BFE460D12AB5A08700BE39DB /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21991F385BEC0095BFBD /* Screen.swift */; };
+ BFE460D22AB5A08700BE39DB /* DeviceFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21961F385BEC0095BFBD /* DeviceFamily.swift */; };
+ BFE460D32AB5A08700BE39DB /* DeviceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21971F385BEC0095BFBD /* DeviceModel.swift */; };
+ BFE460D42AB5A08C00BE39DB /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219C1F385BEC0095BFBD /* UIDeviceExtensions.swift */; };
+ BFE460D52AB5A08C00BE39DB /* UIDeviceComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219B1F385BEC0095BFBD /* UIDeviceComplete.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -58,12 +58,6 @@
AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIDeviceCompleteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AAB1EF3B1F13866F003BBCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WKDeviceComplete.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKDeviceComplete.h; sourceTree = ""; };
- BF72D637298810D700B70A2B /* DeviceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceModel.swift; sourceTree = ""; };
- BF72D6392988115000B70A2B /* Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identifier.swift; sourceTree = ""; };
- BF72D63B29881D1A00B70A2B /* Screen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = ""; };
- BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKInterfaceDeviceExtensions.swift; sourceTree = ""; };
- BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKDeviceComplete.swift; sourceTree = ""; };
BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceModelTests.swift; path = Tests/DeviceModelTests.swift; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@@ -98,7 +92,6 @@
children = (
AAB1EF2D1F13866F003BBCF2 /* UIDeviceComplete */,
AAB1EF381F13866F003BBCF2 /* UIDeviceCompleteTests */,
- BF72D62F29880FAC00B70A2B /* WKDeviceComplete */,
AAB1EF2C1F13866F003BBCF2 /* Products */,
);
sourceTree = "";
@@ -150,19 +143,6 @@
name = Sources;
sourceTree = "";
};
- BF72D62F29880FAC00B70A2B /* WKDeviceComplete */ = {
- isa = PBXGroup;
- children = (
- BF72D63029880FAC00B70A2B /* WKDeviceComplete.h */,
- BF72D637298810D700B70A2B /* DeviceModel.swift */,
- BF72D6392988115000B70A2B /* Identifier.swift */,
- BF72D63B29881D1A00B70A2B /* Screen.swift */,
- BF72D63F2988209C00B70A2B /* WKDeviceComplete.swift */,
- BF72D63D2988206900B70A2B /* WKInterfaceDeviceExtensions.swift */,
- );
- path = WKDeviceComplete;
- sourceTree = "";
- };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -178,7 +158,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- BF72D63129880FAC00B70A2B /* WKDeviceComplete.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -340,12 +319,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- BF72D63E2988206900B70A2B /* WKInterfaceDeviceExtensions.swift in Sources */,
+ BFE460D02AB5A08700BE39DB /* Identifier.swift in Sources */,
+ BFE460D52AB5A08C00BE39DB /* UIDeviceComplete.swift in Sources */,
+ BFE460D42AB5A08C00BE39DB /* UIDeviceExtensions.swift in Sources */,
BF72D63629880FCF00B70A2B /* System.swift in Sources */,
- BF72D63A2988115000B70A2B /* Identifier.swift in Sources */,
- BF72D638298810D700B70A2B /* DeviceModel.swift in Sources */,
- BF72D6402988209C00B70A2B /* WKDeviceComplete.swift in Sources */,
- BF72D63C29881D1A00B70A2B /* Screen.swift in Sources */,
+ BFE460D32AB5A08700BE39DB /* DeviceModel.swift in Sources */,
+ BFE460D12AB5A08700BE39DB /* Screen.swift in Sources */,
+ BFE460D22AB5A08700BE39DB /* DeviceFamily.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/WKDeviceComplete/DeviceModel.swift b/WKDeviceComplete/DeviceModel.swift
deleted file mode 100644
index 3d80f1a..0000000
--- a/WKDeviceComplete/DeviceModel.swift
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// DeviceModel.swift
-//
-// Copyright (c) 2017-2023 Nicholas Maccharoli
-// Copyright (c) 2023 Vincent Neo
-//
-// 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.
-
-public enum DeviceModel: CaseIterable {
- case firstGen
- case series1
- case series2
- case series3
- case series4
- case series5
- case se
- case series6
- case series7
- case series8
- case se2
- case ultra
- case series9
- case ultra2
-
- case unknown
-}
-
-// MARK: - init
-
-extension DeviceModel {
- init(identifier: Identifier) {
- self = DeviceModel.detectWatchModel(with: identifier)
- }
-}
-
-extension DeviceModel {
- fileprivate static func detectWatchModel(with identifier: Identifier) -> DeviceModel {
- guard let major = identifier.version.major,
- let minor = identifier.version.minor
- else { return .unknown }
-
- switch (major, minor) {
- case (1, _): return .firstGen
- case (2, 3), (2, 4): return .series2
- case (2, 6), (2, 7): return .series1
- case (3, _): return .series3
- case (4, _): return .series4
- case (5, 1), (5, 2), (5, 3), (5, 4): return .series5
- case (5, 9), (5, 10), (5, 11), (5, 12): return .se
- case (6, 1), (6, 2), (6, 3), (6, 4): return .series6
- case (6, 6), (6, 7), (6, 8), (6, 9): return .series7
- case (6, 10), (6, 11), (6, 12), (6, 13): return .se2
- case (6, 14), (6, 15), (6, 16), (6, 17): return .series8
- case (6, 18): return .ultra
- case (7, 1), (7, 2), (7, 3), (7, 4): return .series9
- case (7, 5): return .ultra2
-
- default: return .unknown
- }
- }
-}
diff --git a/WKDeviceComplete/Identifier.swift b/WKDeviceComplete/Identifier.swift
deleted file mode 100644
index b282b74..0000000
--- a/WKDeviceComplete/Identifier.swift
+++ /dev/null
@@ -1,162 +0,0 @@
-//
-// Identifier.swift
-//
-// Copyright (c) 2017-2023 Nicholas Maccharoli
-// Copyright (c) 2023 Vincent Neo
-//
-// 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.
-
-struct Identifier {
- let version: (major: Int?, minor: Int?)
-
- init(_ identifier: String) {
- let (major, minor) = Identifier.typeVersionComponents(with: identifier)
- self.version = (major, minor)
- }
-}
-
-
-// MARK: - Identifier String parsing
-
-extension Identifier {
- static func typeVersionComponents(with identifierString: String) -> (major: Int?, minor: Int?) {
-
- let numericCharacters: [String] = (0...9).map { "\($0)" }
- let type = identifierString.prefix(while: { !numericCharacters.contains(String($0))})
-
- let version = identifierString.suffix(from: type.endIndex)
- .split(separator: ",")
- .map { Int($0) }
-
- let major: Int? = !version.isEmpty ? version[0] : nil
- let minor: Int? = version.count > 1 ? version[1] : nil
-
- return (major, minor)
- }
-}
-
-
-// MARK: - String Representation - Watch
-
-extension Identifier: CustomStringConvertible {
- var description: String {
-
- guard let major = version.major,
- let minor = version.minor
- else { return "unknown" }
-
- return watchStringRepresentable(major: major, minor: minor)
- }
-
- private func watchStringRepresentable(major: Int, minor: Int) -> String {
- switch (major, minor) {
- case (1, 1):
- return "Apple Watch (1st generation), 38mm case"
- case (1, 2):
- return "Apple Watch (1st generation), 42mm case"
- case (2, 3):
- return "Apple Watch Series 2, 38mm case"
- case (2, 4):
- return "Apple Watch Series 2, 42mm case"
- case (2, 6):
- return "Apple Watch Series 1, 38mm case"
- case (2, 7):
- return "Apple Watch Series 1, 42mm case"
- case (3, 1):
- return "Apple Watch Series 3, 38mm case (GPS + Cellular)"
- case (3, 2):
- return "Apple Watch Series 3, 42mm case (GPS + Cellular)"
- case (3, 3):
- return "Apple Watch Series 3, 38mm case (GPS)"
- case (3, 4):
- return "Apple Watch Series 3, 42mm case (GPS)"
- case (4, 1):
- return "Apple Watch Series 4, 40mm case (GPS)"
- case (4, 2):
- return "Apple Watch Series 4, 44mm case (GPS)"
- case (4, 3):
- return "Apple Watch Series 4, 40mm case (GPS + Cellular)"
- case (4, 4):
- return "Apple Watch Series 4, 44mm case (GPS + Cellular)"
- case (5, 1):
- return "Apple Watch Series 5, 40mm case (GPS)"
- case (5, 2):
- return "Apple Watch Series 5, 44mm case (GPS)"
- case (5, 3):
- return "Apple Watch Series 5, 40mm case (GPS + Cellular)"
- case (5, 4):
- return "Apple Watch Series 5, 44mm case (GPS + Cellular)"
- case (5, 9):
- return "Apple Watch SE, 40mm case (GPS)"
- case (5, 10):
- return "Apple Watch SE, 44mm case (GPS)"
- case (5, 11):
- return "Apple Watch SE, 40mm case (GPS + Cellular)"
- case (5, 12):
- return "Apple Watch SE, 44mm case (GPS + Cellular)"
- case (6, 1):
- return "Apple Watch Series 6, 40mm case (GPS)"
- case (6, 2):
- return "Apple Watch Series 6, 44mm case (GPS)"
- case (6, 3):
- return "Apple Watch Series 6, 40mm case (GPS + Cellular)"
- case (6, 4):
- return "Apple Watch Series 6, 44mm case (GPS + Cellular)"
- case (6, 6):
- return "Apple Watch Series 7, 41mm case (GPS)"
- case (6, 7):
- return "Apple Watch Series 7, 45mm case (GPS)"
- case (6, 8):
- return "Apple Watch Series 7, 41mm case (GPS + Cellular)"
- case (6, 9):
- return "Apple Watch Series 7, 45mm case (GPS + Cellular)"
- case (6, 10):
- return "Apple Watch SE (2nd Generation), 40mm case (GPS)"
- case (6, 11):
- return "Apple Watch SE (2nd Generation), 44mm case (GPS)"
- case (6, 12):
- return "Apple Watch SE (2nd Generation), 40mm case (GPS + Cellular)"
- case (6, 13):
- return "Apple Watch SE (2nd Generation), 44mm case (GPS + Cellular)"
- case (6, 14):
- return "Apple Watch Series 8, 41mm case (GPS)"
- case (6, 15):
- return "Apple Watch Series 8, 45mm case (GPS)"
- case (6, 16):
- return "Apple Watch Series 8, 41mm case (GPS + Cellular)"
- case (6, 17):
- return "Apple Watch Series 8, 45mm case (GPS + Cellular)"
- case (6, 18):
- return "Apple Watch Ultra"
- case (7, 1):
- return "Apple Watch Series 9, 41mm case (GPS)"
- case (7, 2):
- return "Apple Watch Series 9, 45mm case (GPS)"
- case (7, 3):
- return "Apple Watch Series 9, 41mm case (GPS + Cellular)"
- case (7, 4):
- return "Apple Watch Series 9, 45mm case (GPS + Cellular)"
- case (7, 5):
- return "Apple Watch Ultra 2"
- default:
- return "unknown"
- }
- }
-
-}
diff --git a/WKDeviceComplete/Screen.swift b/WKDeviceComplete/Screen.swift
deleted file mode 100644
index c5856de..0000000
--- a/WKDeviceComplete/Screen.swift
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Screen.swift
-//
-// Copyright (c) 2017-2023 Nicholas Maccharoli
-// Copyright (c) 2023 Vincent Neo
-//
-// 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.
-
-public struct Screen {
- let caseSize: Int?
-}
-
-extension Screen {
- init(identifier: Identifier) {
- self.caseSize = Screen.detectCaseSize(with: identifier)
- }
-}
-
-// MARK: - Detecting Screen size by model, in mm
-
-extension Screen {
- fileprivate static func detectCaseSize(with identifier: Identifier) -> Int? {
- guard let major = identifier.version.major,
- let minor = identifier.version.minor
- else { return nil }
-
- switch (major, minor) {
- case (1, 1), (2, 3), (2, 6), (3, 1), (3, 3): return 38
- case (1, 2), (2, 4), (2, 7), (3, 2), (3, 4): return 42
-
- case (4, 1), (4, 3), (5, 1), (5, 3), (5, 9),
- (5, 11), (6, 1), (6, 3), (6, 10), (6, 12): return 40
- case (4, 2), (4, 4), (5, 2), (5, 4), (5, 10),
- (5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return 44
-
- case (6, 6), (6, 8), (6, 14), (6, 16),
- (7, 1), (7, 3): return 41
- case (6, 7), (6, 9), (6, 15), (6, 17),
- (7, 2), (7, 4): return 45
-
- case (6, 18), (7, 5): return 49
-
- default: return nil
- }
- }
-}
diff --git a/WKDeviceComplete/WKDeviceComplete.h b/WKDeviceComplete/WKDeviceComplete.h
deleted file mode 100644
index 6b75725..0000000
--- a/WKDeviceComplete/WKDeviceComplete.h
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// WKDeviceComplete.h
-// WKDeviceComplete
-//
-// Created by Vincent Neo on 30/1/23.
-// Copyright © 2023 Nicholas Maccharoli. All rights reserved.
-//
-
-#import
-
-//! Project version number for WKDeviceComplete.
-FOUNDATION_EXPORT double WKDeviceCompleteVersionNumber;
-
-//! Project version string for WKDeviceComplete.
-FOUNDATION_EXPORT const unsigned char WKDeviceCompleteVersionString[];
-
-// In this header, you should import all the public headers of your framework using statements like #import
-
-
diff --git a/WKDeviceComplete/WKDeviceComplete.swift b/WKDeviceComplete/WKDeviceComplete.swift
deleted file mode 100644
index a4312be..0000000
--- a/WKDeviceComplete/WKDeviceComplete.swift
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// WKDeviceComplete.swift
-//
-// Copyright (c) 2017-2023 Nicholas Maccharoli
-// Copyright (c) 2023 Vincent Neo
-//
-// 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 WatchKit
-
-public final class WKDeviceComplete {
- let base: Base
- public init(_ base: Base) {
- self.base = base
- }
-}
-
-public protocol WKDeviceCompleteCompatible {
- associatedtype CompatibleType
-
- var dc: CompatibleType { get }
-}
-
-public extension WKDeviceCompleteCompatible {
- var dc: WKDeviceComplete {
- return WKDeviceComplete(self)
- }
-}
-
-extension WKInterfaceDevice: WKDeviceCompleteCompatible { }
diff --git a/WKDeviceComplete/WKInterfaceDeviceExtensions.swift b/WKDeviceComplete/WKInterfaceDeviceExtensions.swift
deleted file mode 100644
index cf19473..0000000
--- a/WKDeviceComplete/WKInterfaceDeviceExtensions.swift
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// WKInterfaceDeviceExtensions.swift
-//
-// Copyright (c) 2017-2023 Nicholas Maccharoli
-// Copyright (c) 2023 Vincent Neo
-//
-// 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 WatchKit
-
-public extension WKDeviceComplete where Base == WKInterfaceDevice {
-
- private var identifier: Identifier? {
- return System.name.flatMap {
- return Identifier($0)
- }
- }
-
- /// Specific model i.e iphone7 or iPhone7s
- var deviceModel: DeviceModel {
- return identifier.flatMap { DeviceModel(identifier: $0) } ?? .unknown
- }
-
- /// Common name for device i.e "iPhone 7 Plus"
- var commonDeviceName: String {
- return identifier?.description ?? "unknown"
- }
-
-}
-
-// MARK: - Screen Size Detection
-
-public extension WKDeviceComplete where Base == WKInterfaceDevice {
- var screenSize: Screen? {
- guard let identifier else { return nil }
- return Screen(identifier: identifier)
- }
-}
From 8eb932898ef788ec11883ab1718c877e469d1bde Mon Sep 17 00:00:00 2001
From: Vincent Neo <23420208+vincentneo@users.noreply.github.com>
Date: Thu, 21 Sep 2023 18:43:31 +0800
Subject: [PATCH 4/5] Add tests for watch devices
---
Tests/DeviceFamilyTests.swift | 7 +-
Tests/DeviceModelTests.swift | 137 ++++++++++++++++
Tests/IdentifierTests.swift | 182 ++++++++++++++++++++-
Tests/UIDeviceExtensionsTests.swift | 8 +
UIDeviceComplete.xcodeproj/project.pbxproj | 151 ++---------------
5 files changed, 345 insertions(+), 140 deletions(-)
diff --git a/Tests/DeviceFamilyTests.swift b/Tests/DeviceFamilyTests.swift
index 8a83d79..73ffd38 100644
--- a/Tests/DeviceFamilyTests.swift
+++ b/Tests/DeviceFamilyTests.swift
@@ -41,6 +41,11 @@ class DeviceFamilyTests: XCTestCase {
XCTAssert(deviceFamily == .iPad, "DeviceFamily - .iPad is failing")
}
+ func testDeviceFamilyWatch() {
+ let deviceFamily = DeviceFamily(rawValue: "Watch")
+ XCTAssert(deviceFamily == .watch, "DeviceFamily - .watch is failing")
+ }
+
func testInvalidDeviceFamily() {
let deviceFamily = DeviceFamily(rawValue: "Apple II")
XCTAssert(deviceFamily == .unknown, "DeviceFamily - .unknown is failing")
@@ -54,5 +59,5 @@ class DeviceFamilyTests: XCTestCase {
XCTAssert(!(deviceFamily.isSimulator), "DeviceFamily - .isSimulator is failing")
#endif
}
-
+
}
diff --git a/Tests/DeviceModelTests.swift b/Tests/DeviceModelTests.swift
index 8c8d7d8..020e47c 100644
--- a/Tests/DeviceModelTests.swift
+++ b/Tests/DeviceModelTests.swift
@@ -28,6 +28,7 @@ import XCTest
class DeviceModelTests: XCTestCase {
+ #if os(iOS)
// MARK: - iPhone Device Model tests
func testDeviceModelIPhone4() {
@@ -511,4 +512,140 @@ class DeviceModelTests: XCTestCase {
withModels.forEach { XCTAssertTrue($0.hasDynamicIsland) }
withoutModels.forEach { XCTAssertFalse($0.hasDynamicIsland) }
}
+ #endif
+
+ #if os(watchOS)
+ // MARK: - Apple Watch Model tests
+
+ func testDeviceModelWatchFirstGen() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch1,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch1,2"))
+ XCTAssert(deviceModel1 == .firstGen, "DeviceModel - .firstGen is failing")
+ XCTAssert(deviceModel2 == .firstGen, "DeviceModel - .firstGen is failing")
+ }
+
+ func testDeviceModelWatchSeries1() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch2,6"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch2,7"))
+ XCTAssert(deviceModel1 == .series1, "DeviceModel - .series1 is failing")
+ XCTAssert(deviceModel2 == .series1, "DeviceModel - .series1 is failing")
+ }
+
+ func testDeviceModelWatchSeries2() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch2,3"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch2,4"))
+ XCTAssert(deviceModel1 == .series2, "DeviceModel - .series2 is failing")
+ XCTAssert(deviceModel2 == .series2, "DeviceModel - .series2 is failing")
+ }
+
+ func testDeviceModelWatchSeries3() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch3,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch3,2"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch3,3"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch3,4"))
+ XCTAssert(deviceModel1 == .series3, "DeviceModel - .series3 is failing")
+ XCTAssert(deviceModel2 == .series3, "DeviceModel - .series3 is failing")
+ XCTAssert(deviceModel3 == .series3, "DeviceModel - .series3 is failing")
+ XCTAssert(deviceModel4 == .series3, "DeviceModel - .series3 is failing")
+ }
+
+ func testDeviceModelWatchSeries4() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch4,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch4,2"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch4,3"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch4,4"))
+ XCTAssert(deviceModel1 == .series4, "DeviceModel - .series4 is failing")
+ XCTAssert(deviceModel2 == .series4, "DeviceModel - .series4 is failing")
+ XCTAssert(deviceModel3 == .series4, "DeviceModel - .series4 is failing")
+ XCTAssert(deviceModel4 == .series4, "DeviceModel - .series4 is failing")
+ }
+
+ func testDeviceModelWatchSeries5() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch5,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch5,2"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch5,3"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch5,4"))
+ XCTAssert(deviceModel1 == .series5, "DeviceModel - .series5 is failing")
+ XCTAssert(deviceModel2 == .series5, "DeviceModel - .series5 is failing")
+ XCTAssert(deviceModel3 == .series5, "DeviceModel - .series5 is failing")
+ XCTAssert(deviceModel4 == .series5, "DeviceModel - .series5 is failing")
+ }
+
+ func testDeviceModelWatchSE() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch5,9"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch5,10"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch5,11"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch5,12"))
+ XCTAssert(deviceModel1 == .se, "DeviceModel - .se is failing")
+ XCTAssert(deviceModel2 == .se, "DeviceModel - .se is failing")
+ XCTAssert(deviceModel3 == .se, "DeviceModel - .se is failing")
+ XCTAssert(deviceModel4 == .se, "DeviceModel - .se is failing")
+ }
+
+ func testDeviceModelWatchSeries6() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch6,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch6,2"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch6,3"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch6,4"))
+ XCTAssert(deviceModel1 == .series6, "DeviceModel - .series6 is failing")
+ XCTAssert(deviceModel2 == .series6, "DeviceModel - .series6 is failing")
+ XCTAssert(deviceModel3 == .series6, "DeviceModel - .series6 is failing")
+ XCTAssert(deviceModel4 == .series6, "DeviceModel - .series6 is failing")
+ }
+
+ func testDeviceModelWatchSeries7() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch6,6"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch6,7"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch6,8"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch6,9"))
+ XCTAssert(deviceModel1 == .series7, "DeviceModel - .series7 is failing")
+ XCTAssert(deviceModel2 == .series7, "DeviceModel - .series7 is failing")
+ XCTAssert(deviceModel3 == .series7, "DeviceModel - .series7 is failing")
+ XCTAssert(deviceModel4 == .series7, "DeviceModel - .series7 is failing")
+ }
+
+ func testDeviceModelWatchSE2() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch6,10"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch6,11"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch6,12"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch6,13"))
+ XCTAssert(deviceModel1 == .se2, "DeviceModel - .se2 is failing")
+ XCTAssert(deviceModel2 == .se2, "DeviceModel - .se2 is failing")
+ XCTAssert(deviceModel3 == .se2, "DeviceModel - .se2 is failing")
+ XCTAssert(deviceModel4 == .se2, "DeviceModel - .se2 is failing")
+ }
+
+ func testDeviceModelWatchSeries8() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch6,14"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch6,15"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch6,16"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch6,17"))
+ XCTAssert(deviceModel1 == .series8, "DeviceModel - .series8 is failing")
+ XCTAssert(deviceModel2 == .series8, "DeviceModel - .series8 is failing")
+ XCTAssert(deviceModel3 == .series8, "DeviceModel - .series8 is failing")
+ XCTAssert(deviceModel4 == .series8, "DeviceModel - .series8 is failing")
+ }
+
+ func testDeviceModelWatchUltra() {
+ let deviceModel = DeviceModel(identifier: Identifier("Watch6,18"))
+ XCTAssert(deviceModel == .ultra, "DeviceModel - .ultra is failing")
+ }
+
+ func testDeviceModelWatchSeries9() {
+ let deviceModel1 = DeviceModel(identifier: Identifier("Watch7,1"))
+ let deviceModel2 = DeviceModel(identifier: Identifier("Watch7,2"))
+ let deviceModel3 = DeviceModel(identifier: Identifier("Watch7,3"))
+ let deviceModel4 = DeviceModel(identifier: Identifier("Watch7,4"))
+ XCTAssert(deviceModel1 == .series9, "DeviceModel - .series9 is failing")
+ XCTAssert(deviceModel2 == .series9, "DeviceModel - .series9 is failing")
+ XCTAssert(deviceModel3 == .series9, "DeviceModel - .series9 is failing")
+ XCTAssert(deviceModel4 == .series9, "DeviceModel - .series9 is failing")
+ }
+
+ func testDeviceModelWatchUltra2() {
+ let deviceModel = DeviceModel(identifier: Identifier("Watch7,5"))
+ XCTAssert(deviceModel == .ultra2, "DeviceModel - .ultra2 is failing")
+ }
+
+ #endif
}
diff --git a/Tests/IdentifierTests.swift b/Tests/IdentifierTests.swift
index 1369805..dd37292 100644
--- a/Tests/IdentifierTests.swift
+++ b/Tests/IdentifierTests.swift
@@ -63,7 +63,7 @@ class IdentifierTests: XCTestCase {
)
}
-
+ #if os(iOS)
// MARK: - iPhone String Description tests
func testDisplayStringiPhone16v2() {
@@ -611,4 +611,184 @@ class IdentifierTests: XCTestCase {
func testDisplayStringiPad1v1() {
XCTAssert(Identifier("iPad1,1").description == "iPad", "iPad1,1 is failing to produce a common device model string")
}
+ #endif
+
+ #if os(watchOS)
+ func testDisplayStringWatch1v1() {
+ XCTAssert(Identifier("Watch1,1").description == "Apple Watch (1st generation), 38mm case", "Watch1,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch1v2() {
+ XCTAssert(Identifier("Watch1,2").description == "Apple Watch (1st generation), 42mm case", "Watch1,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch2v3() {
+ XCTAssert(Identifier("Watch2,3").description == "Apple Watch Series 2, 38mm case", "Watch2,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch2v4() {
+ XCTAssert(Identifier("Watch2,4").description == "Apple Watch Series 2, 42mm case", "Watch2,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch2v6() {
+ XCTAssert(Identifier("Watch2,6").description == "Apple Watch Series 1, 38mm case", "Watch2,6 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch2v7() {
+ XCTAssert(Identifier("Watch2,7").description == "Apple Watch Series 1, 42mm case", "Watch2,7 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch3v1() {
+ XCTAssert(Identifier("Watch3,1").description == "Apple Watch Series 3, 38mm case (GPS + Cellular)", "Watch3,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch3v2() {
+ XCTAssert(Identifier("Watch3,2").description == "Apple Watch Series 3, 42mm case (GPS + Cellular)", "Watch3,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch3v3() {
+ XCTAssert(Identifier("Watch3,3").description == "Apple Watch Series 3, 38mm case (GPS)", "Watch3,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch3v4() {
+ XCTAssert(Identifier("Watch3,4").description == "Apple Watch Series 3, 42mm case (GPS)", "Watch3,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch4v1() {
+ XCTAssert(Identifier("Watch4,1").description == "Apple Watch Series 4, 40mm case (GPS)", "Watch4,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch4v2() {
+ XCTAssert(Identifier("Watch4,2").description == "Apple Watch Series 4, 44mm case (GPS)", "Watch4,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch4v3() {
+ XCTAssert(Identifier("Watch4,3").description == "Apple Watch Series 4, 40mm case (GPS + Cellular)", "Watch4,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch4v4() {
+ XCTAssert(Identifier("Watch4,4").description == "Apple Watch Series 4, 44mm case (GPS + Cellular)", "Watch4,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v1() {
+ XCTAssert(Identifier("Watch5,1").description == "Apple Watch Series 5, 40mm case (GPS)", "Watch5,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v2() {
+ XCTAssert(Identifier("Watch5,2").description == "Apple Watch Series 5, 44mm case (GPS)", "Watch5,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v3() {
+ XCTAssert(Identifier("Watch5,3").description == "Apple Watch Series 5, 40mm case (GPS + Cellular)", "Watch5,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v4() {
+ XCTAssert(Identifier("Watch5,4").description == "Apple Watch Series 5, 44mm case (GPS + Cellular)", "Watch5,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v9() {
+ XCTAssert(Identifier("Watch5,9").description == "Apple Watch SE, 40mm case (GPS)", "Watch5,9 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v10() {
+ XCTAssert(Identifier("Watch5,10").description == "Apple Watch SE, 44mm case (GPS)", "Watch5,10 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v11() {
+ XCTAssert(Identifier("Watch5,11").description == "Apple Watch SE, 40mm case (GPS + Cellular)", "Watch5,11 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch5v12() {
+ XCTAssert(Identifier("Watch5,12").description == "Apple Watch SE, 44mm case (GPS + Cellular)", "Watch5,12 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v1() {
+ XCTAssert(Identifier("Watch6,1").description == "Apple Watch Series 6, 40mm case (GPS)", "Watch6,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v2() {
+ XCTAssert(Identifier("Watch6,2").description == "Apple Watch Series 6, 44mm case (GPS)", "Watch6,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v3() {
+ XCTAssert(Identifier("Watch6,3").description == "Apple Watch Series 6, 40mm case (GPS + Cellular)", "Watch6,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v4() {
+ XCTAssert(Identifier("Watch6,4").description == "Apple Watch Series 6, 44mm case (GPS + Cellular)", "Watch6,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v6() {
+ XCTAssert(Identifier("Watch6,6").description == "Apple Watch Series 7, 41mm case (GPS)", "Watch6,6 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v7() {
+ XCTAssert(Identifier("Watch6,7").description == "Apple Watch Series 7, 45mm case (GPS)", "Watch6,7 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v8() {
+ XCTAssert(Identifier("Watch6,8").description == "Apple Watch Series 7, 41mm case (GPS + Cellular)", "Watch6,8 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v9() {
+ XCTAssert(Identifier("Watch6,9").description == "Apple Watch Series 7, 45mm case (GPS + Cellular)", "Watch6,9 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v10() {
+ XCTAssert(Identifier("Watch6,10").description == "Apple Watch SE (2nd Generation), 40mm case (GPS)", "Watch6,10 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v11() {
+ XCTAssert(Identifier("Watch6,11").description == "Apple Watch SE (2nd Generation), 44mm case (GPS)", "Watch6,11 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v12() {
+ XCTAssert(Identifier("Watch6,12").description == "Apple Watch SE (2nd Generation), 40mm case (GPS + Cellular)", "Watch6,12 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v13() {
+ XCTAssert(Identifier("Watch6,13").description == "Apple Watch SE (2nd Generation), 44mm case (GPS + Cellular)", "Watch6,13 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v14() {
+ XCTAssert(Identifier("Watch6,14").description == "Apple Watch Series 8, 41mm case (GPS)", "Watch6,14 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v15() {
+ XCTAssert(Identifier("Watch6,15").description == "Apple Watch Series 8, 45mm case (GPS)", "Watch6,15 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v16() {
+ XCTAssert(Identifier("Watch6,16").description == "Apple Watch Series 8, 41mm case (GPS + Cellular)", "Watch6,16 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v17() {
+ XCTAssert(Identifier("Watch6,17").description == "Apple Watch Series 8, 45mm case (GPS + Cellular)", "Watch6,17 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch6v18() {
+ XCTAssert(Identifier("Watch6,18").description == "Apple Watch Ultra", "Watch6,18 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch7v1() {
+ XCTAssert(Identifier("Watch7,1").description == "Apple Watch Series 9, 41mm case (GPS)", "Watch7,1 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch7v2() {
+ XCTAssert(Identifier("Watch7,2").description == "Apple Watch Series 9, 45mm case (GPS)", "Watch7,2 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch7v3() {
+ XCTAssert(Identifier("Watch7,3").description == "Apple Watch Series 9, 41mm case (GPS + Cellular)", "Watch7,3 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch7v4() {
+ XCTAssert(Identifier("Watch7,4").description == "Apple Watch Series 9, 45mm case (GPS + Cellular)", "Watch7,4 is failing to produce a common device model string")
+ }
+
+ func testDisplayStringWatch7v5() {
+ XCTAssert(Identifier("Watch7,5").description == "Apple Watch Ultra 2", "Watch7,5 is failing to produce a common device model string")
+ }
+
+ #endif
}
diff --git a/Tests/UIDeviceExtensionsTests.swift b/Tests/UIDeviceExtensionsTests.swift
index f53d6b9..543b1cc 100644
--- a/Tests/UIDeviceExtensionsTests.swift
+++ b/Tests/UIDeviceExtensionsTests.swift
@@ -24,9 +24,17 @@
@testable import UIDeviceComplete
import XCTest
+#if os(watchOS)
+import WatchKit
+#endif
+
class UIDeviceExtensionsTests: XCTestCase {
+ #if os(iOS)
let DeviceExtensions = UIDeviceComplete(UIDevice())
+ #elseif os(watchOS)
+ let DeviceExtensions = UIDeviceComplete(WKInterfaceDevice())
+ #endif
func testDeviceExtensionsDeviceFamily() {
XCTAssertNotEqual(.unknown, DeviceExtensions.deviceFamily, "DeviceExtensions - .deviceFamily is failing")
diff --git a/UIDeviceComplete.xcodeproj/project.pbxproj b/UIDeviceComplete.xcodeproj/project.pbxproj
index 4b73f4f..5b1fc17 100644
--- a/UIDeviceComplete.xcodeproj/project.pbxproj
+++ b/UIDeviceComplete.xcodeproj/project.pbxproj
@@ -20,14 +20,7 @@
AA1C21AB1F385C2A0095BFBD /* UIDeviceExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21A71F385C2A0095BFBD /* UIDeviceExtensionsTests.swift */; };
AAB1EF351F13866F003BBCF2 /* UIDeviceComplete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAB1EF2B1F13866F003BBCF2 /* UIDeviceComplete.framework */; };
AAB1EF3C1F13866F003BBCF2 /* UIDeviceComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = AAB1EF2E1F13866F003BBCF2 /* UIDeviceComplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
- BF72D63629880FCF00B70A2B /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219A1F385BEC0095BFBD /* System.swift */; };
BFA9121C215B9881000CD8A8 /* DeviceModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */; };
- BFE460D02AB5A08700BE39DB /* Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21981F385BEC0095BFBD /* Identifier.swift */; };
- BFE460D12AB5A08700BE39DB /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21991F385BEC0095BFBD /* Screen.swift */; };
- BFE460D22AB5A08700BE39DB /* DeviceFamily.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21961F385BEC0095BFBD /* DeviceFamily.swift */; };
- BFE460D32AB5A08700BE39DB /* DeviceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C21971F385BEC0095BFBD /* DeviceModel.swift */; };
- BFE460D42AB5A08C00BE39DB /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219C1F385BEC0095BFBD /* UIDeviceExtensions.swift */; };
- BFE460D52AB5A08C00BE39DB /* UIDeviceComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1C219B1F385BEC0095BFBD /* UIDeviceComplete.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -57,7 +50,6 @@
AAB1EF2F1F13866F003BBCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIDeviceCompleteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AAB1EF3B1F13866F003BBCF2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WKDeviceComplete.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BFA9121B215B9881000CD8A8 /* DeviceModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceModelTests.swift; path = Tests/DeviceModelTests.swift; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@@ -77,13 +69,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- BF72D62B29880FAC00B70A2B /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -101,7 +86,6 @@
children = (
AAB1EF2B1F13866F003BBCF2 /* UIDeviceComplete.framework */,
AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */,
- BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */,
);
name = Products;
sourceTree = "";
@@ -154,13 +138,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- BF72D62929880FAC00B70A2B /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@@ -200,24 +177,6 @@
productReference = AAB1EF341F13866F003BBCF2 /* UIDeviceCompleteTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
- BF72D62D29880FAC00B70A2B /* WKDeviceComplete */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = BF72D63429880FAC00B70A2B /* Build configuration list for PBXNativeTarget "WKDeviceComplete" */;
- buildPhases = (
- BF72D62929880FAC00B70A2B /* Headers */,
- BF72D62A29880FAC00B70A2B /* Sources */,
- BF72D62B29880FAC00B70A2B /* Frameworks */,
- BF72D62C29880FAC00B70A2B /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = WKDeviceComplete;
- productName = WKDeviceComplete;
- productReference = BF72D62E29880FAC00B70A2B /* WKDeviceComplete.framework */;
- productType = "com.apple.product-type.framework";
- };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -238,10 +197,6 @@
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
- BF72D62D29880FAC00B70A2B = {
- CreatedOnToolsVersion = 14.2;
- ProvisioningStyle = Automatic;
- };
};
};
buildConfigurationList = AAB1EF251F13866F003BBCF2 /* Build configuration list for PBXProject "UIDeviceComplete" */;
@@ -259,7 +214,6 @@
targets = (
AAB1EF2A1F13866F003BBCF2 /* UIDeviceComplete */,
AAB1EF331F13866F003BBCF2 /* UIDeviceCompleteTests */,
- BF72D62D29880FAC00B70A2B /* WKDeviceComplete */,
);
};
/* End PBXProject section */
@@ -279,13 +233,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- BF72D62C29880FAC00B70A2B /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -315,20 +262,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- BF72D62A29880FAC00B70A2B /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- BFE460D02AB5A08700BE39DB /* Identifier.swift in Sources */,
- BFE460D52AB5A08C00BE39DB /* UIDeviceComplete.swift in Sources */,
- BFE460D42AB5A08C00BE39DB /* UIDeviceExtensions.swift in Sources */,
- BF72D63629880FCF00B70A2B /* System.swift in Sources */,
- BFE460D32AB5A08700BE39DB /* DeviceModel.swift in Sources */,
- BFE460D12AB5A08700BE39DB /* Screen.swift in Sources */,
- BFE460D22AB5A08700BE39DB /* DeviceFamily.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -479,10 +412,12 @@
PRODUCT_BUNDLE_IDENTIFIER = nmaccharoli.UIDeviceComplete;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "1,2,4";
+ WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
@@ -503,9 +438,11 @@
PRODUCT_BUNDLE_IDENTIFIER = nmaccharoli.UIDeviceComplete;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = "1,2,4";
+ WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
@@ -521,8 +458,12 @@
PRODUCT_BUNDLE_IDENTIFIER = nmaccharoli.UIDeviceCompleteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
+ SUPPORTS_MACCATALYST = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2,4";
+ WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
@@ -538,67 +479,10 @@
PRODUCT_BUNDLE_IDENTIFIER = nmaccharoli.UIDeviceCompleteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
+ SUPPORTS_MACCATALYST = YES;
SWIFT_VERSION = 5.0;
- };
- name = Release;
- };
- BF72D63229880FAC00B70A2B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- GCC_C_LANGUAGE_STANDARD = gnu11;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nicholas Maccharoli. All rights reserved.";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- MARKETING_VERSION = 1.0;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "com.vincent-neo.WKDeviceComplete";
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SDKROOT = watchos;
- SKIP_INSTALL = YES;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = 4;
- WATCHOS_DEPLOYMENT_TARGET = 4.0;
- };
- name = Debug;
- };
- BF72D63329880FAC00B70A2B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- GCC_C_LANGUAGE_STANDARD = gnu11;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nicholas Maccharoli. All rights reserved.";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- MARKETING_VERSION = 1.0;
- MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = "com.vincent-neo.WKDeviceComplete";
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SDKROOT = watchos;
- SKIP_INSTALL = YES;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = 4;
+ TARGETED_DEVICE_FAMILY = "1,2,4";
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
@@ -633,15 +517,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- BF72D63429880FAC00B70A2B /* Build configuration list for PBXNativeTarget "WKDeviceComplete" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- BF72D63229880FAC00B70A2B /* Debug */,
- BF72D63329880FAC00B70A2B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
/* End XCConfigurationList section */
};
rootObject = AAB1EF221F13866F003BBCF2 /* Project object */;
From a4a2e1ce66d5069d6bf0c3b2acc7409c9af43f7d Mon Sep 17 00:00:00 2001
From: Vincent Neo <23420208+vincentneo@users.noreply.github.com>
Date: Thu, 21 Sep 2023 18:49:09 +0800
Subject: [PATCH 5/5] include testing for watchOS build, via actions
---
.github/workflows/swift.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml
index ce48216..4b145e9 100644
--- a/.github/workflows/swift.yml
+++ b/.github/workflows/swift.yml
@@ -10,5 +10,7 @@ jobs:
DEVELOPER_DIR: /Applications/Xcode_14.0.app/Contents/Developer
steps:
- uses: actions/checkout@v2
- - name: Test
+ - name: Test (iOS)
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=16.0,name=iPhone 14 Pro" clean test | xcpretty
+ - name: Test (watchOS)
+ run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=9.0,name=Apple Watch Series 8 (45mm)" clean test | xcpretty