mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-04-06 21:35:53 +00:00
Fixes
fix localeWithStrings globally (#30)
Fix badge on zoomed devices. closes #9
Hide channel bottom panel closes #27
Another attempt to fix badge on some Zoomed devices
Force System Share sheet tg://sg/debug
fixes for device badge
New Crowdin updates (#34)
* New translations sglocalizable.strings (Chinese Traditional)
* New translations sglocalizable.strings (Chinese Simplified)
* New translations sglocalizable.strings (Chinese Traditional)
Fix input panel hidden on selection (#31)
* added if check for selectionState != nil
* same order of subnodes
Revert "Fix input panel hidden on selection (#31)"
This reverts commit e8a8bb1496.
Fix input panel for channels Closes #37
Quickly share links with system's share menu
force tabbar when editing
increase height for correct animation
New translations sglocalizable.strings (Ukrainian) (#38)
Hide Post Story button
Fix 10.15.1
Fix archive option for long-tap
Enable in-app Safari
Disable some unsupported purchases
disableDeleteChatSwipeOption + refactor restart alert
Hide bot in suggestions list
Fix merge v11.0
Fix exceptions for safari webview controller
New Crowdin updates (#47)
* New translations sglocalizable.strings (Romanian)
* New translations sglocalizable.strings (French)
* New translations sglocalizable.strings (Spanish)
* New translations sglocalizable.strings (Afrikaans)
* New translations sglocalizable.strings (Arabic)
* New translations sglocalizable.strings (Catalan)
* New translations sglocalizable.strings (Czech)
* New translations sglocalizable.strings (Danish)
* New translations sglocalizable.strings (German)
* New translations sglocalizable.strings (Greek)
* New translations sglocalizable.strings (Finnish)
* New translations sglocalizable.strings (Hebrew)
* New translations sglocalizable.strings (Hungarian)
* New translations sglocalizable.strings (Italian)
* New translations sglocalizable.strings (Japanese)
* New translations sglocalizable.strings (Korean)
* New translations sglocalizable.strings (Dutch)
* New translations sglocalizable.strings (Norwegian)
* New translations sglocalizable.strings (Polish)
* New translations sglocalizable.strings (Portuguese)
* New translations sglocalizable.strings (Serbian (Cyrillic))
* New translations sglocalizable.strings (Swedish)
* New translations sglocalizable.strings (Turkish)
* New translations sglocalizable.strings (Vietnamese)
* New translations sglocalizable.strings (Indonesian)
* New translations sglocalizable.strings (Hindi)
* New translations sglocalizable.strings (Uzbek)
New Crowdin updates (#49)
* New translations sglocalizable.strings (Arabic)
* New translations sglocalizable.strings (Arabic)
New translations sglocalizable.strings (Russian) (#51)
Call confirmation
WIP Settings search
Settings Search
Localize placeholder
Update AccountUtils.swift
mark mutual contact
Align back context action to left
New Crowdin updates (#54)
* New translations sglocalizable.strings (Chinese Simplified)
* New translations sglocalizable.strings (Chinese Traditional)
* New translations sglocalizable.strings (Ukrainian)
Independent Playground app for simulator
New translations sglocalizable.strings (Ukrainian) (#55)
Playground UIKit base and controllers
Inject SwiftUI view with overflow to AsyncDisplayKit
Launch Playgound project on simulator
Create .swiftformat
Move Playground to example
Update .swiftformat
Init SwiftUIViewController
wip
New translations sglocalizable.strings (Chinese Traditional) (#57)
Xcode 16 fixes
Fix
New translations sglocalizable.strings (Italian) (#59)
New translations sglocalizable.strings (Chinese Simplified) (#63)
Force disable CallKit integration due to missing NSE Entitlement
Fix merge
Fix whole chat translator
Sweetpad config
Bump version
11.3.1 fixes
Mutual contact placement fix
Disable Video PIP swipe
Update versions.json
Fix PIP crash
422 lines
16 KiB
Swift
422 lines
16 KiB
Swift
import UIKit
|
|
|
|
public enum DeviceType {
|
|
case phone
|
|
case tablet
|
|
}
|
|
|
|
public enum DeviceMetrics: CaseIterable, Equatable {
|
|
public struct Performance {
|
|
public let isGraphicallyCapable: Bool
|
|
|
|
init() {
|
|
var length: Int = 4
|
|
var cpuCount: UInt32 = 0
|
|
sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0)
|
|
|
|
self.isGraphicallyCapable = cpuCount >= 4
|
|
}
|
|
}
|
|
|
|
case iPhone4
|
|
case iPhone5
|
|
case iPhone6
|
|
case iPhone6Plus
|
|
case iPhoneX
|
|
case iPhoneXSMax
|
|
case iPhoneXr
|
|
case iPhone12Mini
|
|
case iPhone12
|
|
case iPhone12ProMax
|
|
case iPhone13Mini
|
|
case iPhone13
|
|
case iPhone13Pro
|
|
case iPhone13ProMax
|
|
case iPhone14Pro
|
|
case iPhone14ProZoomed
|
|
case iPhone14ProMax
|
|
case iPhone14ProMaxZoomed
|
|
case iPhone16Pro
|
|
case iPhone16ProMax
|
|
case iPad
|
|
case iPadMini
|
|
case iPad102Inch
|
|
case iPadPro10Inch
|
|
case iPadPro11Inch
|
|
case iPadPro
|
|
case iPadPro3rdGen
|
|
case iPadMini6thGen
|
|
case unknown(screenSize: CGSize, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?, screenCornerRadius: CGFloat)
|
|
|
|
public static let performance = Performance()
|
|
|
|
public static var allCases: [DeviceMetrics] {
|
|
return [
|
|
.iPhone4,
|
|
.iPhone5,
|
|
.iPhone6,
|
|
.iPhone6Plus,
|
|
.iPhoneX,
|
|
.iPhoneXSMax,
|
|
.iPhoneXr,
|
|
.iPhone12Mini,
|
|
.iPhone12,
|
|
.iPhone12ProMax,
|
|
.iPhone13Mini,
|
|
.iPhone13,
|
|
.iPhone13Pro,
|
|
.iPhone13ProMax,
|
|
.iPhone14Pro,
|
|
.iPhone14ProZoomed,
|
|
.iPhone14ProMax,
|
|
.iPhone14ProMaxZoomed,
|
|
.iPhone16Pro,
|
|
.iPhone16ProMax,
|
|
.iPad,
|
|
.iPadMini,
|
|
.iPad102Inch,
|
|
.iPadPro10Inch,
|
|
.iPadPro11Inch,
|
|
.iPadPro,
|
|
.iPadPro3rdGen,
|
|
.iPadMini6thGen
|
|
]
|
|
}
|
|
|
|
public init(screenSize: CGSize, scale: CGFloat, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?) {
|
|
var screenSize = screenSize
|
|
if screenSize.width > screenSize.height {
|
|
screenSize = CGSize(width: screenSize.height, height: screenSize.width)
|
|
}
|
|
|
|
let additionalSize = CGSize(width: screenSize.width, height: screenSize.height + 20.0)
|
|
for device in DeviceMetrics.allCases {
|
|
if let _ = onScreenNavigationHeight, device.onScreenNavigationHeight(inLandscape: false, systemOnScreenNavigationHeight: nil) == nil {
|
|
if case .tablet = device.type {
|
|
if screenSize.height == 1024.0 && screenSize.width == 768.0 {
|
|
} else {
|
|
continue
|
|
}
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
|
|
let width = device.screenSize.width
|
|
let height = device.screenSize.height
|
|
if ((screenSize.width.isEqual(to: width) && screenSize.height.isEqual(to: height)) || (additionalSize.width.isEqual(to: width) && additionalSize.height.isEqual(to: height))) {
|
|
if case .iPhoneX = device, statusBarHeight == 47.0 {
|
|
self = .iPhone14ProMaxZoomed
|
|
} else if case .iPhoneXSMax = device, scale == 2.0 {
|
|
self = .iPhoneXr
|
|
} else {
|
|
self = device
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
let screenCornerRadius: CGFloat
|
|
if screenSize.width >= 1024.0 || screenSize.height >= 1024.0 {
|
|
screenCornerRadius = 0.0
|
|
} else if onScreenNavigationHeight != nil {
|
|
screenCornerRadius = 39.0
|
|
} else {
|
|
screenCornerRadius = 0.0
|
|
}
|
|
|
|
self = .unknown(screenSize: screenSize, statusBarHeight: statusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight, screenCornerRadius: screenCornerRadius)
|
|
}
|
|
|
|
public var type: DeviceType {
|
|
switch self {
|
|
case .iPad, .iPad102Inch, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
|
|
return .tablet
|
|
case let .unknown(screenSize, _, _, _) where screenSize.width >= 744.0 && screenSize.height >= 1024.0:
|
|
return .tablet
|
|
default:
|
|
return .phone
|
|
}
|
|
}
|
|
|
|
public var screenSize: CGSize {
|
|
switch self {
|
|
case .iPhone4:
|
|
return CGSize(width: 320.0, height: 480.0)
|
|
case .iPhone5:
|
|
return CGSize(width: 320.0, height: 568.0)
|
|
case .iPhone6:
|
|
return CGSize(width: 375.0, height: 667.0)
|
|
case .iPhone6Plus:
|
|
return CGSize(width: 414.0, height: 736.0)
|
|
case .iPhoneX:
|
|
return CGSize(width: 375.0, height: 812.0)
|
|
case .iPhoneXSMax, .iPhoneXr:
|
|
return CGSize(width: 414.0, height: 896.0)
|
|
case .iPhone12Mini:
|
|
return CGSize(width: 360.0, height: 780.0)
|
|
case .iPhone12:
|
|
return CGSize(width: 390.0, height: 844.0)
|
|
case .iPhone12ProMax:
|
|
return CGSize(width: 428.0, height: 926.0)
|
|
case .iPhone13Mini:
|
|
return CGSize(width: 375.0, height: 812.0)
|
|
case .iPhone13:
|
|
return CGSize(width: 390.0, height: 844.0)
|
|
case .iPhone13Pro:
|
|
return CGSize(width: 390.0, height: 844.0)
|
|
case .iPhone13ProMax:
|
|
return CGSize(width: 428.0, height: 926.0)
|
|
case .iPhone14Pro:
|
|
return CGSize(width: 393.0, height: 852.0)
|
|
case .iPhone14ProZoomed:
|
|
return CGSize(width: 320.0, height: 693.0)
|
|
case .iPhone14ProMax:
|
|
return CGSize(width: 430.0, height: 932.0)
|
|
case .iPhone14ProMaxZoomed:
|
|
return CGSize(width: 375.0, height: 812.0)
|
|
case .iPhone16Pro:
|
|
return CGSize(width: 402.0, height: 874.0)
|
|
case .iPhone16ProMax:
|
|
return CGSize(width: 440.0, height: 956.0)
|
|
case .iPad:
|
|
return CGSize(width: 768.0, height: 1024.0)
|
|
case .iPadMini:
|
|
return CGSize(width: 744.0, height: 1133.0)
|
|
case .iPad102Inch:
|
|
return CGSize(width: 810.0, height: 1080.0)
|
|
case .iPadPro10Inch:
|
|
return CGSize(width: 834.0, height: 1112.0)
|
|
case .iPadPro11Inch:
|
|
return CGSize(width: 834.0, height: 1194.0)
|
|
case .iPadPro, .iPadPro3rdGen:
|
|
return CGSize(width: 1024.0, height: 1366.0)
|
|
case .iPadMini6thGen:
|
|
return CGSize(width: 744.0, height: 1133.0)
|
|
case let .unknown(screenSize, _, _, _):
|
|
return screenSize
|
|
}
|
|
}
|
|
|
|
public var screenCornerRadius: CGFloat {
|
|
switch self {
|
|
case .iPhoneX, .iPhoneXSMax:
|
|
return 39.0
|
|
case .iPhoneXr:
|
|
return 41.5
|
|
case .iPhone12Mini:
|
|
return 44.0
|
|
case .iPhone12, .iPhone13, .iPhone13Pro, .iPhone14ProZoomed:
|
|
return 47.0 + UIScreenPixel
|
|
case .iPhone12ProMax, .iPhone13ProMax, .iPhone14ProMaxZoomed:
|
|
return 53.0 + UIScreenPixel
|
|
case .iPhone14Pro, .iPhone14ProMax:
|
|
return 55.0
|
|
case .iPhone16Pro, .iPhone16ProMax:
|
|
return 55.0
|
|
case let .unknown(_, _, _, screenCornerRadius):
|
|
return screenCornerRadius
|
|
default:
|
|
return 0.0
|
|
}
|
|
}
|
|
|
|
func safeInsets(inLandscape: Bool) -> UIEdgeInsets {
|
|
switch self {
|
|
case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone14ProZoomed, .iPhone14ProMaxZoomed:
|
|
return inLandscape ? UIEdgeInsets(top: 0.0, left: 44.0, bottom: 0.0, right: 44.0) : UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
|
|
case .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax:
|
|
return inLandscape ? UIEdgeInsets(top: 0.0, left: 47.0, bottom: 0.0, right: 47.0) : UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
|
|
case .iPhone14Pro, .iPhone14ProMax, .iPhone16Pro, .iPhone16ProMax:
|
|
return inLandscape ? UIEdgeInsets(top: 0.0, left: 59.0, bottom: 0.0, right: 59.0) : UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
|
|
default:
|
|
return UIEdgeInsets.zero
|
|
}
|
|
}
|
|
|
|
public func onScreenNavigationHeight(inLandscape: Bool, systemOnScreenNavigationHeight: CGFloat?) -> CGFloat? {
|
|
switch self {
|
|
case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax, .iPhone14Pro, .iPhone14ProMax, .iPhone16Pro, .iPhone16ProMax:
|
|
return inLandscape ? 21.0 : 34.0
|
|
case .iPhone14ProZoomed:
|
|
return inLandscape ? 21.0 : 28.0
|
|
case .iPhone14ProMaxZoomed:
|
|
return inLandscape ? 21.0 : 31.0
|
|
case .iPadPro3rdGen, .iPadPro11Inch:
|
|
return 21.0
|
|
case .iPad, .iPadPro, .iPadPro10Inch, .iPadMini, .iPadMini6thGen:
|
|
if let systemOnScreenNavigationHeight = systemOnScreenNavigationHeight, !systemOnScreenNavigationHeight.isZero {
|
|
return 21.0
|
|
} else {
|
|
return nil
|
|
}
|
|
case let .unknown(_, _, onScreenNavigationHeight, _):
|
|
return onScreenNavigationHeight
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func statusBarHeight(for size: CGSize) -> CGFloat? {
|
|
let value = self.statusBarHeight
|
|
if self.type == .tablet {
|
|
return value
|
|
} else {
|
|
if size.width < size.height {
|
|
return value
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
var statusBarHeight: CGFloat {
|
|
switch self {
|
|
case .iPhone14Pro, .iPhone14ProMax:
|
|
return 54.0
|
|
case .iPhone14ProMaxZoomed:
|
|
return 47.0
|
|
case .iPhone16Pro, .iPhone16ProMax:
|
|
return 54.0
|
|
case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax:
|
|
return 44.0
|
|
case .iPadPro11Inch, .iPadPro3rdGen, .iPadMini, .iPadMini6thGen:
|
|
return 24.0
|
|
case let .unknown(_, statusBarHeight, _, _):
|
|
return statusBarHeight
|
|
default:
|
|
return 20.0
|
|
}
|
|
}
|
|
|
|
public func keyboardHeight(inLandscape: Bool) -> CGFloat {
|
|
if inLandscape {
|
|
switch self {
|
|
case .iPhone4, .iPhone5:
|
|
return 162.0
|
|
case .iPhone6, .iPhone6Plus:
|
|
return 163.0
|
|
case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax, .iPhone14Pro, .iPhone14ProZoomed, .iPhone14ProMax, .iPhone14ProMaxZoomed, .iPhone16Pro, .iPhone16ProMax:
|
|
return 172.0
|
|
case .iPad, .iPad102Inch, .iPadPro10Inch:
|
|
return 348.0
|
|
case .iPadPro11Inch, .iPadMini, .iPadMini6thGen:
|
|
return 368.0
|
|
case .iPadPro:
|
|
return 421.0
|
|
case .iPadPro3rdGen:
|
|
return 441.0
|
|
case .unknown:
|
|
return 216.0
|
|
}
|
|
} else {
|
|
switch self {
|
|
case .iPhone4, .iPhone5, .iPhone6:
|
|
return 216.0
|
|
case .iPhone6Plus:
|
|
return 226.0
|
|
case .iPhoneX, .iPhone12Mini, .iPhone12, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone14Pro, .iPhone14ProZoomed, .iPhone14ProMaxZoomed, .iPhone16Pro:
|
|
return 292.0
|
|
case .iPhoneXSMax, .iPhoneXr, .iPhone12ProMax, .iPhone13ProMax, .iPhone14ProMax, .iPhone16ProMax:
|
|
return 302.0
|
|
case .iPad, .iPad102Inch, .iPadPro10Inch:
|
|
return 263.0
|
|
case .iPadPro11Inch:
|
|
return 283.0
|
|
case .iPadPro, .iPadMini, .iPadMini6thGen:
|
|
return 328.0
|
|
case .iPadPro3rdGen:
|
|
return 348.0
|
|
case .unknown:
|
|
return 216.0
|
|
}
|
|
}
|
|
}
|
|
|
|
func predictiveInputHeight(inLandscape: Bool) -> CGFloat {
|
|
if inLandscape {
|
|
switch self {
|
|
case .iPhone4, .iPhone5, .iPhone6, .iPhone6Plus, .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax, .iPhone14Pro, .iPhone14ProZoomed, .iPhone14ProMax, .iPhone14ProMaxZoomed, .iPhone16Pro, .iPhone16ProMax:
|
|
return 37.0
|
|
case .iPad, .iPad102Inch, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen, .iPadMini, .iPadMini6thGen:
|
|
return 50.0
|
|
case .unknown:
|
|
return 37.0
|
|
}
|
|
} else {
|
|
switch self {
|
|
case .iPhone4, .iPhone5:
|
|
return 37.0
|
|
case .iPhone6, .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax, .iPhone14Pro, .iPhone14ProZoomed, .iPhone14ProMax, .iPhone14ProMaxZoomed, .iPhone16Pro, .iPhone16ProMax:
|
|
return 44.0
|
|
case .iPhone6Plus:
|
|
return 45.0
|
|
case .iPad, .iPad102Inch, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen, .iPadMini, .iPadMini6thGen:
|
|
return 50.0
|
|
case .unknown:
|
|
return 44.0
|
|
}
|
|
}
|
|
}
|
|
|
|
public func standardInputHeight(inLandscape: Bool) -> CGFloat {
|
|
return self.keyboardHeight(inLandscape: inLandscape) + predictiveInputHeight(inLandscape: inLandscape)
|
|
}
|
|
|
|
public var hasTopNotch: Bool {
|
|
switch self {
|
|
case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
public var hasDynamicIsland: Bool {
|
|
switch self {
|
|
case .iPhone14Pro, .iPhone14ProZoomed, .iPhone14ProMax, .iPhone14ProMaxZoomed, .iPhone16Pro, .iPhone16ProMax:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
public var showAppBadge: Bool {
|
|
if case .iPhoneX = self {
|
|
return false
|
|
}
|
|
// MARK: Swiftgram
|
|
return self.hasTopNotch || self.hasDynamicIsland
|
|
}
|
|
}
|
|
|
|
// MARK: Swifgram
|
|
public extension DeviceMetrics {
|
|
|
|
var deviceModelCode: String {
|
|
var systemInfo = utsname()
|
|
uname(&systemInfo)
|
|
let modelCode = withUnsafePointer(to: &systemInfo.machine) {
|
|
$0.withMemoryRebound(to: CChar.self, capacity: 1) {
|
|
ptr in String.init(validatingUTF8: ptr)
|
|
}
|
|
}
|
|
return modelCode ?? "unknown"
|
|
}
|
|
|
|
var modelHasDynamicIsland: Bool {
|
|
switch self.deviceModelCode {
|
|
case "iPhone15,2", // iPhone 14 Pro
|
|
"iPhone15,3", // iPhone 14 Pro Max
|
|
"iPhone15,4", // iPhone 15
|
|
"iPhone15,5", // iPhone 15 Plus
|
|
"iPhone16,1", // iPhone 15 Pro
|
|
"iPhone16,2": // iPhone 15 Pro Max
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
}
|