1
0
Files
card/ios/AiCard/AiCard/Views/GachaView.swift
2025-06-01 21:39:53 +09:00

190 lines
5.9 KiB
Swift

import SwiftUI
struct GachaView: View {
@EnvironmentObject var authManager: AuthManager
@EnvironmentObject var cardManager: CardManager
@State private var showingAnimation = false
var body: some View {
ZStack {
// Background
LinearGradient(
gradient: Gradient(colors: [
Color(hex: "0a0a0a"),
Color(hex: "1a1a1a")
]),
startPoint: .top,
endPoint: .bottom
)
.ignoresSafeArea()
VStack(spacing: 40) {
// Title
VStack(spacing: 16) {
Text("カードを引く")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(.white)
if let user = authManager.currentUser {
Text("@\(user.handle)")
.font(.subheadline)
.foregroundColor(Color(hex: "fff700"))
}
}
Spacer()
// Gacha buttons
VStack(spacing: 20) {
GachaButton(
title: "通常ガチャ",
subtitle: "無料でカードを1枚引く",
colors: [Color(hex: "667eea"), Color(hex: "764ba2")],
action: {
drawCard(isPaid: false)
},
isLoading: cardManager.isDrawing
)
GachaButton(
title: "プレミアムガチャ",
subtitle: "レア確率アップ!",
colors: [Color(hex: "f093fb"), Color(hex: "f5576c")],
action: {
drawCard(isPaid: true)
},
isLoading: cardManager.isDrawing,
isPremium: true
)
}
.padding(.horizontal, 32)
if let errorMessage = cardManager.errorMessage {
Text(errorMessage)
.font(.caption)
.foregroundColor(.red)
.padding()
}
Spacer()
}
.padding()
// Gacha animation overlay
if let currentDraw = cardManager.currentDraw {
GachaAnimationView(
drawResult: currentDraw,
onComplete: {
cardManager.completeCardDraw()
}
)
.transition(.opacity)
.zIndex(1000)
}
}
.onAppear {
if let userDid = authManager.currentUser?.did {
cardManager.loadUserCards(userDid: userDid)
}
}
}
private func drawCard(isPaid: Bool) {
guard let userDid = authManager.currentUser?.did else { return }
cardManager.drawCard(userDid: userDid, isPaid: isPaid)
}
}
struct GachaButton: View {
let title: String
let subtitle: String
let colors: [Color]
let action: () -> Void
let isLoading: Bool
let isPremium: Bool
init(title: String, subtitle: String, colors: [Color], action: @escaping () -> Void, isLoading: Bool, isPremium: Bool = false) {
self.title = title
self.subtitle = subtitle
self.colors = colors
self.action = action
self.isLoading = isLoading
self.isPremium = isPremium
}
var body: some View {
Button(action: action) {
VStack(spacing: 8) {
Text(title)
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.white)
Text(subtitle)
.font(.caption)
.foregroundColor(.white.opacity(0.8))
}
.frame(maxWidth: .infinity)
.frame(height: 80)
.background(
ZStack {
LinearGradient(
gradient: Gradient(colors: colors),
startPoint: .leading,
endPoint: .trailing
)
if isPremium {
// Shimmer effect for premium
ShimmerView()
}
}
)
.cornerRadius(16)
.shadow(color: colors.first?.opacity(0.3) ?? .clear, radius: 10, x: 0, y: 5)
.overlay(
Group {
if isLoading {
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .white))
}
}
)
}
.disabled(isLoading)
.scaleEffect(isLoading ? 0.95 : 1.0)
.animation(.easeInOut(duration: 0.1), value: isLoading)
}
}
struct ShimmerView: View {
@State private var phase: CGFloat = 0
var body: some View {
LinearGradient(
gradient: Gradient(colors: [
.clear,
.white.opacity(0.2),
.clear
]),
startPoint: .leading,
endPoint: .trailing
)
.rotationEffect(.degrees(45))
.offset(x: phase)
.onAppear {
withAnimation(.linear(duration: 2).repeatForever(autoreverses: false)) {
phase = 300
}
}
}
}
struct GachaView_Previews: PreviewProvider {
static var previews: some View {
GachaView()
.environmentObject(AuthManager())
.environmentObject(CardManager())
}
}