Add CI/CD configuration and API documentation
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// CustomTF.swift
|
||||
// LoginKit
|
||||
//
|
||||
// Created by zues on 04/08/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CustomTF: View {
|
||||
var sfIcon: String
|
||||
var iconTint: Color = .gray
|
||||
var hint: String
|
||||
/// Hides TextField
|
||||
var isPassword: Bool = false
|
||||
var hasDriveLine: Bool = true
|
||||
|
||||
|
||||
@Binding var value: String
|
||||
/// View Properties
|
||||
@State private var showPassword: Bool = false
|
||||
/// When Switching Between Hide/Reveal Password Field, The Keyboard is Closing, to avoid that using the FocusState
|
||||
@FocusState private var passwordState: HideState?
|
||||
|
||||
enum HideState {
|
||||
case hide
|
||||
case reveal
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top, spacing: 8, content: {
|
||||
Image(systemName: sfIcon)
|
||||
.foregroundStyle(iconTint)
|
||||
/// Since I Need Same Width to Align TextFields Equally
|
||||
.frame(width: 30)
|
||||
/// Slightly Bringing Down
|
||||
.offset(y: 2)
|
||||
|
||||
VStack(alignment: .leading, spacing: 8, content: {
|
||||
if isPassword {
|
||||
Group {
|
||||
/// Revealing Password when users wants to show Password
|
||||
if showPassword {
|
||||
TextField(hint, text: $value)
|
||||
.focused($passwordState, equals: .reveal)
|
||||
} else {
|
||||
SecureField(hint, text: $value)
|
||||
.focused($passwordState, equals: .hide)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TextField(hint, text: $value)
|
||||
}
|
||||
|
||||
if hasDriveLine {
|
||||
Divider()
|
||||
}
|
||||
|
||||
})
|
||||
.overlay(alignment: .trailing) {
|
||||
/// Password Reveal Button
|
||||
if isPassword {
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
showPassword.toggle()
|
||||
}
|
||||
passwordState = showPassword ? .reveal : .hide
|
||||
}, label: {
|
||||
Image(systemName: showPassword ? "eye.slash" : "eye")
|
||||
.foregroundStyle(.gray)
|
||||
.padding(10)
|
||||
.contentShape(.rect)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// GradientButton.swift
|
||||
// LoginKit
|
||||
//
|
||||
// Created by zues on 04/08/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GradientButton: View {
|
||||
var title: String
|
||||
var icon: String
|
||||
var onClick: () -> ()
|
||||
var body: some View {
|
||||
Button(action: onClick, label: {
|
||||
HStack(spacing: 15) {
|
||||
Text(title)
|
||||
Image(systemName: icon)
|
||||
}
|
||||
////.fontWeight(.bold)
|
||||
.foregroundStyle(.white)
|
||||
.padding(.vertical, 12)
|
||||
.padding(.horizontal, 35)
|
||||
.background(.linearGradient(colors: [.main, .main2, ], startPoint: .top, endPoint: .bottom), in: .capsule)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// OTPVerificationView.swift
|
||||
// AutoOtpTF
|
||||
//
|
||||
// Created by zues on 23/12/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct OTPVerificationView: View {
|
||||
/// - View Properties
|
||||
@Binding var otpText: String
|
||||
/// - Keyboard State
|
||||
@FocusState private var isKeyboardShowing: Bool
|
||||
var body: some View {
|
||||
HStack(spacing: 0){
|
||||
/// - OTP Text Boxes
|
||||
/// Change Count Based on your OTP Text Size
|
||||
ForEach(0..<6,id: \.self){index in
|
||||
OTPTextBox(index)
|
||||
}
|
||||
}
|
||||
.background(content: {
|
||||
TextField("", text: $otpText.limit(6))
|
||||
.keyboardType(.numberPad)
|
||||
.textContentType(.oneTimeCode)
|
||||
/// - Hiding it Out
|
||||
.frame(width: 1, height: 1)
|
||||
.opacity(0.001)
|
||||
.blendMode(.screen)
|
||||
.focused($isKeyboardShowing)
|
||||
})
|
||||
.contentShape(Rectangle())
|
||||
/// - Opening Keyboard When Tapped
|
||||
.onTapGesture {
|
||||
isKeyboardShowing = true
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .keyboard) {
|
||||
Button("Done"){
|
||||
isKeyboardShowing = false
|
||||
}
|
||||
.tint(.white)
|
||||
////.fontWeight(.heavy)
|
||||
.hSpacing(.trailing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: OTP Text Box
|
||||
@ViewBuilder
|
||||
func OTPTextBox(_ index: Int)->some View{
|
||||
ZStack{
|
||||
if otpText.count > index{
|
||||
/// - Finding Char At Index
|
||||
let startIndex = otpText.startIndex
|
||||
let charIndex = otpText.index(startIndex, offsetBy: index)
|
||||
let charToString = String(otpText[charIndex])
|
||||
Text(charToString)
|
||||
}else{
|
||||
Text(" ")
|
||||
}
|
||||
}
|
||||
.frame(width: 45, height: 45)
|
||||
.background {
|
||||
/// - Highlighting Current Active Box
|
||||
let status = (isKeyboardShowing && otpText.count == index)
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.stroke(status ? .main : Color.gray,lineWidth: status ? 3 : 0.5)
|
||||
/// - Adding Animation
|
||||
.animation(.easeInOut(duration: 0.2), value: isKeyboardShowing)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Binding <String> Extension
|
||||
extension Binding where Value == String{
|
||||
func limit(_ length: Int)->Self{
|
||||
if self.wrappedValue.count > length{
|
||||
DispatchQueue.main.async {
|
||||
self.wrappedValue = String(self.wrappedValue.prefix(length))
|
||||
}
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user