feat(live-room): 하트 롱프레스 시 가운데 빈 하트가 표시되고 물 채워지는 애니메이션 추가

This commit is contained in:
Yu Sung
2025-11-05 16:07:41 +09:00
parent 0a59c6f575
commit 76757215cf
2 changed files with 192 additions and 0 deletions

View File

@@ -8,6 +8,7 @@
import SwiftUI
import Kingfisher
import SDWebImageSwiftUI
import Combine
struct LiveRoomViewV2: View {
@@ -17,6 +18,14 @@ struct LiveRoomViewV2: View {
@State private var textHeight: CGFloat = .zero
@State private var menuTextHeight: CGFloat = .zero
//
@State private var isLongPressingHeart: Bool = false
@State private var longPressStartAt: Date? = nil
@State private var showWaterHeart: Bool = false
@State private var waterProgress: CGFloat = 0
@State private var wavePhase: CGFloat = 0
let heartWaveTimer = Timer.publish(every: 1/60, on: .main, in: .common).autoconnect()
var body: some View {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
@@ -256,6 +265,29 @@ struct LiveRoomViewV2: View {
onClick: { viewModel.likeHeart() },
onLongPress: { viewModel.likeHeart(messageType: .BIG_HEART_DONATION, heartCount: 100) }
)
.onLongPressGesture(
minimumDuration: 2.0,
maximumDistance: 50,
pressing: { pressing in
if pressing {
if !isLongPressingHeart {
isLongPressingHeart = true
longPressStartAt = Date()
//
waterProgress = 0
wavePhase = 0
}
} else {
isLongPressingHeart = false
showWaterHeart = false
waterProgress = 0
longPressStartAt = nil
}
},
perform: {
// perform (onLongPress)
}
)
}
}
@@ -711,6 +743,33 @@ struct LiveRoomViewV2: View {
LoadingView()
}
}
.overlay(alignment: .center) {
WaterHeartView(progress: waterProgress, show: showWaterHeart, phase: wavePhase)
.frame(width: 280, height: 210) // 4:3
.allowsHitTesting(false)
.opacity(showWaterHeart ? 1 : 0)
.animation(.easeInOut(duration: 0.2), value: showWaterHeart)
}
.onReceive(heartWaveTimer) { _ in
guard isLongPressingHeart else { return }
let now = Date()
if longPressStartAt == nil { longPressStartAt = now }
let elapsed = now.timeIntervalSince(longPressStartAt!)
if elapsed >= 0.5 {
if !showWaterHeart {
withAnimation(.spring(response: 0.25, dampingFraction: 0.8)) {
showWaterHeart = true
}
}
let p = min(max((elapsed - 0.5) / 1.5, 0), 1)
waterProgress = p
//
wavePhase += 0.25
} else {
showWaterHeart = false
waterProgress = 0
}
}
.ignoresSafeArea(.keyboard)
.edgesIgnoringSafeArea(keyboardHandler.keyboardHeight > 0 ? .bottom : .init())
.sheet(