// // HomeView.swift // XuXuCheck // // Created by henseycai on 2025/6/11. // import SwiftUI struct HomeView: View { @State var hasScroll = false @Namespace var namespace @State var showMods: Bool = false @State var showStatusBar = true @State var selectedID = UUID() @Environment(Status.self) var status @Environment(LoginStatus.self) var loginStatus var body: some View { ZStack { Color("background").ignoresSafeArea() ScrollView { scrollDetection //featured HomeScanView().padding(20) LazyVGrid(columns: [GridItem(.adaptive(minimum: 140), spacing: 20)]) { homeModCards } .padding(.horizontal, 20) } .coordinateSpace(name: "scroll") .safeAreaInset(edge: .top, content: { Color.clear.frame(height: 70) }) .overlay( NavigationBar(title: Storage.shared.member_name, hasScrolled: $hasScroll) ) } .statusBar(hidden: !showStatusBar) .fullScreenCover(isPresented: $showMods) { if let idx = homeFuncblocks.firstIndex(where: {$0.id == selectedID}){ if let url = homeFuncblocks[idx].link { if(url.contains(API.webrecordUrl) && loginStatus.isLogin == false){ LoginView() }else{ XuXuWebView(currentUrl: url) } } } } } var scrollDetection: some View { GeometryReader { proxy in Color.clear .preference(key: ScrollPreferenceKey.self, value: proxy.frame(in: .named("scroll")).minY) } .frame(height: 0) .onPreferenceChange(ScrollPreferenceKey.self, perform: { value in withAnimation(.easeInOut) { if value < 0 { hasScroll = true } else { hasScroll = false } } }) } struct HomeScanView: View { let bgcolor = Color(hex: 0x2449f1) let bgcolor2 = Color(hex: 0x1638d9) let scale = 9.0 @State private var moveOnCircularPath: Bool = false @State var showModal = false @Environment(LoginStatus.self) var loginStatus var body: some View { VStack { ZStack { Circle() .stroke(bgcolor,lineWidth: scale * 2) .frame(width: 26*scale, height: 26*scale) Circle() .stroke(bgcolor2,lineWidth: scale) .frame(width: 23.5*scale, height: 23.5*scale) Image("lay_cycle1") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 22.5*scale,height: 22.5*scale) Image("ball2") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 18*scale,height: 18*scale) Image("lay3") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 18*scale,height: 18*scale) Image("lay5") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 18*scale,height: 18*scale) Image("lay4") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 18*scale,height: 18*scale) Image("lay6") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 4*scale,height: 4*scale) Image("ball") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 2.2*scale,height: 2.2*scale).offset(x:0,y:10*scale) .rotationEffect(.degrees(moveOnCircularPath ? 0 : -360)) .task { withAnimation(.myLinear.delay(0).repeatForever(autoreverses: false)) { moveOnCircularPath.toggle() } } }.overlay(txtOverlay.offset(x:0,y: -(6*scale)),alignment: .bottom) } .onTapGesture { showModal.toggle() } .fullScreenCover(isPresented: $showModal) { if(loginStatus.isLogin){ ScanView() }else{ LoginView() } } } private var txtOverlay: some View { ZStack{ // Capsule() // .fill(Color.white.opacity(0.5)) // .frame(width: 120, height: 50) Text("SCAN").font(.title) .foregroundColor(.yellow) } } } var homeModCards : some View { ForEach(homeFuncblocks ) { block in Button(action: { showMods.toggle() //status.showNavDetail.toggle() //status.showNavDetail = true showStatusBar = false selectedID = block.id }, label: { HomeCardItem(namespace: namespace, block: block, showMods: $showMods) }) } } struct HomeCardItem: View { var namespace: Namespace.ID var block: BlockItem = homeFuncblocks[0] @Binding var showMods: Bool var body: some View { VStack { Spacer() VStack(alignment: .center) { Image(block.image) .resizable().frame(width: 56,height: 56) .aspectRatio(contentMode: .fit) .matchedGeometryEffect(id: "image\(block.id)", in: namespace) Text(block.title) .font(.headline.weight(.bold)) .matchedGeometryEffect(id: "title\(block.id)", in: namespace) .frame(maxWidth: .infinity, alignment: .center) } .padding(16) .background( Rectangle() .fill(.ultraThinMaterial) .mask(RoundedRectangle(cornerRadius: 30, style: .continuous)) .blur(radius: 30) .matchedGeometryEffect(id: "blur\(block.id)", in: namespace) ) } .foregroundStyle(.white) .background( Image(block.background) .resizable() .aspectRatio(contentMode: .fill) .matchedGeometryEffect(id: "background\(block.id)", in: namespace) ) .mask(RoundedRectangle(cornerRadius: 30, style: .continuous) .matchedGeometryEffect(id: "mask\(block.id)", in: namespace)) .frame(height: 132) } } struct HomeCardItem_Previews: PreviewProvider { @Namespace static var namespace static var previews: some View { HomeCardItem(namespace: namespace, showMods: .constant(true)) } } } #Preview { HomeView() }