fix: 메인 홈 - 인기 크리에이터
- 팔로우 수 제거 - 팔로우 버튼 추가 - 배경: 그라데이션 제거, 하나의 색으로 설정
This commit is contained in:
@@ -151,28 +151,28 @@ struct ContentMainTabHomeRankCreatorView: View {
|
|||||||
nickname: "User1",
|
nickname: "User1",
|
||||||
tags: "",
|
tags: "",
|
||||||
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
followerCount: 1000
|
follow: false
|
||||||
),
|
),
|
||||||
GetExplorerSectionCreatorResponse(
|
GetExplorerSectionCreatorResponse(
|
||||||
id: 2,
|
id: 2,
|
||||||
nickname: "User2",
|
nickname: "User2",
|
||||||
tags: "",
|
tags: "",
|
||||||
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
followerCount: 1000
|
follow: false
|
||||||
),
|
),
|
||||||
GetExplorerSectionCreatorResponse(
|
GetExplorerSectionCreatorResponse(
|
||||||
id: 3,
|
id: 3,
|
||||||
nickname: "User3",
|
nickname: "User3",
|
||||||
tags: "",
|
tags: "",
|
||||||
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
followerCount: 1000
|
follow: false
|
||||||
),
|
),
|
||||||
GetExplorerSectionCreatorResponse(
|
GetExplorerSectionCreatorResponse(
|
||||||
id: 4,
|
id: 4,
|
||||||
nickname: "User4",
|
nickname: "User4",
|
||||||
tags: "",
|
tags: "",
|
||||||
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
profileImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
followerCount: 1000
|
follow: false
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ struct GetExplorerSectionCreatorResponse: Decodable, Hashable {
|
|||||||
let nickname: String
|
let nickname: String
|
||||||
let tags: String
|
let tags: String
|
||||||
let profileImageUrl: String
|
let profileImageUrl: String
|
||||||
let followerCount: Int
|
var follow: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,54 +11,55 @@ import Kingfisher
|
|||||||
struct HomeCreatorRankingItemView: View {
|
struct HomeCreatorRankingItemView: View {
|
||||||
|
|
||||||
let rank: Int
|
let rank: Int
|
||||||
let item: GetExplorerSectionCreatorResponse
|
@State var item: GetExplorerSectionCreatorResponse
|
||||||
|
|
||||||
|
let onClickFollow: (Int, Bool) -> Void
|
||||||
|
|
||||||
let crowns = ["rank_1", "rank_2", "rank_3"]
|
let crowns = ["rank_1", "rank_2", "rank_3"]
|
||||||
|
|
||||||
|
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .topLeading) {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
KFImage(URL(string: item.profileImageUrl))
|
KFImage(URL(string: item.profileImageUrl))
|
||||||
.cancelOnDisappear(true)
|
.cancelOnDisappear(true)
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 70, height: 70)
|
.frame(width: 84, height: 84)
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
|
|
||||||
Text(item.nickname)
|
Text(item.nickname)
|
||||||
.font(.custom(Font.preRegular.rawValue, size: 18))
|
.font(.custom(Font.preRegular.rawValue, size: 16))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.padding(.top, 8)
|
.padding(.top, 20)
|
||||||
|
|
||||||
Text("팔로워")
|
Spacer()
|
||||||
.font(.custom(Font.preBold.rawValue, size: 14))
|
|
||||||
.foregroundColor(Color(hex: "78909C"))
|
|
||||||
.padding(.top, 12)
|
|
||||||
|
|
||||||
Text("\(item.followerCount)")
|
if item.id != UserDefaults.int(forKey: .userId) {
|
||||||
.font(.custom(Font.preRegular.rawValue, size: 14))
|
Text(item.follow ? "팔로잉" : "팔로우")
|
||||||
.foregroundColor(Color(hex: "78909C"))
|
.font(.custom(Font.preRegular.rawValue, size: 14))
|
||||||
.padding(.top, 4)
|
.padding(.vertical, 4)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(
|
||||||
|
item.follow ? Color(hex: "455a64") : Color.white
|
||||||
|
)
|
||||||
|
.cornerRadius(999)
|
||||||
|
.foregroundColor(
|
||||||
|
item.follow ? .white : Color(hex: "263238")
|
||||||
|
)
|
||||||
|
.onTapGesture {
|
||||||
|
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
|
item.follow = !item.follow
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickFollow(item.id, item.follow)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.frame(width: 133, height: 188)
|
.padding(16)
|
||||||
.background(
|
.frame(width: 144, height: 204)
|
||||||
LinearGradient(
|
.background(Color(hex: "263238"))
|
||||||
gradient: Gradient(colors: [Color(hex: "5ACDE1"), Color(hex: "2A339D")]),
|
|
||||||
startPoint: .topLeading,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.cornerRadius(16)
|
.cornerRadius(16)
|
||||||
.overlay {
|
|
||||||
RoundedRectangle(cornerRadius: 16)
|
|
||||||
.strokeBorder(
|
|
||||||
LinearGradient(
|
|
||||||
gradient: Gradient(colors: [Color(hex: "9AE2F6"), .white.opacity(0)]),
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
),
|
|
||||||
lineWidth: 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.padding(.top, 20)
|
.padding(.top, 20)
|
||||||
|
|
||||||
if rank <= 3 {
|
if rank <= 3 {
|
||||||
@@ -79,7 +80,8 @@ struct HomeCreatorRankingItemView: View {
|
|||||||
nickname: "유빈ASMR",
|
nickname: "유빈ASMR",
|
||||||
tags: "",
|
tags: "",
|
||||||
profileImageUrl: "https://cf.sodalive.net/profile/34806/34806-profile-49db6b45-bb1e-4dc7-917e-1a614a853f5f-4232-1752158072656",
|
profileImageUrl: "https://cf.sodalive.net/profile/34806/34806-profile-49db6b45-bb1e-4dc7-917e-1a614a853f5f-4232-1752158072656",
|
||||||
followerCount: 1000
|
follow: true
|
||||||
)
|
),
|
||||||
|
onClickFollow: { _, _ in }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,22 @@ struct HomeTabView: View {
|
|||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
ForEach(0..<viewModel.creatorRanking.count, id: \.self) {
|
ForEach(0..<viewModel.creatorRanking.count, id: \.self) {
|
||||||
let item = viewModel.creatorRanking[$0]
|
let item = viewModel.creatorRanking[$0]
|
||||||
HomeCreatorRankingItemView(rank: $0 + 1, item: item)
|
HomeCreatorRankingItemView(
|
||||||
|
rank: $0 + 1,
|
||||||
|
item: item,
|
||||||
|
onClickFollow: { creatorId, follow in
|
||||||
|
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
|
if follow {
|
||||||
|
viewModel.creatorFollow(creatorId: item.id, follow: true, notify: true)
|
||||||
|
} else {
|
||||||
|
viewModel.creatorFollow(creatorId: item.id, follow: false, notify: false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AppState.shared
|
||||||
|
.setAppStep(step: .login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
AppState.shared
|
AppState.shared
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ enum SeriesPublishedDaysOfWeek: String, Encodable {
|
|||||||
|
|
||||||
final class HomeTabViewModel: ObservableObject {
|
final class HomeTabViewModel: ObservableObject {
|
||||||
private let repository = HomeTabRepository()
|
private let repository = HomeTabRepository()
|
||||||
|
private let userRepository = UserRepository()
|
||||||
private var subscription = Set<AnyCancellable>()
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
@Published var errorMessage = ""
|
@Published var errorMessage = ""
|
||||||
@@ -160,4 +161,40 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
.store(in: &subscription)
|
.store(in: &subscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func creatorFollow(creatorId: Int, follow: Bool = true, notify: Bool = true) {
|
||||||
|
isLoading = true
|
||||||
|
|
||||||
|
userRepository.creatorFollow(creatorId: creatorId, follow: follow, notify: notify)
|
||||||
|
.sink { result in
|
||||||
|
switch result {
|
||||||
|
case .finished:
|
||||||
|
DEBUG_LOG("finish")
|
||||||
|
case .failure(let error):
|
||||||
|
ERROR_LOG(error.localizedDescription)
|
||||||
|
}
|
||||||
|
} receiveValue: { [unowned self] response in
|
||||||
|
self.isLoading = false
|
||||||
|
let responseData = response.data
|
||||||
|
|
||||||
|
do {
|
||||||
|
let jsonDecoder = JSONDecoder()
|
||||||
|
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||||
|
|
||||||
|
if !decoded.success {
|
||||||
|
if let message = decoded.message {
|
||||||
|
self.errorMessage = message
|
||||||
|
} else {
|
||||||
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
}
|
||||||
|
|
||||||
|
self.isShowPopup = true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
self.isShowPopup = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &subscription)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user