Files
sodalive-ios/SodaLive/Sources/V2/Main/Home/Ranking/Components/MainHomeRankingCard.swift
2026-06-30 16:17:02 +09:00

194 lines
6.2 KiB
Swift

import SwiftUI
struct MainHomeRankingCard: View {
let item: MainHomeCreatorRankingItem
let showRankChange: Bool
let columnsPerRow: Int
let onTapCreator: (Int) -> Void
init(
item: MainHomeCreatorRankingItem,
showRankChange: Bool,
columnsPerRow: Int = 1,
onTapCreator: @escaping (Int) -> Void = { _ in }
) {
self.item = item
self.showRankChange = showRankChange
self.columnsPerRow = columnsPerRow
self.onTapCreator = onTapCreator
}
var body: some View {
Button {
onTapCreator(item.creatorId)
} label: {
GeometryReader { proxy in
let side = min(proxy.size.width, proxy.size.height)
ZStack(alignment: .topLeading) {
profileImage(size: CGSize(width: side, height: side))
LinearGradient(
colors: [Color.black.opacity(0), Color.black.opacity(0.72)],
startPoint: .top,
endPoint: .bottom
)
rankColumn(side: side)
.padding(.leading, rankColumnLeadingPadding(side))
.padding(.top, rankColumnTopPadding(side))
VStack {
Spacer()
Text(item.nickname)
.appFont(size: nicknameFontSize(side), weight: .bold)
.foregroundColor(.white)
.lineLimit(1)
.truncationMode(.tail)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.horizontal, nicknameHorizontalPadding(side))
.padding(.bottom, nicknameBottomPadding(side))
}
}
.clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous))
}
.aspectRatio(1, contentMode: .fit)
}
.buttonStyle(.plain)
}
private func profileImage(size: CGSize) -> some View {
DownsampledKFImage(url: URL(string: item.profileImageUrl ?? ""), size: size)
.background(Color.gray800)
}
private func rankText(side: CGFloat) -> some View {
Text("\(item.rank)")
.appFont(size: rankFontSize(side), family: .pattaya)
.foregroundStyle(
LinearGradient(
colors: [.white, Color.gray200],
startPoint: .top,
endPoint: .bottom
)
)
.shadow(color: Color.black.opacity(0.48), radius: 2)
}
private func rankColumn(side: CGFloat) -> some View {
VStack(alignment: .center, spacing: rankColumnSpacing) {
rankText(side: side)
.frame(maxWidth: .infinity, alignment: .center)
MainHomeRankChangeBadge(
showRankChange: showRankChange,
rankChange: item.rankChange,
isNew: item.isNew
)
.frame(maxWidth: .infinity, alignment: .center)
}
.frame(width: rankColumnWidth(side), alignment: .center)
}
private var rankColumnSpacing: CGFloat {
switch columnsPerRow {
case 1:
return -20
case 2:
return -10
case 3:
return -5
default:
return -20
}
}
private func rankFontSize(_ side: CGFloat) -> CGFloat {
max(32, side * 0.26)
}
private func nicknameFontSize(_ side: CGFloat) -> CGFloat {
max(16, side * 0.085)
}
private func rankColumnWidth(_ side: CGFloat) -> CGFloat {
max(49, side * 0.19)
}
private func rankColumnLeadingPadding(_ side: CGFloat) -> CGFloat {
max(0, side * 0.035)
}
private func rankColumnTopPadding(_ side: CGFloat) -> CGFloat {
max(-8, side * 0.02)
}
private func nicknameHorizontalPadding(_ side: CGFloat) -> CGFloat {
max(SodaSpacing.s12, side * 0.11)
}
private func nicknameBottomPadding(_ side: CGFloat) -> CGFloat {
max(SodaSpacing.s16, side * 0.09)
}
}
struct MainHomeRankingCard_Previews: PreviewProvider {
private static let previewImageUrl = "https://picsum.photos/500/500"
static var previews: some View {
VStack(spacing: SodaSpacing.s20) {
MainHomeRankingCard(
item: previewItem(rank: 1, rankChange: 5, isNew: false),
showRankChange: true
)
.frame(width: 374)
HStack(spacing: SodaSpacing.s8) {
MainHomeRankingCard(
item: previewItem(rank: 2, rankChange: -3, isNew: false),
showRankChange: true,
columnsPerRow: 2
)
MainHomeRankingCard(
item: previewItem(rank: 3, rankChange: 0, isNew: false),
showRankChange: true,
columnsPerRow: 2
)
}
HStack(spacing: SodaSpacing.s8) {
MainHomeRankingCard(
item: previewItem(rank: 8, rankChange: nil, isNew: true),
showRankChange: true,
columnsPerRow: 3
)
MainHomeRankingCard(
item: previewItem(rank: 9, rankChange: 2, isNew: false),
showRankChange: false,
columnsPerRow: 3
)
MainHomeRankingCard(
item: previewItem(rank: 10, rankChange: nil, isNew: false),
showRankChange: true,
columnsPerRow: 3
)
}
}
.padding(SodaSpacing.s20)
.background(Color.black)
.previewLayout(.sizeThatFits)
}
private static func previewItem(rank: Int, rankChange: Int?, isNew: Bool) -> MainHomeCreatorRankingItem {
MainHomeCreatorRankingItem(
rank: rank,
rankChange: rankChange,
isNew: isNew,
creatorId: rank,
nickname: "크리에이터이름",
profileImageUrl: previewImageUrl
)
}
}