This commit is contained in:
anlicheng 2026-03-20 00:33:02 +08:00
parent 81ae103730
commit 41cacb7134
3 changed files with 154 additions and 39 deletions

View File

@ -9,6 +9,8 @@ import SwiftUI
struct SettingsAboutView: View {
@Environment(\.openURL) private var openURL
@State private var isShowingFeedbackSheet = false
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 32) {
@ -64,9 +66,7 @@ struct SettingsAboutView: View {
.foregroundColor(.secondary)
}
.onTapGesture {
if let url = URL(string: "https://yourfeedbacklink.com") {
openURL(url)
}
self.isShowingFeedbackSheet = true
}
}
.background(Color.primary.opacity(0.03))
@ -108,7 +108,24 @@ struct SettingsAboutView: View {
.padding(.leading, 4)
}
.padding(32)
.frame(maxWidth: 600, alignment: .leading)
.frame(maxWidth: 600, alignment: .leading)
}
.sheet(isPresented: $isShowingFeedbackSheet) {
VStack {
HStack {
Spacer()
Button {
isShowingFeedbackSheet = false
} label: {
Text("关闭")
}
.buttonStyle(.plain)
.padding()
}
//
SettingsUserIssueView()
}
.frame(width: 500, height: 600) //
}
}
}

View File

@ -4,50 +4,148 @@
//
// Created by on 2026/1/19.
//
import SwiftUI
// MARK: - ()
struct SettingsUserIssueView: View {
//
@State private var account: String = ""
@State private var text: String = ""
//
@State private var isSubmitting: Bool = false
@State private var showSuccessToast: Bool = false
var body: some View {
VStack {
Text("用户反馈")
TextField("", text: $account)
.multilineTextAlignment(.leading)
.textFieldStyle(PlainTextFieldStyle())
.frame(width: 200, height: 25)
.background(Color.clear)
.foregroundColor(Color.black)
.overlay(
Rectangle()
.frame(height: 1)
.foregroundColor(.blue)
.padding(.top, 25)
, alignment: .topLeading)
TextEditor(text: $text)
.padding(4)
.overlay(alignment: .topLeading) {
if text.isEmpty {
Text("请输入内容")
.foregroundColor(.gray)
.padding(.leading, 8)
ZStack {
//
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading, spacing: 24) {
// 1.
HStack(spacing: 12) {
Image(systemName: "envelope.badge.fill")
.foregroundColor(.blue)
Text("用户反馈")
.font(.system(size: 18, weight: .bold))
}
.padding(.leading, 4)
// 2.
VStack(alignment: .leading, spacing: 20) {
//
VStack(alignment: .leading, spacing: 8) {
Text("联系方式 (选填)")
.font(.caption.bold())
.foregroundColor(.secondary)
TextField("邮箱或用户名", text: $account)
.textFieldStyle(.plain)
.padding(10)
.background(Color.primary.opacity(0.04))
.cornerRadius(8)
}
// ( Placeholder )
VStack(alignment: .leading, spacing: 8) {
Text("问题描述").font(.caption.bold()).foregroundColor(.secondary)
ZStack(alignment: .topLeading) {
if text.isEmpty {
Text("请详细描述您遇到的问题...")
.foregroundColor(.gray.opacity(0.5))
.padding(.horizontal, 12).padding(.vertical, 12)
.font(.system(size: 14))
}
TextEditor(text: $text)
.font(.system(size: 14))
.scrollContentBackground(.hidden) //
.padding(8)
.background(Color.primary.opacity(0.04))
.cornerRadius(8)
}
.frame(minHeight: 160)
}
}
.padding(20)
.background(Color.primary.opacity(0.02))
.cornerRadius(12)
.overlay(RoundedRectangle(cornerRadius: 12).stroke(Color.primary.opacity(0.05), lineWidth: 1))
// 3.
Button(action: submitFeedback) {
HStack {
if isSubmitting {
ProgressView().controlSize(.small).brightness(1)
} else {
Image(systemName: "paperplane.fill")
}
Text("发送反馈").fontWeight(.semibold)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 12)
.background(text.isEmpty ? Color.gray : Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.buttonStyle(.plain)
.disabled(text.isEmpty || isSubmitting)
}
.frame(minHeight: 120)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.gray.opacity(0.4))
)
.padding(32)
.frame(maxWidth: 600, alignment: .leading)
}
.blur(radius: showSuccessToast ? 8 : 0) //
.disabled(showSuccessToast) //
// 4. Overlay
if showSuccessToast {
successPopup
}
}
.padding()
}
// MARK: -
private func submitFeedback() {
withAnimation { isSubmitting = true }
//
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
isSubmitting = false
showSuccessToast = true
text = "" //
}
// 2.5
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
withAnimation(.easeOut(duration: 0.3)) {
showSuccessToast = false
}
}
}
}
// MARK: -
private var successPopup: some View {
VStack(spacing: 16) {
Image(systemName: "checkmark.seal.fill")
.font(.system(size: 44))
.foregroundStyle(.green.gradient)
Text("发送成功")
.font(.headline)
Text("感谢您的支持!")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(40)
.background(.ultraThinMaterial) // macOS
.cornerRadius(24)
.shadow(color: .black.opacity(0.15), radius: 20)
.transition(.asymmetric(
insertion: .scale(scale: 0.8).combined(with: .opacity),
removal: .opacity.combined(with: .scale(scale: 1.1))
))
}
}
#Preview {
SettingsUserIssueView()
}

View File

@ -73,7 +73,7 @@ struct punchnetApp: App {
.environment(self.userContext)
.environment(self.appContext)
}
.defaultSize(width: 800, height: 500)
//.defaultSize(width: 800, height: 500)
.defaultPosition(.center)
Window("重置密码", id: "resetPassword") {