Copyright (C) 2021 mntone. All right reserived. This source code is under MIT license.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import CoreGraphics | |
import Foundation | |
import SwiftUI | |
import WatchKit | |
private let _case38Size = CGSize(width: 136, height: 170) | |
private let _case42Size = CGSize(width: 156, height: 195) | |
private let _case40Size = CGSize(width: 162, height: 197) | |
private let _case44Size = CGSize(width: 184, height: 224) | |
private let _case41Size = CGSize(width: 176, height: 215) | |
private let _case45Size = CGSize(width: 198, height: 242) | |
public enum WatchDevice: Int8, CaseIterable { | |
case unknown = 0 | |
case case38 = 38 | |
case case40 = 40 | |
case case41 = 41 | |
case case42 = 42 | |
case case44 = 44 | |
case case45 = 45 | |
} | |
public enum BezelType { | |
case square | |
case round(RoundedBezelSize) | |
} | |
public enum RoundedBezelSize { | |
case wide | |
case narrow | |
} | |
public protocol WatchDeviceMetrics { | |
var device: WatchDevice { get } | |
var defaultControlCornerRadius: Double { get } | |
var smallControlHeight: Double { get } | |
var minimumLayoutHorizontalMargin: Double { get } | |
var bezelType: BezelType { get } | |
var imageScale: Double { get } | |
var edgeCircularButtonHeight: CGFloat { get } | |
} | |
public func getWatchDeviceMetrics(from size: CGSize) -> WatchDeviceMetrics { | |
if #available(watchOS 8.0, *) { | |
switch size { | |
case _case41Size: return Case41WatchDeviceMetrics() | |
case _case45Size: return Case45WatchDeviceMetrics() | |
case _case40Size: return Case40WatchDeviceMetrics() | |
case _case44Size: return Case44WatchDeviceMetrics() | |
case _case38Size: return Case38WatchDeviceMetrics() | |
case _case42Size: return Case42WatchDeviceMetrics() | |
default: return EmptyWatchDeviceMetrics() | |
} | |
} else { | |
switch size { | |
case _case40Size: return Case40WatchDeviceMetrics() | |
case _case44Size: return Case44WatchDeviceMetrics() | |
case _case38Size: return Case38WatchDeviceMetrics() | |
case _case42Size: return Case42WatchDeviceMetrics() | |
default: return EmptyWatchDeviceMetrics() | |
} | |
} | |
} | |
public func getWatchDeviceMetrics() -> WatchDeviceMetrics { | |
let size = WKInterfaceDevice.current().screenBounds.size | |
return getWatchDeviceMetrics(from: size) | |
} | |
// MARK: - each device metrics | |
private struct EmptyWatchDeviceMetrics: WatchDeviceMetrics { | |
var device: WatchDevice { fatalError() } | |
var defaultControlCornerRadius: Double { fatalError() } | |
var smallControlHeight: Double { fatalError() } | |
var minimumLayoutHorizontalMargin: Double { fatalError() } | |
var bezelType: BezelType { fatalError() } | |
var imageScale: Double { fatalError() } | |
var edgeCircularButtonHeight: CGFloat { fatalError() } | |
} | |
private struct Case38WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case38 | |
let defaultControlCornerRadius: Double = 8 | |
let smallControlHeight: Double = 32 | |
let minimumLayoutHorizontalMargin: Double = 1 | |
let bezelType: BezelType = .square | |
let imageScale: Double = 0.9 | |
let edgeCircularButtonHeight: CGFloat = 27 // 0.5 * round(2 * imageScale * 30) | |
} | |
private struct Case42WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case42 | |
let defaultControlCornerRadius: Double = 8 | |
let smallControlHeight: Double = 32 | |
let minimumLayoutHorizontalMargin: Double = 1 | |
let bezelType: BezelType = .square | |
let imageScale: Double = 1 | |
let edgeCircularButtonHeight: CGFloat = 30 // 0.5 * round(2 * imageScale * 30) | |
} | |
private struct Case40WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case40 | |
let defaultControlCornerRadius: Double = 22 | |
let smallControlHeight: Double = 40 | |
let minimumLayoutHorizontalMargin: Double = 8.5 | |
let bezelType: BezelType = .round(.wide) | |
let imageScale: Double = 1 | |
let edgeCircularButtonHeight: CGFloat = 30 // 0.5 * round(2 * imageScale * 30) | |
} | |
private struct Case44WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case44 | |
let defaultControlCornerRadius: Double = 22 | |
let smallControlHeight: Double = 44 | |
let minimumLayoutHorizontalMargin: Double = 9.5 | |
let bezelType: BezelType = .round(.wide) | |
let imageScale: Double = 1.1 | |
let edgeCircularButtonHeight: CGFloat = 33 // 0.5 * round(2 * imageScale * 30) | |
} | |
private struct Case41WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case41 | |
let defaultControlCornerRadius: Double = 22 | |
let smallControlHeight: Double = 40 | |
let minimumLayoutHorizontalMargin: Double = 11 | |
let bezelType: BezelType = .round(.narrow) | |
let imageScale: Double = 1.06 | |
let edgeCircularButtonHeight: CGFloat = 32 // 0.5 * round(2 * imageScale * 30) | |
} | |
private struct Case45WatchDeviceMetrics: WatchDeviceMetrics { | |
let device: WatchDevice = .case45 | |
let defaultControlCornerRadius: Double = 22 | |
let smallControlHeight: Double = 50 | |
let minimumLayoutHorizontalMargin: Double = 12 | |
let bezelType: BezelType = .round(.narrow) | |
let imageScale: Double = 1.19 | |
let edgeCircularButtonHeight: CGFloat = 35.5 // 0.5 * round(2 * imageScale * 30) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct WatchDeviceMetricsKey: EnvironmentKey { | |
static var defaultValue: WatchDeviceMetrics { | |
EmptyWatchDeviceMetrics() | |
} | |
} | |
extension EnvironmentValues { | |
var deviceMetrics: WatchDeviceMetrics { | |
get { self[WatchDeviceMetricsKey.self] } | |
set { self[WatchDeviceMetricsKey.self] = newValue } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment