add swiftUI code
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// ChatViewControllerWrapper.swift
|
||||
// SFI
|
||||
//
|
||||
// Created by Mac on 2024/10/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
import Crisp
|
||||
|
||||
// Step 2: Create a SwiftUI wrapper for ChatViewController
|
||||
struct ChatViewControllerWrapper: UIViewControllerRepresentable {
|
||||
|
||||
// Initialize any properties needed to pass to ChatViewController
|
||||
typealias UIViewControllerType = ChatViewController
|
||||
|
||||
func makeUIViewController(context: Context) -> ChatViewController {
|
||||
// Return the ChatViewController
|
||||
let chatViewController = ChatViewController()
|
||||
return chatViewController
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: ChatViewController, context: Context) {
|
||||
// Update the view controller when needed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// CustomCorners.swift
|
||||
// CustomCorners
|
||||
//
|
||||
// Created by Balaji on 12/09/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CustomCorners: Shape {
|
||||
|
||||
var radius: CGFloat
|
||||
var corners: UIRectCorner
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
|
||||
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
|
||||
|
||||
return Path(path.cgPath)
|
||||
}
|
||||
}
|
||||
|
||||
func getSafeAreaInsets() -> UIEdgeInsets {
|
||||
let windowScene = UIApplication.shared.connectedScenes
|
||||
.filter({ $0.activationState == .foregroundActive })
|
||||
.map({ $0 as? UIWindowScene })
|
||||
.compactMap({ $0 })
|
||||
.first
|
||||
|
||||
guard let keyWindow = windowScene?.windows.filter({ $0.isKeyWindow }).first else {
|
||||
return .zero
|
||||
}
|
||||
|
||||
return keyWindow.safeAreaInsets
|
||||
}
|
||||
|
||||
|
||||
func getRect() -> CGRect {
|
||||
return UIScreen.main.bounds
|
||||
}
|
||||
@ViewBuilder
|
||||
func BackgroundBg()->some View{
|
||||
|
||||
|
||||
|
||||
ZStack{
|
||||
|
||||
LinearGradient(colors: [
|
||||
|
||||
Color("BG1"),
|
||||
Color("BG1"),
|
||||
Color("BG2"),
|
||||
Color("BG2"),
|
||||
|
||||
], startPoint: .top, endPoint: .bottom)
|
||||
|
||||
|
||||
// Little Planet and little stars....
|
||||
Image("mars")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 30, height: 30)
|
||||
.scaleEffect(getRect().height < 750 ? 0.8 : 1)
|
||||
// not using offset...
|
||||
// using postiton..
|
||||
// this will position the object using screen basis...
|
||||
.position(x: 50, y: getRect().height < 750 ? 200 : 220)
|
||||
.opacity(0.7)
|
||||
|
||||
// Sample star points....
|
||||
let stars: [CGPoint] = [
|
||||
|
||||
CGPoint(x: 15, y: 190),
|
||||
CGPoint(x: 25, y: 250),
|
||||
CGPoint(x: 20, y: 350),
|
||||
CGPoint(x: getRect().width - 30, y: 240),
|
||||
]
|
||||
|
||||
ForEach(stars,id: \.x){star in
|
||||
|
||||
Circle()
|
||||
.fill(.white.opacity(0.3))
|
||||
.frame(width: 5, height: 5)
|
||||
.position(star)
|
||||
.offset(y: getRect().height < 750 ? -20 : 0)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// HTMLTextView.swift
|
||||
// SFI
|
||||
//
|
||||
// Created by Mac on 2024/10/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
struct HTMLTextView: UIViewRepresentable {
|
||||
let htmlString: String
|
||||
|
||||
func makeUIView(context: Context) -> UITextView {
|
||||
let textView = UITextView()
|
||||
textView.isEditable = false
|
||||
textView.isScrollEnabled = true
|
||||
textView.backgroundColor = .clear
|
||||
return textView
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UITextView, context: Context) {
|
||||
guard let data = htmlString.data(using: .utf8) else { return }
|
||||
do {
|
||||
|
||||
let attributedString = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
|
||||
uiView.attributedText = attributedString
|
||||
} catch {
|
||||
print("Error loading HTML: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// CustomTF.swift
|
||||
// LoginKit
|
||||
//
|
||||
// Created by Balaji 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 Balaji 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 Balaji 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// LottieView.swift
|
||||
// VPNUI
|
||||
//
|
||||
// Created by Mac on 2024/9/26.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
//import Lottie
|
||||
import SwiftUI
|
||||
import Lottie
|
||||
|
||||
struct LottieView: UIViewRepresentable {
|
||||
|
||||
var animationFileName: String
|
||||
let loopMode: LottieLoopMode
|
||||
|
||||
func updateUIView(_ uiView: UIViewType, context: Context) {
|
||||
|
||||
}
|
||||
|
||||
func makeUIView(context: Context) -> Lottie.LottieAnimationView {
|
||||
let animationView = LottieAnimationView(name: animationFileName)
|
||||
animationView.loopMode = loopMode
|
||||
animationView.play()
|
||||
animationView.contentMode = .scaleAspectFit
|
||||
|
||||
return animationView
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Unitity.swift
|
||||
// SFI
|
||||
//
|
||||
// Created by Mac on 2024/10/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TimestampConverter {
|
||||
|
||||
// Function to convert a timestamp to a formatted date string
|
||||
static func convertTimestampToDateString(_ timestamp: Int, format: String = "yyyy-MM-dd HH:mm:ss") -> String {
|
||||
let timeInterval = TimeInterval(timestamp)
|
||||
let date = Date(timeIntervalSince1970: timeInterval)
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = format
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// UniversalAlert.swift
|
||||
// CustomUniversalAlert
|
||||
//
|
||||
// Created by Balaji Venkatesh on 18/09/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// Alert Config
|
||||
struct AlertConfig {
|
||||
fileprivate var enableBackgroundBlur: Bool = true
|
||||
fileprivate var disableOutsideTap: Bool = true
|
||||
fileprivate var transitionType: TransitionType = .slide
|
||||
fileprivate var slideEdge: Edge = .bottom
|
||||
fileprivate var show: Bool = false
|
||||
fileprivate var showView: Bool = false
|
||||
|
||||
init(enableBackgroundBlur: Bool = true, disableOutsideTap: Bool = true, transitionType: TransitionType = .slide, slideEdge: Edge = .bottom) {
|
||||
self.enableBackgroundBlur = enableBackgroundBlur
|
||||
self.disableOutsideTap = disableOutsideTap
|
||||
self.transitionType = transitionType
|
||||
self.slideEdge = slideEdge
|
||||
}
|
||||
|
||||
/// TransitionType
|
||||
enum TransitionType {
|
||||
case slide
|
||||
case opacity
|
||||
}
|
||||
|
||||
/// Alert Present/Dismiss Methods
|
||||
mutating
|
||||
func present() {
|
||||
show = true
|
||||
}
|
||||
|
||||
mutating
|
||||
func dismiss() {
|
||||
show = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fileprivate struct AlertView<Content: View>: View {
|
||||
@Binding var config: AlertConfig
|
||||
/// View Tag
|
||||
var tag: Int
|
||||
@ViewBuilder var content: () -> Content
|
||||
/// View Properties
|
||||
@State private var showView: Bool = false
|
||||
var body: some View {
|
||||
GeometryReader(content: { geometry in
|
||||
if showView && config.transitionType == .slide {
|
||||
content()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.transition(.move(edge: config.slideEdge))
|
||||
} else {
|
||||
content()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.opacity(showView ? 1 : 0)
|
||||
}
|
||||
})
|
||||
.background {
|
||||
ZStack {
|
||||
if config.enableBackgroundBlur {
|
||||
Rectangle()
|
||||
.fill(.ultraThinMaterial)
|
||||
} else {
|
||||
Rectangle()
|
||||
.fill(.primary.opacity(0.25))
|
||||
}
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.contentShape(.rect)
|
||||
.onTapGesture {
|
||||
if !config.disableOutsideTap {
|
||||
config.dismiss()
|
||||
}
|
||||
}
|
||||
.opacity(showView ? 1 : 0)
|
||||
}
|
||||
.onAppear(perform: {
|
||||
config.showView = true
|
||||
})
|
||||
// .onChange(of: config.showView) { oldValue, newValue in
|
||||
// withAnimation(.smooth(duration: 0.35, extraBounce: 0)) {
|
||||
// showView = newValue
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// View+Extensions.swift
|
||||
// LoginKit
|
||||
//
|
||||
// Created by Balaji on 04/08/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// Custom SwiftUI View Extensions
|
||||
extension View {
|
||||
/// View Alignments
|
||||
@ViewBuilder
|
||||
func hSpacing(_ alignment: Alignment = .center) -> some View {
|
||||
self
|
||||
.frame(maxWidth: .infinity, alignment: alignment)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func vSpacing(_ alignment: Alignment = .center) -> some View {
|
||||
self
|
||||
.frame(maxHeight: .infinity, alignment: alignment)
|
||||
}
|
||||
|
||||
/// Disable With Opacity
|
||||
@ViewBuilder
|
||||
func disableWithOpacity(_ condition: Bool) -> some View {
|
||||
self
|
||||
.disabled(condition)
|
||||
.opacity(condition ? 0.5 : 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extedning View to get Screen Size and Frame....
|
||||
extension View{
|
||||
|
||||
func getRect()->CGRect{
|
||||
UIScreen.main.bounds
|
||||
}
|
||||
|
||||
func getSafeArea()->UIEdgeInsets{
|
||||
guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else{
|
||||
return .zero
|
||||
}
|
||||
|
||||
guard let safeArea = screen.windows.first?.safeAreaInsets else{
|
||||
return .zero
|
||||
}
|
||||
|
||||
return safeArea
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Text {
|
||||
init(_ attributedString: NSAttributedString) {
|
||||
self.init("") // initial, empty Text
|
||||
|
||||
// scan the attributed string for distinctly attributed regions
|
||||
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length),
|
||||
options: []) { (attrs, range, _) in
|
||||
let string = attributedString.attributedSubstring(from: range).string
|
||||
var text = Text(string)
|
||||
|
||||
// then, read applicable attributes and apply them to the Text
|
||||
|
||||
if let font = attrs[.font] as? UIFont {
|
||||
// this takes care of the majority of formatting - text size, font family,
|
||||
// font weight, if it's italic, etc.
|
||||
text = text.font(.init(font))
|
||||
}
|
||||
|
||||
if let color = attrs[.foregroundColor] as? UIColor {
|
||||
text = text.foregroundColor(Color(color))
|
||||
}
|
||||
|
||||
if let kern = attrs[.kern] as? CGFloat {
|
||||
text = text.kerning(kern)
|
||||
}
|
||||
|
||||
if #available(iOS 14.0, *) {
|
||||
if let tracking = attrs[.tracking] as? CGFloat {
|
||||
text = text.tracking(tracking)
|
||||
}
|
||||
}
|
||||
|
||||
if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
|
||||
strikethroughStyle != 0 {
|
||||
if let strikethroughColor = (attrs[.strikethroughColor] as? UIColor) {
|
||||
text = text.strikethrough(true, color: Color(strikethroughColor))
|
||||
} else {
|
||||
text = text.strikethrough(true)
|
||||
}
|
||||
}
|
||||
|
||||
if let underlineStyle = attrs[.underlineStyle] as? NSNumber,
|
||||
underlineStyle != 0 {
|
||||
if let underlineColor = (attrs[.underlineColor] as? UIColor) {
|
||||
text = text.underline(true, color: Color(underlineColor))
|
||||
} else {
|
||||
text = text.underline(true)
|
||||
}
|
||||
}
|
||||
|
||||
if let baselineOffset = attrs[.baselineOffset] as? NSNumber {
|
||||
text = text.baselineOffset(CGFloat(baselineOffset.floatValue))
|
||||
}
|
||||
|
||||
// append the newly styled subtext to the rest of the text
|
||||
self = self + text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Text {
|
||||
init(html htmlString: String, // the HTML-formatted string
|
||||
raw: Bool = false, // set to true if you don't want to embed in the doc skeleton
|
||||
size: CGFloat? = nil, // optional document-wide text size
|
||||
fontFamily: String = "-apple-system") { // optional document-wide font family
|
||||
let fullHTML: String
|
||||
if raw {
|
||||
fullHTML = htmlString
|
||||
} else {
|
||||
var sizeCss = ""
|
||||
if let size = size {
|
||||
sizeCss = "font-size: \(size)px;"
|
||||
}
|
||||
fullHTML = """
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: \(fontFamily);
|
||||
\(sizeCss)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
\(htmlString)
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
}
|
||||
let attributedString: NSAttributedString
|
||||
if let data = fullHTML.data(using: .unicode),
|
||||
let attrString = try? NSAttributedString(data: data,
|
||||
options: [.documentType: NSAttributedString.DocumentType.html],
|
||||
documentAttributes: nil) {
|
||||
attributedString = attrString
|
||||
} else {
|
||||
attributedString = NSAttributedString()
|
||||
}
|
||||
|
||||
self.init(attributedString) // uses the NSAttributedString initializer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public extension View {
|
||||
// 扩展 View 以提供隐藏键盘的功能
|
||||
func hideKeyboard() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
func transparentScrolling() -> some View {
|
||||
if #available(iOS 16.0, *) {
|
||||
return scrollContentBackground(.hidden)
|
||||
} else {
|
||||
return onAppear {
|
||||
UITextView.appearance().backgroundColor = .clear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TriangleShape: Shape {
|
||||
func path(in rect: CGRect) -> Path {
|
||||
var path = Path()
|
||||
path.move(to: CGPoint(x: rect.minX, y: rect.minY))
|
||||
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
|
||||
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
|
||||
path.closeSubpath()
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user