12 Commits

Author SHA1 Message Date
Daniel Arantes Loverde
a24b79f443 only remote crypto kit 2026-05-24 10:26:25 -03:00
c0eb5f95c6 Merge pull request 'fix: update keyboard notification handling for Swift concurrency' (#7) from bugfix/snackbar_for_iOS26 into main
Reviewed-on: #7
2026-04-07 11:22:02 -03:00
a15d95ed59 Merge branch 'main' into bugfix/snackbar_for_iOS26 2026-04-07 11:21:55 -03:00
Daniel Arantes Loverde
40581d791a fix: update keyboard notification handling for Swift concurrency
Keep snackbar keyboard animations on the main actor and read UIKit keyboard values using the expected notification payload types.

Made-with: Cursor
2026-04-07 11:19:39 -03:00
57ce0dc87a Merge pull request 'iPhone UIDevice names updated' (#6) from feature/LCECryptoKit into main
Reviewed-on: #6
2026-02-11 20:57:39 +00:00
Daniel Arantes Loverde
d06a66226e iPhone UIDevice names updated 2026-02-11 17:56:53 -03:00
336b47ace2 Merge pull request 'Optional' (#5) from feature/LCECryptoKit into main
Reviewed-on: #5
2026-02-06 15:38:09 +00:00
b4a081c4d2 Merge branch 'main' into feature/LCECryptoKit 2026-02-06 15:37:58 +00:00
Daniel Arantes Loverde
57696e3036 Optional 2026-02-06 12:25:34 -03:00
560efd2c8b Merge pull request 'Added more options' (#4) from feature/LCECryptoKit into main
Reviewed-on: https://loverde_git.localhost:3334/Loverde-Company-LTDA/LCEssentials/pulls/4
2025-10-07 23:35:46 +00:00
7e24bdf3d5 Merge branch 'main' into feature/LCECryptoKit 2025-10-07 23:35:37 +00:00
Daniel Arantes Loverde
5df2499c4a Added more options 2025-10-07 20:34:33 -03:00
40 changed files with 343 additions and 146 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.DS_Store .DS_Store
/.build /.build
/build
/Packages /Packages
xcuserdata/ xcuserdata/
DerivedData/ DerivedData/

View File

@@ -22,3 +22,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
Autor: Daniel Arantes Loverde

View File

@@ -1,5 +1,5 @@
{ {
"originHash" : "57d4d1724511f49da67a759e590ddf12887d65ffb0702ad7a2ff8f6c830c9b78", "originHash" : "33e7d52ad13cf774717778548edb365d33ff62d766d0049165bc8970f19a23ef",
"pins" : [ "pins" : [
{ {
"identity" : "lcecryptokitbinary", "identity" : "lcecryptokitbinary",

View File

@@ -2,7 +2,24 @@
import PackageDescription import PackageDescription
import Foundation import Foundation
let isLocalDevelopment = FileManager.default.fileExists(atPath: "../LCECryptoKit/PrivateLib/LCECryptoKitBinary") let isLocalDevelopment = false //FileManager.default.fileExists(atPath: "../LCECryptoKit/PrivateLib/LCECryptoKitBinary")
let enableCryptoBinary = ProcessInfo.processInfo.environment["LCE_ENABLE_CRYPTO_BINARY"] != "0"
let cryptoPackageURL = isLocalDevelopment
? "../LCECryptoKit/PrivateLib/LCECryptoKitBinary"
: "https://60c260c85d3a2fe840411b0ff98f521b5eca3c56@git.loverde.com.br/Loverde-Company-LTDA/LCECryptoKitBinary.git"
let packageDependencies: [Package.Dependency] = enableCryptoBinary
? [
.package(url: cryptoPackageURL, exact: "1.0.2")
]
: []
let targetDependencies: [Target.Dependency] = enableCryptoBinary
? [
.product(name: "LCECryptoKit", package: "lcecryptokitbinary")
]
: []
let package = Package( let package = Package(
name: "LCEssentials", name: "LCEssentials",
@@ -17,17 +34,10 @@ let package = Package(
name: "LCEssentials", name: "LCEssentials",
targets: ["LCEssentials"]), targets: ["LCEssentials"]),
], ],
dependencies: [ dependencies: packageDependencies,
.package(
url: isLocalDevelopment ?
"../LCECryptoKit/PrivateLib/LCECryptoKitBinary" :
"https://60c260c85d3a2fe840411b0ff98f521b5eca3c56@git.loverde.com.br/Loverde-Company-LTDA/LCECryptoKitBinary.git",
exact: "1.0.2"
)
],
targets: [ targets: [
.target( .target(
name: "LCEssentials", name: "LCEssentials",
dependencies: [.product(name: "LCECryptoKit", package: "lcecryptokitbinary")]), dependencies: targetDependencies),
] ]
) )

View File

@@ -59,12 +59,11 @@ And then import `LCEssentials ` wherever you import UIKit or SwiftUI
import LCEssentials import LCEssentials
``` ```
Author:
----
Any question or doubts, please send thru email Any question or doubts, please send thru email
Daniel Arantes Loverde - <daniel@loverde.com.br> Daniel Arantes Loverde - <daniel@loverde.com.br>
[![Alt text](https://loverde.com.br/_signature/loverde_github_mail.gif "My Resume")](https://github.com/loverde-co/resume/) [![Alt text](https://loverde.com.br/_signature/loverde_github_mail.gif "My Resume")](https://github.com/loverde-co/resume/)
[![Alt text](https://loverde.com.br/_signature/loverde_github_mail.gif "Loverde Co. Github")](https://github.com/loverde-co) [![Alt text](https://loverde.com.br/_signature/loverde_github_mail.gif "Loverde Co. Github")](https://github.com/loverde-co)
Autor: Daniel Arantes Loverde

View File

@@ -5,8 +5,10 @@
// Created by iOSDevCenters on 11/12/15. // Created by iOSDevCenters on 11/12/15.
// Copyright © 2016 iOSDevCenters. All rights reserved. // Copyright © 2016 iOSDevCenters. All rights reserved.
// //
#if canImport(UIKit)
import UIKit import UIKit
#if os(iOS) || os(macOS) #endif
#if canImport(UIKit)
import ImageIO import ImageIO
//let jeremyGif = UIImage.gifWithName("jeremy") //let jeremyGif = UIImage.gifWithName("jeremy")

View File

@@ -21,31 +21,76 @@
import Foundation import Foundation
#if canImport(LCECryptoKit)
import LCECryptoKit import LCECryptoKit
public final class LCECrypto { public final class LCECryptoKitManager {
private let hashKey: String private let hashKey: String
init(privateKey: String){ public init() {
self.hashKey = ""
}
public init(privateKey: String){
self.hashKey = privateKey self.hashKey = privateKey
} }
func encodeTP(email: String, password: String) -> String? { public static func generateKey() -> String {
LCECryptoKit.generateRandomAESKeyString()
}
public func encodeTP(email: String, password: String) -> String? {
return LCECryptoKit.encodeSeed(email: email, password: password) return LCECryptoKit.encodeSeed(email: email, password: password)
} }
func decodeOTP(_ otpHash: String) -> String? { public func decodeOTP(_ otpHash: String) -> String? {
return LCECryptoKit.decodeSeed(otpKey: otpHash) return LCECryptoKit.decodeSeed(otpKey: otpHash)
} }
// MARK: Need hashKey to decode // MARK: Need hashKey to decode
func encodeOTPWithKey(email: String, password: String) -> String? { public func encodeOTPWithKey(email: String, password: String) -> String? {
return LCECryptoKit.encodeSeed(email: email, password: password, hashKey: self.hashKey) return LCECryptoKit.encodeSeed(email: email, password: password, hashKey: self.hashKey)
} }
func decodeOTPWithKey(_ otpHash: String) -> Bool { public func decodeOTPWithKey(_ otpHash: String) -> Bool {
LCECryptoKit.decodeSeed(otpKey: otpHash, hashKey: self.hashKey) LCECryptoKit.decodeSeed(otpKey: otpHash, hashKey: self.hashKey)
} }
} }
#else
public final class LCECryptoKitManager {
private let hashKey: String
public init() {
self.hashKey = ""
}
public init(privateKey: String){
self.hashKey = privateKey
}
public static func generateKey() -> String {
""
}
public func encodeTP(email: String, password: String) -> String? {
nil
}
public func decodeOTP(_ otpHash: String) -> String? {
nil
}
public func encodeOTPWithKey(email: String, password: String) -> String? {
nil
}
public func decodeOTPWithKey(_ otpHash: String) -> Bool {
false
}
}
#endif

View File

@@ -26,8 +26,10 @@ import Foundation
import Security import Security
#endif #endif
#if canImport(UIKit) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif #endif
#endif
/// A generic `Result` enumeration to represent either a success `Value` or a failure `Error`. /// A generic `Result` enumeration to represent either a success `Value` or a failure `Error`.
public enum Result<Value, Error: Swift.Error> { public enum Result<Value, Error: Swift.Error> {

View File

@@ -21,8 +21,12 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if canImport(AVFoundation)
import AVFoundation import AVFoundation
#endif
#if os(watchOS) #if os(watchOS)
import WatchKit import WatchKit
#endif #endif
@@ -155,7 +159,7 @@ public struct LCEssentials {
diskPath: "file_cache" diskPath: "file_cache"
) )
#if os(iOS) || os(macOS) #if canImport(UIKit)
/// Extract the file name from the file path /// Extract the file name from the file path
/// ///
/// - Parameter filePath: Full file path in bundle /// - Parameter filePath: Full file path in bundle
@@ -266,7 +270,11 @@ public struct LCEssentials {
/// - LoverdeCo: Check if app is running in debug mode. /// - LoverdeCo: Check if app is running in debug mode.
@MainActor @MainActor
public static var isInDebuggingMode: Bool { public static var isInDebuggingMode: Bool {
#if canImport(UIKit)
return UIApplication.inferredEnvironment == .debug return UIApplication.inferredEnvironment == .debug
#else
return false
#endif
} }
#if !os(macOS) #if !os(macOS)
@@ -416,7 +424,7 @@ public struct LCEssentials {
// MARK: - Methods // MARK: - Methods
public extension LCEssentials { public extension LCEssentials {
#if os(iOS) || os(macOS) #if canImport(UIKit)
/// - LoverdeCo: Share link with message /// - LoverdeCo: Share link with message
/// ///
/// - Parameters: /// - Parameters:

View File

@@ -20,7 +20,9 @@
// THE SOFTWARE. // THE SOFTWARE.
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
@objc public protocol LCESingletonDelegate: AnyObject { @objc public protocol LCESingletonDelegate: AnyObject {
@objc optional func singleton(object: Any?, withData: Any) @objc optional func singleton(object: Any?, withData: Any)

View File

@@ -21,7 +21,9 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
// MARK: - Methods (Equatable) // MARK: - Methods (Equatable)
public extension Array where Element: Equatable { public extension Array where Element: Equatable {
@@ -148,6 +150,7 @@ public extension Array where Element: Equatable {
} }
} }
#if canImport(UIKit)
extension Array where Element == NSLayoutConstraint { extension Array where Element == NSLayoutConstraint {
@MainActor @MainActor
@@ -169,3 +172,5 @@ extension Array where Element == NSLayoutConstraint {
} }
} }
} }
#endif

View File

@@ -21,8 +21,12 @@
import Foundation import Foundation
#if canImport(CryptoKit)
import CryptoKit import CryptoKit
#endif
#if canImport(CommonCrypto)
import CommonCrypto import CommonCrypto
#endif
public extension Data { public extension Data {
@@ -71,17 +75,25 @@ public extension Data {
@available(iOS 13.0, *) @available(iOS 13.0, *)
func HMACSHA512(key: Data) -> Data { func HMACSHA512(key: Data) -> Data {
#if canImport(CryptoKit)
var hmac = HMAC<SHA512>.init(key: SymmetricKey(data: key)) var hmac = HMAC<SHA512>.init(key: SymmetricKey(data: key))
hmac.update(data: self) hmac.update(data: self)
return Data(hmac.finalize()) return Data(hmac.finalize())
#else
return Data()
#endif
} }
func SHA512() -> Data { func SHA512() -> Data {
#if canImport(CommonCrypto)
var digest = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH)) var digest = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH))
self.withUnsafeBytes { self.withUnsafeBytes {
_ = CC_SHA512($0.baseAddress, CC_LONG(self.count), &digest) _ = CC_SHA512($0.baseAddress, CC_LONG(self.count), &digest)
} }
return Data(digest) return Data(digest)
#else
return Data()
#endif
} }
func XOR(with other: Data) -> Data { func XOR(with other: Data) -> Data {
@@ -89,11 +101,15 @@ public extension Data {
} }
func SHA256() -> Data { func SHA256() -> Data {
#if canImport(CommonCrypto)
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
self.withUnsafeBytes { self.withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(self.count), &digest) _ = CC_SHA256($0.baseAddress, CC_LONG(self.count), &digest)
} }
return Data(digest) return Data(digest)
#else
return Data()
#endif
} }
func object<T: Codable>() -> T? { func object<T: Codable>() -> T? {
@@ -124,9 +140,13 @@ public extension Data {
///print("md5Hex: \(md5Hex)") ///print("md5Hex: \(md5Hex)")
@available(iOS 13.0, *) @available(iOS 13.0, *)
static func MD5(string: String) -> Data { static func MD5(string: String) -> Data {
#if canImport(CryptoKit)
let messageData = string.data(using: .utf8)! let messageData = string.data(using: .utf8)!
let digestData = Insecure.MD5.hash (data: messageData) let digestData = Insecure.MD5.hash (data: messageData)
let digestHex = String(digestData.map { String(format: "%02hhx", $0) }.joined().prefix(32)) let digestHex = String(digestData.map { String(format: "%02hhx", $0) }.joined().prefix(32))
return Data(digestHex.utf8) return Data(digestHex.utf8)
#else
return Data()
#endif
} }
} }

View File

@@ -21,7 +21,9 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension Dictionary { public extension Dictionary {

View File

@@ -21,7 +21,9 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension FileManager { public extension FileManager {
@@ -54,7 +56,7 @@ public extension FileManager {
} }
} }
#if os(iOS) || os(macOS) #if canImport(UIKit)
func saveImageToDirectory( _ imageWithPath : String, imagem : UIImage ) -> Bool { func saveImageToDirectory( _ imageWithPath : String, imagem : UIImage ) -> Bool {
let data = imagem.pngData() let data = imagem.pngData()

View File

@@ -21,8 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if canImport(UIKit)
extension NSLayoutConstraint { extension NSLayoutConstraint {
func constraintWithMultiplier(_ multiplier: CGFloat) -> NSLayoutConstraint { func constraintWithMultiplier(_ multiplier: CGFloat) -> NSLayoutConstraint {
@@ -72,3 +75,4 @@ extension NSLayoutConstraint {
return false return false
} }
} }
#endif

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension NSMutableAttributedString { public extension NSMutableAttributedString {
@discardableResult func customize(_ text: String, @discardableResult func customize(_ text: String,

View File

@@ -20,7 +20,9 @@
// THE SOFTWARE. // THE SOFTWARE.
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension Optional { public extension Optional {
/// Get self of default value (if self is nil). /// Get self of default value (if self is nil).

View File

@@ -21,7 +21,9 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if canImport(CommonCrypto) #if canImport(CommonCrypto)
import CommonCrypto import CommonCrypto
#endif #endif
@@ -48,10 +50,14 @@ public extension String {
} }
var convertToHTML: NSAttributedString? { var convertToHTML: NSAttributedString? {
#if canImport(UIKit)
return convertHtmlToAttributedStringWithCSS(font: nil, return convertHtmlToAttributedStringWithCSS(font: nil,
csscolor: "", csscolor: "",
lineheight: 0, lineheight: 0,
csstextalign: "") csstextalign: "")
#else
return convertHtmlToNSAttributedString
#endif
} }
/// Check if string is a valid URL. /// Check if string is a valid URL.
@@ -646,7 +652,7 @@ public extension String {
return strDate?.date(withCurrFormatt: newFormatt, localeIdentifier: localeIdentifier, timeZone: timeZone) return strDate?.date(withCurrFormatt: newFormatt, localeIdentifier: localeIdentifier, timeZone: timeZone)
} }
#if os(iOS) || os(macOS) #if canImport(UIKit)
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat { func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil) let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
@@ -757,7 +763,7 @@ public extension String {
} }
return self return self
} }
#if canImport(UIKit)
/// Converte String para HTML com CSS. /// Converte String para HTML com CSS.
/// ///
/// - Parameters: /// - Parameters:
@@ -801,6 +807,7 @@ public extension String {
return nil return nil
} }
} }
#endif
/// Float value from string (if applicable). /// Float value from string (if applicable).
/// ///

View File

@@ -19,8 +19,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#if canImport(UIKit) && os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension UIApplication { public extension UIApplication {
/// Application running environment. /// Application running environment.

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
// MARK: - Properties // MARK: - Properties
public extension UIButton { public extension UIButton {

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension UICollectionView { public extension UICollectionView {

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
public extension UIColor { public extension UIColor {
var redValue: CGFloat{ return CIColor(color: self).red } var redValue: CGFloat{ return CIColor(color: self).red }

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
public extension UIDevice { public extension UIDevice {
static var topNotch: CGFloat { static var topNotch: CGFloat {
@@ -78,7 +80,6 @@ public extension UIDevice {
case "iPhone8,2": return "iPhone 6s Plus" case "iPhone8,2": return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3": return "iPhone 7" case "iPhone9,1", "iPhone9,3": return "iPhone 7"
case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
case "iPhone8,4", "iPhone12,8": return "iPhone SE"
case "iPhone10,1", "iPhone10,4": return "iPhone 8" case "iPhone10,1", "iPhone10,4": return "iPhone 8"
case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus"
case "iPhone10,3", "iPhone10,6": return "iPhone X" case "iPhone10,3", "iPhone10,6": return "iPhone X"
@@ -92,30 +93,76 @@ public extension UIDevice {
case "iPhone13,2": return "iPhone 12" case "iPhone13,2": return "iPhone 12"
case "iPhone13,3": return "iPhone 12 Pro" case "iPhone13,3": return "iPhone 12 Pro"
case "iPhone13,4": return "iPhone 12 Pro Max" case "iPhone13,4": return "iPhone 12 Pro Max"
case "iPhone14,4": return "iPhone 13 mini"
case "iPhone14,5": return "iPhone 13"
case "iPhone14,2": return "iPhone 13 Pro"
case "iPhone14,3": return "iPhone 13 Pro Max"
case "iPhone14,7": return "iPhone 14"
case "iPhone14,8": return "iPhone 14 Plus"
case "iPhone15,2": return "iPhone 14 Pro"
case "iPhone15,3": return "iPhone 14 Pro Max"
case "iPhone15,4": return "iPhone 15"
case "iPhone15,5": return "iPhone 15 Plus"
case "iPhone16,1": return "iPhone 15 Pro"
case "iPhone16,2": return "iPhone 15 Pro Max"
case "iPhone17,3": return "iPhone 16"
case "iPhone17,4": return "iPhone 16 Plus"
case "iPhone17,1": return "iPhone 16 Pro"
case "iPhone17,2": return "iPhone 16 Pro Max"
case "iPhone17,5": return "iPhone 16e"
case "iPhone18,3": return "iPhone 17"
case "iPhone18,4": return "iPhone Air"
case "iPhone18,1": return "iPhone 17 Pro"
case "iPhone18,2": return "iPhone 17 Pro Max"
case "iPhone8,4": return "iPhone SE"
case "iPhone12,8": return "iPhone SE (2nd generation)"
case "iPhone14,6": return "iPhone SE (3rd generation)"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2" case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3" case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4" case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)"
case "iPad6,11", "iPad6,12": return "iPad (5th generation)"
case "iPad7,5", "iPad7,6": return "iPad (6th generation)"
case "iPad7,11", "iPad7,12": return "iPad (7th generation)"
case "iPad11,6", "iPad11,7": return "iPad (8th generation)"
case "iPad12,1", "iPad12,2": return "iPad (9th generation)"
case "iPad13,18", "iPad13,19": return "iPad (10th generation)"
case "iPad15,7", "iPad15,8": return "iPad (11th generation)"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2" case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad6,11", "iPad6,12": return "iPad 5" case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)"
case "iPad7,5", "iPad7,6": return "iPad 6" case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)"
case "iPad7,11", "iPad7,12": return "iPad 7" case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)"
case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)" case "iPad14,8", "iPad14,9": return "iPad Air (11-inch) (M2)"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini" case "iPad14,10", "iPad14,11": return "iPad Air (13-inch) (M2)"
case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2" case "iPad15,3", "iPad15,4": return "iPad Air (11-inch) (M3)"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3" case "iPad15,5", "iPad15,6": return "iPad Air (13-inch) (M3)"
case "iPad5,1", "iPad5,2": return "iPad Mini 4" case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini"
case "iPad11,1", "iPad11,2": return "iPad Mini 5" case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3"
case "iPad5,1", "iPad5,2": return "iPad mini 4"
case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)"
case "iPad14,1", "iPad14,2": return "iPad mini (6th generation)"
case "iPad16,1", "iPad16,2": return "iPad mini (A17 Pro)"
case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)"
case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)"
case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)"
case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)"
case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return "iPad Pro (11-inch)" case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch) (1st generation)"
case "iPad8,9", "iPad8,10": return "iPad Pro (11-inch) (2nd generation)"
case "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7": return "iPad Pro (11-inch) (3rd generation)"
case "iPad14,3", "iPad14,4": return "iPad Pro (11-inch) (4th generation)"
case "iPad16,3", "iPad16,4": return "iPad Pro (11-inch) (M4)"
case "iPad17,1", "iPad17,2": return "iPad Pro (11-inch) (M5)"
case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch) (1st generation)"
case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)"
case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)" case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)"
case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch) (4th generation)"
case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11":return "iPad Pro (12.9-inch) (5th generation)"
case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch) (6th generation)"
case "iPad16,5", "iPad16,6": return "iPad Pro (13-inch) (M4)"
case "iPad17,3", "iPad17,4": return "iPad Pro (13-inch) (M5)"
case "AppleTV5,3": return "Apple TV" case "AppleTV5,3": return "Apple TV"
case "AppleTV6,2": return "Apple TV 4K" case "AppleTV6,2": return "Apple TV 4K"
case "AudioAccessory1,1": return "HomePod" case "AudioAccessory1,1": return "HomePod"
case "i386", "x86_64": return "Simulator \(identifier)" case "AudioAccessory5,1": return "HomePod mini"
default: return identifier default: return identifier
} }
#endif #endif

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
public extension UIImage { public extension UIImage {
//Extension Required by RoundedButton to create UIImage from UIColor //Extension Required by RoundedButton to create UIImage from UIColor
func imageWithColor(color: UIColor) -> UIImage { func imageWithColor(color: UIColor) -> UIImage {

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
@MainActor @MainActor
public extension UIImageView { public extension UIImageView {

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
public extension UILabel { public extension UILabel {
func lineNumbers() -> Int{ func lineNumbers() -> Int{

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
import QuartzCore import QuartzCore
public extension UINavigationController { public extension UINavigationController {

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension UIResponder { public extension UIResponder {

View File

@@ -21,7 +21,9 @@
#if canImport(UIKit) && !os(watchOS) #if canImport(UIKit) && !os(watchOS)
#if canImport(UIKit)
import UIKit import UIKit
#endif
// MARK: - Methods // MARK: - Methods
public extension UIScrollView { public extension UIScrollView {

View File

@@ -21,7 +21,9 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) #if os(iOS)
// MARK: - Initializers // MARK: - Initializers

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public class CustomTabBadge: UILabel { public class CustomTabBadge: UILabel {

View File

@@ -21,9 +21,11 @@
import Foundation import Foundation
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
//MARK: - UITableView Animation Cell //MARK: - UITableView Animation Cell
public typealias UITableViewCellAnimation = (UITableViewCell, IndexPath, UITableView) -> Void public typealias UITableViewCellAnimation = (UITableViewCell, IndexPath, UITableView) -> Void

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if canImport(UIKit) && os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension UITapGestureRecognizer { public extension UITapGestureRecognizer {

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
public extension UITextField { public extension UITextField {

View File

@@ -21,8 +21,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
typealias GradientPoints = (startPoint: CGPoint, endPoint: CGPoint) typealias GradientPoints = (startPoint: CGPoint, endPoint: CGPoint)

View File

@@ -22,8 +22,10 @@
import Foundation import Foundation
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
import QuartzCore import QuartzCore
public enum ToastPosition { public enum ToastPosition {

View File

@@ -20,8 +20,10 @@
// THE SOFTWARE. // THE SOFTWARE.
#if os(iOS) || os(macOS) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif
import AVFoundation import AVFoundation
import Photos import Photos

View File

@@ -19,9 +19,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#if canImport(UIKit)
import UIKit import UIKit
#endif
#if os(iOS) || os(macOS) #if canImport(UIKit)
/// A protocol for delegates of `ImageZoomController` to provide callbacks for zoom and close events. /// A protocol for delegates of `ImageZoomController` to provide callbacks for zoom and close events.
@objc public protocol ImageZoomControllerDelegate { @objc public protocol ImageZoomControllerDelegate {
/// Called when the image in the controller is zoomed. /// Called when the image in the controller is zoomed.

View File

@@ -20,6 +20,8 @@
// THE SOFTWARE. // THE SOFTWARE.
// MARK: - Framework headers // MARK: - Framework headers
#if canImport(UIKit)
import Foundation
import UIKit import UIKit
// MARK: - Protocols // MARK: - Protocols
@@ -231,54 +233,37 @@ public extension LCSnackBarView {
/// Handles the `keyboardWillShowNotification` to adjust the snackbar's position. /// Handles the `keyboardWillShowNotification` to adjust the snackbar's position.
/// - Parameter notification: The `Notification` object containing keyboard information. /// - Parameter notification: The `Notification` object containing keyboard information.
@objc private func keyboardWillShow(_ notification: Notification?) -> Void { @MainActor
@objc private func keyboardWillShow(_ notification: Notification?) {
if let info = notification?.userInfo { guard let info = notification?.userInfo else { return }
systemKeyboardVisible = true systemKeyboardVisible = true
//
let curveUserInfoKey = UIResponder.keyboardAnimationCurveUserInfoKey
let durationUserInfoKey = UIResponder.keyboardAnimationDurationUserInfoKey
let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey
//
var animationCurve: UIView.AnimationOptions = .curveEaseOut
var animationDuration: TimeInterval = 0.25
var height:CGFloat = 0.0
// Getting keyboard animation. let animationCurveRaw = (info[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue
if let curve = info[curveUserInfoKey] as? UIView.AnimationOptions { ?? UInt(UIView.AnimationCurve.easeOut.rawValue)
animationCurve = curve let animationDuration = (info[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue
} ?? 0.25
let keyboardFrame = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
?? .zero
let height = keyboardFrame.height
let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw << 16)
// Getting keyboard animation duration UIView.animate(
if let duration = info[durationUserInfoKey] as? TimeInterval { withDuration: animationDuration,
animationDuration = duration
}
// Getting UIKeyboardSize.
if let kbFrame = info[frameEndUserInfoKey] as? CGRect {
height = kbFrame.size.height
}
DispatchQueue.main.async { [weak self] in
UIView.animate(withDuration: animationDuration,
delay: 0, delay: 0,
options: animationCurve, options: animationCurve
animations: { ) { [weak self] in
self?.frame.origin.y += height self?.frame.origin.y += height
})
}
} }
} }
/// Handles the `keyboardWillHideNotification`. /// Handles the `keyboardWillHideNotification`.
/// - Parameter notification: The `Notification` object. /// - Parameter notification: The `Notification` object.
@objc private func keyboardWillHide(_ notification: Notification?) -> Void { @MainActor
DispatchQueue.main.async { [weak self] in @objc private func keyboardWillHide(_ notification: Notification?) {
self?.systemKeyboardVisible = false systemKeyboardVisible = false
// keyboard is hidded // keyboard is hidded
} }
}
/// Updates the snackbar's style properties, such as width and corner radius, based on `_style`. /// Updates the snackbar's style properties, such as width and corner radius, based on `_style`.
private func updateStyle() { private func updateStyle() {
@@ -512,3 +497,5 @@ public extension LCSnackBarView {
} }
} }
} }
#endif

View File

@@ -18,7 +18,7 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#if canImport(SwiftUI) #if canImport(SwiftUI) && os(iOS)
import SwiftUI import SwiftUI
/// `LCENavigationState` is an `ObservableObject` that manages the state for `LCENavigationView`. /// `LCENavigationState` is an `ObservableObject` that manages the state for `LCENavigationView`.
@@ -47,6 +47,8 @@ class LCENavigationState: ObservableObject {
@Published var title: (any View) = Text("") @Published var title: (any View) = Text("")
/// The subtitle view of the navigation bar. /// The subtitle view of the navigation bar.
@Published var subTitle: (any View) = Text("") @Published var subTitle: (any View) = Text("")
/// The background color of the navigation bar.
@Published var navigationBarBackgroundColor: Color = .clear
} }
/// `LCENavigationView` is a SwiftUI `View` that provides a customizable navigation bar. /// `LCENavigationView` is a SwiftUI `View` that provides a customizable navigation bar.
@@ -79,7 +81,7 @@ public struct LCENavigationView<Content: View>: View {
/// The body of the `LCENavigationView`. /// The body of the `LCENavigationView`.
public var body: some View { public var body: some View {
VStack { VStack(spacing: 0) {
if !state.hideNavigationBar { if !state.hideNavigationBar {
NavigationBarView NavigationBarView
} }
@@ -100,7 +102,7 @@ public struct LCENavigationView<Content: View>: View {
.font(.headline) .font(.headline)
.padding() .padding()
.background { .background {
Color.clear.ignoresSafeArea(edges: .top) state.navigationBarBackgroundColor.ignoresSafeArea(edges: .top)
} }
} }
@@ -217,6 +219,14 @@ public struct LCENavigationView<Content: View>: View {
state.hideNavigationBar = hide state.hideNavigationBar = hide
return self return self
} }
/// Sets the background color for the navigation bar.
/// - Parameter color: The color to use as the navigation bar background.
/// - Returns: The `LCENavigationView` instance for chaining.
public func setNavigationBarBackgroundColor(_ color: Color) -> LCENavigationView {
state.navigationBarBackgroundColor = color
return self
}
} }
/// Extension to `FormatStyle` to format any value as a string. /// Extension to `FormatStyle` to format any value as a string.