1 Commits

Author SHA1 Message Date
Daniel Arantes Loverde
27b6b45ee9 Complete documentation 2025-10-23 13:26:03 -03:00
41 changed files with 3333 additions and 458 deletions

1
.gitignore vendored
View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -22,5 +22,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
THE SOFTWARE.
Autor: Daniel Arantes Loverde

View File

@@ -1,15 +0,0 @@
{
"originHash" : "33e7d52ad13cf774717778548edb365d33ff62d766d0049165bc8970f19a23ef",
"pins" : [
{
"identity" : "lcecryptokitbinary",
"kind" : "remoteSourceControl",
"location" : "https://60c260c85d3a2fe840411b0ff98f521b5eca3c56@git.loverde.com.br/Loverde-Company-LTDA/LCECryptoKitBinary.git",
"state" : {
"revision" : "2c5c47cebef40a8adc5557d071a35be405c05e30",
"version" : "1.0.2"
}
}
],
"version" : 3
}

View File

@@ -1,43 +1,16 @@
// swift-tools-version: 6.0
import PackageDescription
import Foundation
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(
name: "LCEssentials",
platforms: [
.iOS(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6)
],
products: [
.library(
name: "LCEssentials",
targets: ["LCEssentials"]),
],
dependencies: packageDependencies,
targets: [
.target(
name: "LCEssentials",
dependencies: targetDependencies),
name: "LCEssentials"),
]
)

View File

@@ -17,47 +17,21 @@ Installation
#### Swift Package Manager (SPM)
``` swift
dependencies: [
.package(url: "https://git.loverde.com.br/Loverde-Company-LTDA/LCEssentials", .upToNextMajor(from: "1.0.0"))
.package(url: "http://git.loverde.com.br:3000/git/LCEssentials.git", .upToNextMajor(from: "1.0.0"))
]
```
You can also add it via XCode SPM editor with URL:
``` swift
https://git.loverde.com.br/Loverde-Company-LTDA/LCEssentials
http://git.loverde.com.br:3000/git/LCEssentials.git
```
## Usage example
[Read full documentation](LCEssentials_DOCUMENTATION.md)
* Background Trhead
```swift
LCEssentials.backgroundThread(delay: 0.6, background: {
//Do something im background
}) {
//When finish, update UI
}
```
* NavigationController with Completion Handler
```swift
self.navigationController?.popViewControllerWithHandler(completion: {
//Do some stuff after pop
})
//or more simple
self.navigationController?.popViewControllerWithHandler {
//Do some stuff after pop
}
```
## Another components
> LCESnackBarView - **great way to send feedback to user**
And then import `LCEssentials ` wherever you import UIKit or SwiftUI
``` swift
import LCEssentials
```
Author:
----
Any question or doubts, please send thru email
@@ -65,5 +39,3 @@ 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 "Loverde Co. Github")](https://github.com/loverde-co)
Autor: Daniel Arantes Loverde

View File

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

View File

@@ -1,96 +0,0 @@
//
// Copyright (c) 2025 Loverde Co.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// 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
// THE SOFTWARE.
import Foundation
#if canImport(LCECryptoKit)
import LCECryptoKit
public final class LCECryptoKitManager {
private let hashKey: String
public init() {
self.hashKey = ""
}
public init(privateKey: String){
self.hashKey = privateKey
}
public static func generateKey() -> String {
LCECryptoKit.generateRandomAESKeyString()
}
public func encodeTP(email: String, password: String) -> String? {
return LCECryptoKit.encodeSeed(email: email, password: password)
}
public func decodeOTP(_ otpHash: String) -> String? {
return LCECryptoKit.decodeSeed(otpKey: otpHash)
}
// MARK: Need hashKey to decode
public func encodeOTPWithKey(email: String, password: String) -> String? {
return LCECryptoKit.encodeSeed(email: email, password: password, hashKey: self.hashKey)
}
public func decodeOTPWithKey(_ otpHash: String) -> Bool {
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,10 +26,8 @@ import Foundation
import Security
#endif
#if canImport(UIKit)
#if canImport(UIKit)
import UIKit
#endif
#endif
/// A generic `Result` enumeration to represent either a success `Value` or a failure `Error`.
public enum Result<Value, Error: Swift.Error> {
@@ -131,26 +129,15 @@ public struct API {
// Add the file
let fileName = fileURL.lastPathComponent
let mimeType = mimeTypeForPath(path: fileName)
printInfo(title: "Body size before", msg: "\(body.count) bytes")
let fileData: Data
do {
fileData = try Data(contentsOf: fileURL)
printInfo(title: "Body size after", msg: "\(body.count) bytes")
} catch {
printError(title: "Upload File", msg: error.localizedDescription)
throw error
}
do {
let fileData = try Data(contentsOf: fileURL)
body.append("--\(boundary)\r\n".data(using: .utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
body.append("Content-Type: \(mimeType)\r\n\r\n".data(using: .utf8)!)
let fileDataCopy = Data(fileData)
body.append(fileDataCopy)
let dataUTF8 = "\r\n".data(using: .utf8)!
body.append(dataUTF8)
printInfo(title: "Body size after", msg: "\(body.count) bytes")
body.append(fileData)
body.append("\r\n".data(using: .utf8)!)
} catch {
printError(title: "Upload File", msg: error.localizedDescription)
}
// Finalize the request body

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,11 +21,9 @@
import Foundation
#if canImport(UIKit)
import UIKit
#endif
#if canImport(UIKit)
#if os(iOS) || os(macOS)
public extension UIDevice {
static var topNotch: CGFloat {
@@ -80,6 +78,7 @@ public extension UIDevice {
case "iPhone8,2": return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3": return "iPhone 7"
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,2", "iPhone10,5": return "iPhone 8 Plus"
case "iPhone10,3", "iPhone10,6": return "iPhone X"
@@ -93,76 +92,30 @@ public extension UIDevice {
case "iPhone13,2": return "iPhone 12"
case "iPhone13,3": return "iPhone 12 Pro"
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 "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)"
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 "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)"
case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)"
case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)"
case "iPad14,8", "iPad14,9": return "iPad Air (11-inch) (M2)"
case "iPad14,10", "iPad14,11": return "iPad Air (13-inch) (M2)"
case "iPad15,3", "iPad15,4": return "iPad Air (11-inch) (M3)"
case "iPad15,5", "iPad15,6": return "iPad Air (13-inch) (M3)"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini"
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,11", "iPad6,12": return "iPad 5"
case "iPad7,5", "iPad7,6": return "iPad 6"
case "iPad7,11", "iPad7,12": return "iPad 7"
case "iPad11,4", "iPad11,5": return "iPad Air (3rd generation)"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini"
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 5"
case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-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) (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 "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)"
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,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 "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,5", "iPad8,6", "iPad8,7", "iPad8,8":return "iPad Pro (12.9-inch) (3rd generation)"
case "AppleTV5,3": return "Apple TV"
case "AppleTV6,2": return "Apple TV 4K"
case "AudioAccessory1,1": return "HomePod"
case "AudioAccessory5,1": return "HomePod mini"
case "i386", "x86_64": return "Simulator \(identifier)"
default: return identifier
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@
// 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
// THE SOFTWARE.
#if canImport(SwiftUI) && os(iOS)
#if canImport(SwiftUI)
import SwiftUI
/// `LCENavigationState` is an `ObservableObject` that manages the state for `LCENavigationView`.
@@ -47,8 +47,6 @@ class LCENavigationState: ObservableObject {
@Published var title: (any View) = Text("")
/// The subtitle view of the navigation bar.
@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.
@@ -81,7 +79,7 @@ public struct LCENavigationView<Content: View>: View {
/// The body of the `LCENavigationView`.
public var body: some View {
VStack(spacing: 0) {
VStack {
if !state.hideNavigationBar {
NavigationBarView
}
@@ -102,7 +100,7 @@ public struct LCENavigationView<Content: View>: View {
.font(.headline)
.padding()
.background {
state.navigationBarBackgroundColor.ignoresSafeArea(edges: .top)
Color.clear.ignoresSafeArea(edges: .top)
}
}
@@ -219,14 +217,6 @@ public struct LCENavigationView<Content: View>: View {
state.hideNavigationBar = hide
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.