3196 lines
62 KiB
Markdown
3196 lines
62 KiB
Markdown
# 📚 LCEssentials - Documentação Completa
|
||
|
||
> **Loverde Co. Essentials Swift Scripts** - Biblioteca completa de utilitários Swift para iOS, macOS, tvOS e watchOS
|
||
|
||
## 📋 Índice
|
||
|
||
- [🔧 Instalação](#-instalação)
|
||
- [🏗️ Classes Principais](#️-classes-principais)
|
||
- [🎨 Componentes UI](#-componentes-ui)
|
||
- [⚡ SwiftUI](#-swiftui)
|
||
- [🔗 Extensões](#-extensões)
|
||
- [📱 Helpers](#-helpers)
|
||
- [🔐 Criptografia](#-criptografia)
|
||
- [🌐 API & Networking](#-api--networking)
|
||
|
||
---
|
||
|
||
## 🔧 Instalação
|
||
|
||
### Swift Package Manager (SPM)
|
||
|
||
```swift
|
||
dependencies: [
|
||
.package(url: "https://git.loverde.com.br/Loverde-Company-LTDA/LCEssentials", .upToNextMajor(from: "1.0.0"))
|
||
]
|
||
```
|
||
|
||
### Xcode SPM
|
||
|
||
```
|
||
https://git.loverde.com.br/Loverde-Company-LTDA/LCEssentials
|
||
```
|
||
|
||
### Import
|
||
|
||
```swift
|
||
import LCEssentials
|
||
```
|
||
|
||
---
|
||
|
||
## 🏗️ Classes Principais
|
||
|
||
<details>
|
||
<summary><strong>LCEssentials - Classe Principal</strong></summary>
|
||
|
||
### LCEssentials
|
||
|
||
Classe principal com métodos utilitários gerais para desenvolvimento iOS.
|
||
|
||
#### Propriedades Estáticas
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
public struct LCEssentials {
|
||
public static let DEFAULT_ERROR_DOMAIN = "LoverdeCoErrorDomain"
|
||
public static let DEFAULT_ERROR_CODE = -99
|
||
public static let DEFAULT_ERROR_MSG = "Error Unknow"
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Verificar informações do app
|
||
let appName = LCEssentials.appDisplayName
|
||
let appVersion = LCEssentials.appVersion
|
||
let appBuild = LCEssentials.appBuild
|
||
let bundleID = LCEssentials.appBundleID
|
||
|
||
// Verificar informações do dispositivo
|
||
let isDebug = LCEssentials.isInDebuggingMode
|
||
let isTestFlight = LCEssentials.isInTestFlight
|
||
let isSimulator = LCEssentials.isRunningOnSimulator
|
||
let isPad = LCEssentials.isPad
|
||
let isPhone = LCEssentials.isPhone
|
||
|
||
// Dimensões da tela
|
||
let screenWidth = LCEssentials.screenWidth
|
||
let screenHeight = LCEssentials.screenHeight
|
||
```
|
||
|
||
#### Métodos Principais
|
||
|
||
**backgroundThread**
|
||
|
||
```swift
|
||
static func backgroundThread(delay: Double = 0.0,
|
||
background: (@Sendable () -> Void)? = nil,
|
||
completion: (@Sendable () -> Void)? = nil)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCEssentials.backgroundThread(delay: 0.6, background: {
|
||
// Fazer algo em background
|
||
print("Processando...")
|
||
}) {
|
||
// Quando terminar, atualizar UI
|
||
DispatchQueue.main.async {
|
||
self.updateUI()
|
||
}
|
||
}
|
||
```
|
||
|
||
**delay**
|
||
|
||
```swift
|
||
@discardableResult
|
||
static func delay(milliseconds: Double,
|
||
queue: DispatchQueue = .main,
|
||
completion: @escaping () -> Void) -> DispatchWorkItem
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let task = LCEssentials.delay(milliseconds: 2000) {
|
||
print("Executado após 2 segundos")
|
||
}
|
||
// Para cancelar: task.cancel()
|
||
```
|
||
|
||
**debounce**
|
||
|
||
```swift
|
||
static func debounce(millisecondsDelay: Int,
|
||
queue: DispatchQueue = .main,
|
||
action: @escaping (() -> Void)) -> () -> Void
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let debouncedAction = LCEssentials.debounce(millisecondsDelay: 500) {
|
||
print("Executado apenas uma vez após 500ms de inatividade")
|
||
}
|
||
|
||
// Chamar múltiplas vezes rapidamente
|
||
debouncedAction() // Primeira chamada
|
||
debouncedAction() // Segunda chamada (cancela a primeira)
|
||
debouncedAction() // Terceira chamada (cancela a segunda)
|
||
// Apenas a última será executada após 500ms
|
||
```
|
||
|
||
**getTopViewController**
|
||
|
||
```swift
|
||
static func getTopViewController(base: UIViewController? = nil,
|
||
aboveBars: Bool = true) -> UIViewController?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let topVC = LCEssentials.getTopViewController() {
|
||
// Fazer algo com o view controller do topo
|
||
topVC.present(alert, animated: true)
|
||
}
|
||
```
|
||
|
||
**shareApp**
|
||
|
||
```swift
|
||
static func shareApp(message: String = "", url: String = "")
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCEssentials.shareApp(message: "Confira este app!", url: "https://appstore.com/app")
|
||
```
|
||
|
||
**call**
|
||
|
||
```swift
|
||
static func call(_ number: String!)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCEssentials.call("+5511999999999")
|
||
```
|
||
|
||
**openSafari**
|
||
|
||
```swift
|
||
static func openSafari(_ urlStr: String)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCEssentials.openSafari("https://loverde.com.br")
|
||
```
|
||
|
||
**downloadFileWithCache**
|
||
|
||
```swift
|
||
static func downloadFileWithCache(from url: URL,
|
||
completion: @escaping (Result<URL, Error>) -> Void)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCEssentials.downloadFileWithCache(from: imageURL) { result in
|
||
switch result {
|
||
case .success(let localURL):
|
||
print("Arquivo baixado: \(localURL)")
|
||
case .failure(let error):
|
||
print("Erro: \(error)")
|
||
}
|
||
}
|
||
```
|
||
|
||
**cleanExpiredCache**
|
||
|
||
```swift
|
||
static func cleanExpiredCache(expiration: TimeInterval = 7 * 24 * 60 * 60)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Limpar cache com mais de 1 semana
|
||
LCEssentials.cleanExpiredCache(expiration: 7 * 24 * 60 * 60)
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>API - Sistema de Requisições HTTP</strong></summary>
|
||
|
||
### API
|
||
|
||
Sistema completo para requisições HTTP com suporte a certificados, cache e retry automático.
|
||
|
||
#### Configuração
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
@available(iOS 13.0.0, *)
|
||
@MainActor
|
||
public struct API {
|
||
public static let shared = API()
|
||
public static var defaultParams: [String:Any] = [String: Any]()
|
||
public static var persistConnectionDelay: Double = 3
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Configurar parâmetros padrão
|
||
API.defaultParams = ["api_key": "sua_chave_aqui"]
|
||
|
||
// Configurar certificado cliente
|
||
let certData = Data(contentsOf: Bundle.main.url(forResource: "client", withExtension: "p12")!)
|
||
API.shared.setupCertificationRequest(certData: certData, password: "senha_do_certificado")
|
||
```
|
||
|
||
#### Método Principal
|
||
|
||
**request**
|
||
|
||
```swift
|
||
public func request<T: Codable>(url: String,
|
||
params: Any? = nil,
|
||
method: httpMethod,
|
||
headers: [String: String] = [:],
|
||
jsonEncoding: Bool = true,
|
||
debug: Bool = true,
|
||
timeoutInterval: TimeInterval = 30,
|
||
networkServiceType: URLRequest.NetworkServiceType = .default,
|
||
persistConnection: Bool = false) async throws -> T
|
||
```
|
||
|
||
**Uso - GET Request:**
|
||
|
||
```swift
|
||
struct User: Codable {
|
||
let id: Int
|
||
let name: String
|
||
let email: String
|
||
}
|
||
|
||
do {
|
||
let users: [User] = try await API.shared.request(
|
||
url: "https://api.exemplo.com/users",
|
||
method: .get,
|
||
headers: ["Authorization": "Bearer token_aqui"]
|
||
)
|
||
print("Usuários: \(users)")
|
||
} catch {
|
||
print("Erro: \(error)")
|
||
}
|
||
```
|
||
|
||
**Uso - POST Request:**
|
||
|
||
```swift
|
||
struct LoginRequest: Codable {
|
||
let email: String
|
||
let password: String
|
||
}
|
||
|
||
struct LoginResponse: Codable {
|
||
let token: String
|
||
let user: User
|
||
}
|
||
|
||
do {
|
||
let loginData = LoginRequest(email: "user@exemplo.com", password: "senha123")
|
||
let response: LoginResponse = try await API.shared.request(
|
||
url: "https://api.exemplo.com/login",
|
||
params: loginData,
|
||
method: .post
|
||
)
|
||
print("Token: \(response.token)")
|
||
} catch {
|
||
print("Erro no login: \(error)")
|
||
}
|
||
```
|
||
|
||
**Uso - Upload de Arquivo:**
|
||
|
||
```swift
|
||
let fileURL = URL(fileURLWithPath: "/path/to/image.jpg")
|
||
let params = [
|
||
"title": "Minha Imagem",
|
||
"description": "Descrição da imagem",
|
||
"file": fileURL.absoluteString
|
||
]
|
||
|
||
do {
|
||
let response: [String: Any] = try await API.shared.request(
|
||
url: "https://api.exemplo.com/upload",
|
||
params: params,
|
||
method: .post
|
||
)
|
||
print("Upload realizado: \(response)")
|
||
} catch {
|
||
print("Erro no upload: \(error)")
|
||
}
|
||
```
|
||
|
||
**Uso - Com Retry Automático:**
|
||
|
||
```swift
|
||
do {
|
||
let data: MyResponse = try await API.shared.request(
|
||
url: "https://api.exemplo.com/data",
|
||
method: .get,
|
||
persistConnection: true // Habilita retry automático
|
||
)
|
||
} catch {
|
||
print("Erro após tentativas: \(error)")
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>LCECryptoKitManager - Gerenciador de Criptografia</strong></summary>
|
||
|
||
### LCECryptoKitManager
|
||
|
||
Gerenciador para operações de criptografia usando LCECryptoKit.
|
||
|
||
#### Inicialização
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
public final class LCECryptoKitManager {
|
||
public init()
|
||
public init(privateKey: String)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Sem chave privada
|
||
let cryptoManager = LCECryptoKitManager()
|
||
|
||
// Com chave privada
|
||
let cryptoManager = LCECryptoKitManager(privateKey: "minha_chave_privada")
|
||
```
|
||
|
||
#### Métodos
|
||
|
||
**generateKey**
|
||
|
||
```swift
|
||
public static func generateKey() -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let newKey = LCECryptoKitManager.generateKey()
|
||
print("Nova chave gerada: \(newKey)")
|
||
```
|
||
|
||
**encodeTP**
|
||
|
||
```swift
|
||
public func encodeTP(email: String, password: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let encoded = cryptoManager.encodeTP(email: "user@exemplo.com", password: "senha123") {
|
||
print("Dados codificados: \(encoded)")
|
||
}
|
||
```
|
||
|
||
**decodeOTP**
|
||
|
||
```swift
|
||
public func decodeOTP(_ otpHash: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let decoded = cryptoManager.decodeOTP("hash_codificado") {
|
||
print("Dados decodificados: \(decoded)")
|
||
}
|
||
```
|
||
|
||
**encodeOTPWithKey**
|
||
|
||
```swift
|
||
public func encodeOTPWithKey(email: String, password: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let encoded = cryptoManager.encodeOTPWithKey(email: "user@exemplo.com", password: "senha123") {
|
||
print("Dados codificados com chave: \(encoded)")
|
||
}
|
||
```
|
||
|
||
**decodeOTPWithKey**
|
||
|
||
```swift
|
||
public func decodeOTPWithKey(_ otpHash: String) -> Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let isValid = cryptoManager.decodeOTPWithKey("hash_codificado")
|
||
if isValid {
|
||
print("Hash válido!")
|
||
} else {
|
||
print("Hash inválido!")
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>LCSingleton - Protocolo Singleton</strong></summary>
|
||
|
||
### LCSingleton
|
||
|
||
Protocolo para implementação de padrão Singleton.
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
@objc public protocol LCESingletonDelegate: AnyObject {
|
||
@objc optional func singleton(object: Any?, withData: Any)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
class MySingleton: LCESingletonDelegate {
|
||
static let shared = MySingleton()
|
||
|
||
private init() {}
|
||
|
||
func singleton(object: Any?, withData: Any) {
|
||
print("Singleton chamado com dados: \(withData)")
|
||
}
|
||
}
|
||
|
||
// Uso
|
||
MySingleton.shared.singleton(object: nil, withData: "dados_importantes")
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>GifHelper - Utilitários para GIFs</strong></summary>
|
||
|
||
### GifHelper
|
||
|
||
Utilitários para trabalhar com arquivos GIF animados.
|
||
|
||
#### UIImageView Extensions
|
||
|
||
**loadGif**
|
||
|
||
```swift
|
||
public func loadGif(name: String)
|
||
public func loadGif(asset: String)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Carregar GIF do bundle
|
||
imageView.loadGif(name: "animacao")
|
||
|
||
// Carregar GIF do asset catalog
|
||
imageView.loadGif(asset: "animacao_gif")
|
||
```
|
||
|
||
#### UIImage Extensions
|
||
|
||
**gif**
|
||
|
||
```swift
|
||
public class func gif(data: Data) -> UIImage?
|
||
public class func gif(url: String) -> UIImage?
|
||
public class func gif(name: String) -> UIImage?
|
||
public class func gif(asset: String) -> UIImage?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Criar GIF a partir de Data
|
||
if let gifData = Data(contentsOf: gifURL) {
|
||
let gifImage = UIImage.gif(data: gifData)
|
||
imageView.image = gifImage
|
||
}
|
||
|
||
// Criar GIF a partir de URL
|
||
if let gifImage = UIImage.gif(url: "https://exemplo.com/animacao.gif") {
|
||
imageView.image = gifImage
|
||
}
|
||
|
||
// Criar GIF a partir do bundle
|
||
if let gifImage = UIImage.gif(name: "animacao") {
|
||
imageView.image = gifImage
|
||
}
|
||
|
||
// Criar GIF a partir do asset catalog
|
||
if let gifImage = UIImage.gif(asset: "animacao_gif") {
|
||
imageView.image = gifImage
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>Repositorio - Estrutura de Repositório</strong></summary>
|
||
|
||
### Repositorio
|
||
|
||
Estrutura básica para repositórios.
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
struct Repositorio {
|
||
var text = "Hello, World!"
|
||
private var testBin: [Int] = []
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
var repo = Repositorio()
|
||
print(repo.text) // "Hello, World!"
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 🎨 Componentes UI
|
||
|
||
<details>
|
||
<summary><strong>LCSnackBarView - Sistema de Notificações</strong></summary>
|
||
|
||
### LCSnackBarView
|
||
|
||
Sistema completo de notificações estilo SnackBar para iOS.
|
||
|
||
#### Inicialização
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
public final class LCSnackBarView: UIView {
|
||
public init(style: LCSnackBarViewType = .default,
|
||
orientation: LCSnackBarOrientation = .top,
|
||
delegate: LCSnackBarViewDelegate? = nil)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
// Básico
|
||
let snackBar = LCSnackBarView()
|
||
snackBar.configure(text: "Operação realizada com sucesso!")
|
||
.present()
|
||
|
||
// Com delegate
|
||
let snackBar = LCSnackBarView(delegate: self)
|
||
snackBar.configure(text: "Mensagem importante!")
|
||
.present()
|
||
|
||
// Com estilo e orientação
|
||
let snackBar = LCSnackBarView(style: .rounded, orientation: .bottom)
|
||
snackBar.configure(text: "Mensagem no bottom!")
|
||
.present()
|
||
```
|
||
|
||
#### Configuração
|
||
|
||
**configure(text:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(text: String) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.configure(text: "Sua mensagem aqui")
|
||
```
|
||
|
||
**configure(textColor:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(textColor: UIColor) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.configure(textColor: .white)
|
||
```
|
||
|
||
**configure(textFont:alignment:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(textFont: UIFont, alignment: NSTextAlignment = .center) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.configure(textFont: .boldSystemFont(ofSize: 16), alignment: .left)
|
||
```
|
||
|
||
**configure(backgroundColor:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(backgroundColor: UIColor) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.configure(backgroundColor: .systemGreen)
|
||
```
|
||
|
||
**configure(exibition:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(exibition timer: LCSnackBarTimer) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.configure(exibition: .medium) // 5 segundos
|
||
snackBar.configure(exibition: .infinity) // Permanece até ser fechado manualmente
|
||
```
|
||
|
||
**configure(imageIconBefore:withTintColor:)**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func configure(imageIconBefore icon: UIImageView, withTintColor: UIColor? = nil) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let icon = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
|
||
snackBar.configure(imageIconBefore: icon, withTintColor: .white)
|
||
```
|
||
|
||
**present(completion:)**
|
||
|
||
```swift
|
||
func present(completion: (()->())? = nil)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
snackBar.present {
|
||
print("SnackBar apresentado!")
|
||
}
|
||
```
|
||
|
||
#### Enums
|
||
|
||
**LCSnackBarViewType**
|
||
|
||
```swift
|
||
public enum LCSnackBarViewType {
|
||
case `default` // Retangular
|
||
case rounded // Arredondado
|
||
}
|
||
```
|
||
|
||
**LCSnackBarOrientation**
|
||
|
||
```swift
|
||
public enum LCSnackBarOrientation {
|
||
case top // Aparece no topo
|
||
case bottom // Aparece na parte inferior
|
||
}
|
||
```
|
||
|
||
**LCSnackBarTimer**
|
||
|
||
```swift
|
||
public enum LCSnackBarTimer: CGFloat {
|
||
case infinity = 0 // Permanece até ser fechado
|
||
case minimum = 2 // 2 segundos
|
||
case medium = 5 // 5 segundos
|
||
case maximum = 10 // 10 segundos
|
||
}
|
||
```
|
||
|
||
#### Delegate
|
||
|
||
**LCSnackBarViewDelegate**
|
||
|
||
```swift
|
||
@objc public protocol LCSnackBarViewDelegate {
|
||
@objc optional func snackbar(didStartExibition: LCSnackBarView)
|
||
@objc optional func snackbar(didTouchOn snackbar: LCSnackBarView)
|
||
@objc optional func snackbar(didEndExibition: LCSnackBarView)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
class MyViewController: UIViewController, LCSnackBarViewDelegate {
|
||
|
||
func showNotification() {
|
||
let snackBar = LCSnackBarView(delegate: self)
|
||
snackBar.configure(text: "Notificação importante!")
|
||
.present()
|
||
}
|
||
|
||
func snackbar(didStartExibition: LCSnackBarView) {
|
||
print("SnackBar começou a ser exibido")
|
||
}
|
||
|
||
func snackbar(didTouchOn snackbar: LCSnackBarView) {
|
||
print("Usuário tocou no SnackBar")
|
||
}
|
||
|
||
func snackbar(didEndExibition: LCSnackBarView) {
|
||
print("SnackBar foi fechado")
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class ViewController: UIViewController, LCSnackBarViewDelegate {
|
||
|
||
@IBAction func showSuccessNotification() {
|
||
let snackBar = LCSnackBarView(style: .rounded, orientation: .top, delegate: self)
|
||
|
||
let icon = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
|
||
|
||
snackBar
|
||
.configure(text: "Dados salvos com sucesso!")
|
||
.configure(textColor: .white)
|
||
.configure(backgroundColor: .systemGreen)
|
||
.configure(exibition: .medium)
|
||
.configure(imageIconBefore: icon, withTintColor: .white)
|
||
.present()
|
||
}
|
||
|
||
@IBAction func showErrorNotification() {
|
||
let snackBar = LCSnackBarView(style: .default, orientation: .bottom)
|
||
|
||
snackBar
|
||
.configure(text: "Erro ao salvar dados. Tente novamente.")
|
||
.configure(textColor: .white)
|
||
.configure(backgroundColor: .systemRed)
|
||
.configure(exibition: .maximum)
|
||
.present()
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>ImagePickerController - Seletor de Imagens</strong></summary>
|
||
|
||
### ImagePickerController
|
||
|
||
Controlador para seleção de imagens da câmera ou biblioteca de fotos.
|
||
|
||
#### Inicialização
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
public class ImagePickerController: UIViewController, UINavigationControllerDelegate {
|
||
public weak var delegate: ImagePickerControllerDelegate?
|
||
public var isEditable: Bool = false
|
||
public init()
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let imagePicker = ImagePickerController()
|
||
imagePicker.delegate = self
|
||
imagePicker.isEditable = true // Permite edição da imagem
|
||
```
|
||
|
||
#### Delegate
|
||
|
||
**ImagePickerControllerDelegate**
|
||
|
||
```swift
|
||
public protocol ImagePickerControllerDelegate: AnyObject {
|
||
func imagePicker(didSelect image: UIImage?)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
class MyViewController: UIViewController, ImagePickerControllerDelegate {
|
||
|
||
@IBAction func selectImage() {
|
||
let imagePicker = ImagePickerController()
|
||
imagePicker.delegate = self
|
||
imagePicker.isEditable = true
|
||
present(imagePicker, animated: true)
|
||
}
|
||
|
||
func imagePicker(didSelect image: UIImage?) {
|
||
if let selectedImage = image {
|
||
imageView.image = selectedImage
|
||
print("Imagem selecionada: \(selectedImage.size)")
|
||
} else {
|
||
print("Seleção cancelada")
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Método Principal
|
||
|
||
**openImagePicker**
|
||
|
||
```swift
|
||
public func openImagePicker()
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let imagePicker = ImagePickerController()
|
||
imagePicker.delegate = self
|
||
imagePicker.openImagePicker() // Abre automaticamente o seletor
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class ProfileViewController: UIViewController, ImagePickerControllerDelegate {
|
||
|
||
@IBOutlet weak var profileImageView: UIImageView!
|
||
|
||
@IBAction func changeProfileImage() {
|
||
let imagePicker = ImagePickerController()
|
||
imagePicker.delegate = self
|
||
imagePicker.isEditable = true
|
||
present(imagePicker, animated: true)
|
||
}
|
||
|
||
func imagePicker(didSelect image: UIImage?) {
|
||
dismiss(animated: true) {
|
||
if let selectedImage = image {
|
||
self.profileImageView.image = selectedImage
|
||
self.saveProfileImage(selectedImage)
|
||
}
|
||
}
|
||
}
|
||
|
||
private func saveProfileImage(_ image: UIImage) {
|
||
// Implementar lógica de salvamento
|
||
print("Imagem do perfil atualizada!")
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>ImageZoomController - Visualizador de Imagens com Zoom</strong></summary>
|
||
|
||
### ImageZoomController
|
||
|
||
Controlador para visualização de imagens com zoom e pan.
|
||
|
||
#### Inicialização
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
public class ImageZoomController: UIViewController {
|
||
public init(_ withImage: UIImage)
|
||
public weak var delegate: ImageZoomControllerDelegate?
|
||
public var minimumZoomScale: CGFloat = 1.0
|
||
public var maximumZoomScale: CGFloat = 6.0
|
||
public var addGestureToDismiss: Bool = true
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let image = UIImage(named: "minha_imagem")!
|
||
let zoomController = ImageZoomController(image)
|
||
zoomController.delegate = self
|
||
zoomController.minimumZoomScale = 0.5
|
||
zoomController.maximumZoomScale = 8.0
|
||
zoomController.addGestureToDismiss = true
|
||
```
|
||
|
||
#### Delegate
|
||
|
||
**ImageZoomControllerDelegate**
|
||
|
||
```swift
|
||
@objc public protocol ImageZoomControllerDelegate {
|
||
@objc optional func imageZoomController(controller: ImageZoomController, didZoom image: UIImage?)
|
||
@objc optional func imageZoomController(controller: ImageZoomController, didClose image: UIImage?)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
class MyViewController: UIViewController, ImageZoomControllerDelegate {
|
||
|
||
@IBAction func showImageZoom() {
|
||
guard let image = imageView.image else { return }
|
||
|
||
let zoomController = ImageZoomController(image)
|
||
zoomController.delegate = self
|
||
zoomController.present()
|
||
}
|
||
|
||
func imageZoomController(controller: ImageZoomController, didZoom image: UIImage?) {
|
||
print("Usuário fez zoom na imagem")
|
||
}
|
||
|
||
func imageZoomController(controller: ImageZoomController, didClose image: UIImage?) {
|
||
print("Visualizador foi fechado")
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Métodos
|
||
|
||
**present(completion:)**
|
||
|
||
```swift
|
||
public func present(completion: (()->())? = nil)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
zoomController.present {
|
||
print("Visualizador apresentado!")
|
||
}
|
||
```
|
||
|
||
**dismiss(completion:)**
|
||
|
||
```swift
|
||
public func dismiss(completion: (()->())? = nil)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
zoomController.dismiss {
|
||
print("Visualizador fechado!")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class GalleryViewController: UIViewController, ImageZoomControllerDelegate {
|
||
|
||
@IBOutlet weak var collectionView: UICollectionView!
|
||
var images: [UIImage] = []
|
||
|
||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||
let selectedImage = images[indexPath.item]
|
||
showImageZoom(selectedImage)
|
||
}
|
||
|
||
private func showImageZoom(_ image: UIImage) {
|
||
let zoomController = ImageZoomController(image)
|
||
zoomController.delegate = self
|
||
zoomController.minimumZoomScale = 0.5
|
||
zoomController.maximumZoomScale = 10.0
|
||
zoomController.addGestureToDismiss = true
|
||
zoomController.present()
|
||
}
|
||
|
||
func imageZoomController(controller: ImageZoomController, didZoom image: UIImage?) {
|
||
// Opcional: implementar lógica quando usuário faz zoom
|
||
}
|
||
|
||
func imageZoomController(controller: ImageZoomController, didClose image: UIImage?) {
|
||
// Opcional: implementar lógica quando visualizador é fechado
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## ⚡ SwiftUI
|
||
|
||
<details>
|
||
<summary><strong>LCENavigationView - Navegação Customizada SwiftUI</strong></summary>
|
||
|
||
### LCENavigationView
|
||
|
||
Componente SwiftUI para navegação customizada com botões e títulos.
|
||
|
||
#### Inicialização
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
@available(iOS 15, *)
|
||
public struct LCENavigationView<Content: View>: View {
|
||
public init(title: (any View) = Text(""),
|
||
subTitle: (any View) = Text(""),
|
||
@ViewBuilder content: () -> Content)
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCENavigationView {
|
||
Text("Conteúdo da tela")
|
||
}
|
||
```
|
||
|
||
#### Configuração
|
||
|
||
**setTitle**
|
||
|
||
```swift
|
||
public func setTitle(text: (any View) = Text(""),
|
||
subTitle: (any View)? = nil) -> LCENavigationView
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCENavigationView {
|
||
Text("Conteúdo")
|
||
}
|
||
.setTitle(text: Text("Meu Título"), subTitle: Text("Subtítulo"))
|
||
```
|
||
|
||
**setLeftButton**
|
||
|
||
```swift
|
||
public func setLeftButton(text: Text = Text(""),
|
||
image: (any View)? = nil,
|
||
action: @escaping () -> Void) -> LCENavigationView
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCENavigationView {
|
||
Text("Conteúdo")
|
||
}
|
||
.setLeftButton(text: Text("Voltar")) {
|
||
print("Botão esquerdo pressionado")
|
||
}
|
||
.setLeftButton(image: Image(systemName: "arrow.left")) {
|
||
print("Seta esquerda pressionada")
|
||
}
|
||
```
|
||
|
||
**setRightButton**
|
||
|
||
```swift
|
||
public func setRightButton(text: Text = Text(""),
|
||
image: (any View)? = nil,
|
||
action: @escaping () -> Void) -> LCENavigationView
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCENavigationView {
|
||
Text("Conteúdo")
|
||
}
|
||
.setRightButton(text: Text("Salvar")) {
|
||
print("Salvar pressionado")
|
||
}
|
||
.setRightButton(image: Image(systemName: "checkmark")) {
|
||
print("Checkmark pressionado")
|
||
}
|
||
```
|
||
|
||
**hideNavigationView**
|
||
|
||
```swift
|
||
public func hideNavigationView(_ hide: Bool) -> LCENavigationView
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
LCENavigationView {
|
||
Text("Conteúdo")
|
||
}
|
||
.hideNavigationView(true) // Esconde a barra de navegação
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
struct ContentView: View {
|
||
@State private var isEditing = false
|
||
|
||
var body: some View {
|
||
LCENavigationView {
|
||
VStack {
|
||
Text("Conteúdo da tela")
|
||
.padding()
|
||
|
||
if isEditing {
|
||
Text("Modo de edição ativo")
|
||
.foregroundColor(.blue)
|
||
}
|
||
}
|
||
}
|
||
.setTitle(text: Text("Minha App"), subTitle: Text("Tela Principal"))
|
||
.setLeftButton(image: Image(systemName: "line.horizontal.3")) {
|
||
print("Menu pressionado")
|
||
}
|
||
.setRightButton(text: Text(isEditing ? "Concluir" : "Editar")) {
|
||
isEditing.toggle()
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>View+Ext - Extensões SwiftUI</strong></summary>
|
||
|
||
### View+Ext
|
||
|
||
Extensões para Views SwiftUI.
|
||
|
||
#### getTag
|
||
|
||
**Declaração:**
|
||
|
||
```swift
|
||
@available(iOS 13.0, *)
|
||
extension View {
|
||
func getTag<TagType: Hashable>() throws -> TagType
|
||
func extractTag<TagType: Hashable>(_ closure: (() throws -> TagType) -> Void) -> Self
|
||
}
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
struct MyView: View {
|
||
var body: some View {
|
||
Text("Hello")
|
||
.tag("myTag")
|
||
.extractTag { tag in
|
||
print("Tag extraída: \(tag)")
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 🔗 Extensões
|
||
|
||
<details>
|
||
<summary><strong>String - Extensões para String</strong></summary>
|
||
|
||
### String Extensions
|
||
|
||
Extensões poderosas para manipulação de strings.
|
||
|
||
#### Validações
|
||
|
||
**isEmail**
|
||
|
||
```swift
|
||
var isEmail: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let email = "user@exemplo.com"
|
||
if email.isEmail {
|
||
print("Email válido!")
|
||
}
|
||
```
|
||
|
||
**isCPF**
|
||
|
||
```swift
|
||
var isCPF: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let cpf = "12345678901"
|
||
if cpf.isCPF {
|
||
print("CPF válido!")
|
||
}
|
||
```
|
||
|
||
**isValidCNPJ**
|
||
|
||
```swift
|
||
var isValidCNPJ: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let cnpj = "12345678000195"
|
||
if cnpj.isValidCNPJ {
|
||
print("CNPJ válido!")
|
||
}
|
||
```
|
||
|
||
#### Transformações
|
||
|
||
**urlEncoded**
|
||
|
||
```swift
|
||
var urlEncoded: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let text = "Hello World!"
|
||
let encoded = text.urlEncoded
|
||
print(encoded) // "Hello%20World%21"
|
||
```
|
||
|
||
**urlDecoded**
|
||
|
||
```swift
|
||
var urlDecoded: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let encoded = "Hello%20World%21"
|
||
let decoded = encoded.urlDecoded
|
||
print(decoded) // "Hello World!"
|
||
```
|
||
|
||
**base64Encode**
|
||
|
||
```swift
|
||
var base64Encode: String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let text = "Hello World!"
|
||
if let encoded = text.base64Encode {
|
||
print("Base64: \(encoded)")
|
||
}
|
||
```
|
||
|
||
**base64Decode**
|
||
|
||
```swift
|
||
var base64Decode: String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let encoded = "SGVsbG8gV29ybGQh"
|
||
if let decoded = encoded.base64Decode {
|
||
print("Decoded: \(decoded)")
|
||
}
|
||
```
|
||
|
||
#### Limpeza e Filtros
|
||
|
||
**onlyNumbers**
|
||
|
||
```swift
|
||
var onlyNumbers: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let phone = "+55 (11) 99999-9999"
|
||
let numbers = phone.onlyNumbers
|
||
print(numbers) // "5511999999999"
|
||
```
|
||
|
||
**removeSpecialChars**
|
||
|
||
```swift
|
||
var removeSpecialChars: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let text = "Hello@#$%World!"
|
||
let clean = text.removeSpecialChars
|
||
print(clean) // "HelloWorld"
|
||
```
|
||
|
||
**removeHTMLTags**
|
||
|
||
```swift
|
||
var removeHTMLTags: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let html = "<p>Hello <strong>World</strong>!</p>"
|
||
let text = html.removeHTMLTags
|
||
print(text) // "Hello World!"
|
||
```
|
||
|
||
**removeEmoji**
|
||
|
||
```swift
|
||
var removeEmoji: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let text = "Hello 😀 World 🌍!"
|
||
let clean = text.removeEmoji
|
||
print(clean) // "Hello World !"
|
||
```
|
||
|
||
#### Conversões
|
||
|
||
**int**
|
||
|
||
```swift
|
||
var int: Int?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let numberString = "123"
|
||
if let number = numberString.int {
|
||
print("Número: \(number)")
|
||
}
|
||
```
|
||
|
||
**double**
|
||
|
||
```swift
|
||
var double: Double?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let numberString = "123.45"
|
||
if let number = numberString.double {
|
||
print("Número: \(number)")
|
||
}
|
||
```
|
||
|
||
**bool**
|
||
|
||
```swift
|
||
var bool: Bool?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let boolString = "true"
|
||
if let value = boolString.bool {
|
||
print("Valor: \(value)")
|
||
}
|
||
```
|
||
|
||
#### Formatação
|
||
|
||
**applyMask**
|
||
|
||
```swift
|
||
func applyMask(toText: String, mask: String) -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let phone = "11999999999"
|
||
let masked = "".applyMask(toText: phone, mask: "(##) #####-####")
|
||
print(masked) // "(11) 99999-9999"
|
||
```
|
||
|
||
**currencyStringToDouble**
|
||
|
||
```swift
|
||
var currencyStringToDouble: Double
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let currency = "R$ 1.234,56"
|
||
let value = currency.currencyStringToDouble
|
||
print(value) // 1234.56
|
||
```
|
||
|
||
#### Data e Hora
|
||
|
||
**date**
|
||
|
||
```swift
|
||
func date(withCurrFormatt: String = "yyyy-MM-dd HH:mm:ss",
|
||
localeIdentifier: String = "pt-BR",
|
||
timeZone: TimeZone? = TimeZone.current) -> Date?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let dateString = "2023-12-25 15:30:00"
|
||
if let date = dateString.date(withCurrFormatt: "yyyy-MM-dd HH:mm:ss") {
|
||
print("Data: \(date)")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class StringUtils {
|
||
|
||
static func validateUserInput(_ input: String) -> Bool {
|
||
// Remover caracteres especiais
|
||
let cleanInput = input.removeSpecialChars
|
||
|
||
// Verificar se não está vazio
|
||
guard !cleanInput.isEmpty else { return false }
|
||
|
||
// Verificar se contém apenas letras e espaços
|
||
let lettersOnly = cleanInput.lettersWithWhiteSpace
|
||
return lettersOnly == cleanInput
|
||
}
|
||
|
||
static func formatPhoneNumber(_ phone: String) -> String {
|
||
let numbers = phone.onlyNumbers
|
||
return "".applyMask(toText: numbers, mask: "(##) #####-####")
|
||
}
|
||
|
||
static func validateEmail(_ email: String) -> Bool {
|
||
return email.isEmail
|
||
}
|
||
|
||
static func validateCPF(_ cpf: String) -> Bool {
|
||
return cpf.isCPF
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>Date - Extensões para Date</strong></summary>
|
||
|
||
### Date Extensions
|
||
|
||
Extensões completas para manipulação de datas.
|
||
|
||
#### Propriedades
|
||
|
||
**year, month, day, hour, minute, second**
|
||
|
||
```swift
|
||
var year: Int { get set }
|
||
var month: Int { get set }
|
||
var day: Int { get set }
|
||
var hour: Int { get set }
|
||
var minute: Int { get set }
|
||
var second: Int { get set }
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let now = Date()
|
||
print("Ano: \(now.year)")
|
||
print("Mês: \(now.month)")
|
||
print("Dia: \(now.day)")
|
||
print("Hora: \(now.hour)")
|
||
print("Minuto: \(now.minute)")
|
||
print("Segundo: \(now.second)")
|
||
|
||
// Modificar data
|
||
var tomorrow = Date()
|
||
tomorrow.day += 1
|
||
print("Amanhã: \(tomorrow)")
|
||
```
|
||
|
||
#### Verificações
|
||
|
||
**isInToday, isInYesterday, isInTomorrow**
|
||
|
||
```swift
|
||
var isInToday: Bool
|
||
var isInYesterday: Bool
|
||
var isInTomorrow: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let date = Date()
|
||
if date.isInToday {
|
||
print("É hoje!")
|
||
} else if date.isInYesterday {
|
||
print("É ontem!")
|
||
} else if date.isInTomorrow {
|
||
print("É amanhã!")
|
||
}
|
||
```
|
||
|
||
**isInFuture, isInPast**
|
||
|
||
```swift
|
||
var isInFuture: Bool
|
||
var isInPast: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let futureDate = Date().adding(.day, value: 1)
|
||
if futureDate.isInFuture {
|
||
print("Data futura!")
|
||
}
|
||
|
||
let pastDate = Date().adding(.day, value: -1)
|
||
if pastDate.isInPast {
|
||
print("Data passada!")
|
||
}
|
||
```
|
||
|
||
#### Operações
|
||
|
||
**adding**
|
||
|
||
```swift
|
||
func adding(_ component: Calendar.Component, value: Int) -> Date
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let tomorrow = Date().adding(.day, value: 1)
|
||
let nextWeek = Date().adding(.weekOfYear, value: 1)
|
||
let nextMonth = Date().adding(.month, value: 1)
|
||
let nextYear = Date().adding(.year, value: 1)
|
||
```
|
||
|
||
**changing**
|
||
|
||
```swift
|
||
func changing(_ component: Calendar.Component, value: Int) -> Date?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let newDate = Date().changing(.hour, value: 15) // Muda para 15:00
|
||
let newDate2 = Date().changing(.day, value: 25) // Muda para dia 25
|
||
```
|
||
|
||
#### Formatação
|
||
|
||
**string**
|
||
|
||
```swift
|
||
func string(withFormat format: String = "dd/MM/yyyy HH:mm") -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let date = Date()
|
||
print(date.string(withFormat: "dd/MM/yyyy")) // "25/12/2023"
|
||
print(date.string(withFormat: "HH:mm")) // "15:30"
|
||
print(date.string(withFormat: "EEEE, dd 'de' MMMM 'de' yyyy")) // "Segunda-feira, 25 de dezembro de 2023"
|
||
```
|
||
|
||
**dateString, timeString, dateTimeString**
|
||
|
||
```swift
|
||
func dateString(ofStyle style: DateFormatter.Style = .medium) -> String
|
||
func timeString(ofStyle style: DateFormatter.Style = .medium) -> String
|
||
func dateTimeString(ofStyle style: DateFormatter.Style = .medium) -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let date = Date()
|
||
print(date.dateString()) // "25 de dez de 2023"
|
||
print(date.timeString()) // "15:30:00"
|
||
print(date.dateTimeString()) // "25 de dez de 2023 às 15:30:00"
|
||
```
|
||
|
||
#### Nomes
|
||
|
||
**dayName, monthName**
|
||
|
||
```swift
|
||
func dayName(ofStyle style: DayNameStyle = .full) -> String
|
||
func monthName(ofStyle style: MonthNameStyle = .full) -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let date = Date()
|
||
print(date.dayName()) // "Segunda-feira"
|
||
print(date.dayName(ofStyle: .threeLetters)) // "Seg"
|
||
print(date.monthName()) // "Dezembro"
|
||
print(date.monthName(ofStyle: .threeLetters)) // "Dez"
|
||
```
|
||
|
||
#### Comparações
|
||
|
||
**secondsSince, minutesSince, hoursSince, daysSince**
|
||
|
||
```swift
|
||
func secondsSince(_ date: Date) -> Double
|
||
func minutesSince(_ date: Date) -> Double
|
||
func hoursSince(_ date: Date) -> Double
|
||
func daysSince(_ date: Date) -> Double
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let startDate = Date()
|
||
// ... alguma operação ...
|
||
let endDate = Date()
|
||
|
||
let seconds = endDate.secondsSince(startDate)
|
||
let minutes = endDate.minutesSince(startDate)
|
||
let hours = endDate.hoursSince(startDate)
|
||
let days = endDate.daysSince(startDate)
|
||
|
||
print("Passaram \(seconds) segundos")
|
||
print("Passaram \(minutes) minutos")
|
||
print("Passaram \(hours) horas")
|
||
print("Passaram \(days) dias")
|
||
```
|
||
|
||
**isBetween**
|
||
|
||
```swift
|
||
func isBetween(_ startDate: Date, _ endDate: Date, includeBounds: Bool = false) -> Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let startDate = Date().adding(.day, value: -7)
|
||
let endDate = Date().adding(.day, value: 7)
|
||
let checkDate = Date()
|
||
|
||
if checkDate.isBetween(startDate, endDate) {
|
||
print("Data está no intervalo!")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class DateUtils {
|
||
|
||
static func formatRelativeDate(_ date: Date) -> String {
|
||
let now = Date()
|
||
|
||
if date.isInToday {
|
||
return "Hoje às \(date.string(withFormat: "HH:mm"))"
|
||
} else if date.isInYesterday {
|
||
return "Ontem às \(date.string(withFormat: "HH:mm"))"
|
||
} else if date.isInTomorrow {
|
||
return "Amanhã às \(date.string(withFormat: "HH:mm"))"
|
||
} else if date.isInCurrentWeek {
|
||
return date.dayName(ofStyle: .full)
|
||
} else {
|
||
return date.string(withFormat: "dd/MM/yyyy")
|
||
}
|
||
}
|
||
|
||
static func getAge(from birthDate: Date) -> Int {
|
||
let now = Date()
|
||
let age = now.year - birthDate.year
|
||
return age
|
||
}
|
||
|
||
static func isWeekend(_ date: Date) -> Bool {
|
||
return date.isInWeekend
|
||
}
|
||
|
||
static func getBusinessDaysBetween(_ startDate: Date, and endDate: Date) -> Int {
|
||
var currentDate = startDate
|
||
var businessDays = 0
|
||
|
||
while currentDate <= endDate {
|
||
if !currentDate.isInWeekend {
|
||
businessDays += 1
|
||
}
|
||
currentDate = currentDate.adding(.day, value: 1)
|
||
}
|
||
|
||
return businessDays
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>UIView - Extensões para UIView</strong></summary>
|
||
|
||
### UIView Extensions
|
||
|
||
Extensões poderosas para manipulação de views.
|
||
|
||
#### Propriedades
|
||
|
||
**borderColor, borderWidth, cornerRadius**
|
||
|
||
```swift
|
||
var borderColor: UIColor? { get set }
|
||
var borderWidth: CGFloat { get set }
|
||
var cornerRadius: CGFloat { get set }
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let view = UIView()
|
||
view.borderColor = .systemBlue
|
||
view.borderWidth = 2.0
|
||
view.cornerRadius = 8.0
|
||
```
|
||
|
||
**screenshot**
|
||
|
||
```swift
|
||
var screenshot: UIImage?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let screenshot = view.screenshot {
|
||
// Usar screenshot da view
|
||
imageView.image = screenshot
|
||
}
|
||
```
|
||
|
||
#### Constraint Helpers
|
||
|
||
**setConstraintsTo**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func setConstraintsTo(parentView: UIView, anchorType: AnchorType, value: CGFloat, safeArea: Bool = false) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let childView = UIView()
|
||
parentView.addSubview(childView)
|
||
|
||
// Configurar constraints
|
||
childView.setConstraintsTo(parentView, .top, 20, true) // 20pt do topo da safe area
|
||
.setConstraints(.leading, 16)
|
||
.setConstraints(.trailing, -16)
|
||
.setConstraints(.bottom, -20)
|
||
```
|
||
|
||
**setHeight, setWidth**
|
||
|
||
```swift
|
||
@discardableResult
|
||
func setHeight(size: CGFloat) -> Self
|
||
@discardableResult
|
||
func setWidth(size: CGFloat) -> Self
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
view.setHeight(size: 100)
|
||
.setWidth(size: 200)
|
||
```
|
||
|
||
#### Efeitos Visuais
|
||
|
||
**applyShadow**
|
||
|
||
```swift
|
||
func applyShadow(color: UIColor, offSet: CGSize, radius: CGFloat, opacity: Float, shouldRasterize: Bool = true, rasterizationScaleTo: CGFloat = UIScreen.main.scale)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
view.applyShadow(color: .black, offSet: CGSize(width: 0, height: 2), radius: 4, opacity: 0.3)
|
||
```
|
||
|
||
**insertBlurView**
|
||
|
||
```swift
|
||
func insertBlurView(style: UIBlurEffect.Style, color: UIColor = .black, alpha: CGFloat = 0.9)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
view.insertBlurView(style: .dark, color: .black, alpha: 0.8)
|
||
```
|
||
|
||
#### Animações
|
||
|
||
**fadeIn, fadeOut**
|
||
|
||
```swift
|
||
func fadeIn(withDuration duration: TimeInterval = 1.0, withDelay delay: TimeInterval = 0, completionHandler: @escaping (Bool) -> ())
|
||
func fadeOut(withDuration duration: TimeInterval = 1.0, withDelay delay: TimeInterval = 0, completionHandler: @escaping (Bool) -> ())
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
view.fadeIn(withDuration: 0.5) { finished in
|
||
print("Fade in concluído!")
|
||
}
|
||
|
||
view.fadeOut(withDuration: 0.3) { finished in
|
||
print("Fade out concluído!")
|
||
}
|
||
```
|
||
|
||
#### Utilitários
|
||
|
||
**addSubviews**
|
||
|
||
```swift
|
||
func addSubviews(_ subviews: [UIView], translatesAutoresizingMaskIntoConstraints: Bool = false)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let views = [view1, view2, view3]
|
||
parentView.addSubviews(views)
|
||
```
|
||
|
||
**subviews(ofType:)**
|
||
|
||
```swift
|
||
func subviews<T>(ofType _: T.Type) -> [T]
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let buttons = view.subviews(ofType: UIButton.self)
|
||
let labels = view.subviews(ofType: UILabel.self)
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class CustomCardView: UIView {
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setupCard()
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
super.init(coder: coder)
|
||
setupCard()
|
||
}
|
||
|
||
private func setupCard() {
|
||
// Configurar aparência
|
||
backgroundColor = .systemBackground
|
||
cornerRadius = 12
|
||
borderWidth = 1
|
||
borderColor = .systemGray4
|
||
|
||
// Aplicar sombra
|
||
applyShadow(color: .black, offSet: CGSize(width: 0, height: 2), radius: 8, opacity: 0.1)
|
||
|
||
// Configurar constraints se necessário
|
||
setHeight(size: 200)
|
||
}
|
||
|
||
func showWithAnimation() {
|
||
alpha = 0
|
||
fadeIn(withDuration: 0.3) { finished in
|
||
print("Card apareceu!")
|
||
}
|
||
}
|
||
|
||
func hideWithAnimation() {
|
||
fadeOut(withDuration: 0.3) { finished in
|
||
self.removeFromSuperview()
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>UIImage - Extensões para UIImage</strong></summary>
|
||
|
||
### UIImage Extensions
|
||
|
||
Extensões para manipulação de imagens.
|
||
|
||
#### Criação
|
||
|
||
**init(base64String:scale:)**
|
||
|
||
```swift
|
||
convenience init?(base64String: String, scale: CGFloat = 1.0)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let base64String = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
|
||
if let image = UIImage(base64String: base64String) {
|
||
imageView.image = image
|
||
}
|
||
```
|
||
|
||
**init(view:)**
|
||
|
||
```swift
|
||
@MainActor
|
||
convenience init(view: UIView)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let image = UIImage(view: myView)
|
||
```
|
||
|
||
#### Transformações
|
||
|
||
**tintImage**
|
||
|
||
```swift
|
||
func tintImage(color: UIColor) -> UIImage
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let originalImage = UIImage(systemName: "heart.fill")
|
||
let tintedImage = originalImage?.tintImage(color: .red)
|
||
```
|
||
|
||
**resizeImage**
|
||
|
||
```swift
|
||
func resizeImage(newWidth: CGFloat) -> UIImage
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let resizedImage = originalImage.resizeImage(newWidth: 200)
|
||
```
|
||
|
||
**createThumbnail**
|
||
|
||
```swift
|
||
func createThumbnail(_ maxPixelSize: UInt) -> UIImage
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let thumbnail = originalImage.createThumbnail(150)
|
||
```
|
||
|
||
#### Utilitários
|
||
|
||
**isAnimated**
|
||
|
||
```swift
|
||
func isAnimated() -> Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if image.isAnimated() {
|
||
print("É uma imagem animada (GIF)")
|
||
}
|
||
```
|
||
|
||
**imageWithColor**
|
||
|
||
```swift
|
||
func imageWithColor(color: UIColor) -> UIImage
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let coloredImage = UIImage().imageWithColor(color: .systemBlue)
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class ImageProcessor {
|
||
|
||
static func processImage(_ image: UIImage) -> UIImage {
|
||
// Redimensionar se muito grande
|
||
var processedImage = image
|
||
if image.size.width > 1000 {
|
||
processedImage = image.resizeImage(newWidth: 1000)
|
||
}
|
||
|
||
// Criar thumbnail
|
||
let thumbnail = processedImage.createThumbnail(200)
|
||
|
||
return thumbnail
|
||
}
|
||
|
||
static func createColoredIcon(systemName: String, color: UIColor, size: CGSize) -> UIImage? {
|
||
let config = UIImage.SymbolConfiguration(pointSize: size.width, weight: .medium)
|
||
let image = UIImage(systemName: systemName, withConfiguration: config)
|
||
return image?.tintImage(color: color)
|
||
}
|
||
|
||
static func convertViewToImage(_ view: UIView) -> UIImage {
|
||
return UIImage(view: view)
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>UIColor - Extensões para UIColor</strong></summary>
|
||
|
||
### UIColor Extensions
|
||
|
||
Extensões para manipulação de cores.
|
||
|
||
#### Inicialização
|
||
|
||
**init(hex:)**
|
||
|
||
```swift
|
||
convenience init(hex: String)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let color1 = UIColor(hex: "#FF0000") // Vermelho
|
||
let color2 = UIColor(hex: "#00FF00") // Verde
|
||
let color3 = UIColor(hex: "#0000FF") // Azul
|
||
let color4 = UIColor(hex: "#FF0000FF") // Vermelho com alpha
|
||
```
|
||
|
||
#### Propriedades
|
||
|
||
**hexString**
|
||
|
||
```swift
|
||
var hexString: String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let color = UIColor.red
|
||
if let hex = color.hexString {
|
||
print("Hex: \(hex)") // "#FF0000"
|
||
}
|
||
```
|
||
|
||
**redValue, greenValue, blueValue, alphaValue**
|
||
|
||
```swift
|
||
var redValue: CGFloat
|
||
var greenValue: CGFloat
|
||
var blueValue: CGFloat
|
||
var alphaValue: CGFloat
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let color = UIColor(red: 0.5, green: 0.3, blue: 0.8, alpha: 1.0)
|
||
print("Red: \(color.redValue)")
|
||
print("Green: \(color.greenValue)")
|
||
print("Blue: \(color.blueValue)")
|
||
print("Alpha: \(color.alphaValue)")
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class ColorUtils {
|
||
|
||
static func randomColor() -> UIColor {
|
||
let red = CGFloat.random(in: 0...1)
|
||
let green = CGFloat.random(in: 0...1)
|
||
let blue = CGFloat.random(in: 0...1)
|
||
return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
|
||
}
|
||
|
||
static func hexToColor(_ hex: String) -> UIColor? {
|
||
return UIColor(hex: hex)
|
||
}
|
||
|
||
static func colorToHex(_ color: UIColor) -> String? {
|
||
return color.hexString
|
||
}
|
||
|
||
static func createGradientColors(from startColor: UIColor, to endColor: UIColor, steps: Int) -> [UIColor] {
|
||
var colors: [UIColor] = []
|
||
|
||
for i in 0..<steps {
|
||
let ratio = CGFloat(i) / CGFloat(steps - 1)
|
||
let red = startColor.redValue + (endColor.redValue - startColor.redValue) * ratio
|
||
let green = startColor.greenValue + (endColor.greenValue - startColor.greenValue) * ratio
|
||
let blue = startColor.blueValue + (endColor.blueValue - startColor.blueValue) * ratio
|
||
let alpha = startColor.alphaValue + (endColor.alphaValue - startColor.alphaValue) * ratio
|
||
|
||
let color = UIColor(red: red, green: green, blue: blue, alpha: alpha)
|
||
colors.append(color)
|
||
}
|
||
|
||
return colors
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>Array - Extensões para Array</strong></summary>
|
||
|
||
### Array Extensions
|
||
|
||
Extensões para manipulação de arrays.
|
||
|
||
#### Remoção de Duplicatas
|
||
|
||
**unique**
|
||
|
||
```swift
|
||
var unique: [Element]
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let numbers = [1, 2, 2, 3, 3, 3, 4]
|
||
let uniqueNumbers = numbers.unique
|
||
print(uniqueNumbers) // [1, 2, 3, 4]
|
||
```
|
||
|
||
**removeDuplicates**
|
||
|
||
```swift
|
||
@discardableResult
|
||
mutating func removeDuplicates() -> [Element]
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
var numbers = [1, 2, 2, 3, 3, 3, 4]
|
||
numbers.removeDuplicates()
|
||
print(numbers) // [1, 2, 3, 4]
|
||
```
|
||
|
||
**withoutDuplicates**
|
||
|
||
```swift
|
||
func withoutDuplicates() -> [Element]
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let numbers = [1, 2, 2, 3, 3, 3, 4]
|
||
let uniqueNumbers = numbers.withoutDuplicates()
|
||
print(uniqueNumbers) // [1, 2, 3, 4]
|
||
```
|
||
|
||
#### Remoção de Elementos
|
||
|
||
**removeAll**
|
||
|
||
```swift
|
||
@discardableResult
|
||
mutating func removeAll(_ item: Element) -> [Element]
|
||
@discardableResult
|
||
mutating func removeAll(_ items: [Element]) -> [Element]
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
var numbers = [1, 2, 2, 3, 4, 5]
|
||
numbers.removeAll(2)
|
||
print(numbers) // [1, 3, 4, 5]
|
||
|
||
var letters = ["a", "b", "c", "a", "b"]
|
||
letters.removeAll(["a", "b"])
|
||
print(letters) // ["c"]
|
||
```
|
||
|
||
#### Inserção
|
||
|
||
**prepend**
|
||
|
||
```swift
|
||
mutating func prepend(_ newElement: Element)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
var numbers = [2, 3, 4]
|
||
numbers.prepend(1)
|
||
print(numbers) // [1, 2, 3, 4]
|
||
```
|
||
|
||
#### Troca
|
||
|
||
**safeSwap**
|
||
|
||
```swift
|
||
mutating func safeSwap(from index: Index, to otherIndex: Index)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
var numbers = [1, 2, 3, 4, 5]
|
||
numbers.safeSwap(from: 0, to: 4)
|
||
print(numbers) // [5, 2, 3, 4, 1]
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class ArrayUtils {
|
||
|
||
static func removeDuplicates<T: Equatable>(from array: [T]) -> [T] {
|
||
return array.unique
|
||
}
|
||
|
||
static func shuffle<T>(_ array: [T]) -> [T] {
|
||
var shuffled = array
|
||
for i in 0..<shuffled.count {
|
||
let randomIndex = Int.random(in: 0..<shuffled.count)
|
||
shuffled.safeSwap(from: i, to: randomIndex)
|
||
}
|
||
return shuffled
|
||
}
|
||
|
||
static func chunk<T>(_ array: [T], size: Int) -> [[T]] {
|
||
var chunks: [[T]] = []
|
||
for i in stride(from: 0, to: array.count, by: size) {
|
||
let chunk = Array(array[i..<min(i + size, array.count)])
|
||
chunks.append(chunk)
|
||
}
|
||
return chunks
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>Data - Extensões para Data</strong></summary>
|
||
|
||
### Data Extensions
|
||
|
||
Extensões para manipulação de dados.
|
||
|
||
#### Conversões
|
||
|
||
**toHexString**
|
||
|
||
```swift
|
||
var toHexString: String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let data = "Hello".data(using: .utf8)!
|
||
let hex = data.toHexString
|
||
print(hex) // "48656c6c6f"
|
||
```
|
||
|
||
**init(hexString:)**
|
||
|
||
```swift
|
||
init?(hexString: String)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let data = Data(hexString: "48656c6c6f") {
|
||
let string = String(data: data, encoding: .utf8)
|
||
print(string) // "Hello"
|
||
}
|
||
```
|
||
|
||
**bool**
|
||
|
||
```swift
|
||
var bool: Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let trueData = Data([1])
|
||
let falseData = Data([0])
|
||
print(trueData.bool) // true
|
||
print(falseData.bool) // false
|
||
```
|
||
|
||
#### Hash e Criptografia
|
||
|
||
**SHA256**
|
||
|
||
```swift
|
||
func SHA256() -> Data
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let data = "Hello World".data(using: .utf8)!
|
||
let hash = data.SHA256()
|
||
print(hash.toHexString)
|
||
```
|
||
|
||
**SHA512**
|
||
|
||
```swift
|
||
func SHA512() -> Data
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let data = "Hello World".data(using: .utf8)!
|
||
let hash = data.SHA512()
|
||
print(hash.toHexString)
|
||
```
|
||
|
||
**HMACSHA512**
|
||
|
||
```swift
|
||
@available(iOS 13.0, *)
|
||
func HMACSHA512(key: Data) -> Data
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let data = "Hello World".data(using: .utf8)!
|
||
let key = "secret".data(using: .utf8)!
|
||
let hmac = data.HMACSHA512(key: key)
|
||
print(hmac.toHexString)
|
||
```
|
||
|
||
**XOR**
|
||
|
||
```swift
|
||
func XOR(with other: Data) -> Data
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let data1 = "Hello".data(using: .utf8)!
|
||
let data2 = "World".data(using: .utf8)!
|
||
let xor = data1.XOR(with: data2)
|
||
```
|
||
|
||
#### JSON
|
||
|
||
**prettyJson**
|
||
|
||
```swift
|
||
var prettyJson: String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let jsonData = """
|
||
{"name": "John", "age": 30, "city": "New York"}
|
||
""".data(using: .utf8)!
|
||
|
||
if let pretty = jsonData.prettyJson {
|
||
print(pretty)
|
||
// {
|
||
// "name" : "John",
|
||
// "age" : 30,
|
||
// "city" : "New York"
|
||
// }
|
||
}
|
||
```
|
||
|
||
**toDictionay**
|
||
|
||
```swift
|
||
var toDictionay: Dictionary<String, Any>?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let jsonData = """
|
||
{"name": "John", "age": 30}
|
||
""".data(using: .utf8)!
|
||
|
||
if let dict = jsonData.toDictionay {
|
||
print(dict["name"]) // "John"
|
||
print(dict["age"]) // 30
|
||
}
|
||
```
|
||
|
||
**object**
|
||
|
||
```swift
|
||
func object<T: Codable>() -> T?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
struct User: Codable {
|
||
let name: String
|
||
let age: Int
|
||
}
|
||
|
||
let jsonData = """
|
||
{"name": "John", "age": 30}
|
||
""".data(using: .utf8)!
|
||
|
||
if let user: User = jsonData.object() {
|
||
print("Nome: \(user.name), Idade: \(user.age)")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class DataUtils {
|
||
|
||
static func hashString(_ string: String) -> String {
|
||
let data = string.data(using: .utf8)!
|
||
let hash = data.SHA256()
|
||
return hash.toHexString
|
||
}
|
||
|
||
static func createHMAC(message: String, key: String) -> String {
|
||
let messageData = message.data(using: .utf8)!
|
||
let keyData = key.data(using: .utf8)!
|
||
let hmac = messageData.HMACSHA512(key: keyData)
|
||
return hmac.toHexString
|
||
}
|
||
|
||
static func encryptData(_ data: Data, with key: Data) -> Data {
|
||
return data.XOR(with: key)
|
||
}
|
||
|
||
static func decryptData(_ encryptedData: Data, with key: Data) -> Data {
|
||
return encryptedData.XOR(with: key)
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>UIButton - Extensões para UIButton</strong></summary>
|
||
|
||
### UIButton Extensions
|
||
|
||
Extensões para manipulação de botões.
|
||
|
||
#### Propriedades por Estado
|
||
|
||
**imageForNormal, imageForHighlighted, imageForSelected, imageForDisabled**
|
||
|
||
```swift
|
||
var imageForNormal: UIImage? { get set }
|
||
var imageForHighlighted: UIImage? { get set }
|
||
var imageForSelected: UIImage? { get set }
|
||
var imageForDisabled: UIImage? { get set }
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let button = UIButton()
|
||
button.imageForNormal = UIImage(systemName: "heart")
|
||
button.imageForHighlighted = UIImage(systemName: "heart.fill")
|
||
button.imageForSelected = UIImage(systemName: "heart.fill")
|
||
```
|
||
|
||
**titleForNormal, titleForHighlighted, titleForSelected, titleForDisabled**
|
||
|
||
```swift
|
||
var titleForNormal: String? { get set }
|
||
var titleForHighlighted: String? { get set }
|
||
var titleForSelected: String? { get set }
|
||
var titleForDisabled: String? { get set }
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
button.titleForNormal = "Normal"
|
||
button.titleForHighlighted = "Highlighted"
|
||
button.titleForSelected = "Selected"
|
||
button.titleForDisabled = "Disabled"
|
||
```
|
||
|
||
**titleColorForNormal, titleColorForHighlighted, titleColorForSelected, titleColorForDisabled**
|
||
|
||
```swift
|
||
var titleColorForNormal: UIColor? { get set }
|
||
var titleColorForHighlighted: UIColor? { get set }
|
||
var titleColorForSelected: UIColor? { get set }
|
||
var titleColorForDisabled: UIColor? { get set }
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
button.titleColorForNormal = .systemBlue
|
||
button.titleColorForHighlighted = .systemRed
|
||
button.titleColorForSelected = .systemGreen
|
||
button.titleColorForDisabled = .systemGray
|
||
```
|
||
|
||
#### Métodos
|
||
|
||
**setImageForAllStates**
|
||
|
||
```swift
|
||
func setImageForAllStates(_ image: UIImage)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let image = UIImage(systemName: "star.fill")
|
||
button.setImageForAllStates(image)
|
||
```
|
||
|
||
**setTitleForAllStates**
|
||
|
||
```swift
|
||
func setTitleForAllStates(_ title: String)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
button.setTitleForAllStates("Botão")
|
||
```
|
||
|
||
**setTitleColorForAllStates**
|
||
|
||
```swift
|
||
func setTitleColorForAllStates(_ color: UIColor)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
button.setTitleColorForAllStates(.white)
|
||
```
|
||
|
||
**centerTextAndImage**
|
||
|
||
```swift
|
||
func centerTextAndImage(spacing: CGFloat)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
button.centerTextAndImage(spacing: 8)
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class CustomButton: UIButton {
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setupButton()
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
super.init(coder: coder)
|
||
setupButton()
|
||
}
|
||
|
||
private func setupButton() {
|
||
// Configurar imagem para todos os estados
|
||
let image = UIImage(systemName: "heart")
|
||
setImageForAllStates(image)
|
||
|
||
// Configurar título
|
||
setTitleForAllStates("Curtir")
|
||
|
||
// Configurar cores
|
||
titleColorForNormal = .systemBlue
|
||
titleColorForHighlighted = .systemRed
|
||
titleColorForSelected = .systemGreen
|
||
|
||
// Centralizar texto e imagem
|
||
centerTextAndImage(spacing: 8)
|
||
|
||
// Configurar aparência
|
||
backgroundColor = .systemBackground
|
||
layer.cornerRadius = 8
|
||
layer.borderWidth = 1
|
||
layer.borderColor = UIColor.systemBlue.cgColor
|
||
}
|
||
|
||
func setLiked(_ isLiked: Bool) {
|
||
isSelected = isLiked
|
||
titleForSelected = isLiked ? "Curtido" : "Curtir"
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 📱 Helpers
|
||
|
||
<details>
|
||
<summary><strong>Funções de Log</strong></summary>
|
||
|
||
### Funções de Log
|
||
|
||
Sistema completo de logging com diferentes níveis.
|
||
|
||
#### printLog
|
||
```swift
|
||
public func printLog(title: String, msg: Any, prettyPrint: Bool = false)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
printLog(title: "DEBUG", msg: "Mensagem de debug")
|
||
printLog(title: "USER", msg: userData, prettyPrint: true)
|
||
```
|
||
|
||
#### printInfo
|
||
```swift
|
||
public func printInfo(title: String, msg: Any, prettyPrint: Bool = false, function: String = #function, file: String = #file, line: Int = #line, column: Int = #column)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
printInfo(title: "API", msg: "Requisição realizada com sucesso")
|
||
```
|
||
|
||
#### printWarn
|
||
```swift
|
||
public func printWarn(title: String, msg: Any, prettyPrint: Bool = false, function: String = #function, file: String = #file, line: Int = #line, column: Int = #column)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
printWarn(title: "DEPRECATED", msg: "Este método será removido na próxima versão")
|
||
```
|
||
|
||
#### printError
|
||
```swift
|
||
public func printError(title: String, msg: Any, prettyPrint: Bool = false, function: String = #function, file: String = #file, line: Int = #line, column: Int = #column)
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
printError(title: "NETWORK", msg: "Falha na conexão com o servidor")
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class NetworkManager {
|
||
|
||
func fetchData() {
|
||
printInfo(title: "NETWORK", msg: "Iniciando requisição")
|
||
|
||
// Simular requisição
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||
let success = Bool.random()
|
||
|
||
if success {
|
||
printLog(title: "SUCCESS", msg: "Dados carregados com sucesso")
|
||
} else {
|
||
printError(title: "ERROR", msg: "Falha ao carregar dados")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary><strong>Operador de Potência</strong></summary>
|
||
|
||
### Operador de Potência
|
||
|
||
Operador customizado para cálculos de potência.
|
||
|
||
#### Declaração
|
||
```swift
|
||
precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }
|
||
infix operator ^^ : PowerPrecedence
|
||
public func ^^ (radix: Float, power: Float) -> Float
|
||
```
|
||
|
||
#### Uso
|
||
```swift
|
||
let result1 = 2.0 ^^ 3.0 // 8.0 (2³)
|
||
let result2 = 5.0 ^^ 2.0 // 25.0 (5²)
|
||
let result3 = 10.0 ^^ 0.5 // 3.16... (√10)
|
||
|
||
print("2³ = \(result1)")
|
||
print("5² = \(result2)")
|
||
print("√10 = \(result3)")
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 🔐 Criptografia
|
||
|
||
<details>
|
||
<summary><strong>LCECryptoKitManager - Gerenciador de Criptografia</strong></summary>
|
||
|
||
### LCECryptoKitManager
|
||
|
||
Sistema completo de criptografia usando LCECryptoKit.
|
||
|
||
#### Inicialização
|
||
|
||
```swift
|
||
// Sem chave privada
|
||
let cryptoManager = LCECryptoKitManager()
|
||
|
||
// Com chave privada
|
||
let cryptoManager = LCECryptoKitManager(privateKey: "minha_chave_privada")
|
||
```
|
||
|
||
#### Métodos
|
||
|
||
**generateKey**
|
||
|
||
```swift
|
||
public static func generateKey() -> String
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let newKey = LCECryptoKitManager.generateKey()
|
||
print("Nova chave: \(newKey)")
|
||
```
|
||
|
||
**encodeTP**
|
||
|
||
```swift
|
||
public func encodeTP(email: String, password: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let encoded = cryptoManager.encodeTP(email: "user@exemplo.com", password: "senha123") {
|
||
print("Dados codificados: \(encoded)")
|
||
}
|
||
```
|
||
|
||
**decodeOTP**
|
||
|
||
```swift
|
||
public func decodeOTP(_ otpHash: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let decoded = cryptoManager.decodeOTP("hash_codificado") {
|
||
print("Dados decodificados: \(decoded)")
|
||
}
|
||
```
|
||
|
||
**encodeOTPWithKey**
|
||
|
||
```swift
|
||
public func encodeOTPWithKey(email: String, password: String) -> String?
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
if let encoded = cryptoManager.encodeOTPWithKey(email: "user@exemplo.com", password: "senha123") {
|
||
print("Dados codificados com chave: \(encoded)")
|
||
}
|
||
```
|
||
|
||
**decodeOTPWithKey**
|
||
|
||
```swift
|
||
public func decodeOTPWithKey(_ otpHash: String) -> Bool
|
||
```
|
||
|
||
**Uso:**
|
||
|
||
```swift
|
||
let isValid = cryptoManager.decodeOTPWithKey("hash_codificado")
|
||
if isValid {
|
||
print("Hash válido!")
|
||
} else {
|
||
print("Hash inválido!")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class CryptoService {
|
||
private let cryptoManager: LCECryptoKitManager
|
||
|
||
init(privateKey: String? = nil) {
|
||
if let key = privateKey {
|
||
cryptoManager = LCECryptoKitManager(privateKey: key)
|
||
} else {
|
||
cryptoManager = LCECryptoKitManager()
|
||
}
|
||
}
|
||
|
||
func encryptUserData(email: String, password: String) -> String? {
|
||
return cryptoManager.encodeTP(email: email, password: password)
|
||
}
|
||
|
||
func decryptUserData(_ hash: String) -> String? {
|
||
return cryptoManager.decodeOTP(hash)
|
||
}
|
||
|
||
func validateHash(_ hash: String) -> Bool {
|
||
return cryptoManager.decodeOTPWithKey(hash)
|
||
}
|
||
|
||
static func generateNewKey() -> String {
|
||
return LCECryptoKitManager.generateKey()
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 🌐 API & Networking
|
||
|
||
<details>
|
||
<summary><strong>API - Sistema de Requisições HTTP</strong></summary>
|
||
|
||
### API
|
||
|
||
Sistema completo para requisições HTTP com suporte a certificados, cache e retry automático.
|
||
|
||
#### Configuração
|
||
|
||
```swift
|
||
// Configurar parâmetros padrão
|
||
API.defaultParams = ["api_key": "sua_chave_aqui"]
|
||
|
||
// Configurar certificado cliente
|
||
let certData = Data(contentsOf: Bundle.main.url(forResource: "client", withExtension: "p12")!)
|
||
API.shared.setupCertificationRequest(certData: certData, password: "senha_do_certificado")
|
||
```
|
||
|
||
#### Método Principal
|
||
|
||
**request**
|
||
|
||
```swift
|
||
public func request<T: Codable>(url: String,
|
||
params: Any? = nil,
|
||
method: httpMethod,
|
||
headers: [String: String] = [:],
|
||
jsonEncoding: Bool = true,
|
||
debug: Bool = true,
|
||
timeoutInterval: TimeInterval = 30,
|
||
networkServiceType: URLRequest.NetworkServiceType = .default,
|
||
persistConnection: Bool = false) async throws -> T
|
||
```
|
||
|
||
#### Exemplos de Uso
|
||
|
||
**GET Request:**
|
||
|
||
```swift
|
||
struct User: Codable {
|
||
let id: Int
|
||
let name: String
|
||
let email: String
|
||
}
|
||
|
||
do {
|
||
let users: [User] = try await API.shared.request(
|
||
url: "https://api.exemplo.com/users",
|
||
method: .get,
|
||
headers: ["Authorization": "Bearer token_aqui"]
|
||
)
|
||
print("Usuários: \(users)")
|
||
} catch {
|
||
print("Erro: \(error)")
|
||
}
|
||
```
|
||
|
||
**POST Request:**
|
||
|
||
```swift
|
||
struct LoginRequest: Codable {
|
||
let email: String
|
||
let password: String
|
||
}
|
||
|
||
struct LoginResponse: Codable {
|
||
let token: String
|
||
let user: User
|
||
}
|
||
|
||
do {
|
||
let loginData = LoginRequest(email: "user@exemplo.com", password: "senha123")
|
||
let response: LoginResponse = try await API.shared.request(
|
||
url: "https://api.exemplo.com/login",
|
||
params: loginData,
|
||
method: .post
|
||
)
|
||
print("Token: \(response.token)")
|
||
} catch {
|
||
print("Erro no login: \(error)")
|
||
}
|
||
```
|
||
|
||
**Upload de Arquivo:**
|
||
|
||
```swift
|
||
let fileURL = URL(fileURLWithPath: "/path/to/image.jpg")
|
||
let params = [
|
||
"title": "Minha Imagem",
|
||
"description": "Descrição da imagem",
|
||
"file": fileURL.absoluteString
|
||
]
|
||
|
||
do {
|
||
let response: [String: Any] = try await API.shared.request(
|
||
url: "https://api.exemplo.com/upload",
|
||
params: params,
|
||
method: .post
|
||
)
|
||
print("Upload realizado: \(response)")
|
||
} catch {
|
||
print("Erro no upload: \(error)")
|
||
}
|
||
```
|
||
|
||
**Com Retry Automático:**
|
||
|
||
```swift
|
||
do {
|
||
let data: MyResponse = try await API.shared.request(
|
||
url: "https://api.exemplo.com/data",
|
||
method: .get,
|
||
persistConnection: true // Habilita retry automático
|
||
)
|
||
} catch {
|
||
print("Erro após tentativas: \(error)")
|
||
}
|
||
```
|
||
|
||
#### Exemplo Completo
|
||
|
||
```swift
|
||
class APIService {
|
||
|
||
func fetchUsers() async throws -> [User] {
|
||
return try await API.shared.request(
|
||
url: "https://api.exemplo.com/users",
|
||
method: .get,
|
||
headers: ["Authorization": "Bearer \(getToken())"]
|
||
)
|
||
}
|
||
|
||
func createUser(_ user: User) async throws -> User {
|
||
return try await API.shared.request(
|
||
url: "https://api.exemplo.com/users",
|
||
params: user,
|
||
method: .post
|
||
)
|
||
}
|
||
|
||
func uploadImage(_ imageData: Data, filename: String) async throws -> [String: Any] {
|
||
let params = [
|
||
"filename": filename,
|
||
"data": imageData.base64EncodedString()
|
||
]
|
||
|
||
return try await API.shared.request(
|
||
url: "https://api.exemplo.com/upload",
|
||
params: params,
|
||
method: .post
|
||
)
|
||
}
|
||
|
||
private func getToken() -> String {
|
||
// Implementar lógica de obtenção de token
|
||
return "seu_token_aqui"
|
||
}
|
||
}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
|
||
## 📝 Conclusão
|
||
|
||
O **LCEssentials** é uma biblioteca completa e poderosa que oferece:
|
||
|
||
- ✅ **50+ Extensões** para tipos fundamentais do Swift/UIKit
|
||
- ✅ **Componentes UI** prontos para uso (SnackBar, ImagePicker, ImageZoom)
|
||
- ✅ **Suporte SwiftUI** com componentes customizados
|
||
- ✅ **Sistema de API** completo com retry automático e certificados
|
||
- ✅ **Criptografia** integrada com LCECryptoKit
|
||
- ✅ **Helpers** e utilitários para desenvolvimento iOS
|
||
- ✅ **Logging** avançado com diferentes níveis
|
||
- ✅ **Cache** inteligente para downloads
|
||
- ✅ **Validações** para CPF, CNPJ, Email, etc.
|
||
|
||
### 🚀 Começando
|
||
|
||
1. **Instale** via Swift Package Manager
|
||
2. **Importe** `import LCEssentials`
|
||
3. **Use** as extensões e componentes conforme necessário
|
||
|
||
### 📚 Recursos Adicionais
|
||
|
||
- **Documentação completa** com exemplos práticos
|
||
- **Suporte** para iOS 13+, macOS 10.15+, tvOS 13+, watchOS 6+
|
||
- **Código aberto** e mantido pela Loverde Co.
|
||
- **Atualizações** regulares com novas funcionalidades
|
||
|
||
---
|
||
|
||
**Desenvolvido com ❤️ pela [Loverde Co.](https://loverde.com.br)**
|
||
|
||
*Para dúvidas ou sugestões, entre em contato: daniel@loverde.com.br*
|