Skip to content

Commit

Permalink
Xcode 16 beta 1 and more OLED devices (#1188)
Browse files Browse the repository at this point in the history
* Add new OLED iPads to the OLED device list

* Fix compiler warnings in Xcode 16 beta 1 and update build settings
  • Loading branch information
nolanw authored Jun 19, 2024
1 parent 2c1a8bb commit b256de1
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 66 deletions.
2 changes: 1 addition & 1 deletion AwfulCore/Sources/AwfulCore/Data/CachePruner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Foundation

private let Log = Logger.get()

final class CachePruner: Operation {
final class CachePruner: Operation, @unchecked Sendable {
let managedObjectContext: NSManagedObjectContext

init(managedObjectContext context: NSManagedObjectContext) {
Expand Down
3 changes: 0 additions & 3 deletions AwfulSettingsUI/Sources/AwfulSettingsUI/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@
},
"Scale Text %@%%" : {

},
"Settings" : {

},
"Show Avatars" : {

Expand Down
4 changes: 4 additions & 0 deletions Config/Common-Debug.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
// Anything shared by multiple build configurations should go in the common config.
#include "Common.xcconfig"

DEBUG_INFORMATION_FORMAT = dwarf

ENABLE_TESTABILITY = YES

GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1
GCC_OPTIMIZATION_LEVEL = 0

MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE

ONLY_ACTIVE_ARCH = YES

OTHER_CFLAGS = -ftrapv
Expand Down
2 changes: 1 addition & 1 deletion Config/Common-Release.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

ASSETCATALOG_COMPILER_OPTIMIZATION = time

GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym

LLVM_LTO = YES

Expand Down
22 changes: 17 additions & 5 deletions Config/Common.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@

ALWAYS_SEARCH_USER_PATHS = NO

ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES

CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES
CLANG_ANALYZER_NONNULL = YES
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE

CLANG_CXX_LANGUAGE_STANDARD = gnu++17
CLANG_CXX_LIBRARY = libc++
CLANG_CXX_LANGUAGE_STANDARD = gnu++20

CLANG_ENABLE_MODULES = YES
CLANG_ENABLE_OBJC_ARC = YES
CLANG_ENABLE_OBJC_WEAK = YES

CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
CLANG_WARN_BOOL_CONVERSION = YES
CLANG_WARN_COMMA = YES
CLANG_WARN_CONSTANT_CONVERSION = YES
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_EMPTY_BODY = YES
CLANG_WARN_ENUM_CONVERSION = YES
Expand All @@ -26,10 +31,12 @@ CLANG_WARN_INT_CONVERSION = YES
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
CLANG_WARN_SUSPICIOUS_MOVE = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN_UNREACHABLE_CODE = YES

COPY_PHASE_STRIP = NO
Expand All @@ -39,14 +46,14 @@ DYLIB_CURRENT_VERSION = 70300
ENABLE_NS_ASSERTIONS = YES
ENABLE_STRICT_OBJC_MSGSEND = YES

GCC_C_LANGUAGE_STANDARD = gnu99
GCC_C_LANGUAGE_STANDARD = gnu17
GCC_NO_COMMON_BLOCKS = YES
GCC_THREADSAFE_STATICS = NO
GCC_TREAT_WARNINGS_AS_ERRORS = YES

GCC_WARN_64_TO_32_BIT_CONVERSION = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
GCC_WARN_SIGN_COMPARE = YES
GCC_WARN_UNDECLARED_SELECTOR = YES
Expand All @@ -56,15 +63,20 @@ GCC_WARN_UNUSED_LABEL = YES
GCC_WARN_UNUSED_VARIABLE = YES

LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
LOCALIZATION_PREFERS_STRING_CATALOGS = YES

MARKETING_VERSION = 7.3

MTL_ENABLE_DEBUG_INFO = NO
MTL_FAST_MATH = YES

RUN_CLANG_STATIC_ANALYZER = YES

SDKROOT = iphoneos

SWIFT_EMIT_LOC_STRINGS = YES
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES
SWIFT_VERSION = 5.5
SWIFT_VERSION = 5.0

TARGETED_DEVICE_FAMILY = 1,2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Foundation
* Can conveniently locate dependent operations with a particular result type.
* Error reporting via convenient `throw`.
*/
internal class AsynchronousOperation<T>: Foundation.Operation {
internal class AsynchronousOperation<T>: Foundation.Operation, @unchecked Sendable {
private let queue = DispatchQueue(label: "com.nolanw.ImgurAnonymousAPI.async-operation-state")
private(set) var result: Result<T>?
private var _state: AsynchronousOperationState = .ready
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ internal enum ImageError: LocalizedError {
The image is resized without being fully dragged into memory.
*/
internal final class ResizeImage: AsynchronousOperation<ImageFile> {
internal final class ResizeImage: AsynchronousOperation<ImageFile>, @unchecked Sendable {

private let maximumFileSizeBytes: Int

init(maximumFileSizeBytes: Int) {
Expand Down Expand Up @@ -134,8 +134,8 @@ import Photos

/// Retrieves image data for a `PHAsset` and saves it to a file in a temporary folder.
@available(macOS 10.13, tvOS 10.0, *)
internal final class SavePHAsset: AsynchronousOperation<ImageFile> {
internal final class SavePHAsset: AsynchronousOperation<ImageFile>, @unchecked Sendable {

/// Returns `true` when the app has a photo library usage description and the user has authorized said access.
static var hasRequiredPhotoLibraryAuthorization: Bool {

Expand Down Expand Up @@ -199,7 +199,7 @@ import MobileCoreServices
import UIKit

/// Writes the image data to file in a temporary folder.
internal final class SaveUIImage: AsynchronousOperation<ImageFile> {
internal final class SaveUIImage: AsynchronousOperation<ImageFile>, @unchecked Sendable {
private let image: UIImage

init(_ image: UIImage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal struct TemporaryFolder {
}

/// Creates a randomly-named folder in a temporary directory.
internal final class MakeTemporaryFolder: AsynchronousOperation<TemporaryFolder> {
internal final class MakeTemporaryFolder: AsynchronousOperation<TemporaryFolder>, @unchecked Sendable {
override func execute() throws {
let url = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent(UUID().uuidString, isDirectory: true)
Expand All @@ -20,7 +20,7 @@ internal final class MakeTemporaryFolder: AsynchronousOperation<TemporaryFolder>
}

/// Attempts to delete a temporary folder, but doesn't throw an error on failure (presumably the operating system will clean up after us).
internal final class DeleteTemporaryFolder: AsynchronousOperation<Void> {
internal final class DeleteTemporaryFolder: AsynchronousOperation<Void>, @unchecked Sendable {
override func execute() throws {
do {
let tempFolder = try firstDependencyValue(ofType: TemporaryFolder.self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extension ImgurUploader.Either: Decodable {
}

/// Runs a URLSessionTask and decodes the response data as JSON.
internal final class FetchURL<T: Decodable>: AsynchronousOperation<T> {
internal final class FetchURL<T: Decodable>: AsynchronousOperation<T>, @unchecked Sendable {
private var task: URLSessionDataTask?

init(urlSession: URLSession, request: URLRequest) {
Expand Down Expand Up @@ -111,7 +111,7 @@ internal final class FetchURL<T: Decodable>: AsynchronousOperation<T> {
}

/// Sends a multipart/form-data upload request, then parses the response's body and headers.
internal final class UploadImageAsFormData: AsynchronousOperation<ImgurUploader.UploadResponse> {
internal final class UploadImageAsFormData: AsynchronousOperation<ImgurUploader.UploadResponse>, @unchecked Sendable {
private let request: URLRequest
private var task: URLSessionUploadTask?
private let urlSession: URLSession
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal enum WriteError: CustomNSError {
}
}

internal final class WriteMultipartFormData: AsynchronousOperation<FormDataFile> {
internal final class WriteMultipartFormData: AsynchronousOperation<FormDataFile>, @unchecked Sendable {
override func execute() throws {
let tempFolder = try firstDependencyValue(ofType: TemporaryFolder.self)
let imageFile = try firstDependencyValue(ofType: ImageFile.self)
Expand Down
125 changes: 80 additions & 45 deletions SystemCapabilities/Sources/SystemCapabilities/OLED.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,62 +7,97 @@ import Logger

private let Log = Logger.get()

/// Device information that's not particularly convenient to retrieve.
public enum SystemCapabilities {

/// Whether the device's main screen is OLED.
public static let oled: Bool = {
// Models are listed at https://ipsw.me/ and/or http://theiphonewiki.com/wiki/Models
// Display technology is in each model's Wikipedia page.
// Not gonna bother trying to guess at future models.
let scanner = Scanner(string: modelIdentifier)
guard scanner.scanString("iPhone") != nil,
let major = scanner.scanInt(),
scanner.scanString(",") != nil,
let minor = scanner.scanInt()
else { return false }
switch (major, minor) {
case (10, 3), (10, 6), // iPhone X
(11, 2), // iPhone XS
(11, 4), (11, 6), // iPhone XS Max
(12, 3), // iPhone 11 Pro
(12, 5), // iPhone 11 Pro Max
(13, 1), // iPhone 12 Mini
(13, 2), // iPhone 12
(13, 3), // iPhone 12 Pro
(13, 4), // iPhone 12 Pro Max
(14, 2), // iPhone 13 Pro
(14, 3), // iPhone 13 Pro Max
(14, 4), // iPhone 13 Mini
(14, 5), // iPhone 13
(14, 7), // iPhone 14
(14, 8), // iPhone 14 Plus
(15, 2), // iPhone 14 Pro
(15, 3), // iPhone 14 Pro Max
(15, 4), // iPhone 15
(15, 5), // iPhone 15 Plus
(16, 1), // iPhone 15 Pro
(16, 2): // iPhone 15 Pro Max
return true
default:
return false
guard let modelID = ModelIdentifier.makeFromSysctl() else { return false }
switch modelID.device {
case .iPhone:
switch (modelID.major, modelID.minor) {
case (10,3), (10,6), // iPhone X
(11,2), // iPhone XS
(11,4), (11,6), // iPhone XS Max
(12,3), // iPhone 11 Pro
(12,5), // iPhone 11 Pro Max
(13,1), // iPhone 12 Mini
(13,2), // iPhone 12
(13,3), // iPhone 12 Pro
(13,4), // iPhone 12 Pro Max
(14,2), // iPhone 13 Pro
(14,3), // iPhone 13 Pro Max
(14,4), // iPhone 13 Mini
(14,5), // iPhone 13
(14,7), // iPhone 14
(14,8), // iPhone 14 Plus
(15,2), // iPhone 14 Pro
(15,3), // iPhone 14 Pro Max
(15,4), // iPhone 15
(15,5), // iPhone 15 Plus
(16,1), // iPhone 15 Pro
(16,2): // iPhone 15 Pro Max
return true
case (_,_):
return false
}
case .iPad:
switch (modelID.major, modelID.minor) {
case (16,3), (16,4), (16,5), (16,6): // iPad Pro (M4) aka iPad Pro (7th generation)
return true
case (_,_):
return false
}
}
}()
}

private let modelIdentifier: String = {
var size: Int = 0
guard sysctlbyname("hw.machine", nil, &size, nil, 0) == 0 else {
Log.e("could not find model identifier: could not get buffer size")
return ""
private struct ModelIdentifier {
let device: Device
let major: Int
let minor: Int

enum Device {
case iPad, iPhone
}

let bufferSize = Int(size) + 1
let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }
init?(_ rawValue: String) {
let scanner = Scanner(string: rawValue)
if scanner.scanString("iPhone") != nil {
device = .iPhone
} else if scanner.scanString("iPad") != nil {
device = .iPad
} else {
return nil
}

guard sysctlbyname("hw.machine", buffer, &size, nil, 0) == 0 else {
Log.e("could not find model identifier")
return ""
guard let major = scanner.scanInt(),
scanner.scanString(",") != nil,
let minor = scanner.scanInt()
else { return nil }
self.major = major
self.minor = minor
}

buffer[Int(size)] = 0
return String(cString: buffer)
}()
static func makeFromSysctl() -> ModelIdentifier? {
var size: Int = 0
guard sysctlbyname("hw.machine", nil, &size, nil, 0) == 0 else {
Log.e("could not find model identifier: could not get buffer size")
return nil
}

let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: size + 1)
defer { buffer.deallocate() }

guard sysctlbyname("hw.machine", buffer, &size, nil, 0) == 0 else {
Log.e("could not find model identifier")
return nil
}

buffer[Int(size)] = 0
return ModelIdentifier(String(cString: buffer))
}
}

0 comments on commit b256de1

Please sign in to comment.