Files
e-party-iOS/yana/MVVM/CommonComponents.swift
edwinQQQ 428aa95c5e feat: 更新Swift助手样式规则和应用结构
- 在swift-assistant-style.mdc中添加项目背景、代码结构、命名规范、Swift最佳实践、UI开发、性能、安全性、测试与质量、核心功能、开发流程、App Store指南等详细规则。
- 在yanaApp.swift中将SplashView替换为Splash,简化应用结构。
2025-08-06 14:12:20 +08:00

201 lines
6.8 KiB
Swift

import SwiftUI
// MARK: -
struct LoginBackgroundView: View {
var body: some View {
Image("bg")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea(.all)
}
}
// MARK: -
struct LoginHeaderView: View {
let onBack: () -> Void
var body: some View {
HStack {
Button(action: onBack) {
Image(systemName: "chevron.left")
.font(.system(size: 24, weight: .medium))
.foregroundColor(.white)
.frame(width: 44, height: 44)
}
Spacer()
}
.padding(.horizontal, 16)
.padding(.top, 8)
}
}
// MARK: -
enum InputFieldType {
case text
case number
case password
case verificationCode
}
struct CustomInputField: View {
let type: InputFieldType
let placeholder: String
let text: Binding<String>
let isPasswordVisible: Binding<Bool>?
let onGetCode: (() -> Void)?
let isCodeButtonEnabled: Bool
let isCodeLoading: Bool
let getCodeButtonText: String
init(
type: InputFieldType,
placeholder: String,
text: Binding<String>,
isPasswordVisible: Binding<Bool>? = nil,
onGetCode: (() -> Void)? = nil,
isCodeButtonEnabled: Bool = false,
isCodeLoading: Bool = false,
getCodeButtonText: String = ""
) {
self.type = type
self.placeholder = placeholder
self.text = text
self.isPasswordVisible = isPasswordVisible
self.onGetCode = onGetCode
self.isCodeButtonEnabled = isCodeButtonEnabled
self.isCodeLoading = isCodeLoading
self.getCodeButtonText = getCodeButtonText
}
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 25)
.fill(Color.white.opacity(0.1))
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white.opacity(0.3), lineWidth: 1)
)
.frame(height: 56)
HStack {
//
Group {
switch type {
case .text, .number:
TextField("", text: text)
.placeholder(when: text.wrappedValue.isEmpty) {
Text(placeholder)
.foregroundColor(.white.opacity(0.6))
}
.keyboardType(type == .number ? .numberPad : .default)
case .password:
if let isPasswordVisible = isPasswordVisible {
if isPasswordVisible.wrappedValue {
TextField("", text: text)
.placeholder(when: text.wrappedValue.isEmpty) {
Text(placeholder)
.foregroundColor(.white.opacity(0.6))
}
} else {
SecureField("", text: text)
.placeholder(when: text.wrappedValue.isEmpty) {
Text(placeholder)
.foregroundColor(.white.opacity(0.6))
}
}
}
case .verificationCode:
TextField("", text: text)
.placeholder(when: text.wrappedValue.isEmpty) {
Text(placeholder)
.foregroundColor(.white.opacity(0.6))
}
.keyboardType(.numberPad)
}
}
.foregroundColor(.white)
.font(.system(size: 16))
//
if type == .password, let isPasswordVisible = isPasswordVisible {
Button(action: {
isPasswordVisible.wrappedValue.toggle()
}) {
Image(systemName: isPasswordVisible.wrappedValue ? "eye.slash" : "eye")
.foregroundColor(.white.opacity(0.7))
.font(.system(size: 18))
}
} else if type == .verificationCode, let onGetCode = onGetCode {
Button(action: onGetCode) {
ZStack {
if isCodeLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(0.7)
} else {
Text(getCodeButtonText)
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
}
}
.frame(width: 60, height: 36)
.background(
RoundedRectangle(cornerRadius: 15)
.fill(Color.white.opacity(isCodeButtonEnabled ? 0.2 : 0.1))
)
}
.disabled(!isCodeButtonEnabled || isCodeLoading)
}
}
.padding(.horizontal, 24)
}
}
}
// MARK: -
struct LoginButtonView: View {
let isLoading: Bool
let isEnabled: Bool
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
Group {
if isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.scaleEffect(1.2)
} else {
Text("Login")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
}
}
}
.frame(maxWidth: .infinity)
.padding(.vertical, 16)
.background(isEnabled ? Color(red: 0.5, green: 0.3, blue: 0.8) : Color.gray)
.cornerRadius(8)
.disabled(!isEnabled)
}
}
#Preview {
VStack(spacing: 20) {
LoginBackgroundView()
LoginHeaderView(onBack: {})
CustomInputField(
type: .text,
placeholder: "Test Input",
text: .constant("")
)
LoginButtonView(
isLoading: false,
isEnabled: true,
onTap: {}
)
}
}