fix: resolve 3 compilation errors
- NotificationListView.swift: unwrap optional String? for Text() - LocalCache.swift: add @escaping to fetch closure parameter - ContentView.swift: reformat ZXTabBar body for item scope fix Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
89d89e542c
commit
be7fca5305
@ -21,17 +21,80 @@ struct ContentView: View {
|
||||
|
||||
struct ZXTabBar: View {
|
||||
@Binding var active: String
|
||||
private let items = [("ai","AI","brain.head.profile"),("library","知识库","books.vertical.fill"),("study","学习","bolt.fill"),("analysis","分析","chart.bar.fill"),("profile","我的","person.fill")]
|
||||
var body: some View{HStack(spacing:0){ForEach(items,id:\.0){item in let on=item.0==active;Button{active=item.0}label:{VStack(spacing:4){ZStack{if on{Circle().fill(Color.zxPurple.opacity(0.2)).frame(width:28,height:28).scaleEffect(1.4)};Image(systemName:item.2).font(.system(size:22,weight:on ? .semibold:.regular)).foregroundColor(on ? Color.zxPurple:Color.zxF03)};Text(item.1).font(.system(size:10,weight:on ? .semibold:.regular)).foregroundColor(on ? Color.zxPurple:Color.zxF03)}}.frame(maxWidth:.infinity)}.accessibilityLabel("\(item.1)标签")}.padding(.top,6).padding(.bottom,34).frame(height:83).background(.ultraThinMaterial).background(Color.zxBg0.opacity(0.95)).overlay(alignment:.top){Rectangle().fill(Color.zxBorder008).frame(height:1)}}
|
||||
private let items = [
|
||||
("ai", "AI", "brain.head.profile"),
|
||||
("library", "知识库", "books.vertical.fill"),
|
||||
("study", "学习", "bolt.fill"),
|
||||
("analysis", "分析", "chart.bar.fill"),
|
||||
("profile", "我的", "person.fill"),
|
||||
]
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
ForEach(items, id: \.0) { item in
|
||||
let on = item.0 == active
|
||||
Button {
|
||||
active = item.0
|
||||
} label: {
|
||||
VStack(spacing: 4) {
|
||||
ZStack {
|
||||
if on {
|
||||
Circle()
|
||||
.fill(Color.zxPurple.opacity(0.2))
|
||||
.frame(width: 28, height: 28)
|
||||
.scaleEffect(1.4)
|
||||
}
|
||||
Image(systemName: item.2)
|
||||
.font(.system(size: 22, weight: on ? .semibold : .regular))
|
||||
.foregroundColor(on ? Color.zxPurple : Color.zxF03)
|
||||
}
|
||||
Text(item.1)
|
||||
.font(.system(size: 10, weight: on ? .semibold : .regular))
|
||||
.foregroundColor(on ? Color.zxPurple : Color.zxF03)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.accessibilityLabel("\(item.1)标签")
|
||||
}
|
||||
}
|
||||
.padding(.top, 6)
|
||||
.padding(.bottom, 34)
|
||||
.frame(height: 83)
|
||||
.background(.ultraThinMaterial)
|
||||
.background(Color.zxBg0.opacity(0.95))
|
||||
.overlay(alignment: .top) {
|
||||
Rectangle().fill(Color.zxBorder008).frame(height: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ZXIconBtn: View {
|
||||
let icon: String; let size: CGFloat; var branded = false; let action: () -> Void
|
||||
var body: some View {Button(action:action){Image(systemName:icon).font(.system(size:size*0.44)).frame(width:size,height:size)}.foregroundColor(branded ? .white:Color.zxF05).background(branded ? AnyView(ZXGradient.brand):AnyView(Color(hex:"#FFFFFF",opacity:0.05))).clipShape(RoundedRectangle(cornerRadius:10)).overlay{if !branded{RoundedRectangle(cornerRadius:10).stroke(Color.zxBorder008,lineWidth:1)}}}
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
Image(systemName: icon).font(.system(size: size * 0.44)).frame(width: size, height: size)
|
||||
}
|
||||
.foregroundColor(branded ? .white : Color.zxF05)
|
||||
.background(branded ? AnyView(ZXGradient.brand) : AnyView(Color(hex: "#FFFFFF", opacity: 0.05)))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.overlay {
|
||||
if !branded {
|
||||
RoundedRectangle(cornerRadius: 10).stroke(Color.zxBorder008, lineWidth: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ZXScoreBox: View {let score:Int;let bg:Color;let fg:Color
|
||||
var body: some View {Text("\(score)").font(.system(size:12,weight:.heavy)).foregroundColor(fg).frame(width:36,height:36).background(bg).clipShape(RoundedRectangle(cornerRadius:10))}
|
||||
struct ZXScoreBox: View {
|
||||
let score: Int; let bg: Color; let fg: Color
|
||||
var body: some View {
|
||||
Text("\(score)")
|
||||
.font(.system(size: 12, weight: .heavy))
|
||||
.foregroundColor(fg)
|
||||
.frame(width: 36, height: 36)
|
||||
.background(bg)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
}
|
||||
|
||||
struct ZXWeakRow: View {
|
||||
@ -58,5 +121,24 @@ struct ZXWeakRow: View {
|
||||
|
||||
struct ZXAIInputBar: View {
|
||||
@Binding var text: String; let onSend: () -> Void
|
||||
var body: some View {HStack(spacing:10){Image(systemName:"sparkles").font(.system(size:16)).foregroundColor(Color.zxPurple);TextField("问 AI 任何学习问题…",text:$text).font(.system(size:14)).tint(Color.zxPurple).accessibilityLabel("AI 学习问题输入框");Spacer();Image(systemName:"mic.fill").font(.system(size:18)).foregroundColor(Color.zxF03).accessibilityLabel("语音输入");Button(action:onSend){Image(systemName:"arrow.up").font(.system(size:14,weight:.bold)).foregroundColor(.white).frame(width:30,height:30).background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius:9))}.zxPressable().disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty).accessibilityLabel("发送消息")}.padding(.horizontal,14).padding(.vertical,10).background(.ultraThinMaterial).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius:20).stroke(Color.zxBorder008,lineWidth:1)).clipShape(RoundedRectangle(cornerRadius:20)).padding(.horizontal,20).padding(.bottom,34)}
|
||||
var body: some View {
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "sparkles").font(.system(size: 16)).foregroundColor(Color.zxPurple)
|
||||
TextField("问 AI 任何学习问题…", text: $text).font(.system(size: 14)).tint(Color.zxPurple).accessibilityLabel("AI 学习问题输入框")
|
||||
Spacer()
|
||||
Image(systemName: "mic.fill").font(.system(size: 18)).foregroundColor(Color.zxF03).accessibilityLabel("语音输入")
|
||||
Button(action: onSend) {
|
||||
Image(systemName: "arrow.up").font(.system(size: 14, weight: .bold)).foregroundColor(.white)
|
||||
.frame(width: 30, height: 30).background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius: 9))
|
||||
}
|
||||
.zxPressable()
|
||||
.disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
.accessibilityLabel("发送消息")
|
||||
}
|
||||
.padding(.horizontal, 14).padding(.vertical, 10)
|
||||
.background(.ultraThinMaterial).background(Color.zxFill004)
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder008, lineWidth: 1))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.padding(.horizontal, 20).padding(.bottom, 34)
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ extension LocalCache {
|
||||
func cacheFirst<T: Codable>(
|
||||
key: String,
|
||||
ttl: TimeInterval = 300,
|
||||
fetch: @Sendable () async throws -> T
|
||||
fetch: @Sendable @escaping () async throws -> T
|
||||
) async throws -> T {
|
||||
if let cached: T = getWithExpiry(key, ttl: ttl) {
|
||||
Task { try? await refreshCache(key: key, ttl: ttl, fetch: fetch) }
|
||||
@ -84,7 +84,7 @@ extension LocalCache {
|
||||
private func refreshCache<T: Codable>(
|
||||
key: String,
|
||||
ttl: TimeInterval,
|
||||
fetch: @Sendable () async throws -> T
|
||||
fetch: @Sendable @escaping () async throws -> T
|
||||
) async throws {
|
||||
let fresh = try await fetch()
|
||||
setWithExpiry(fresh, forKey: key, ttl: ttl)
|
||||
|
||||
@ -94,7 +94,7 @@ struct ZXNotificationItemRow: View {
|
||||
Circle().fill(Color.zxPurple).frame(width: 6, height: 6)
|
||||
}
|
||||
}
|
||||
Text(item.content).font(.system(size: 12)).foregroundColor(Color.zxF04).lineLimit(2)
|
||||
Text(item.content ?? "").font(.system(size: 12)).foregroundColor(Color.zxF04).lineLimit(2)
|
||||
if let createdAt = item.createdAt {
|
||||
Text(createdAt.prefix(10).description).font(.system(size: 10)).foregroundColor(Color.zxF03)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user