From 0d5b441e2a7b99b5605b38e73df92837fe39f644 Mon Sep 17 00:00:00 2001 From: noppe Date: Wed, 21 Jul 2021 17:57:20 +0900 Subject: [PATCH] format --- .github/workflows/format.yml | 25 ++ .swift-format | 54 ++++ Makefile | 7 + Sources/DebugMenu/DebugMenu.swift | 14 +- Sources/DebugMenu/Entity/AnyDebugItem.swift | 6 +- Sources/DebugMenu/Entity/Application.swift | 37 ++- .../Entity/ComplicationPresentable.swift | 3 +- .../Entity/DebugMenuPresentable.swift | 16 +- Sources/DebugMenu/Entity/Device.swift | 77 ++--- Sources/DebugMenu/Entity/Device/CPU.swift | 10 +- Sources/DebugMenu/Entity/Device/GPU.swift | 6 +- Sources/DebugMenu/Entity/Device/Memory.swift | 6 +- Sources/DebugMenu/Entity/Device/Network.swift | 56 ++-- .../Entity/Device/NetworkUsage.swift | 4 +- Sources/DebugMenu/Entity/Device/System.swift | 8 +- Sources/DebugMenu/Entity/Envelope.swift | 4 +- Sources/DebugMenu/Entity/MetricsFetcher.swift | 2 +- Sources/DebugMenu/Entity/Options.swift | 4 +- .../DebugMenu/Entity/RecentItemStore.swift | 7 +- Sources/DebugMenu/Extensions/Cell+.swift | 25 +- .../FloatingItemGestureRecognizer.swift | 124 ++++---- .../DebugMenu/Extensions/UIApplication+.swift | 9 +- .../Complication/CPUGraphComplication.swift | 2 +- .../Complication/CPUUsageComplication.swift | 4 +- .../Plugin/Complication/FPSComplication.swift | 16 +- .../GPUMemoryUsageComplication.swift | 6 +- .../Complication/IntervalComplication.swift | 42 +-- .../MemoryUsageComplication.swift | 2 +- .../NetworkUsageComplication.swift | 29 +- .../ThermalStateComplication.swift | 14 +- .../Complication/UI/GraphTableViewCell.swift | 8 +- .../Plugin/Complication/UI/GraphView.swift | 29 +- .../UI/IntervalTableViewCell.swift | 8 +- .../Plugin/Complication/UI/IntervalView.swift | 14 +- .../Plugin/DebugMenu/AppInfoDebugItem.swift | 36 +-- .../DebugMenu/CaseSelectableDebugItem.swift | 9 +- .../DebugMenu/ClearCacheDebugItem.swift | 12 +- .../DebugMenu/DeviceInfoDebugItem.swift | 45 +-- .../Plugin/DebugMenu/ExitDebugItem.swift | 4 +- .../Plugin/DebugMenu/GroupDebugItem.swift | 8 +- .../Plugin/DebugMenu/KeyValueDebugItem.swift | 9 +- .../Plugin/DebugMenu/RangeDebugItem.swift | 21 +- .../Plugin/DebugMenu/ToggleDebugItem.swift | 13 +- .../UI/CaseSelectableTableController.swift | 29 +- .../EnvelopePreviewTableViewController.swift | 52 ++-- .../Plugin/DebugMenu/UI/SliderCell.swift | 34 ++- .../Plugin/DebugMenu/UI/ToogleCell.swift | 16 +- .../DebugMenu/UI/Value1TableViewCell.swift | 4 +- .../UserDefaultsResetDebugItem.swift | 4 +- .../DebugMenu/ViewControllerDebugItem.swift | 20 +- .../DebugMenu/SwiftUI/DebugMenuModifier.swift | 34 ++- .../View/FloatingViewController.swift | 101 ++++--- .../View/InAppDebuggerViewController.swift | 271 +++++++++++------- .../DebugMenu/View/InAppDebuggerWindow.swift | 42 ++- Sources/DebugMenu/View/LaunchView.swift | 14 +- Sources/DebugMenu/View/WidgetView.swift | 38 +-- 56 files changed, 941 insertions(+), 553 deletions(-) create mode 100644 .github/workflows/format.yml create mode 100644 .swift-format create mode 100644 Makefile diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..80432c3 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,25 @@ +name: Format + +on: + push: + branches: + - main + +jobs: + swift_format: + name: swift-format + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Tap + run: brew tap pointfreeco/formulae + - name: Install + run: brew install Formulae/swift-format@5.3 + - name: Format + run: make format + - uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Run swift-format + branch: "main" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..2ddae3b --- /dev/null +++ b/.swift-format @@ -0,0 +1,54 @@ +{ + "version": 1, + "lineLength": 100, + "indentation": { + "spaces": 4 + }, + "tabWidth": 4, + "maximumBlankLines": 1, + "respectsExistingLineBreaks": true, + "lineBreakBeforeControlFlowKeywords": false, + "lineBreakBeforeEachArgument": true, + "lineBreakBeforeEachGenericRequirement": true, + "prioritizeKeepingFunctionOutputTogether": false, + "indentConditionalCompilationBlocks": false, + "lineBreakAroundMultilineExpressionChainComponents": true, + "indentSwitchCaseLabels": false, + "fileScopedDeclarationPrivacy": { + "accessLevel": "private" + }, + "rules": { + "AllPublicDeclarationsHaveDocumentation": false, + "AlwaysUseLowerCamelCase": false, + "AmbiguousTrailingClosureOverload": false, + "BeginDocumentationCommentWithOneLineSummary": false, + "DoNotUseSemicolons": true, + "DontRepeatTypeInStaticProperties": false, + "FileScopedDeclarationPrivacy": false, + "FullyIndirectEnum": false, + "GroupNumericLiterals": false, + "IdentifiersMustBeASCII": false, + "NeverForceUnwrap": false, + "NeverUseForceTry": false, + "NeverUseImplicitlyUnwrappedOptionals": false, + "NoAccessLevelOnExtensionDeclaration": false, + "NoBlockComments": false, + "NoCasesWithOnlyFallthrough": false, + "NoEmptyTrailingClosureParentheses": true, + "NoLabelsInCasePatterns": true, + "NoLeadingUnderscores": false, + "NoParensAroundConditions": true, + "NoVoidReturnOnFunctionSignature": true, + "OneCasePerLine": true, + "OneVariableDeclarationPerLine": true, + "OnlyOneTrailingClosureArgument": false, + "OrderedImports": true, + "ReturnVoidInsteadOfEmptyTuple": true, + "UseLetInEveryBoundCaseVariable": false, + "UseShorthandTypeNames": true, + "UseSingleLinePropertyGetter": true, + "UseSynthesizedInitializer": false, + "UseTripleSlashForDocumentationComments": false, + "ValidateDocumentationComments": false + } +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3331559 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +format: + @swift format \ + --ignore-unparsable-files \ + --configuration .swift-format \ + --in-place \ + --recursive \ + ./Sources/ \ No newline at end of file diff --git a/Sources/DebugMenu/DebugMenu.swift b/Sources/DebugMenu/DebugMenu.swift index fb121f7..173c729 100644 --- a/Sources/DebugMenu/DebugMenu.swift +++ b/Sources/DebugMenu/DebugMenu.swift @@ -2,7 +2,17 @@ import UIKit @available(iOSApplicationExtension, unavailable) public struct DebugMenu { - public static func install(windowScene: UIWindowScene? = nil, items: [DebugMenuPresentable] = [], complications: [ComplicationPresentable] = [], options: [Options] = Options.default) { - InAppDebuggerWindow.install(windowScene: windowScene, debuggerItems: items, complications: complications, options: options) + public static func install( + windowScene: UIWindowScene? = nil, + items: [DebugMenuPresentable] = [], + complications: [ComplicationPresentable] = [], + options: [Options] = Options.default + ) { + InAppDebuggerWindow.install( + windowScene: windowScene, + debuggerItems: items, + complications: complications, + options: options + ) } } diff --git a/Sources/DebugMenu/Entity/AnyDebugItem.swift b/Sources/DebugMenu/Entity/AnyDebugItem.swift index 83af6fa..8b2e275 100644 --- a/Sources/DebugMenu/Entity/AnyDebugItem.swift +++ b/Sources/DebugMenu/Entity/AnyDebugItem.swift @@ -11,17 +11,17 @@ struct AnyDebugItem: Hashable, Identifiable, DebugMenuPresentable { let id: String let debuggerItemTitle: String let action: DebugMenuAction - + init(_ item: DebugMenuPresentable) { id = UUID().uuidString debuggerItemTitle = item.debuggerItemTitle action = item.action } - + func hash(into hasher: inout Hasher) { hasher.combine(id) } - + static func == (lhs: AnyDebugItem, rhs: AnyDebugItem) -> Bool { lhs.id == rhs.id } diff --git a/Sources/DebugMenu/Entity/Application.swift b/Sources/DebugMenu/Entity/Application.swift index 67a2a68..76b6587 100644 --- a/Sources/DebugMenu/Entity/Application.swift +++ b/Sources/DebugMenu/Entity/Application.swift @@ -9,35 +9,35 @@ import Foundation public class Application { public static var current: Application = .init() - + public var appName: String { Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String } - + public var version: String { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String } - + public var build: String { Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as! String } - + public var buildNumber: Int { Int(build) ?? 0 } - + public var bundleIdentifier: String { Bundle.main.bundleIdentifier ?? "" } - + public var locale: String { Locale.current.identifier } - + public var preferredLocalizations: String { Bundle.main.preferredLocalizations.joined(separator: ",") } - + public var isTestFlight: Bool { #if DEBUG return false @@ -45,7 +45,7 @@ public class Application { return Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" #endif } - + public var size: String { let byteCount = try? getByteCount() let formatter = ByteCountFormatter() @@ -58,12 +58,21 @@ public class Application { extension Application { public func getByteCount() throws -> UInt64 { let bundlePath = Bundle.main.bundlePath - let documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] - let libraryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0] + let documentPath = NSSearchPathForDirectoriesInDomains( + .documentDirectory, + .userDomainMask, + true + )[0] + let libraryPath = NSSearchPathForDirectoriesInDomains( + .libraryDirectory, + .userDomainMask, + true + )[0] let tmpPath = NSTemporaryDirectory() - return try [bundlePath, documentPath, libraryPath, tmpPath].map(getFileSize(atDirectory:)).reduce(0, +) + return try [bundlePath, documentPath, libraryPath, tmpPath].map(getFileSize(atDirectory:)) + .reduce(0, +) } - + internal func getFileSize(atDirectory path: String) throws -> UInt64 { let files = try FileManager.default.subpathsOfDirectory(atPath: path) var fileSize: UInt64 = 0 @@ -74,5 +83,3 @@ extension Application { return fileSize } } - - diff --git a/Sources/DebugMenu/Entity/ComplicationPresentable.swift b/Sources/DebugMenu/Entity/ComplicationPresentable.swift index 8351e8d..af51ab0 100644 --- a/Sources/DebugMenu/Entity/ComplicationPresentable.swift +++ b/Sources/DebugMenu/Entity/ComplicationPresentable.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -14,4 +14,3 @@ public protocol ComplicationPresentable { func update() var fetcher: MetricsFetcher { get } } - diff --git a/Sources/DebugMenu/Entity/DebugMenuPresentable.swift b/Sources/DebugMenu/Entity/DebugMenuPresentable.swift index b89aaac..e503667 100644 --- a/Sources/DebugMenu/Entity/DebugMenuPresentable.swift +++ b/Sources/DebugMenu/Entity/DebugMenuPresentable.swift @@ -13,8 +13,18 @@ public protocol DebugMenuPresentable { } public enum DebugMenuAction { - case didSelect(action: (_ controller: UIViewController, _ completions: @escaping (DebugMenuResult) -> Void) -> Void) + case didSelect( + action: (_ controller: UIViewController, _ completions: @escaping (DebugMenuResult) -> Void) + -> Void + ) case execute(action: (_ completions: @escaping (DebugMenuResult) -> Void) -> Void) - case toggle(current: () -> Bool, action: (_ isOn: Bool, _ completions: @escaping (DebugMenuResult) -> Void) -> Void) - case slider(current: () -> Double, range: ClosedRange, action: (_ value: Double, _ completions: @escaping (DebugMenuResult) -> Void) -> Void) + case toggle( + current: () -> Bool, + action: (_ isOn: Bool, _ completions: @escaping (DebugMenuResult) -> Void) -> Void + ) + case slider( + current: () -> Double, + range: ClosedRange, + action: (_ value: Double, _ completions: @escaping (DebugMenuResult) -> Void) -> Void + ) } diff --git a/Sources/DebugMenu/Entity/Device.swift b/Sources/DebugMenu/Entity/Device.swift index c64d6fa..f8d2c68 100644 --- a/Sources/DebugMenu/Entity/Device.swift +++ b/Sources/DebugMenu/Entity/Device.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // @@ -9,39 +9,39 @@ import UIKit public class Device { public static let current: Device = .init() - + public var localizedModel: String { UIDevice.current.localizedModel } - + public var model: String { UIDevice.current.model } - + public var name: String { UIDevice.current.name } - + public var systemName: String { UIDevice.current.systemName } - + public var systemVersion: String { UIDevice.current.systemVersion } - + public var localizedBatteryLevel: String { "\(batteryLevel * 100.00) %" } - + public var batteryLevel: Float { UIDevice.current.batteryLevel } - + public var batteryState: UIDevice.BatteryState { UIDevice.current.batteryState } - + public var localizedBatteryState: String { switch batteryState { case .unknown: return "unknown" @@ -51,15 +51,15 @@ public class Device { @unknown default: return "default" } } - + public var isJailbreaked: Bool { FileManager.default.fileExists(atPath: "/private/var/lib/apt") } - + public var thermalState: ProcessInfo.ThermalState { ProcessInfo.processInfo.thermalState } - + public var localizedThermalState: String { switch thermalState { case .nominal: return "nominal" @@ -69,108 +69,113 @@ public class Device { @unknown default: return "default" } } - + public var processorCount: Int { ProcessInfo.processInfo.processorCount } - + public var activeProcessorCount: Int { ProcessInfo.processInfo.activeProcessorCount } - + public var processor: String { "\(activeProcessorCount) / \(processorCount)" } - + public var isLowPowerModeEnabled: Bool { ProcessInfo.processInfo.isLowPowerModeEnabled } - + public var physicalMemory: UInt64 { ProcessInfo.processInfo.physicalMemory } - + public var localizedPhysicalMemory: String { let formatter = ByteCountFormatter() formatter.countStyle = .memory formatter.allowsNonnumericFormatting = false return formatter.string(fromByteCount: Int64(physicalMemory)) } - + // without sleep time public var systemUptime: TimeInterval { ProcessInfo.processInfo.systemUptime } - + // include sleep time public func uptime() -> time_t { System.uptime() } - + public var localizedSystemUptime: String { let formatter = DateComponentsFormatter() formatter.unitsStyle = .brief formatter.allowedUnits = [.day, .hour, .minute, .second] return formatter.string(from: systemUptime) ?? "-" } - + public var localizedUptime: String { let formatter = DateComponentsFormatter() formatter.unitsStyle = .brief formatter.allowedUnits = [.day, .hour, .minute, .second] return formatter.string(from: TimeInterval(uptime())) ?? "-" } - + public var diskTotalSpace: Int64 { - if let attributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()) { + if let attributes = try? FileManager.default.attributesOfFileSystem( + forPath: NSHomeDirectory() + ) { return attributes[.systemSize] as! Int64 } else { return 0 } } - + public var diskFreeSpace: Int64 { - if let attributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()) { + if let attributes = try? FileManager.default.attributesOfFileSystem( + forPath: NSHomeDirectory() + ) { return attributes[.systemFreeSize] as! Int64 } else { return 0 } } - + public var diskUsage: Int64 { diskTotalSpace - diskFreeSpace } - + public var localizedDiskUsage: String { let formatter = ByteCountFormatter() formatter.countStyle = .file formatter.allowsNonnumericFormatting = false - return "\(formatter.string(fromByteCount: diskUsage)) / \(formatter.string(fromByteCount: diskTotalSpace))" + return + "\(formatter.string(fromByteCount: diskUsage)) / \(formatter.string(fromByteCount: diskTotalSpace))" } - + public var localizedMemoryUsage: String { let formatter = ByteCountFormatter() formatter.countStyle = .memory formatter.allowsNonnumericFormatting = false return formatter.string(fromByteCount: Int64(memoryUsage())) } - + public func memoryUsage() -> UInt64 { Memory.usage() } - + public var localizedCPUUsage: String { String(format: "%.1f%%", cpuUsage() * 100.0) } - + public func cpuUsage() -> Double { CPU.usage() } - + public func networkUsage() -> NetworkUsage? { Network.usage() } - + public var localizedGPUMemory: String { let formatter = ByteCountFormatter() formatter.countStyle = .memory diff --git a/Sources/DebugMenu/Entity/Device/CPU.swift b/Sources/DebugMenu/Entity/Device/CPU.swift index 203f06c..9c061f5 100644 --- a/Sources/DebugMenu/Entity/Device/CPU.swift +++ b/Sources/DebugMenu/Entity/Device/CPU.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -17,10 +17,12 @@ class CPU { } return totalUsage } - + static func threadIDs() -> [thread_inspect_t] { var threadList: thread_act_array_t? - var threadCount = UInt32(MemoryLayout.size / MemoryLayout.size) + var threadCount = UInt32( + MemoryLayout.size / MemoryLayout.size + ) let result = task_threads(mach_task_self_, &threadList, &threadCount) if result != KERN_SUCCESS { return [] } var ids: [thread_inspect_t] = [] @@ -29,7 +31,7 @@ class CPU { } return ids } - + static func threadUsage(id: thread_inspect_t) -> Double { var threadInfo = thread_basic_info() var threadInfoCount = UInt32(THREAD_INFO_MAX) diff --git a/Sources/DebugMenu/Entity/Device/GPU.swift b/Sources/DebugMenu/Entity/Device/GPU.swift index 4dbf382..f7609d8 100644 --- a/Sources/DebugMenu/Entity/Device/GPU.swift +++ b/Sources/DebugMenu/Entity/Device/GPU.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -11,11 +11,11 @@ import Metal class GPU { static var current: GPU = .init() let device: MTLDevice - + init() { device = MTLCreateSystemDefaultDevice()! } - + var currentAllocatedSize: Int { device.currentAllocatedSize } diff --git a/Sources/DebugMenu/Entity/Device/Memory.swift b/Sources/DebugMenu/Entity/Device/Memory.swift index 3d95e70..8371628 100644 --- a/Sources/DebugMenu/Entity/Device/Memory.swift +++ b/Sources/DebugMenu/Entity/Device/Memory.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -15,7 +15,9 @@ class Memory { task_info( mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), - $0.withMemoryRebound(to: Int32.self, capacity: 1) { UnsafeMutablePointer($0) }, + $0.withMemoryRebound(to: Int32.self, capacity: 1) { + UnsafeMutablePointer($0) + }, &count ) } diff --git a/Sources/DebugMenu/Entity/Device/Network.swift b/Sources/DebugMenu/Entity/Device/Network.swift index 31ba2e2..e08bdb8 100644 --- a/Sources/DebugMenu/Entity/Device/Network.swift +++ b/Sources/DebugMenu/Entity/Device/Network.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -10,19 +10,26 @@ import Foundation class Network { private static func ifaddrs() -> [String] { var addresses = [String]() - - var ifaddr : UnsafeMutablePointer? + + var ifaddr: UnsafeMutablePointer? guard getifaddrs(&ifaddr) == 0 else { return [] } guard let firstAddr = ifaddr else { return [] } - + for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) { let flags = Int32(ptr.pointee.ifa_flags) var addr = ptr.pointee.ifa_addr.pointee - if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) { + if (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) { if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) { var hostname: [CChar] = Array.init(repeating: 0, count: Int(NI_MAXHOST)) - if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count), - nil, socklen_t(0), NI_NUMERICHOST) == 0) { + if getnameinfo( + &addr, + socklen_t(addr.sa_len), + &hostname, + socklen_t(hostname.count), + nil, + socklen_t(0), + NI_NUMERICHOST + ) == 0 { let address = String(cString: hostname) addresses.append(address) } @@ -32,41 +39,52 @@ class Network { freeifaddrs(ifaddr) return addresses } - + static func usage() -> NetworkUsage? { - var ifaddr : UnsafeMutablePointer? + var ifaddr: UnsafeMutablePointer? guard getifaddrs(&ifaddr) == 0 else { return nil } guard let firstAddr = ifaddr else { return nil } - + var networkData: UnsafeMutablePointer! - + var wifiDataSent: UInt64 = 0 var wifiDataReceived: UInt64 = 0 var wwanDataSent: UInt64 = 0 var wwanDataReceived: UInt64 = 0 - + for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) { let name = String(cString: ptr.pointee.ifa_name) let addr = ptr.pointee.ifa_addr.pointee - + guard addr.sa_family == UInt8(AF_LINK) else { continue } - + if name.hasPrefix("en") { - networkData = unsafeBitCast(ptr.pointee.ifa_data, to: UnsafeMutablePointer.self) + networkData = unsafeBitCast( + ptr.pointee.ifa_data, + to: UnsafeMutablePointer.self + ) wifiDataSent += UInt64(networkData.pointee.ifi_obytes) wifiDataReceived += UInt64(networkData.pointee.ifi_ibytes) } - + if name.hasPrefix("pdp_ip") { - networkData = unsafeBitCast(ptr.pointee.ifa_data, to: UnsafeMutablePointer.self) + networkData = unsafeBitCast( + ptr.pointee.ifa_data, + to: UnsafeMutablePointer.self + ) wwanDataSent += UInt64(networkData.pointee.ifi_obytes) wwanDataReceived += UInt64(networkData.pointee.ifi_ibytes) } } freeifaddrs(ifaddr) - - return .init(wifiDataSent: wifiDataSent, wifiDataReceived: wifiDataReceived, wwanDataSent: wwanDataSent, wwanDataReceived: wwanDataReceived) + + return .init( + wifiDataSent: wifiDataSent, + wifiDataReceived: wifiDataReceived, + wwanDataSent: wwanDataSent, + wwanDataReceived: wwanDataReceived + ) } } diff --git a/Sources/DebugMenu/Entity/Device/NetworkUsage.swift b/Sources/DebugMenu/Entity/Device/NetworkUsage.swift index 6571871..c9467be 100644 --- a/Sources/DebugMenu/Entity/Device/NetworkUsage.swift +++ b/Sources/DebugMenu/Entity/Device/NetworkUsage.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // @@ -12,7 +12,7 @@ public struct NetworkUsage { public let wifiDataReceived: UInt64 public let wwanDataSent: UInt64 public let wwanDataReceived: UInt64 - + public var sent: UInt64 { wifiDataSent + wwanDataSent } public var received: UInt64 { wifiDataReceived + wwanDataReceived } } diff --git a/Sources/DebugMenu/Entity/Device/System.swift b/Sources/DebugMenu/Entity/Device/System.swift index 4f66a97..9725d46 100644 --- a/Sources/DebugMenu/Entity/Device/System.swift +++ b/Sources/DebugMenu/Entity/Device/System.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -12,12 +12,12 @@ class System { var boottime = timeval() var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME] var size = MemoryLayout.stride - + var now = time_t() var uptime: time_t = -1 - + time(&now) - if (sysctl(&mib, 2, &boottime, &size, nil, 0) != -1 && boottime.tv_sec != 0) { + if sysctl(&mib, 2, &boottime, &size, nil, 0) != -1 && boottime.tv_sec != 0 { uptime = now - boottime.tv_sec } return uptime diff --git a/Sources/DebugMenu/Entity/Envelope.swift b/Sources/DebugMenu/Entity/Envelope.swift index a851e82..19ccc74 100644 --- a/Sources/DebugMenu/Entity/Envelope.swift +++ b/Sources/DebugMenu/Entity/Envelope.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/23. // @@ -12,7 +12,7 @@ public struct Envelope { self.key = key self.value = value } - + public let key: String public let value: String } diff --git a/Sources/DebugMenu/Entity/MetricsFetcher.swift b/Sources/DebugMenu/Entity/MetricsFetcher.swift index 543dcfb..514adb7 100644 --- a/Sources/DebugMenu/Entity/MetricsFetcher.swift +++ b/Sources/DebugMenu/Entity/MetricsFetcher.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // diff --git a/Sources/DebugMenu/Entity/Options.swift b/Sources/DebugMenu/Entity/Options.swift index 64968e2..3a30434 100644 --- a/Sources/DebugMenu/Entity/Options.swift +++ b/Sources/DebugMenu/Entity/Options.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // @@ -10,6 +10,6 @@ import Foundation public enum Options { case showsWidgetOnLaunch case showsRecentItems - + public static var `default`: [Options] = [.showsRecentItems] } diff --git a/Sources/DebugMenu/Entity/RecentItemStore.swift b/Sources/DebugMenu/Entity/RecentItemStore.swift index f6b758b..a6567da 100644 --- a/Sources/DebugMenu/Entity/RecentItemStore.swift +++ b/Sources/DebugMenu/Entity/RecentItemStore.swift @@ -11,12 +11,13 @@ struct RecentItemStore { let key: String = "dev.noppe.debugmenu.recent-item-names" let items: [AnyDebugItem] let maxCount: Int = 3 - + func get() -> [AnyDebugItem] { let titles = UserDefaults.standard.stringArray(forKey: key)?.prefix(maxCount) ?? [] - return titles.compactMap({ title in items.first(where: { $0.debuggerItemTitle == title }) }).map(AnyDebugItem.init) + return titles.compactMap({ title in items.first(where: { $0.debuggerItemTitle == title }) }) + .map(AnyDebugItem.init) } - + func insert(_ item: AnyDebugItem) { var titles = UserDefaults.standard.stringArray(forKey: key) ?? [] titles.removeAll(where: { $0 == item.debuggerItemTitle }) diff --git a/Sources/DebugMenu/Extensions/Cell+.swift b/Sources/DebugMenu/Extensions/Cell+.swift index 018d473..b112526 100644 --- a/Sources/DebugMenu/Extensions/Cell+.swift +++ b/Sources/DebugMenu/Extensions/Cell+.swift @@ -1,6 +1,6 @@ // // Cell.swift -// +// // // Created by Tomoya Hirano on 2019/12/07. // Copyright © 2019 Tomoya Hirano. All rights reserved. @@ -12,7 +12,7 @@ public extension UITableView { func register(_ cellClass: T.Type) { register(cellClass, forCellReuseIdentifier: NSStringFromClass(cellClass)) } - + func dequeue(_ cellClass: T.Type, for indexPath: IndexPath) -> T { dequeueReusableCell(withIdentifier: NSStringFromClass(cellClass), for: indexPath) as! T } @@ -22,17 +22,26 @@ public extension UICollectionView { func register(_ cellClass: T.Type) { register(cellClass, forCellWithReuseIdentifier: String(describing: cellClass)) } - + func register(_ cellClass: T.Type) { - register(cellClass, forSupplementaryViewOfKind: cellClass.elementKind, withReuseIdentifier: String(describing: cellClass)) + register( + cellClass, + forSupplementaryViewOfKind: cellClass.elementKind, + withReuseIdentifier: String(describing: cellClass) + ) } - + func dequeue(_ cellClass: T.Type, for indexPath: IndexPath) -> T { - dequeueReusableCell(withReuseIdentifier: String(describing: cellClass), for: indexPath) as! T + dequeueReusableCell(withReuseIdentifier: String(describing: cellClass), for: indexPath) + as! T } - + func dequeue(_ cellClass: T.Type, for indexPath: IndexPath) -> T { - dequeueReusableSupplementaryView(ofKind: cellClass.elementKind, withReuseIdentifier: String(describing: cellClass), for: indexPath) as! T + dequeueReusableSupplementaryView( + ofKind: cellClass.elementKind, + withReuseIdentifier: String(describing: cellClass), + for: indexPath + ) as! T } } diff --git a/Sources/DebugMenu/Extensions/FloatingItemGestureRecognizer.swift b/Sources/DebugMenu/Extensions/FloatingItemGestureRecognizer.swift index e35916c..e7920fe 100644 --- a/Sources/DebugMenu/Extensions/FloatingItemGestureRecognizer.swift +++ b/Sources/DebugMenu/Extensions/FloatingItemGestureRecognizer.swift @@ -17,113 +17,139 @@ public class FloatingItemGestureRecognizer: UIPanGestureRecognizer { case bottomLeading case bottomTrailing } - + public init(groundView: UIView) { super.init(target: nil, action: nil) self.addTarget(self, action: #selector(pan(_:))) self.groundView = groundView - + } - + deinit { self.removeTarget(self, action: #selector(pan(_:))) } - + public func moveInitialPosition(_ edge: Edge = .bottomTrailing) { DispatchQueue.main.async { [weak self] in self?.view?.center = self?.cornerPositions()[edge] ?? .zero - UIView.animate(withDuration: 0.2, animations: { [weak self] in - self?.view?.alpha = 1.0 - }) + UIView.animate( + withDuration: 0.2, + animations: { [weak self] in + self?.view?.alpha = 1.0 + } + ) } } - + @objc private func pan(_ gesture: UIPanGestureRecognizer) { guard let targetView = self.view else { return } guard let groundView = groundView else { return } switch gesture.state { case .began: // ジェスチャ座標とオブジェクトの中心座標までの“ギャップ”を計算 - + let location = gesture.location(in: groundView) - let gap = CGPoint(x: targetView.center.x - location.x, y: targetView.center.y - location.y) + let gap = CGPoint( + x: targetView.center.x - location.x, + y: targetView.center.y - location.y + ) self.gestureGap = gap - + case .ended: let lastObjectLocation = targetView.center - let velocity = gesture.velocity(in: groundView) // points per second - + let velocity = gesture.velocity(in: groundView) // points per second + // 仮想の移動先を計算 - let projectedPosition = CGPoint(x: lastObjectLocation.x + project(initialVelocity: velocity.x, decelerationRate: .fast), - y: lastObjectLocation.y + project(initialVelocity: velocity.y, decelerationRate: .fast)) + let projectedPosition = CGPoint( + x: lastObjectLocation.x + + project(initialVelocity: velocity.x, decelerationRate: .fast), + y: lastObjectLocation.y + + project(initialVelocity: velocity.y, decelerationRate: .fast) + ) // 最適な移動先を計算 let destination = nearestCornerPosition(projectedPosition) - - let initialVelocity = initialAnimationVelocity(for: velocity, from: self.view!.center, to: destination) - + + let initialVelocity = initialAnimationVelocity( + for: velocity, + from: self.view!.center, + to: destination + ) + // iOSの一般的な動きに近い動きを再現 - let parameters = UISpringTimingParameters(dampingRatio: 0.5, initialVelocity: initialVelocity) + let parameters = UISpringTimingParameters( + dampingRatio: 0.5, + initialVelocity: initialVelocity + ) let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: parameters) - + animator.addAnimations { self.view!.center = destination } animator.startAnimation() - + self.gestureGap = nil - + default: // ジェスチャに合わせてオブジェクトをドラッグ - + let gestureGap = self.gestureGap ?? CGPoint.zero let location = gesture.location(in: groundView) let destination = CGPoint(x: location.x + gestureGap.x, y: location.y + gestureGap.y) self.view!.center = destination - + } } - - + // アニメーション開始時の変化率を計算 - private func initialAnimationVelocity(for gestureVelocity: CGPoint, from currentPosition: CGPoint, to finalPosition: CGPoint) -> CGVector { + private func initialAnimationVelocity( + for gestureVelocity: CGPoint, + from currentPosition: CGPoint, + to finalPosition: CGPoint + ) -> CGVector { // https://developer.apple.com/documentation/uikit/uispringtimingparameters/1649909-initialvelocity - + var animationVelocity = CGVector.zero let xDistance = finalPosition.x - currentPosition.x let yDistance = finalPosition.y - currentPosition.y - + if xDistance != 0 { animationVelocity.dx = gestureVelocity.x / xDistance } if yDistance != 0 { animationVelocity.dy = gestureVelocity.y / yDistance } - + return animationVelocity } - + // 仮想の移動先を計算 - private func project(initialVelocity: CGFloat, decelerationRate: UIScrollView.DecelerationRate) -> CGFloat { + private func project(initialVelocity: CGFloat, decelerationRate: UIScrollView.DecelerationRate) + -> CGFloat + { // https://developer.apple.com/videos/play/wwdc2018/803/ - - return (initialVelocity / 1000.0) * decelerationRate.rawValue / (1.0 - decelerationRate.rawValue) + + return (initialVelocity / 1000.0) * decelerationRate.rawValue + / (1.0 - decelerationRate.rawValue) } - + // 引数にもっとも近い位置を返す private func nearestCornerPosition(_ projectedPosition: CGPoint) -> CGPoint { let destinations = cornerPositions() - let nearestPosition = destinations.sorted(by: { - return distance(from: $0.value, to: projectedPosition) < distance(from: $1.value, to: projectedPosition) - }).first! - + let nearestPosition = + destinations.sorted(by: { + return distance(from: $0.value, to: projectedPosition) + < distance(from: $1.value, to: projectedPosition) + }) + .first! + return nearestPosition.value } - + private func distance(from: CGPoint, to: CGPoint) -> CGFloat { return sqrt(pow(from.x - to.x, 2) + pow(from.y - to.y, 2)) } - - private func cornerPositions() -> [Edge : CGPoint] { + + private func cornerPositions() -> [Edge: CGPoint] { guard let targetView = self.view else { return [:] } guard let groundView = groundView else { return [:] } let viewSize = groundView.bounds.size @@ -131,12 +157,12 @@ public class FloatingItemGestureRecognizer: UIPanGestureRecognizer { let xCenter = targetView.bounds.width / 2 let yCenter = targetView.bounds.height / 2 let safeAreaInsets = groundView.safeAreaInsets - + let topLeading = CGPoint( x: self.margin + xCenter + safeAreaInsets.left, y: self.margin + yCenter + safeAreaInsets.top ) - + let topTrailing = CGPoint( x: viewSize.width - objectSize.width - self.margin + xCenter - safeAreaInsets.right, y: self.margin + yCenter + safeAreaInsets.top @@ -145,16 +171,16 @@ public class FloatingItemGestureRecognizer: UIPanGestureRecognizer { x: self.margin + xCenter + safeAreaInsets.left, y: viewSize.height - objectSize.height - self.margin + yCenter - safeAreaInsets.bottom ) - + let bottomTrailing = CGPoint( x: viewSize.width - objectSize.width - self.margin + xCenter - safeAreaInsets.right, y: viewSize.height - objectSize.height - self.margin + yCenter - safeAreaInsets.bottom ) return [ - .topLeading : topLeading, - .topTrailing : topTrailing, - .bottomLeading : bottomLeading, - .bottomTrailing : bottomTrailing + .topLeading: topLeading, + .topTrailing: topTrailing, + .bottomLeading: bottomLeading, + .bottomTrailing: bottomTrailing, ] } } diff --git a/Sources/DebugMenu/Extensions/UIApplication+.swift b/Sources/DebugMenu/Extensions/UIApplication+.swift index 5acf267..0621a50 100644 --- a/Sources/DebugMenu/Extensions/UIApplication+.swift +++ b/Sources/DebugMenu/Extensions/UIApplication+.swift @@ -11,10 +11,11 @@ import UIKit extension UIApplication { func findKeyWindow() -> UIWindow? { (connectedScenes - .filter({$0.activationState == .foregroundActive}) - .compactMap({$0 as? UIWindowScene}) - .first?.windows ?? windows) + .filter({ $0.activationState == .foregroundActive }) + .compactMap({ $0 as? UIWindowScene }) + .first? + .windows ?? windows) .filter({ !($0 is InAppDebuggerWindow) }) - .filter({$0.isKeyWindow}).first + .filter({ $0.isKeyWindow }).first } } diff --git a/Sources/DebugMenu/Plugin/Complication/CPUGraphComplication.swift b/Sources/DebugMenu/Plugin/Complication/CPUGraphComplication.swift index c704218..2af3991 100644 --- a/Sources/DebugMenu/Plugin/Complication/CPUGraphComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/CPUGraphComplication.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // diff --git a/Sources/DebugMenu/Plugin/Complication/CPUUsageComplication.swift b/Sources/DebugMenu/Plugin/Complication/CPUUsageComplication.swift index dec9f8f..05e7087 100644 --- a/Sources/DebugMenu/Plugin/Complication/CPUUsageComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/CPUUsageComplication.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -22,5 +22,3 @@ public class CPUUsageComplication: ComplicationPresentable { } } } - - diff --git a/Sources/DebugMenu/Plugin/Complication/FPSComplication.swift b/Sources/DebugMenu/Plugin/Complication/FPSComplication.swift index 56f7195..2d5e4ec 100644 --- a/Sources/DebugMenu/Plugin/Complication/FPSComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/FPSComplication.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -14,21 +14,21 @@ public class FPSComplication: ComplicationPresentable { var lastupdated: CFTimeInterval = 0 var updateCount: Int = 1 var currentFPS: Int = 0 - + public init() {} - + public func startMonitoring() { displayLink = .init(target: self, selector: #selector(updateDisplayLink)) displayLink?.preferredFramesPerSecond = 0 displayLink?.add(to: .main, forMode: .common) } - + public func stopMonitoring() { displayLink?.remove(from: .main, forMode: .common) displayLink?.invalidate() displayLink = nil } - + @objc func updateDisplayLink(_ displayLink: CADisplayLink) { if displayLink.timestamp - lastupdated > 1.0 { currentFPS = updateCount @@ -38,11 +38,11 @@ public class FPSComplication: ComplicationPresentable { updateCount += 1 } } - + public func update() { - + } - + public var fetcher: MetricsFetcher { .text { [weak self] in guard let self = self else { return "-" } diff --git a/Sources/DebugMenu/Plugin/Complication/GPUMemoryUsageComplication.swift b/Sources/DebugMenu/Plugin/Complication/GPUMemoryUsageComplication.swift index b781186..d4249b4 100644 --- a/Sources/DebugMenu/Plugin/Complication/GPUMemoryUsageComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/GPUMemoryUsageComplication.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // @@ -22,7 +22,3 @@ public class GPUMemoryUsageComplication: ComplicationPresentable { } } } - - - - diff --git a/Sources/DebugMenu/Plugin/Complication/IntervalComplication.swift b/Sources/DebugMenu/Plugin/Complication/IntervalComplication.swift index 583fb03..3785ece 100644 --- a/Sources/DebugMenu/Plugin/Complication/IntervalComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/IntervalComplication.swift @@ -1,40 +1,44 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // -import Foundation import Combine +import Foundation public class IntervalComplication: ComplicationPresentable { public init(title: String, name: String) { self.title = title self.name = Notification.Name(name) } - + public let title: String private let name: Notification.Name var intervals: [TimeInterval] = [] private var cancellables: Set = [] - + public func startMonitoring() { - NotificationCenter.default.publisher(for: name).sink { notification in - if let interval = notification.userInfo?[IntervalTracker.intervalKey] as? TimeInterval { - self.intervals.append(interval) + NotificationCenter.default.publisher(for: name) + .sink { notification in + if let interval = notification.userInfo?[IntervalTracker.intervalKey] + as? TimeInterval + { + self.intervals.append(interval) + } } - }.store(in: &cancellables) + .store(in: &cancellables) } - + public func stopMonitoring() { cancellables = [] } - + public func update() { - + } - + public var fetcher: MetricsFetcher { .interval { [weak self] in guard let self = self else { return [] } @@ -49,14 +53,14 @@ public class IntervalTracker { case end } static let intervalKey: String = "dev.noppe.intervalTracker.interval" - + public init(name: String) { notificationName = .init(name) } - + let notificationName: Notification.Name var beginDate: Date? - + public func track(_ type: SignpostType) { switch type { case .begin: @@ -64,7 +68,13 @@ public class IntervalTracker { case .end: guard let beginDate = beginDate else { return } let interval = Date().timeIntervalSince(beginDate) - NotificationCenter.default.post(Notification(name: notificationName, object: nil, userInfo: [IntervalTracker.intervalKey : interval])) + NotificationCenter.default.post( + Notification( + name: notificationName, + object: nil, + userInfo: [IntervalTracker.intervalKey: interval] + ) + ) } } } diff --git a/Sources/DebugMenu/Plugin/Complication/MemoryUsageComplication.swift b/Sources/DebugMenu/Plugin/Complication/MemoryUsageComplication.swift index 3d527e6..d6b9273 100644 --- a/Sources/DebugMenu/Plugin/Complication/MemoryUsageComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/MemoryUsageComplication.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // diff --git a/Sources/DebugMenu/Plugin/Complication/NetworkUsageComplication.swift b/Sources/DebugMenu/Plugin/Complication/NetworkUsageComplication.swift index 398c12e..c4550cf 100644 --- a/Sources/DebugMenu/Plugin/Complication/NetworkUsageComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/NetworkUsageComplication.swift @@ -1,12 +1,12 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/29. // -import Foundation import Combine +import Foundation public class NetworkUsageComplication: ComplicationPresentable { public init() {} @@ -14,19 +14,21 @@ public class NetworkUsageComplication: ComplicationPresentable { var lastNetworkUsage: NetworkUsage? = nil var sendPerSec: UInt64 = 0 var receivedPerSec: UInt64 = 0 - + private var cancellables: Set = [] - + public func startMonitoring() { - Timer.publish(every: 1, on: .main, in: .default).autoconnect().sink { [weak self] _ in - self?.updateNetworkUsage() - }.store(in: &cancellables) + Timer.publish(every: 1, on: .main, in: .default).autoconnect() + .sink { [weak self] _ in + self?.updateNetworkUsage() + } + .store(in: &cancellables) } - + public func stopMonitoring() { cancellables = [] } - + private func updateNetworkUsage() { let networkUsage = Device.current.networkUsage() if let lastUsage = lastNetworkUsage, let newUsage = networkUsage { @@ -37,18 +39,19 @@ public class NetworkUsageComplication: ComplicationPresentable { } lastNetworkUsage = networkUsage } - + public func update() { - + } - + public var fetcher: MetricsFetcher { .text { [weak self] in guard let self = self else { return "-" } let formatter = ByteCountFormatter() formatter.countStyle = .file formatter.allowsNonnumericFormatting = false - return "↑\(formatter.string(fromByteCount: Int64(self.sendPerSec)))/s\n↓\(formatter.string(fromByteCount: Int64(self.receivedPerSec)))/s" + return + "↑\(formatter.string(fromByteCount: Int64(self.sendPerSec)))/s\n↓\(formatter.string(fromByteCount: Int64(self.receivedPerSec)))/s" } } } diff --git a/Sources/DebugMenu/Plugin/Complication/ThermalStateComplication.swift b/Sources/DebugMenu/Plugin/Complication/ThermalStateComplication.swift index 7bfb32b..4585ba0 100644 --- a/Sources/DebugMenu/Plugin/Complication/ThermalStateComplication.swift +++ b/Sources/DebugMenu/Plugin/Complication/ThermalStateComplication.swift @@ -1,31 +1,31 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/07/12. // -import Foundation import Combine +import Foundation public class ThermalStateComplication: ComplicationPresentable { public init() {} public let title: String = "Thermal" var currentThermalState: ProcessInfo.ThermalState = .nominal - + private var cancellables: Set = [] - + public func startMonitoring() { } - + public func stopMonitoring() { cancellables = [] } - + public func update() { currentThermalState = Device.current.thermalState } - + public var fetcher: MetricsFetcher { .text { [weak self] in switch self?.currentThermalState { diff --git a/Sources/DebugMenu/Plugin/Complication/UI/GraphTableViewCell.swift b/Sources/DebugMenu/Plugin/Complication/UI/GraphTableViewCell.swift index e33aa8b..80b1980 100644 --- a/Sources/DebugMenu/Plugin/Complication/UI/GraphTableViewCell.swift +++ b/Sources/DebugMenu/Plugin/Complication/UI/GraphTableViewCell.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // @@ -9,7 +9,7 @@ import UIKit class GraphTableViewCell: UITableViewCell { let graph = GraphView() - + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) graph.frame = .init(x: 0, y: 0, width: 64, height: 36) @@ -18,11 +18,11 @@ class GraphTableViewCell: UITableViewCell { textLabel?.textColor = .white textLabel?.adjustsFontSizeToFitWidth = true } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func setData(_ data: [Double]) { graph.reload(data: data, capacity: 60) } diff --git a/Sources/DebugMenu/Plugin/Complication/UI/GraphView.swift b/Sources/DebugMenu/Plugin/Complication/UI/GraphView.swift index 0738501..7529a4c 100644 --- a/Sources/DebugMenu/Plugin/Complication/UI/GraphView.swift +++ b/Sources/DebugMenu/Plugin/Complication/UI/GraphView.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // @@ -11,12 +11,12 @@ class GraphView: UIView { private var maxValue: Double = 0 private var capacity: Int = 60 private var data: [Double] = [] - + func setCapacity(_ capacity: Int) { self.capacity = capacity setNeedsDisplay() } - + func append(data: Double) { self.data.append(data) if self.data.count >= 10 { @@ -25,23 +25,23 @@ class GraphView: UIView { self.maxValue = max(self.maxValue, data) setNeedsDisplay() } - + func reload(data: [Double], capacity: Int, maxValue: Double? = nil) { self.data = data.suffix(capacity).map({ $0 }) self.capacity = capacity self.maxValue = maxValue ?? data.max() ?? 0 setNeedsDisplay() } - + override func draw(_ rect: CGRect) { guard data.count >= 1, data.count <= capacity else { return } let context = UIGraphicsGetCurrentContext() context?.clear(rect) - + let graph = UIBezierPath() - + graph.move(to: .init(x: 0, y: rect.height)) - + for (index, data) in data.enumerated() { let x = rect.width * CGFloat(index) / CGFloat(capacity) let y = rect.height - CGFloat(data / maxValue) * rect.height @@ -56,12 +56,15 @@ class GraphView: UIView { graph.close() UIColor.lightGray.setFill() graph.fill() - + let string = String(format: "%.2f", maxValue) - let text = NSAttributedString(string: string, attributes: [ - .foregroundColor : UIColor.white, - .font : UIFont.preferredFont(forTextStyle: .caption1) - ]) + let text = NSAttributedString( + string: string, + attributes: [ + .foregroundColor: UIColor.white, + .font: UIFont.preferredFont(forTextStyle: .caption1), + ] + ) text.draw(at: .zero) } } diff --git a/Sources/DebugMenu/Plugin/Complication/UI/IntervalTableViewCell.swift b/Sources/DebugMenu/Plugin/Complication/UI/IntervalTableViewCell.swift index 5259369..2773412 100644 --- a/Sources/DebugMenu/Plugin/Complication/UI/IntervalTableViewCell.swift +++ b/Sources/DebugMenu/Plugin/Complication/UI/IntervalTableViewCell.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // @@ -9,7 +9,7 @@ import UIKit class IntervalTableViewCell: UITableViewCell { let graph = IntervalView(frame: .null) - + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) graph.frame = .init(x: 0, y: 0, width: 64, height: 36) @@ -18,11 +18,11 @@ class IntervalTableViewCell: UITableViewCell { textLabel?.textColor = .white textLabel?.adjustsFontSizeToFitWidth = true } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func setDurations(_ durations: [TimeInterval]) { graph.reload(durations: durations) } diff --git a/Sources/DebugMenu/Plugin/Complication/UI/IntervalView.swift b/Sources/DebugMenu/Plugin/Complication/UI/IntervalView.swift index 7b3d466..5aa8d1c 100644 --- a/Sources/DebugMenu/Plugin/Complication/UI/IntervalView.swift +++ b/Sources/DebugMenu/Plugin/Complication/UI/IntervalView.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/30. // @@ -11,11 +11,11 @@ class IntervalView: UIStackView { private var latestInterval: TimeInterval? private var minInterval: TimeInterval? private var maxInterval: TimeInterval? - + private var latestIntervalLabel: UILabel = .init() private var minIntervalLabel: UILabel = .init() private var maxIntervalLabel: UILabel = .init() - + override init(frame: CGRect) { super.init(frame: frame) distribution = .fillEqually @@ -32,25 +32,25 @@ class IntervalView: UIStackView { maxIntervalLabel.font = UIFont.systemFont(ofSize: 10) maxIntervalLabel.textColor = .systemRed } - + required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func set(duration: TimeInterval) { latestInterval = duration minInterval = minInterval.map({ min(duration, $0) }) ?? duration maxInterval = maxInterval.map({ max(duration, $0) }) ?? duration updateLabels() } - + func reload(durations: [TimeInterval]) { latestInterval = durations.last minInterval = durations.min() maxInterval = durations.max() updateLabels() } - + private func updateLabels() { latestIntervalLabel.text = latestInterval.map({ String(format: "%.3f", $0) }) minIntervalLabel.text = minInterval.map({ String(format: "%.3f", $0) }) diff --git a/Sources/DebugMenu/Plugin/DebugMenu/AppInfoDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/AppInfoDebugItem.swift index 3812032..4081b4d 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/AppInfoDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/AppInfoDebugItem.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // @@ -12,26 +12,28 @@ public struct AppInfoDebugItem: DebugMenuPresentable { public var debuggerItemTitle: String = "App Info" public var action: DebugMenuAction = .didSelect { parent, completions in let vc = EnvelopePreviewTableViewController { completions in - DispatchQueue.global().async { - let envelops = [ - "App Name" : Application.current.appName, - "Version" : Application.current.version, - "Build" : Application.current.build, - "Bundle ID" : Application.current.bundleIdentifier, - "App Size" : Application.current.size, - "Locale" : Application.current.locale, - "Localization" : Application.current.preferredLocalizations, - "TestFlight?" : Application.current.isTestFlight ? "YES" : "NO" - ].map({ Envelope.init(key: $0.key, value: $0.value) }).sorted(by: { $0.key < $1.key }) - DispatchQueue.main.async { - completions(envelops) + DispatchQueue.global() + .async { + let envelops = [ + "App Name": Application.current.appName, + "Version": Application.current.version, + "Build": Application.current.build, + "Bundle ID": Application.current.bundleIdentifier, + "App Size": Application.current.size, + "Locale": Application.current.locale, + "Localization": Application.current.preferredLocalizations, + "TestFlight?": Application.current.isTestFlight ? "YES" : "NO", + ] + .map({ Envelope.init(key: $0.key, value: $0.value) }) + .sorted(by: { $0.key < $1.key }) + DispatchQueue.main.async { + completions(envelops) + } } - } - + } parent.navigationController?.pushViewController(vc, animated: true) completions(.success()) } - } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/CaseSelectableDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/CaseSelectableDebugItem.swift index 9e99dc6..6ef7e8f 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/CaseSelectableDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/CaseSelectableDebugItem.swift @@ -7,14 +7,17 @@ import UIKit -public struct CaseSelectableDebugItem: DebugMenuPresentable where T.RawValue: Equatable { +public struct CaseSelectableDebugItem: DebugMenuPresentable +where T.RawValue: Equatable { public init(currentValue: T, didSelected: @escaping (T) -> Void) { self.action = .didSelect { (controller, completions) in - let vc = CaseSelectableTableController(currentValue: currentValue, didSelected: didSelected) + let vc = CaseSelectableTableController( + currentValue: currentValue, + didSelected: didSelected + ) controller.navigationController?.pushViewController(vc, animated: true) } } public var debuggerItemTitle: String { String(describing: T.self) } public let action: DebugMenuAction } - diff --git a/Sources/DebugMenu/Plugin/DebugMenu/ClearCacheDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/ClearCacheDebugItem.swift index 6a101d3..0882320 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/ClearCacheDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/ClearCacheDebugItem.swift @@ -9,7 +9,7 @@ import UIKit public struct ClearCacheDebugItem: DebugMenuPresentable { public init() {} - + public let debuggerItemTitle: String = "Clear Cache" public let action: DebugMenuAction = .execute { (completions) in do { @@ -19,12 +19,16 @@ public struct ClearCacheDebugItem: DebugMenuPresentable { completions(.failure(message: "\(error)")) } } - + static func clearCache() throws { - let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! + let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! let fileManager = FileManager.default // Get the directory contents urls (including subfolders urls) - let directoryContents = try FileManager.default.contentsOfDirectory( at: cacheURL, includingPropertiesForKeys: nil, options: []) + let directoryContents = try FileManager.default.contentsOfDirectory( + at: cacheURL, + includingPropertiesForKeys: nil, + options: [] + ) for file in directoryContents { try fileManager.removeItem(at: file) } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/DeviceInfoDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/DeviceInfoDebugItem.swift index 1fcff85..9229824 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/DeviceInfoDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/DeviceInfoDebugItem.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // @@ -12,31 +12,32 @@ public struct DeviceInfoDebugItem: DebugMenuPresentable { public var debuggerItemTitle: String = "Device Info" public var action: DebugMenuAction = .didSelect { parent, completions in let vc = EnvelopePreviewTableViewController { completions in - DispatchQueue.global().async { - let envelops = [ - "Name" : Device.current.name, - "Battery level" : Device.current.localizedBatteryLevel, - "Battery state" : Device.current.localizedBatteryState, - "Model" : Device.current.localizedModel, - "System name" : Device.current.systemName, - "System version" : Device.current.systemVersion, - "Jailbreak?" : Device.current.isJailbreaked ? "YES" : "NO", - "System uptime" : Device.current.localizedSystemUptime, - "Uptime" : Device.current.localizedUptime, - "LowPower mode?" : Device.current.isLowPowerModeEnabled ? "YES" : "NO", - "Processor" : Device.current.processor, - "Physical Memory" : Device.current.localizedPhysicalMemory, - "Disk usage" : Device.current.localizedDiskUsage, - ].map({ Envelope(key: $0.key, value: $0.value) }).sorted(by: { $0.key < $1.key }) - DispatchQueue.main.async { - completions(envelops) + DispatchQueue.global() + .async { + let envelops = [ + "Name": Device.current.name, + "Battery level": Device.current.localizedBatteryLevel, + "Battery state": Device.current.localizedBatteryState, + "Model": Device.current.localizedModel, + "System name": Device.current.systemName, + "System version": Device.current.systemVersion, + "Jailbreak?": Device.current.isJailbreaked ? "YES" : "NO", + "System uptime": Device.current.localizedSystemUptime, + "Uptime": Device.current.localizedUptime, + "LowPower mode?": Device.current.isLowPowerModeEnabled ? "YES" : "NO", + "Processor": Device.current.processor, + "Physical Memory": Device.current.localizedPhysicalMemory, + "Disk usage": Device.current.localizedDiskUsage, + ] + .map({ Envelope(key: $0.key, value: $0.value) }).sorted(by: { $0.key < $1.key }) + DispatchQueue.main.async { + completions(envelops) + } } - } - + } parent.navigationController?.pushViewController(vc, animated: true) completions(.success()) } - } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/ExitDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/ExitDebugItem.swift index b9fbd92..6a529ef 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/ExitDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/ExitDebugItem.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/05. // @@ -13,7 +13,7 @@ public struct ExitDebugItem: DebugMenuPresentable { exit(0) }) } - + public var debuggerItemTitle: String { "exit" } public let action: DebugMenuAction } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/GroupDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/GroupDebugItem.swift index 176eae4..5560995 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/GroupDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/GroupDebugItem.swift @@ -16,7 +16,7 @@ public struct GroupDebugItem: DebugMenuPresentable, HasDebugItems { self.debuggerItemTitle = title self.debugItems = items.map(AnyGroupDebugItem.init) } - + public var debuggerItemTitle: String public var action: DebugMenuAction { .didSelect { controller, completions in @@ -37,7 +37,7 @@ struct AnyGroupDebugItem: Hashable, Identifiable, DebugMenuPresentable, HasDebug let debuggerItemTitle: String let action: DebugMenuAction let debugItems: [AnyGroupDebugItem] - + init(_ item: DebugMenuPresentable) { id = UUID().uuidString debuggerItemTitle = item.debuggerItemTitle @@ -48,11 +48,11 @@ struct AnyGroupDebugItem: Hashable, Identifiable, DebugMenuPresentable, HasDebug debugItems = [] } } - + func hash(into hasher: inout Hasher) { hasher.combine(id) } - + static func == (lhs: AnyGroupDebugItem, rhs: AnyGroupDebugItem) -> Bool { lhs.id == rhs.id } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/KeyValueDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/KeyValueDebugItem.swift index d7af458..dee1d81 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/KeyValueDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/KeyValueDebugItem.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/23. // @@ -8,7 +8,10 @@ import Foundation public struct KeyValueDebugItem: DebugMenuPresentable { - public init(title: String, fetcher: @escaping (_ completions: @escaping ([Envelope]) -> Void) -> Void) { + public init( + title: String, + fetcher: @escaping (_ completions: @escaping ([Envelope]) -> Void) -> Void + ) { self.title = title self.action = .didSelect(action: { parent, result in let vc = EnvelopePreviewTableViewController(fetcher: fetcher) @@ -16,7 +19,7 @@ public struct KeyValueDebugItem: DebugMenuPresentable { result(.success()) }) } - + let title: String public var debuggerItemTitle: String { title } public let action: DebugMenuAction diff --git a/Sources/DebugMenu/Plugin/DebugMenu/RangeDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/RangeDebugItem.swift index 655386b..23969bf 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/RangeDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/RangeDebugItem.swift @@ -8,14 +8,23 @@ import Foundation public struct RangeDebugItem: DebugMenuPresentable { - public init(title: String, current: @escaping () -> Double, range: ClosedRange = 0.0...1.0, onChange: @escaping (Double) -> Void) { + public init( + title: String, + current: @escaping () -> Double, + range: ClosedRange = 0.0...1.0, + onChange: @escaping (Double) -> Void + ) { self.title = title - self.action = .slider(current: current, range: range, action: { (value, completions) in - onChange(value) - completions(.success()) - }) + self.action = .slider( + current: current, + range: range, + action: { (value, completions) in + onChange(value) + completions(.success()) + } + ) } - + let title: String public var debuggerItemTitle: String { title } public let action: DebugMenuAction diff --git a/Sources/DebugMenu/Plugin/DebugMenu/ToggleDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/ToggleDebugItem.swift index 2ae6426..ac5f693 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/ToggleDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/ToggleDebugItem.swift @@ -10,12 +10,15 @@ import Foundation public struct ToggleDebugItem: DebugMenuPresentable { public init(title: String, current: @escaping () -> Bool, onChange: @escaping (Bool) -> Void) { self.title = title - self.action = .toggle(current: current, action: { (isOn, completions) in - onChange(isOn) - completions(.success()) - }) + self.action = .toggle( + current: current, + action: { (isOn, completions) in + onChange(isOn) + completions(.success()) + } + ) } - + let title: String public var debuggerItemTitle: String { title } public let action: DebugMenuAction diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UI/CaseSelectableTableController.swift b/Sources/DebugMenu/Plugin/DebugMenu/UI/CaseSelectableTableController.swift index 56d4569..50859b9 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UI/CaseSelectableTableController.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UI/CaseSelectableTableController.swift @@ -8,38 +8,47 @@ import Foundation import UIKit -public class CaseSelectableTableController: UITableViewController where T.RawValue: Equatable { +public class CaseSelectableTableController: + UITableViewController +where T.RawValue: Equatable { public let currentValue: T public let didSelected: (T) -> Void private var selectedIndex: IndexPath? = nil - + public init(currentValue: T, didSelected: @escaping (T) -> Void) { self.currentValue = currentValue self.didSelected = didSelected super.init(style: .grouped) tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") } - + required init?(coder: NSCoder) { fatalError() } - + public override func viewDidLoad() { super.viewDidLoad() - selectedIndex = IndexPath(row: T.allCases.enumerated().first(where: { $1 == currentValue })?.offset ?? 0, section: 0) + selectedIndex = IndexPath( + row: T.allCases.enumerated().first(where: { $1 == currentValue })?.offset ?? 0, + section: 0 + ) tableView.tableFooterView = UIView() } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + + public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) + -> Int + { T.allCases.count } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) + -> UITableViewCell + { let cell = tableView.dequeueReusableCell(withIdentifier: "cell")! let value = T.allCases.map({ $0 })[indexPath.row] cell.textLabel?.text = "\(value)" cell.accessoryType = (indexPath == selectedIndex) ? .checkmark : .none return cell } - + public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let indexPathes: [IndexPath] = [indexPath, selectedIndex].compactMap({ $0 }) selectedIndex = indexPath diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UI/EnvelopePreviewTableViewController.swift b/Sources/DebugMenu/Plugin/DebugMenu/UI/EnvelopePreviewTableViewController.swift index 3a87cc2..400b777 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UI/EnvelopePreviewTableViewController.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UI/EnvelopePreviewTableViewController.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/23. // @@ -10,34 +10,38 @@ import UIKit class EnvelopePreviewTableViewController: UITableViewController { var envelops: [Envelope] = [] var fetcher: ((_ completions: @escaping ([Envelope]) -> Void) -> Void) - + init(fetcher: @escaping (_ completions: @escaping ([Envelope]) -> Void) -> Void) { self.fetcher = fetcher super.init(style: .plain) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + public override func viewDidLoad() { tableView.register(Value1TableViewCell.self) - + let refreshControlAction: UIAction = .init { [weak self] _ in self?.fetch() } let refreshControl = UIRefreshControl(frame: .zero, primaryAction: refreshControlAction) tableView.refreshControl = refreshControl - + let rightBarButtonAction: UIAction = .init { [weak self] _ in self?.presentActivity() } - let rightBarButtonItem = UIBarButtonItem(systemItem: .action, primaryAction: rightBarButtonAction, menu: nil) + let rightBarButtonItem = UIBarButtonItem( + systemItem: .action, + primaryAction: rightBarButtonAction, + menu: nil + ) navigationItem.rightBarButtonItem = rightBarButtonItem - + fetch() } - + private func fetch() { fetcher { [weak self] envelops in DispatchQueue.main.async { [weak self] in @@ -47,34 +51,44 @@ class EnvelopePreviewTableViewController: UITableViewController { } } } - + private func presentAlert(title: String, message: String) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(.init(title: "Copy", style: .default, handler: { _ in - UIPasteboard.general.string = message - })) + alert.addAction( + .init( + title: "Copy", + style: .default, + handler: { _ in + UIPasteboard.general.string = message + } + ) + ) alert.addAction(.init(title: "OK", style: .default, handler: nil)) present(alert, animated: true, completion: nil) } - + private func presentActivity() { let texts = envelops.map({ "\($0.key) : \($0.value)" }).joined(separator: "\n") let vc = UIActivityViewController(activityItems: [texts], applicationActivities: nil) present(vc, animated: true, completion: nil) } - - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + + public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) + -> Int + { envelops.count } - - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) + -> UITableViewCell + { let cell = tableView.dequeue(Value1TableViewCell.self, for: indexPath) let envelop = envelops[indexPath.row] cell.textLabel?.text = envelop.key cell.detailTextLabel?.text = envelop.value return cell } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let envelop = envelops[indexPath.row] presentAlert(title: envelop.key, message: envelop.value) diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UI/SliderCell.swift b/Sources/DebugMenu/Plugin/DebugMenu/UI/SliderCell.swift index f5abae5..eb5072a 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UI/SliderCell.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UI/SliderCell.swift @@ -14,7 +14,12 @@ class SliderCell: UICollectionViewListCell { var onChange: ((Double) -> Void)! override func updateConfiguration(using state: UICellConfigurationState) { - let configuration = SliderCellConfiguration(title: title, current: current, range: range, onChange: onChange) + let configuration = SliderCellConfiguration( + title: title, + current: current, + range: range, + onChange: onChange + ) contentConfiguration = configuration } } @@ -34,29 +39,32 @@ struct SliderCellConfiguration: UIContentConfiguration { class SliderCellView: UIView, UIContentView { var configuration: UIContentConfiguration - + init(configuration: SliderCellConfiguration) { self.configuration = configuration super.init(frame: .null) - + let titleLabel = UILabel(frame: .null) titleLabel.text = configuration.title let valueLabel = UILabel(frame: .null) - - let slider = UISlider(frame: .null, primaryAction: UIAction(handler: { (action) in - if let slider = action.sender as? UISlider { - valueLabel.text = String(format: "%.2f", slider.value) - configuration.onChange(Double(slider.value)) - } - })) + + let slider = UISlider( + frame: .null, + primaryAction: UIAction(handler: { (action) in + if let slider = action.sender as? UISlider { + valueLabel.text = String(format: "%.2f", slider.value) + configuration.onChange(Double(slider.value)) + } + }) + ) slider.maximumValue = Float(configuration.range.upperBound) slider.minimumValue = Float(configuration.range.lowerBound) slider.setValue(Float(configuration.current()), animated: false) valueLabel.text = String(format: "%.2f", slider.value) - + let hStack = UIStackView(arrangedSubviews: [titleLabel, valueLabel]) hStack.axis = .horizontal - + let vStack = UIStackView(arrangedSubviews: [hStack, slider]) vStack.axis = .vertical vStack.spacing = 6 @@ -69,7 +77,7 @@ class SliderCellView: UIView, UIContentView { vStack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), ]) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UI/ToogleCell.swift b/Sources/DebugMenu/Plugin/DebugMenu/UI/ToogleCell.swift index 54a2a62..0e51f33 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UI/ToogleCell.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UI/ToogleCell.swift @@ -10,14 +10,20 @@ import UIKit class ToggleCell: UICollectionViewListCell { var current: (() -> Bool)! var onChange: ((Bool) -> Void)! - + override func updateConfiguration(using state: UICellConfigurationState) { let toggle = UISwitch() toggle.isOn = current() - toggle.addAction(.init(handler: { [weak self] action in - self?.onChange(toggle.isOn) - }), for: .valueChanged) - let configuration = UICellAccessory.CustomViewConfiguration(customView: toggle, placement: .trailing()) + toggle.addAction( + .init(handler: { [weak self] action in + self?.onChange(toggle.isOn) + }), + for: .valueChanged + ) + let configuration = UICellAccessory.CustomViewConfiguration( + customView: toggle, + placement: .trailing() + ) accessories = [.customView(configuration: configuration)] } } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UI/Value1TableViewCell.swift b/Sources/DebugMenu/Plugin/DebugMenu/UI/Value1TableViewCell.swift index 6282b27..6d90983 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UI/Value1TableViewCell.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UI/Value1TableViewCell.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/23. // @@ -12,7 +12,7 @@ class Value1TableViewCell: UITableViewCell { super.init(style: .value1, reuseIdentifier: reuseIdentifier) textLabel?.adjustsFontSizeToFitWidth = true } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/Sources/DebugMenu/Plugin/DebugMenu/UserDefaultsResetDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/UserDefaultsResetDebugItem.swift index 666b3a9..31aff86 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/UserDefaultsResetDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/UserDefaultsResetDebugItem.swift @@ -9,9 +9,9 @@ import UIKit public struct UserDefaultsResetDebugItem: DebugMenuPresentable { public init() {} - + public let debuggerItemTitle: String = "Reset UserDefaults" - + public let action: DebugMenuAction = .execute { (_) in let appDomain = Bundle.main.bundleIdentifier! UserDefaults.standard.removePersistentDomain(forName: appDomain) diff --git a/Sources/DebugMenu/Plugin/DebugMenu/ViewControllerDebugItem.swift b/Sources/DebugMenu/Plugin/DebugMenu/ViewControllerDebugItem.swift index bdc02df..7cf3f87 100644 --- a/Sources/DebugMenu/Plugin/DebugMenu/ViewControllerDebugItem.swift +++ b/Sources/DebugMenu/Plugin/DebugMenu/ViewControllerDebugItem.swift @@ -12,23 +12,31 @@ public struct ViewControllerDebugItem: DebugMenuPresentable case present case push } - - public init(title: String? = nil, presentationMode: PresentationMode = .push, builder: @escaping ((T.Type) -> T) = { $0.init() }) { + + public init( + title: String? = nil, + presentationMode: PresentationMode = .push, + builder: @escaping ((T.Type) -> T) = { $0.init() } + ) { debuggerItemTitle = title ?? String(describing: T.self) action = .didSelect { (controller, completions) in let viewController = builder(T.self) switch presentationMode { case .present: - controller.present(viewController, animated: true, completion: { - completions(.success()) - }) + controller.present( + viewController, + animated: true, + completion: { + completions(.success()) + } + ) case .push: controller.navigationController?.pushViewController(viewController, animated: true) completions(.success()) } } } - + public let debuggerItemTitle: String public let action: DebugMenuAction } diff --git a/Sources/DebugMenu/SwiftUI/DebugMenuModifier.swift b/Sources/DebugMenu/SwiftUI/DebugMenuModifier.swift index 0f5782b..530dd23 100644 --- a/Sources/DebugMenu/SwiftUI/DebugMenuModifier.swift +++ b/Sources/DebugMenu/SwiftUI/DebugMenuModifier.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/05. // @@ -10,20 +10,29 @@ import SwiftUI @available(iOSApplicationExtension, unavailable) struct DebugMenuModifier: ViewModifier { - internal init(debuggerItems: [DebugMenuPresentable], complications: [ComplicationPresentable], options: [Options]) { + internal init( + debuggerItems: [DebugMenuPresentable], + complications: [ComplicationPresentable], + options: [Options] + ) { self.debuggerItems = debuggerItems self.complications = complications self.options = options } - + let debuggerItems: [DebugMenuPresentable] let complications: [ComplicationPresentable] let options: [Options] - + func body(content: Content) -> some View { content.onAppear(perform: { if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { - DebugMenu.install(windowScene: windowScene, items: debuggerItems, complications: complications, options: options) + DebugMenu.install( + windowScene: windowScene, + items: debuggerItems, + complications: complications, + options: options + ) } }) } @@ -32,9 +41,20 @@ struct DebugMenuModifier: ViewModifier { @available(iOSApplicationExtension, unavailable) public extension View { @ViewBuilder - func debugMenu(debuggerItems: [DebugMenuPresentable] = [], complications: [ComplicationPresentable] = [], options: [Options] = Options.default, enabled: Bool = true) -> some View { + func debugMenu( + debuggerItems: [DebugMenuPresentable] = [], + complications: [ComplicationPresentable] = [], + options: [Options] = Options.default, + enabled: Bool = true + ) -> some View { if enabled { - modifier(DebugMenuModifier(debuggerItems: debuggerItems, complications: complications, options: options)) + modifier( + DebugMenuModifier( + debuggerItems: debuggerItems, + complications: complications, + options: options + ) + ) } else { self } diff --git a/Sources/DebugMenu/View/FloatingViewController.swift b/Sources/DebugMenu/View/FloatingViewController.swift index d9ca838..e33c60f 100644 --- a/Sources/DebugMenu/View/FloatingViewController.swift +++ b/Sources/DebugMenu/View/FloatingViewController.swift @@ -5,8 +5,8 @@ // Created by Tomoya Hirano on 2020/12/23. // -import UIKit import Combine +import UIKit internal class FloatingViewController: UIViewController { class View: UIView, TouchThrowing {} @@ -15,57 +15,68 @@ internal class FloatingViewController: UIViewController { private let debuggerItems: [DebugMenuPresentable] private var cancellables: Set = [] private let options: [Options] - - init(debuggerItems: [DebugMenuPresentable], complications: [ComplicationPresentable], options: [Options]) { + + init( + debuggerItems: [DebugMenuPresentable], + complications: [ComplicationPresentable], + options: [Options] + ) { self.debuggerItems = debuggerItems self.widgetView = .init(complications: complications) self.options = options super.init(nibName: nil, bundle: nil) } - + required init?(coder: NSCoder) { fatalError() } - + override func loadView() { view = View(frame: .null) - + view.addSubview(launchView) view.addSubview(widgetView) - + launchView.isHidden = true widgetView.isHidden = true } - + override func viewDidLoad() { super.viewDidLoad() - + bug: do { let gesture = FloatingItemGestureRecognizer(groundView: self.view) launchView.addGestureRecognizer(gesture) gesture.moveInitialPosition() - + let longPress = UILongPressGestureRecognizer() - longPress.publisher(for: \.state).filter({ $0 == .began }).sink { [weak self] _ in - self?.presentMenu() - }.store(in: &cancellables) + longPress.publisher(for: \.state).filter({ $0 == .began }) + .sink { [weak self] _ in + self?.presentMenu() + } + .store(in: &cancellables) launchView.addGestureRecognizer(longPress) - - launchView.addAction(.init(handler: { [weak self] _ in - guard let self = self else { return } - let vc = InAppDebuggerViewController(debuggerItems: self.debuggerItems, options: self.options) - let nc = UINavigationController(rootViewController: vc) - nc.modalPresentationStyle = .fullScreen - let ac = CustomActivityViewController(controller: nc) - ac.popoverPresentationController?.sourceView = self.launchView - self.present(ac, animated: true, completion: nil) - })) + + launchView.addAction( + .init(handler: { [weak self] _ in + guard let self = self else { return } + let vc = InAppDebuggerViewController( + debuggerItems: self.debuggerItems, + options: self.options + ) + let nc = UINavigationController(rootViewController: vc) + nc.modalPresentationStyle = .fullScreen + let ac = CustomActivityViewController(controller: nc) + ac.popoverPresentationController?.sourceView = self.launchView + self.present(ac, animated: true, completion: nil) + }) + ) } - + widget: do { let gesture = FloatingItemGestureRecognizer(groundView: self.view) widgetView.addGestureRecognizer(gesture) gesture.moveInitialPosition(.topLeading) } - + if options.contains(.showsWidgetOnLaunch) { widgetView.show() } else { @@ -73,21 +84,39 @@ internal class FloatingViewController: UIViewController { } launchView.isHidden = false } - + private func presentMenu() { let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - sheet.addAction(.init(title: "Hide until next launch", style: .destructive, handler: { [weak self] _ in - self?.launchView.isHidden = true - self?.widgetView.hide() - })) + sheet.addAction( + .init( + title: "Hide until next launch", + style: .destructive, + handler: { [weak self] _ in + self?.launchView.isHidden = true + self?.widgetView.hide() + } + ) + ) if widgetView.isHidden { - sheet.addAction(.init(title: "Show widget", style: .default, handler: { [weak self] _ in - self?.widgetView.show() - })) + sheet.addAction( + .init( + title: "Show widget", + style: .default, + handler: { [weak self] _ in + self?.widgetView.show() + } + ) + ) } else { - sheet.addAction(.init(title: "Hide widget", style: .destructive, handler: { [weak self] _ in - self?.widgetView.hide() - })) + sheet.addAction( + .init( + title: "Hide widget", + style: .destructive, + handler: { [weak self] _ in + self?.widgetView.hide() + } + ) + ) } sheet.addAction(.init(title: "Cancel", style: .cancel, handler: nil)) present(sheet, animated: true, completion: nil) diff --git a/Sources/DebugMenu/View/InAppDebuggerViewController.swift b/Sources/DebugMenu/View/InAppDebuggerViewController.swift index ffc8b0f..6081c97 100644 --- a/Sources/DebugMenu/View/InAppDebuggerViewController.swift +++ b/Sources/DebugMenu/View/InAppDebuggerViewController.swift @@ -12,12 +12,14 @@ class InAppDebuggerViewController: UIViewController { let flattenDebugItems: [AnyDebugItem] let debuggerItems: [AnyDebugItem] let options: [Options] - lazy var dataSource: UICollectionViewDiffableDataSource = { preconditionFailure() }() - + lazy var dataSource: UICollectionViewDiffableDataSource = { + preconditionFailure() + }() + enum Section: Int, CaseIterable { case recent case items - + var title: String { switch self { case .recent: @@ -27,10 +29,11 @@ class InAppDebuggerViewController: UIViewController { } } } - + init(title: String = "DebugMenu", debuggerItems: [DebugMenuPresentable], options: [Options]) { self.options = options - self.flattenDebugItems = debuggerItems.map(AnyGroupDebugItem.init).flatten().map(AnyDebugItem.init) + self.flattenDebugItems = debuggerItems.map(AnyGroupDebugItem.init).flatten() + .map(AnyDebugItem.init) self.debuggerItems = debuggerItems.map(AnyDebugItem.init) var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) configuration.headerMode = .supplementary @@ -42,59 +45,64 @@ class InAppDebuggerViewController: UIViewController { super.init(nibName: nil, bundle: nil) self.title = title } - + required init?(coder: NSCoder) { fatalError() } - + override func loadView() { view = collectionView } - + override func viewDidLoad() { super.viewDidLoad() - + navigationItem.largeTitleDisplayMode = .always - - search: do { - let searchController = UISearchController(searchResultsController: nil) - searchController.searchResultsUpdater = self - navigationItem.searchController = searchController - } - - navigation: do { - let rightItem = UIBarButtonItem(systemItem: .done, primaryAction: UIAction(handler: { [weak self] (_) in - self?.parent?.parent?.dismiss(animated: true) - }), menu: nil) - navigationItem.rightBarButtonItem = rightItem - } - - toolbar: do { - let label = UILabel(frame: .null) - label.font = UIFont.preferredFont(forTextStyle: .caption1) - label.textColor = UIColor.label - label.text = "\(Application.current.appName) \(Application.current.version) (\(Application.current.build))" - let bundleIDLabel = UILabel(frame: .null) - bundleIDLabel.font = UIFont.preferredFont(forTextStyle: .caption2) - bundleIDLabel.textColor = UIColor.secondaryLabel - bundleIDLabel.text = "\(Application.current.bundleIdentifier)" - let vStack = UIStackView(arrangedSubviews: [label, bundleIDLabel]) - vStack.axis = .vertical - vStack.alignment = .center - let space = UIBarButtonItem.flexibleSpace() - let item = UIBarButtonItem(customView: vStack) - navigationController?.isToolbarHidden = false - toolbarItems = [space, item, space] - } + + search: do { + let searchController = UISearchController(searchResultsController: nil) + searchController.searchResultsUpdater = self + navigationItem.searchController = searchController + } + + navigation: do { + let rightItem = UIBarButtonItem( + systemItem: .done, + primaryAction: UIAction(handler: { [weak self] (_) in + self?.parent?.parent?.dismiss(animated: true) + }), + menu: nil + ) + navigationItem.rightBarButtonItem = rightItem + } + + toolbar: do { + let label = UILabel(frame: .null) + label.font = UIFont.preferredFont(forTextStyle: .caption1) + label.textColor = UIColor.label + label.text = + "\(Application.current.appName) \(Application.current.version) (\(Application.current.build))" + let bundleIDLabel = UILabel(frame: .null) + bundleIDLabel.font = UIFont.preferredFont(forTextStyle: .caption2) + bundleIDLabel.textColor = UIColor.secondaryLabel + bundleIDLabel.text = "\(Application.current.bundleIdentifier)" + let vStack = UIStackView(arrangedSubviews: [label, bundleIDLabel]) + vStack.axis = .vertical + vStack.alignment = .center + let space = UIBarButtonItem.flexibleSpace() + let item = UIBarButtonItem(customView: vStack) + navigationController?.isToolbarHidden = false + toolbarItems = [space, item, space] + } configureDataSource() collectionView.delegate = self - + performUpdate() } - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) deselectSelectedItems() } - + private func onCompleteAction(_ result: DebugMenuResult) { switch result { case .success(let message) where message != nil: @@ -105,103 +113,144 @@ class InAppDebuggerViewController: UIViewController { break } } - + private func deselectSelectedItems(animated: Bool = true) { - collectionView.indexPathsForSelectedItems?.forEach { (indexPath) in - collectionView.deselectItem(at: indexPath, animated: animated) - } + collectionView.indexPathsForSelectedItems? + .forEach { (indexPath) in + collectionView.deselectItem(at: indexPath, animated: animated) + } } } extension InAppDebuggerViewController { - + func configureDataSource() { - let selectCellRegstration = UICollectionView.CellRegistration { (cell: UICollectionViewListCell, indexPath, title: String) in + let selectCellRegstration = UICollectionView.CellRegistration { + (cell: UICollectionViewListCell, indexPath, title: String) in var content = cell.defaultContentConfiguration() content.text = title cell.contentConfiguration = content cell.accessories = [.disclosureIndicator()] } - - let executableCellRegstration = UICollectionView.CellRegistration { (cell: UICollectionViewListCell, indexPath, title: String) in + + let executableCellRegstration = UICollectionView.CellRegistration { + (cell: UICollectionViewListCell, indexPath, title: String) in var content = cell.defaultContentConfiguration() content.text = title cell.contentConfiguration = content } - - let toggleCellRegstration = UICollectionView.CellRegistration { (cell: ToggleCell, indexPath, item: (title: String, current: () -> Bool, onChange: (Bool) -> Void)) in + + let toggleCellRegstration = UICollectionView.CellRegistration { + ( + cell: ToggleCell, + indexPath, + item: (title: String, current: () -> Bool, onChange: (Bool) -> Void) + ) in var content = cell.defaultContentConfiguration() content.text = item.title cell.contentConfiguration = content cell.current = item.current cell.onChange = item.onChange } - - let sliderCellRegstration = UICollectionView.CellRegistration { (cell: SliderCell, indexPath, item: (title: String, current: () -> Double, range: ClosedRange, onChange: (Double) -> Void)) in + + let sliderCellRegstration = UICollectionView.CellRegistration { + ( + cell: SliderCell, + indexPath, + item: ( + title: String, current: () -> Double, range: ClosedRange, + onChange: (Double) -> Void + ) + ) in cell.title = item.title cell.current = item.current cell.range = item.range cell.onChange = item.onChange } - - dataSource = .init(collectionView: collectionView, cellProvider: { [weak self] (collectionView, indexPath, item) in - switch item.action { - case .didSelect: - return collectionView.dequeueConfiguredReusableCell( - using: selectCellRegstration, - for: indexPath, - item: item.debuggerItemTitle - ) - case .execute: - return collectionView.dequeueConfiguredReusableCell( - using: executableCellRegstration, - for: indexPath, - item: item.debuggerItemTitle - ) - case let .toggle(current, onChange): - return collectionView.dequeueConfiguredReusableCell( - using: toggleCellRegstration, - for: indexPath, - item: (item.debuggerItemTitle, current, { [weak self] (value) in - onChange(value, { [weak self] (result) in - self?.onCompleteAction(result) - }) - }) - ) - case let .slider(current, range, onChange): - return collectionView.dequeueConfiguredReusableCell( - using: sliderCellRegstration, - for: indexPath, - item: (item.debuggerItemTitle, current, range, { [weak self] (value) in - onChange(value, { [weak self] (result) in - self?.onCompleteAction(result) - }) - }) - ) + + dataSource = .init( + collectionView: collectionView, + cellProvider: { [weak self] (collectionView, indexPath, item) in + switch item.action { + case .didSelect: + return collectionView.dequeueConfiguredReusableCell( + using: selectCellRegstration, + for: indexPath, + item: item.debuggerItemTitle + ) + case .execute: + return collectionView.dequeueConfiguredReusableCell( + using: executableCellRegstration, + for: indexPath, + item: item.debuggerItemTitle + ) + case let .toggle(current, onChange): + return collectionView.dequeueConfiguredReusableCell( + using: toggleCellRegstration, + for: indexPath, + item: ( + item.debuggerItemTitle, current, + { [weak self] (value) in + onChange( + value, + { [weak self] (result) in + self?.onCompleteAction(result) + } + ) + } + ) + ) + case let .slider(current, range, onChange): + return collectionView.dequeueConfiguredReusableCell( + using: sliderCellRegstration, + for: indexPath, + item: ( + item.debuggerItemTitle, current, range, + { [weak self] (value) in + onChange( + value, + { [weak self] (result) in + self?.onCompleteAction(result) + } + ) + } + ) + ) + } } - }) - - let headerRegistration = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { [weak self] (headerView, elementKind, indexPath) in + ) + + let headerRegistration = UICollectionView.SupplementaryRegistration< + UICollectionViewListCell + >(elementKind: UICollectionView.elementKindSectionHeader) { + [weak self] (headerView, elementKind, indexPath) in var configuration = headerView.defaultContentConfiguration() if #available(iOSApplicationExtension 15.0, *) { - configuration.text = self?.dataSource.sectionIdentifier(for: indexPath.section)?.title + configuration.text = + self?.dataSource.sectionIdentifier(for: indexPath.section)?.title } else { // FIXME: Index is wrong when unused showsRecentItems configuration.text = Section(rawValue: indexPath.section)?.title } headerView.contentConfiguration = configuration } - dataSource.supplementaryViewProvider = { (collectionView, kind, indexPath) -> UICollectionReusableView? in - collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath) + dataSource.supplementaryViewProvider = { + (collectionView, kind, indexPath) -> UICollectionReusableView? in + collectionView.dequeueConfiguredReusableSupplementary( + using: headerRegistration, + for: indexPath + ) } } - + func performUpdate(_ query: String? = nil) { var snapshot = NSDiffableDataSourceSnapshot() - + if let query = query, !query.isEmpty { snapshot.appendSections([Section.items]) - let filteredItems = flattenDebugItems.filter({ $0.debuggerItemTitle.lowercased().contains(query.lowercased()) }) + let filteredItems = flattenDebugItems.filter({ + $0.debuggerItemTitle.lowercased().contains(query.lowercased()) + }) snapshot.appendItems(filteredItems, toSection: .items) } else { let recentItems = RecentItemStore(items: debuggerItems).get() @@ -212,7 +261,7 @@ extension InAppDebuggerViewController { snapshot.appendSections([Section.items]) snapshot.appendItems(debuggerItems, toSection: .items) } - + dataSource.apply(snapshot) } } @@ -240,8 +289,10 @@ extension InAppDebuggerViewController: UICollectionViewDelegate { fatalError() } } - - func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { + + func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) + -> Bool + { switch Section(rawValue: indexPath.section) { case .items, .recent: let item = dataSource.itemIdentifier(for: indexPath)! @@ -255,13 +306,19 @@ extension InAppDebuggerViewController: UICollectionViewDelegate { fatalError() } } - + private func presentAlert(title: String, message: String?) { DispatchQueue.main.async { [weak self] in let vc = UIAlertController(title: title, message: message, preferredStyle: .alert) - vc.addAction(.init(title: "OK", style: .cancel, handler: { [weak self] _ in - self?.deselectSelectedItems() - })) + vc.addAction( + .init( + title: "OK", + style: .cancel, + handler: { [weak self] _ in + self?.deselectSelectedItems() + } + ) + ) self?.present(vc, animated: true, completion: nil) } } @@ -286,5 +343,3 @@ open class CollectionViewCell: UICollectionViewCell { } } } - - diff --git a/Sources/DebugMenu/View/InAppDebuggerWindow.swift b/Sources/DebugMenu/View/InAppDebuggerWindow.swift index d21f6a7..487b0df 100644 --- a/Sources/DebugMenu/View/InAppDebuggerWindow.swift +++ b/Sources/DebugMenu/View/InAppDebuggerWindow.swift @@ -5,38 +5,60 @@ // Created by Tomoya Hirano on 2020/03/01. // -import UIKit import Combine +import UIKit protocol TouchThrowing {} @available(iOSApplicationExtension, unavailable) public class InAppDebuggerWindow: UIWindow { internal static var shared: InAppDebuggerWindow! - - internal static func install(windowScene: UIWindowScene? = nil, debuggerItems: [DebugMenuPresentable], complications: [ComplicationPresentable], options: [Options]) { - install({ windowScene.map(InAppDebuggerWindow.init(windowScene:)) ?? InAppDebuggerWindow(frame: UIScreen.main.bounds) }, debuggerItems: debuggerItems, complications: complications, options: options) + + internal static func install( + windowScene: UIWindowScene? = nil, + debuggerItems: [DebugMenuPresentable], + complications: [ComplicationPresentable], + options: [Options] + ) { + install( + { + windowScene.map(InAppDebuggerWindow.init(windowScene:)) + ?? InAppDebuggerWindow(frame: UIScreen.main.bounds) + }, + debuggerItems: debuggerItems, + complications: complications, + options: options + ) } - + internal override init(windowScene: UIWindowScene) { super.init(windowScene: windowScene) } - + internal override init(frame: CGRect) { super.init(frame: frame) } - private static func install(_ factory: (() -> InAppDebuggerWindow), debuggerItems: [DebugMenuPresentable], complications: [ComplicationPresentable], options: [Options]) { + private static func install( + _ factory: (() -> InAppDebuggerWindow), + debuggerItems: [DebugMenuPresentable], + complications: [ComplicationPresentable], + options: [Options] + ) { let keyWindow = UIApplication.shared.findKeyWindow() shared = factory() shared.windowLevel = UIWindow.Level.statusBar + 1 - shared.rootViewController = FloatingViewController(debuggerItems: debuggerItems, complications: complications, options: options) + shared.rootViewController = FloatingViewController( + debuggerItems: debuggerItems, + complications: complications, + options: options + ) shared!.makeKeyAndVisible() keyWindow?.makeKeyAndVisible() } - + internal required init?(coder: NSCoder) { fatalError() } - + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let view = super.hitTest(point, with: event) if view is TouchThrowing { diff --git a/Sources/DebugMenu/View/LaunchView.swift b/Sources/DebugMenu/View/LaunchView.swift index ddf6ae2..67cac04 100644 --- a/Sources/DebugMenu/View/LaunchView.swift +++ b/Sources/DebugMenu/View/LaunchView.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // @@ -9,11 +9,11 @@ import UIKit class LaunchView: UIVisualEffectView { private let button: UIButton = .init(frame: .null) - + init() { super.init(effect: UIBlurEffect(style: .systemMaterialDark)) frame = CGRect(x: 0, y: 0, width: 44, height: 44) - + let image = UIImage(systemName: "ant.fill") button.setImage(image, for: .normal) button.tintColor = UIColor.white @@ -25,21 +25,21 @@ class LaunchView: UIVisualEffectView { button.rightAnchor.constraint(equalTo: contentView.rightAnchor), button.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) - + layer.cornerCurve = .continuous layer.cornerRadius = 22 layer.masksToBounds = true } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + var menu: UIMenu? { get { button.menu } set { button.menu = newValue } } - + func addAction(_ action: UIAction) { button.addAction(action, for: .touchUpInside) } diff --git a/Sources/DebugMenu/View/WidgetView.swift b/Sources/DebugMenu/View/WidgetView.swift index 2b5af2b..1e80926 100644 --- a/Sources/DebugMenu/View/WidgetView.swift +++ b/Sources/DebugMenu/View/WidgetView.swift @@ -1,23 +1,23 @@ // // File.swift -// +// // // Created by Tomoya Hirano on 2021/05/28. // -import UIKit import Combine +import UIKit class WidgetView: UIVisualEffectView { private let tableView: UITableView = .init(frame: .null, style: .plain) private var cancellables: Set = [] private let complications: [ComplicationPresentable] - + init(complications: [ComplicationPresentable]) { self.complications = complications super.init(effect: UIBlurEffect(style: .systemMaterialDark)) frame = .init(origin: .zero, size: .init(width: 200, height: 200)) - + let stackView = UIStackView(arrangedSubviews: [tableView]) stackView.axis = .vertical stackView.translatesAutoresizingMaskIntoConstraints = false @@ -28,11 +28,11 @@ class WidgetView: UIVisualEffectView { stackView.leftAnchor.constraint(equalTo: contentView.leftAnchor), stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) - + layer.cornerCurve = .continuous layer.cornerRadius = 16 layer.masksToBounds = true - + tableView.backgroundColor = .clear tableView.separatorStyle = .none tableView.register(Value1TableViewCell.self) @@ -41,25 +41,27 @@ class WidgetView: UIVisualEffectView { tableView.delegate = self tableView.dataSource = self } - + required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func show() { isHidden = false complications.forEach({ $0.startMonitoring() }) - Timer.publish(every: 1, on: .main, in: .default).autoconnect().sink { [weak self] _ in - self?.reloadData() - }.store(in: &cancellables) + Timer.publish(every: 1, on: .main, in: .default).autoconnect() + .sink { [weak self] _ in + self?.reloadData() + } + .store(in: &cancellables) } - + func hide() { isHidden = true complications.forEach({ $0.stopMonitoring() }) cancellables = [] } - + private func reloadData() { complications.forEach({ $0.update() }) tableView.reloadData() @@ -70,7 +72,7 @@ extension WidgetView: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { complications.count } - + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let complication = complications[indexPath.row] switch complication.fetcher { @@ -95,8 +97,12 @@ extension WidgetView: UITableViewDelegate, UITableViewDataSource { return cell } } - - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + + func tableView( + _ tableView: UITableView, + willDisplay cell: UITableViewCell, + forRowAt indexPath: IndexPath + ) { cell.contentView.backgroundColor = .clear cell.backgroundColor = .clear }