From 3591c7af9aff9b2d5404425d3312b319c0971af3 Mon Sep 17 00:00:00 2001 From: JungDohyeon Date: Thu, 21 Nov 2024 17:50:16 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[Feat]=20=EB=9D=BC=EC=9D=B4=EC=97=87=20?= =?UTF-8?q?=EA=B3=84=EC=A0=95=20=EB=93=B1=EB=A1=9D=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GameLink-iOS.xcodeproj/project.pbxproj | 20 +++++++++++++++++-- .../Profile/{ => View}/ProfileMainView.swift | 0 .../{ => ViewModel}/ProfileViewModel.swift | 9 ++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) rename GameLink-iOS/Feature/Profile/{ => View}/ProfileMainView.swift (100%) rename GameLink-iOS/Feature/Profile/{ => ViewModel}/ProfileViewModel.swift (94%) diff --git a/GameLink-iOS.xcodeproj/project.pbxproj b/GameLink-iOS.xcodeproj/project.pbxproj index 57827ab..f1e15d7 100644 --- a/GameLink-iOS.xcodeproj/project.pbxproj +++ b/GameLink-iOS.xcodeproj/project.pbxproj @@ -212,8 +212,8 @@ CD277DAE2CCE25E800BE57C4 /* Profile */ = { isa = PBXGroup; children = ( - CD277DAF2CCE25F300BE57C4 /* ProfileMainView.swift */, - CD277DB12CCE260900BE57C4 /* ProfileViewModel.swift */, + CDA1CBE82CEF2AF00041116B /* ViewModel */, + CDA1CBE92CEF2AF40041116B /* View */, ); path = Profile; sourceTree = ""; @@ -294,6 +294,22 @@ path = Core; sourceTree = ""; }; + CDA1CBE82CEF2AF00041116B /* ViewModel */ = { + isa = PBXGroup; + children = ( + CD277DB12CCE260900BE57C4 /* ProfileViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + CDA1CBE92CEF2AF40041116B /* View */ = { + isa = PBXGroup; + children = ( + CD277DAF2CCE25F300BE57C4 /* ProfileMainView.swift */, + ); + path = View; + sourceTree = ""; + }; CDC0C5822CEA63DD002988BF /* Entity */ = { isa = PBXGroup; children = ( diff --git a/GameLink-iOS/Feature/Profile/ProfileMainView.swift b/GameLink-iOS/Feature/Profile/View/ProfileMainView.swift similarity index 100% rename from GameLink-iOS/Feature/Profile/ProfileMainView.swift rename to GameLink-iOS/Feature/Profile/View/ProfileMainView.swift diff --git a/GameLink-iOS/Feature/Profile/ProfileViewModel.swift b/GameLink-iOS/Feature/Profile/ViewModel/ProfileViewModel.swift similarity index 94% rename from GameLink-iOS/Feature/Profile/ProfileViewModel.swift rename to GameLink-iOS/Feature/Profile/ViewModel/ProfileViewModel.swift index 5e84c2a..1167384 100644 --- a/GameLink-iOS/Feature/Profile/ProfileViewModel.swift +++ b/GameLink-iOS/Feature/Profile/ViewModel/ProfileViewModel.swift @@ -24,6 +24,7 @@ final class ProfileViewModel: ObservableObject { // Inner Business Action case _setNickname(String) case _setTag(String) + case _fetchUserInfo } private let service: RiotService @@ -37,11 +38,14 @@ final class ProfileViewModel: ObservableObject { public func action(_ action: Action) { switch action { case .mainViewAppear: - self.fetchUserInfo() + self.action(._fetchUserInfo) case .tappedRegistButton: self.registerAccount(gameName: nickname, tagLine: tag) + case ._fetchUserInfo: + self.fetchUserInfo() + case let ._setNickname(text): self.setNickname(text: text) @@ -87,11 +91,10 @@ private extension ProfileViewModel { func registerAccount(gameName: String, tagLine: String) { self.service.registerAccount(gameName: gameName, tagLine: tagLine) { [weak self] result in guard let self = self else { return } - switch result { case .success: print("SUCCESS!") - self.fetchUserInfo() + self.action(._fetchUserInfo) case let .failure(error): print(error.localizedDescription) From 6cf251f187f082ab7a15796c33de70699ea23792 Mon Sep 17 00:00:00 2001 From: JungDohyeon Date: Fri, 22 Nov 2024 01:53:39 +0900 Subject: [PATCH 2/4] [Feat] ProfileView RankData --- GameLink-iOS.xcodeproj/project.pbxproj | 20 ++ GameLink-iOS/Domain/Entity/RankEntity.swift | 28 ++ GameLink-iOS/Domain/Enum/RankType.swift | 22 ++ GameLink-iOS/Domain/Enum/Tier.swift | 11 +- .../Feature/Core/CachedImageView.swift | 1 - GameLink-iOS/Feature/Core/RankCardView.swift | 138 +++++++++ .../Profile/View/ProfileMainView.swift | 29 +- .../Profile/View/UserProfileView.swift | 274 ++++++++++++++++++ .../Networks/Sources/Entity/RankDTO.swift | 52 ++++ .../Sources/Entity/RiotAccountDTO.swift | 27 +- 10 files changed, 567 insertions(+), 35 deletions(-) create mode 100644 GameLink-iOS/Domain/Entity/RankEntity.swift create mode 100644 GameLink-iOS/Domain/Enum/RankType.swift create mode 100644 GameLink-iOS/Feature/Core/RankCardView.swift create mode 100644 GameLink-iOS/Feature/Profile/View/UserProfileView.swift create mode 100644 GameLink-iOS/Networks/Sources/Entity/RankDTO.swift diff --git a/GameLink-iOS.xcodeproj/project.pbxproj b/GameLink-iOS.xcodeproj/project.pbxproj index f1e15d7..f99e712 100644 --- a/GameLink-iOS.xcodeproj/project.pbxproj +++ b/GameLink-iOS.xcodeproj/project.pbxproj @@ -36,6 +36,11 @@ CD929F1F2CD2B87A00E67E4E /* GridRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD929F1E2CD2B87A00E67E4E /* GridRules.swift */; }; CD929F212CD2B9E700E67E4E /* GLButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD929F202CD2B9E700E67E4E /* GLButton.swift */; }; CDA1CBE72CEE24A20041116B /* PositionSelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBE62CEE24A20041116B /* PositionSelectView.swift */; }; + CDA1CBEB2CEF2C230041116B /* RankDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBEA2CEF2C230041116B /* RankDTO.swift */; }; + CDA1CBED2CEF84850041116B /* UserProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBEC2CEF84850041116B /* UserProfileView.swift */; }; + CDA1CBEF2CEF8FEB0041116B /* RankCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */; }; + CDA1CBF32CEF948E0041116B /* RankEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF22CEF948E0041116B /* RankEntity.swift */; }; + CDA1CBF52CEF95870041116B /* RankType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF42CEF95870041116B /* RankType.swift */; }; CDC0C5812CEA61D1002988BF /* ChatroomDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5802CEA61D1002988BF /* ChatroomDTO.swift */; }; CDC0C5842CEA63E6002988BF /* ChatroomEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */; }; CDC0C5862CEA6733002988BF /* ChatroomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5852CEA6733002988BF /* ChatroomView.swift */; }; @@ -130,6 +135,11 @@ CD929F1E2CD2B87A00E67E4E /* GridRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridRules.swift; sourceTree = ""; }; CD929F202CD2B9E700E67E4E /* GLButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GLButton.swift; sourceTree = ""; }; CDA1CBE62CEE24A20041116B /* PositionSelectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionSelectView.swift; sourceTree = ""; }; + CDA1CBEA2CEF2C230041116B /* RankDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankDTO.swift; sourceTree = ""; }; + CDA1CBEC2CEF84850041116B /* UserProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileView.swift; sourceTree = ""; }; + CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankCardView.swift; sourceTree = ""; }; + CDA1CBF22CEF948E0041116B /* RankEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankEntity.swift; sourceTree = ""; }; + CDA1CBF42CEF95870041116B /* RankType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankType.swift; sourceTree = ""; }; CDC0C5802CEA61D1002988BF /* ChatroomDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomDTO.swift; sourceTree = ""; }; CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomEntity.swift; sourceTree = ""; }; CDC0C5852CEA6733002988BF /* ChatroomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomView.swift; sourceTree = ""; }; @@ -256,6 +266,7 @@ CD8CD2A52CEBB7C800DD7BB4 /* GameType.swift */, CD8CD2A92CEBC02F00DD7BB4 /* GameFilter.swift */, CD8CD2AC2CEC796B00DD7BB4 /* ChattingViewDestination.swift */, + CDA1CBF42CEF95870041116B /* RankType.swift */, ); path = Enum; sourceTree = ""; @@ -290,6 +301,7 @@ CD8CD2A72CEBBB4600DD7BB4 /* FlowRowLayoutView.swift */, CD8CD2B12CEC7BBB00DD7BB4 /* GLNavigationBar.swift */, CDF1F09F2CECFCBF0033F03F /* CachedImageView.swift */, + CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */, ); path = Core; sourceTree = ""; @@ -306,6 +318,7 @@ isa = PBXGroup; children = ( CD277DAF2CCE25F300BE57C4 /* ProfileMainView.swift */, + CDA1CBEC2CEF84850041116B /* UserProfileView.swift */, ); path = View; sourceTree = ""; @@ -314,6 +327,7 @@ isa = PBXGroup; children = ( CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */, + CDA1CBF22CEF948E0041116B /* RankEntity.swift */, ); path = Entity; sourceTree = ""; @@ -475,6 +489,7 @@ CDF1F0A32CECFD850033F03F /* ChatRoomUserListDetailDTO.swift */, CDF1F0A72CECFE150033F03F /* GameInfoDTO.swift */, CDF1F0A92CECFE220033F03F /* ChampionDTO.swift */, + CDA1CBEA2CEF2C230041116B /* RankDTO.swift */, ); path = Entity; sourceTree = ""; @@ -703,11 +718,14 @@ CD929F1B2CD2B27400E67E4E /* GLTextFieldType.swift in Sources */, CDCB988D2C9DEA5C00DF9FD3 /* UserDefaultsWrapper.swift in Sources */, CD8CD2A82CEBBB4600DD7BB4 /* FlowRowLayoutView.swift in Sources */, + CDA1CBF52CEF95870041116B /* RankType.swift in Sources */, + CDA1CBED2CEF84850041116B /* UserProfileView.swift in Sources */, CDCB988B2C9DEA4A00DF9FD3 /* Config.swift in Sources */, CD277DB72CCE2A5E00BE57C4 /* RiotService.swift in Sources */, CDF1F09C2CECFC930033F03F /* ImageCacheManager.swift in Sources */, CD277DB22CCE260900BE57C4 /* ProfileViewModel.swift in Sources */, CD8CD2AD2CEC796B00DD7BB4 /* ChattingViewDestination.swift in Sources */, + CDA1CBEF2CEF8FEB0041116B /* RankCardView.swift in Sources */, CDF1F09E2CECFC9F0033F03F /* ImageCacheLoader.swift in Sources */, CDF1F0A22CECFCF80033F03F /* ChattingRoomCarouselView.swift in Sources */, CDCB98922C9DEAAA00DF9FD3 /* UserDefaultsList.swift in Sources */, @@ -726,11 +744,13 @@ CDF1F0A82CECFE150033F03F /* GameInfoDTO.swift in Sources */, CDC0C5862CEA6733002988BF /* ChatroomView.swift in Sources */, CD929F1D2CD2B33800E67E4E /* View + placeholder.swift in Sources */, + CDA1CBF32CEF948E0041116B /* RankEntity.swift in Sources */, CDD5CD2E2CA47B1A00208740 /* AuthViewModel.swift in Sources */, CDCB98592C9DE61200DF9FD3 /* GameLink_iOSApp.swift in Sources */, CDD5CD362CA483A900208740 /* UserService.swift in Sources */, CD8CD2B22CEC7BBB00DD7BB4 /* GLNavigationBar.swift in Sources */, CDCD34B42CBFF6670068E4F7 /* ChatroomAPI.swift in Sources */, + CDA1CBEB2CEF2C230041116B /* RankDTO.swift in Sources */, CDD5CD312CA47C0A00208740 /* AuthProvider.swift in Sources */, CDCB98852C9DE98E00DF9FD3 /* NetworkError.swift in Sources */, CDCB98832C9DE98000DF9FD3 /* ErrorResponse.swift in Sources */, diff --git a/GameLink-iOS/Domain/Entity/RankEntity.swift b/GameLink-iOS/Domain/Entity/RankEntity.swift new file mode 100644 index 0000000..448fc6f --- /dev/null +++ b/GameLink-iOS/Domain/Entity/RankEntity.swift @@ -0,0 +1,28 @@ +// +// RankEntity.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import Foundation + +public struct RankEntity: Hashable { + let type: RankType + let tier: LOLTier + let rank: String + let leaguePoints: Int + let wins: Int + let losses: Int + let winRate: Double + let kda: Double + let avgKills: Double + let avgDeaths: Double + let avgAssists: Double + let avgCs: Double + let best3champions: [ChampionDTO] + let veteran: Bool + let inactive: Bool + let freshBlood: Bool + let hotStreak: Bool +} diff --git a/GameLink-iOS/Domain/Enum/RankType.swift b/GameLink-iOS/Domain/Enum/RankType.swift new file mode 100644 index 0000000..dd0a77c --- /dev/null +++ b/GameLink-iOS/Domain/Enum/RankType.swift @@ -0,0 +1,22 @@ +// +// RankType.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import Foundation + +public enum RankType { + case solo + case team + + public var korTitle: String { + switch self { + case .solo: + return "개인/2인 랭크" + case .team: + return "팀 랭크" + } + } +} diff --git a/GameLink-iOS/Domain/Enum/Tier.swift b/GameLink-iOS/Domain/Enum/Tier.swift index fca0203..5df62a1 100644 --- a/GameLink-iOS/Domain/Enum/Tier.swift +++ b/GameLink-iOS/Domain/Enum/Tier.swift @@ -32,7 +32,6 @@ public enum LOLTier: String, CaseIterable { case challenger public var tierImage: UIImage { - return UIImage(named: "ic_\(self.rawValue)") ?? UIImage() } @@ -60,6 +59,16 @@ public enum LOLTier: String, CaseIterable { return "챌린저" } } + + public var engName: String { + switch self { + case .grandmaster: + return "GRANDMASTER" + + default: + return self.rawValue.uppercased() + } + } } extension LOLTier { diff --git a/GameLink-iOS/Feature/Core/CachedImageView.swift b/GameLink-iOS/Feature/Core/CachedImageView.swift index 372e6af..e87cbb0 100644 --- a/GameLink-iOS/Feature/Core/CachedImageView.swift +++ b/GameLink-iOS/Feature/Core/CachedImageView.swift @@ -19,7 +19,6 @@ struct CachedImageView: View { if let image = loader.image { Image(uiImage: image) .resizable() - .aspectRatio(contentMode: .fit) } else { ProgressView() .frame(maxWidth: .infinity, maxHeight: .infinity) diff --git a/GameLink-iOS/Feature/Core/RankCardView.swift b/GameLink-iOS/Feature/Core/RankCardView.swift new file mode 100644 index 0000000..a260c9c --- /dev/null +++ b/GameLink-iOS/Feature/Core/RankCardView.swift @@ -0,0 +1,138 @@ +// +// RankCardView.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import SwiftUI + +public struct RankCardView: View { + + public let rankData: RankEntity + + public var body: some View { + VStack(spacing: 14) { + topInfo() + + most3Champ() + } + .padding(.horizontal, GridRules.globalHorizontalPadding) + .padding(.vertical, 10) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(.glBackground1) + .stroke(.glGray3, lineWidth: 0.8) + ) + } +} + +private extension RankCardView { + @ViewBuilder + func topInfo() -> some View { + HStack(spacing: 10) { + VStack(alignment: .leading, spacing: 0) { + Text(rankData.type.korTitle) + .glFont(.body2Bold) + .foregroundStyle(.glPrimary1) + .padding(.vertical, 4) + .padding(.horizontal, 8) + .background( + RoundedRectangle(cornerRadius: 8) + .fill(.glWinBlue) + ) + + HStack(spacing: 8) { + Text("\(rankData.tier) \(rankData.rank)") + .glFont(.body1Bold) + .foregroundStyle(.white) + + Text("\(rankData.leaguePoints) LP") + .glFont(.body2Bold) + .foregroundStyle(.glGray1) + } + .padding(.top, 8) + + Text("\(rankData.wins)승 \(rankData.losses)패 (\(Int(rankData.winRate*100))%)") + .glFont(.body2) + .foregroundStyle(.glGray2) + .padding(.top, 4) + } + + Spacer() + + Image(uiImage: rankData.tier.tierImage) + .resizable() + .scaledToFit() + .frame(width: 90, height: 90) + } + } + + @ViewBuilder + func most3Champ() -> some View { + HStack(spacing: 20) { + ForEach(rankData.best3champions, id:\.self) { champion in + VStack(spacing: 10) { + CachedImageView(url: URL(string: champion.championImageUrl)) + .clipShape(Circle()) + .scaledToFit() + .frame(maxWidth: .infinity) + + Text("\(String(format: "%.1f", champion.kills)) / \(String(format: "%.1f", champion.deaths)) / \(String(format: "%.1f", champion.assists))") + .glFont(.navi).bold() + .foregroundStyle(.glGray1) + } + } + } + } +} + +#Preview { + RankCardView(rankData: RankEntity( + type: .solo, + tier: .bronze, + rank: "III", + leaguePoints: 40, + wins: 7, + losses: 4, + winRate: 0.6363636363636364, + kda: 2.9615384615384617, + avgKills: 12.909090909090908, + avgDeaths: 7.090909090909091, + avgAssists: 8.090909090909092, + avgCs: 208, + best3champions: [ + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Jhin_0.jpg", + kills: 14.8, + deaths: 5.0, + assists: 7.4, + winRate: 0.8, + wins: 4, + losses: 1 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Aphelios_0.jpg", + kills: 9.0, + deaths: 8.0, + assists: 8.0, + winRate: 1.0, + wins: 1, + losses: 0 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Varus_0.jpg", + kills: 15.0, + deaths: 7.0, + assists: 6.0, + winRate: 1.0, + wins: 1, + losses: 0 + ) + ], + veteran: false, + inactive: false, + freshBlood: false, + hotStreak: false + )) +} diff --git a/GameLink-iOS/Feature/Profile/View/ProfileMainView.swift b/GameLink-iOS/Feature/Profile/View/ProfileMainView.swift index 5bef1fc..274ab19 100644 --- a/GameLink-iOS/Feature/Profile/View/ProfileMainView.swift +++ b/GameLink-iOS/Feature/Profile/View/ProfileMainView.swift @@ -14,21 +14,30 @@ struct ProfileMainView: View { @FocusState private var focusState: GLTextFieldType? var body: some View { - VStack(spacing: 0) { - noAccountView() - - Spacer() - } - .onAppear() { - viewModel.action(.mainViewAppear) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.glBackground1, ignoresSafeAreaEdges: .all) + contents() + .task { + viewModel.action(.mainViewAppear) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.glBackground1, ignoresSafeAreaEdges: .all) } } private extension ProfileMainView { + @ViewBuilder + func contents() -> some View { + if let userData = viewModel.userProfileInfo { + UserProfileView(userData: userData) + } else { + VStack(spacing: 0) { + noAccountView() + + Spacer() + } + } + } + @ViewBuilder func noAccountView() -> some View { VStack(spacing: 0) { diff --git a/GameLink-iOS/Feature/Profile/View/UserProfileView.swift b/GameLink-iOS/Feature/Profile/View/UserProfileView.swift new file mode 100644 index 0000000..22cc7a3 --- /dev/null +++ b/GameLink-iOS/Feature/Profile/View/UserProfileView.swift @@ -0,0 +1,274 @@ +// +// UserProfileView.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import SwiftUI + +public struct UserProfileView: View { + + let userData: RiotAccountDTO + + public init(userData: RiotAccountDTO) { + self.userData = userData + } + + public var body: some View { + VStack(spacing: 0) { + userInfoTitle(userData: userData) + + updateSection() + + rankInfo() + + ScrollView { + + } + } + .ignoresSafeArea(edges: .top) + .background(.glBackground1) + } +} + +private extension UserProfileView { + + @ViewBuilder + func userInfoTitle(userData: RiotAccountDTO) -> some View { + ZStack(alignment: .bottom) { + CachedImageView(url: URL(string: userData.backgroundImageUrl)) + .scaledToFit() + .frame(width: .infinity) + + HStack(alignment: .center, spacing: 0) { + CachedImageView(url: URL(string: userData.summonerIconUrl)) + .clipShape(Circle()) + .frame(width: 80, height: 80) + .overlay(alignment: .bottom) { + Text(userData.summonerLevel.description) + .glFont(.body2Bold) + .foregroundStyle(.white) + .padding(.vertical, 2) + .padding(.horizontal, 8) + .background( + Capsule() + .fill(.glBackground2) + ) + .offset(y: 4) + } + .padding(.trailing, 20) + + VStack(alignment: .leading, spacing: 10) { + HStack(spacing: 8) { + Text(userData.summonerName) + .glFont(.title1) + .foregroundStyle(.white) + + Text("# \(userData.summonerTag)") + .glFont(.body1Bold) + .foregroundStyle(.glGray2) + } + + HStack(spacing: 8) { + Text("레더 랭킹") + } + } + + Spacer() + } + .padding(.bottom, 30) + .padding(.horizontal, GridRules.globalHorizontalPadding) + } + } + + @ViewBuilder + func updateSection() -> some View { + HStack(spacing: 0) { + GLButton( + title: "전적 갱신", + isValid: true, action: { }, + activeColor: .glPrimary4 + ) + + // TODO: Update Date + Text("최근 업데이트: 하루전") + .glFont(.body2Bold) + .foregroundStyle(.glGray1) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.leading, 20) + } + .padding(.vertical, 12) + .padding(.horizontal, GridRules.globalHorizontalPadding) + .background(.glBackground1) + } + + @ViewBuilder + func rankInfo() -> some View { + ScrollView(.horizontal, showsIndicators: false) { + LazyHStack(spacing: 10) { + RankCardView(rankData: RankDTO.toRankEntity(type: .solo, data: userData.soloRank)) + RankCardView(rankData: RankDTO.toRankEntity(type: .team, data: userData.teamRank)) + } + .padding(.horizontal, GridRules.globalHorizontalPadding) + } + .frame(height: 240) + } +} + +#Preview { + UserProfileView(userData: RiotAccountDTO( + userId: "ecc553e3-3adc-4710-9d53-67851f5d67ff", + nickname: "기백있는 아이번", + backgroundImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-background/Nautilus_0.jpg", + email: "jdh1109ok@naver.com", + puuid: "HL5muZIQq3OAA87WRlVh2z8ndQ4mPmjVv2pDMxiZbvOiYepS19VAcZ3SpWvEOrZhCmbu_ajpoR2Hpg", + summonerId: "WbcIo9pJ5P542CxTRtqnqUTltD8NYC13xWhx2Rc_f7y1CK0", + summonerName: "Legend Mouse", + summonerTag: "KR1", + summonerIconUrl: "https://ddragon.leagueoflegends.com/cdn/14.18.1/img/profileicon/746.png", + revisionDate: "2024-11-21T17:49:35.672165", + summonerLevel: 249, + total: RankDTO( + rankImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/lol-tier-image/bronze.png", + tier: "BRONZE", + rank: "III", + leaguePoints: 40, + wins: 13, + losses: 7, + winRate: 0.65, + kda: 4.0894308943089435, + avgKills: 11.15, + avgDeaths: 6.15, + avgAssists: 14.0, + avgCs: 143.95, + best3champions: [ + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Jhin_0.jpg", + kills: 12.25, + deaths: 3.75, + assists: 7.125, + winRate: 0.875, + wins: 7, + losses: 1 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Aphelios_0.jpg", + kills: 10.0, + deaths: 11.0, + assists: 16.5, + winRate: 1.0, + wins: 2, + losses: 0 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Ezreal_0.jpg", + kills: 14.5, + deaths: 8.0, + assists: 14.0, + winRate: 0.5, + wins: 1, + losses: 1 + ) + ], + veteran: false, + inactive: false, + freshBlood: false, + hotStreak: false + ), + soloRank: RankDTO( + rankImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/lol-tier-image/bronze.png", + tier: "BRONZE", + rank: "III", + leaguePoints: 40, + wins: 7, + losses: 4, + winRate: 0.6363636363636364, + kda: 2.9615384615384617, + avgKills: 12.909090909090908, + avgDeaths: 7.090909090909091, + avgAssists: 8.090909090909092, + avgCs: 208, + best3champions: [ + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Jhin_0.jpg", + kills: 14.8, + deaths: 5.0, + assists: 7.4, + winRate: 0.8, + wins: 4, + losses: 1 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Aphelios_0.jpg", + kills: 9.0, + deaths: 8.0, + assists: 8.0, + winRate: 1.0, + wins: 1, + losses: 0 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Varus_0.jpg", + kills: 15.0, + deaths: 7.0, + assists: 6.0, + winRate: 1.0, + wins: 1, + losses: 0 + ) + ], + veteran: false, + inactive: false, + freshBlood: false, + hotStreak: false + ), + teamRank: RankDTO( + rankImageUrl: "", + tier: "UNRANKED", + rank: "", + leaguePoints: 0, + wins: 5, + losses: 4, + winRate: 0.5555555555555556, + kda: 3.6842105263157894, + avgKills: 8.222222222222221, + avgDeaths: 4.222222222222222, + avgAssists: 7.333333333333333, + avgCs: 159.44444444444446, + best3champions: [ + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Jhin_0.jpg", + kills: 11.333333333333334, + deaths: 3.3333333333333335, + assists: 4.333333333333333, + winRate: 0.6666666666666666, + wins: 2, + losses: 1 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Ezreal_0.jpg", + kills: 7.5, + deaths: 3.0, + assists: 11.5, + winRate: 0.5, + wins: 1, + losses: 1 + ), + ChampionDTO( + championImageUrl: "https://gamelink-dev.s3.ap-northeast-2.amazonaws.com/champion-profile/Xerath_0.jpg", + kills: 13.0, + deaths: 3.0, + assists: 14.0, + winRate: 1.0, + wins: 1, + losses: 0 + ) + ], + veteran: false, + inactive: false, + freshBlood: false, + hotStreak: false + )) + ) +} diff --git a/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift b/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift new file mode 100644 index 0000000..031d37e --- /dev/null +++ b/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift @@ -0,0 +1,52 @@ +// +// RankDTO.swift +// GameLink-iOS +// +// Created by 정도현 on 11/21/24. +// + +import Foundation + +public struct RankDTO: Codable, Hashable { + let rankImageUrl: String + let tier: String + let rank: String + let leaguePoints: Int + let wins: Int + let losses: Int + let winRate: Double + let kda: Double + let avgKills: Double + let avgDeaths: Double + let avgAssists: Double + let avgCs: Double + let best3champions: [ChampionDTO] + let veteran: Bool + let inactive: Bool + let freshBlood: Bool + let hotStreak: Bool +} + +public extension RankDTO { + static func toRankEntity(type: RankType, data: RankDTO) -> RankEntity { + return RankEntity( + type: type, + tier: LOLTier.stringToLOLTier(tier: data.tier), + rank: data.rank, + leaguePoints: data.leaguePoints, + wins: data.wins, + losses: data.losses, + winRate: data.winRate, + kda: data.kda, + avgKills: data.avgKills, + avgDeaths: data.avgDeaths, + avgAssists: data.avgAssists, + avgCs: data.avgCs, + best3champions: data.best3champions, + veteran: data.veteran, + inactive: data.inactive, + freshBlood: data.freshBlood, + hotStreak: data.hotStreak + ) + } +} diff --git a/GameLink-iOS/Networks/Sources/Entity/RiotAccountDTO.swift b/GameLink-iOS/Networks/Sources/Entity/RiotAccountDTO.swift index 9be89f3..cb93d36 100644 --- a/GameLink-iOS/Networks/Sources/Entity/RiotAccountDTO.swift +++ b/GameLink-iOS/Networks/Sources/Entity/RiotAccountDTO.swift @@ -10,7 +10,7 @@ import Foundation public struct RiotAccountDTO: Codable { let userId: String let nickname: String - let profileImageUrl: [ProfileImage] + let backgroundImageUrl: String let email: String let puuid: String let summonerId: String @@ -19,26 +19,7 @@ public struct RiotAccountDTO: Codable { let summonerIconUrl: String let revisionDate: String let summonerLevel: Int - let soloRank: Rank - let teamRank: Rank - - struct ProfileImage: Codable { - let id: String - let url: String - let originalName: String - let mimeType: String - } - - struct Rank: Codable { - let rankImageUrl: String - let tier: String - let rank: String - let leaguePoints: Int - let wins: Int - let losses: Int - let veteran: Bool - let inactive: Bool - let freshBlood: Bool - let hotStreak: Bool - } + let total: RankDTO + let soloRank: RankDTO + let teamRank: RankDTO } From 4b6b391d38c1f5c86a655c0b6495d66c16655fbd Mon Sep 17 00:00:00 2001 From: JungDohyeon Date: Fri, 22 Nov 2024 02:40:38 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[Fix]=20GameType=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GameLink-iOS/Domain/Enum/GameType.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GameLink-iOS/Domain/Enum/GameType.swift b/GameLink-iOS/Domain/Enum/GameType.swift index c1d0dd2..0adab1b 100644 --- a/GameLink-iOS/Domain/Enum/GameType.swift +++ b/GameLink-iOS/Domain/Enum/GameType.swift @@ -20,11 +20,11 @@ public enum LOLGameType: CaseIterable { public var korName: String { switch self { case .soloRank: - return "솔로랭크" + return "개인/2인 랭크" case .freeRank: - return "자유랭크" + return "자유 랭크" case .normal: - return "일반게임" + return "일반" } } } From d8e4a77e19c2b5bb224525732a85bbac68107200 Mon Sep 17 00:00:00 2001 From: JungDohyeon Date: Fri, 22 Nov 2024 02:41:16 +0900 Subject: [PATCH 4/4] [Feat] LOL MatchCardView Prototype --- GameLink-iOS.xcodeproj/project.pbxproj | 20 ++- .../Domain/Entity/LOLMatchEntity.swift | 41 ++++++ GameLink-iOS/Domain/Entity/RankEntity.swift | 2 +- GameLink-iOS/Domain/Enum/RankType.swift | 22 --- GameLink-iOS/Feature/Core/MatchCardView.swift | 128 ++++++++++++++++++ GameLink-iOS/Feature/Core/RankCardView.swift | 4 +- .../Profile/View/UserMatchListView.swift | 18 +++ .../Profile/View/UserProfileView.swift | 4 +- .../Networks/Sources/Entity/LOLMatchDTO.swift | 41 ++++++ .../Networks/Sources/Entity/RankDTO.swift | 2 +- 10 files changed, 250 insertions(+), 32 deletions(-) create mode 100644 GameLink-iOS/Domain/Entity/LOLMatchEntity.swift delete mode 100644 GameLink-iOS/Domain/Enum/RankType.swift create mode 100644 GameLink-iOS/Feature/Core/MatchCardView.swift create mode 100644 GameLink-iOS/Feature/Profile/View/UserMatchListView.swift create mode 100644 GameLink-iOS/Networks/Sources/Entity/LOLMatchDTO.swift diff --git a/GameLink-iOS.xcodeproj/project.pbxproj b/GameLink-iOS.xcodeproj/project.pbxproj index f99e712..e81785d 100644 --- a/GameLink-iOS.xcodeproj/project.pbxproj +++ b/GameLink-iOS.xcodeproj/project.pbxproj @@ -40,7 +40,10 @@ CDA1CBED2CEF84850041116B /* UserProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBEC2CEF84850041116B /* UserProfileView.swift */; }; CDA1CBEF2CEF8FEB0041116B /* RankCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */; }; CDA1CBF32CEF948E0041116B /* RankEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF22CEF948E0041116B /* RankEntity.swift */; }; - CDA1CBF52CEF95870041116B /* RankType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF42CEF95870041116B /* RankType.swift */; }; + CDA1CBF72CEF9D390041116B /* UserMatchListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF62CEF9D390041116B /* UserMatchListView.swift */; }; + CDA1CBF92CEF9D5D0041116B /* LOLMatchDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBF82CEF9D5D0041116B /* LOLMatchDTO.swift */; }; + CDA1CBFB2CEF9F7C0041116B /* MatchCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBFA2CEF9F7C0041116B /* MatchCardView.swift */; }; + CDA1CBFD2CEFA0820041116B /* LOLMatchEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1CBFC2CEFA0820041116B /* LOLMatchEntity.swift */; }; CDC0C5812CEA61D1002988BF /* ChatroomDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5802CEA61D1002988BF /* ChatroomDTO.swift */; }; CDC0C5842CEA63E6002988BF /* ChatroomEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */; }; CDC0C5862CEA6733002988BF /* ChatroomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC0C5852CEA6733002988BF /* ChatroomView.swift */; }; @@ -139,7 +142,10 @@ CDA1CBEC2CEF84850041116B /* UserProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileView.swift; sourceTree = ""; }; CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankCardView.swift; sourceTree = ""; }; CDA1CBF22CEF948E0041116B /* RankEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankEntity.swift; sourceTree = ""; }; - CDA1CBF42CEF95870041116B /* RankType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RankType.swift; sourceTree = ""; }; + CDA1CBF62CEF9D390041116B /* UserMatchListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserMatchListView.swift; sourceTree = ""; }; + CDA1CBF82CEF9D5D0041116B /* LOLMatchDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LOLMatchDTO.swift; sourceTree = ""; }; + CDA1CBFA2CEF9F7C0041116B /* MatchCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchCardView.swift; sourceTree = ""; }; + CDA1CBFC2CEFA0820041116B /* LOLMatchEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LOLMatchEntity.swift; sourceTree = ""; }; CDC0C5802CEA61D1002988BF /* ChatroomDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomDTO.swift; sourceTree = ""; }; CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomEntity.swift; sourceTree = ""; }; CDC0C5852CEA6733002988BF /* ChatroomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatroomView.swift; sourceTree = ""; }; @@ -266,7 +272,6 @@ CD8CD2A52CEBB7C800DD7BB4 /* GameType.swift */, CD8CD2A92CEBC02F00DD7BB4 /* GameFilter.swift */, CD8CD2AC2CEC796B00DD7BB4 /* ChattingViewDestination.swift */, - CDA1CBF42CEF95870041116B /* RankType.swift */, ); path = Enum; sourceTree = ""; @@ -302,6 +307,7 @@ CD8CD2B12CEC7BBB00DD7BB4 /* GLNavigationBar.swift */, CDF1F09F2CECFCBF0033F03F /* CachedImageView.swift */, CDA1CBEE2CEF8FEB0041116B /* RankCardView.swift */, + CDA1CBFA2CEF9F7C0041116B /* MatchCardView.swift */, ); path = Core; sourceTree = ""; @@ -319,6 +325,7 @@ children = ( CD277DAF2CCE25F300BE57C4 /* ProfileMainView.swift */, CDA1CBEC2CEF84850041116B /* UserProfileView.swift */, + CDA1CBF62CEF9D390041116B /* UserMatchListView.swift */, ); path = View; sourceTree = ""; @@ -328,6 +335,7 @@ children = ( CDC0C5832CEA63E6002988BF /* ChatroomEntity.swift */, CDA1CBF22CEF948E0041116B /* RankEntity.swift */, + CDA1CBFC2CEFA0820041116B /* LOLMatchEntity.swift */, ); path = Entity; sourceTree = ""; @@ -490,6 +498,7 @@ CDF1F0A72CECFE150033F03F /* GameInfoDTO.swift */, CDF1F0A92CECFE220033F03F /* ChampionDTO.swift */, CDA1CBEA2CEF2C230041116B /* RankDTO.swift */, + CDA1CBF82CEF9D5D0041116B /* LOLMatchDTO.swift */, ); path = Entity; sourceTree = ""; @@ -709,19 +718,21 @@ CDF1F0A02CECFCBF0033F03F /* CachedImageView.swift in Sources */, CDF1F0AC2CED103C0033F03F /* UserCarouselCardView.swift in Sources */, CD277DB02CCE25F300BE57C4 /* ProfileMainView.swift in Sources */, + CDA1CBFD2CEFA0820041116B /* LOLMatchEntity.swift in Sources */, CDD5CD2C2CA47B0D00208740 /* AuthView.swift in Sources */, CD534BF92CD3EA60003F3CA6 /* ReissueDTO.swift in Sources */, CDD5CD342CA4839B00208740 /* UserAPI.swift in Sources */, + CDA1CBF92CEF9D5D0041116B /* LOLMatchDTO.swift in Sources */, CDCB985B2C9DE61200DF9FD3 /* ChattingListView.swift in Sources */, CDD5CD3D2CA4864700208740 /* OAuthDTO.swift in Sources */, CD760A3E2CE5E9CF006AEB85 /* GLColor.swift in Sources */, CD929F1B2CD2B27400E67E4E /* GLTextFieldType.swift in Sources */, CDCB988D2C9DEA5C00DF9FD3 /* UserDefaultsWrapper.swift in Sources */, CD8CD2A82CEBBB4600DD7BB4 /* FlowRowLayoutView.swift in Sources */, - CDA1CBF52CEF95870041116B /* RankType.swift in Sources */, CDA1CBED2CEF84850041116B /* UserProfileView.swift in Sources */, CDCB988B2C9DEA4A00DF9FD3 /* Config.swift in Sources */, CD277DB72CCE2A5E00BE57C4 /* RiotService.swift in Sources */, + CDA1CBF72CEF9D390041116B /* UserMatchListView.swift in Sources */, CDF1F09C2CECFC930033F03F /* ImageCacheManager.swift in Sources */, CD277DB22CCE260900BE57C4 /* ProfileViewModel.swift in Sources */, CD8CD2AD2CEC796B00DD7BB4 /* ChattingViewDestination.swift in Sources */, @@ -737,6 +748,7 @@ CDD5CD3F2CA48AE400208740 /* Utils.swift in Sources */, CD8CD2A42CEBB35000DD7BB4 /* ChattingFilterDetailView.swift in Sources */, CDD5CD382CA4850F00208740 /* BaseService.swift in Sources */, + CDA1CBFB2CEF9F7C0041116B /* MatchCardView.swift in Sources */, CD277DC22CCE2F5B00BE57C4 /* DefaultRiotService.swift in Sources */, CD277DC42CCE2F9B00BE57C4 /* DefaultChatService.swift in Sources */, CD8CD2AA2CEBC02F00DD7BB4 /* GameFilter.swift in Sources */, diff --git a/GameLink-iOS/Domain/Entity/LOLMatchEntity.swift b/GameLink-iOS/Domain/Entity/LOLMatchEntity.swift new file mode 100644 index 0000000..4f7e7ab --- /dev/null +++ b/GameLink-iOS/Domain/Entity/LOLMatchEntity.swift @@ -0,0 +1,41 @@ +// +// LOLMatchEntity.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import Foundation + +public struct LOLMatchEntity: Hashable { + let matchId: String + let matchType: LOLGameType + let championName: String + let doubleKills: Int + let firstBloodKill: Bool + let teamPosition: LOLPosition + let pentaKills: Int + let assists: Int + let deaths: Int + let kills: Int + let kda: Double + let firstBloodAssist: Bool + let firstTowerAssist: Bool + let firstTowerKill: Bool + let goldPerMinute: Int + let gameEndedInEarlySurrender: Bool + let gameEndedInSurrender: Bool + let timePlayed: Int + let totalMinionsKilled: Int + let win: Bool + let soloKills: Int + let legendaryCount: Int + let damagePerMinute: Int + let dragonTakedowns: Int + let epicMonsterSteals: Int + let baronTakedowns: Int + let voidMonsterKill: Int + let perfectDragonSoulsTaken: Int + let elderDragonMultikills: Int + let killParticipation: Int +} diff --git a/GameLink-iOS/Domain/Entity/RankEntity.swift b/GameLink-iOS/Domain/Entity/RankEntity.swift index 448fc6f..f147298 100644 --- a/GameLink-iOS/Domain/Entity/RankEntity.swift +++ b/GameLink-iOS/Domain/Entity/RankEntity.swift @@ -8,7 +8,7 @@ import Foundation public struct RankEntity: Hashable { - let type: RankType + let type: LOLGameType let tier: LOLTier let rank: String let leaguePoints: Int diff --git a/GameLink-iOS/Domain/Enum/RankType.swift b/GameLink-iOS/Domain/Enum/RankType.swift deleted file mode 100644 index dd0a77c..0000000 --- a/GameLink-iOS/Domain/Enum/RankType.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// RankType.swift -// GameLink-iOS -// -// Created by 정도현 on 11/22/24. -// - -import Foundation - -public enum RankType { - case solo - case team - - public var korTitle: String { - switch self { - case .solo: - return "개인/2인 랭크" - case .team: - return "팀 랭크" - } - } -} diff --git a/GameLink-iOS/Feature/Core/MatchCardView.swift b/GameLink-iOS/Feature/Core/MatchCardView.swift new file mode 100644 index 0000000..87eb329 --- /dev/null +++ b/GameLink-iOS/Feature/Core/MatchCardView.swift @@ -0,0 +1,128 @@ +// +// MatchCardView.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import SwiftUI + +public struct MatchCardView: View { + + let matchData: LOLMatchEntity + + public init(matchData: LOLMatchEntity) { + self.matchData = matchData + } + + public var body: some View { + HStack(spacing: 0) { + Rectangle() + .fill(matchData.win ? .blue : .errorRed) + .frame(width: 8) + .padding(.trailing, 10) + + VStack(alignment: .leading, spacing: 0) { + Text(matchData.matchType.korName) + .glFont(.body2Bold) + .foregroundStyle(matchData.win ? .blue : .errorRed) + .padding(.bottom, 2) + + Text(matchData.win ? "승리" : "패배") + .glFont(.body2) + .foregroundStyle(.glGray2) + + Spacer() + } + .padding(.vertical, 10) + + Spacer() + + if let positionImage = matchData.teamPosition.positionImage { + Image(uiImage: positionImage) + .resizable() + .frame(width: 50, height: 50) + } + } + .padding(.trailing, 14) + .frame(height: 100) + .background( + matchData.win ? .winBlue : .glLooseRed + ) + .clipShape(.rect(cornerRadius: 8)) + } +} + +#Preview { + VStack { + MatchCardView( + matchData: LOLMatchEntity( + matchId: "string", + matchType: .freeRank, + championName: "아트록스", + doubleKills: 1, + firstBloodKill: true, + teamPosition: .mid, + pentaKills: 0, + assists: 5, + deaths: 3, + kills: 5, + kda: 3.3, + firstBloodAssist: true, + firstTowerAssist: true, + firstTowerKill: true, + goldPerMinute: 300, + gameEndedInEarlySurrender: true, + gameEndedInSurrender: true, + timePlayed: 0, + totalMinionsKilled: 0, + win: true, + soloKills: 0, + legendaryCount: 0, + damagePerMinute: 0, + dragonTakedowns: 0, + epicMonsterSteals: 0, + baronTakedowns: 0, + voidMonsterKill: 0, + perfectDragonSoulsTaken: 0, + elderDragonMultikills: 0, + killParticipation: 0 + ) + ) + MatchCardView( + matchData: LOLMatchEntity( + matchId: "string", + matchType: .freeRank, + championName: "아트록스", + doubleKills: 1, + firstBloodKill: true, + teamPosition: .top, + pentaKills: 0, + assists: 5, + deaths: 3, + kills: 5, + kda: 3.3, + firstBloodAssist: true, + firstTowerAssist: true, + firstTowerKill: true, + goldPerMinute: 300, + gameEndedInEarlySurrender: true, + gameEndedInSurrender: true, + timePlayed: 0, + totalMinionsKilled: 0, + win: false, + soloKills: 0, + legendaryCount: 0, + damagePerMinute: 0, + dragonTakedowns: 0, + epicMonsterSteals: 0, + baronTakedowns: 0, + voidMonsterKill: 0, + perfectDragonSoulsTaken: 0, + elderDragonMultikills: 0, + killParticipation: 0 + ) + ) + } + .padding() +} diff --git a/GameLink-iOS/Feature/Core/RankCardView.swift b/GameLink-iOS/Feature/Core/RankCardView.swift index a260c9c..8feb809 100644 --- a/GameLink-iOS/Feature/Core/RankCardView.swift +++ b/GameLink-iOS/Feature/Core/RankCardView.swift @@ -32,7 +32,7 @@ private extension RankCardView { func topInfo() -> some View { HStack(spacing: 10) { VStack(alignment: .leading, spacing: 0) { - Text(rankData.type.korTitle) + Text(rankData.type.korName) .glFont(.body2Bold) .foregroundStyle(.glPrimary1) .padding(.vertical, 4) @@ -89,7 +89,7 @@ private extension RankCardView { #Preview { RankCardView(rankData: RankEntity( - type: .solo, + type: .soloRank, tier: .bronze, rank: "III", leaguePoints: 40, diff --git a/GameLink-iOS/Feature/Profile/View/UserMatchListView.swift b/GameLink-iOS/Feature/Profile/View/UserMatchListView.swift new file mode 100644 index 0000000..99eb2f5 --- /dev/null +++ b/GameLink-iOS/Feature/Profile/View/UserMatchListView.swift @@ -0,0 +1,18 @@ +// +// UserMatchListView.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import SwiftUI + +struct UserMatchListView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + UserMatchListView() +} diff --git a/GameLink-iOS/Feature/Profile/View/UserProfileView.swift b/GameLink-iOS/Feature/Profile/View/UserProfileView.swift index 22cc7a3..91b01bd 100644 --- a/GameLink-iOS/Feature/Profile/View/UserProfileView.swift +++ b/GameLink-iOS/Feature/Profile/View/UserProfileView.swift @@ -107,8 +107,8 @@ private extension UserProfileView { func rankInfo() -> some View { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 10) { - RankCardView(rankData: RankDTO.toRankEntity(type: .solo, data: userData.soloRank)) - RankCardView(rankData: RankDTO.toRankEntity(type: .team, data: userData.teamRank)) + RankCardView(rankData: RankDTO.toRankEntity(type: .soloRank, data: userData.soloRank)) + RankCardView(rankData: RankDTO.toRankEntity(type: .freeRank, data: userData.teamRank)) } .padding(.horizontal, GridRules.globalHorizontalPadding) } diff --git a/GameLink-iOS/Networks/Sources/Entity/LOLMatchDTO.swift b/GameLink-iOS/Networks/Sources/Entity/LOLMatchDTO.swift new file mode 100644 index 0000000..6604fcb --- /dev/null +++ b/GameLink-iOS/Networks/Sources/Entity/LOLMatchDTO.swift @@ -0,0 +1,41 @@ +// +// LOLMatchDTO.swift +// GameLink-iOS +// +// Created by 정도현 on 11/22/24. +// + +import Foundation + +public struct LOLMatchDTO: Codable, Hashable { + let matchId: String + let matchType: String + let championName: String + let doubleKills: Int + let firstBloodKill: Bool + let teamPosition: String + let pentaKills: Int + let assists: Int + let deaths: Int + let kills: Int + let kda: Double + let firstBloodAssist: Bool + let firstTowerAssist: Bool + let firstTowerKill: Bool + let goldPerMinute: Int + let gameEndedInEarlySurrender: Bool + let gameEndedInSurrender: Bool + let timePlayed: Int + let totalMinionsKilled: Int + let win: Bool + let soloKills: Int + let legendaryCount: Int + let damagePerMinute: Int + let dragonTakedowns: Int + let epicMonsterSteals: Int + let baronTakedowns: Int + let voidMonsterKill: Int + let perfectDragonSoulsTaken: Int + let elderDragonMultikills: Int + let killParticipation: Int +} diff --git a/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift b/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift index 031d37e..dc2088b 100644 --- a/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift +++ b/GameLink-iOS/Networks/Sources/Entity/RankDTO.swift @@ -28,7 +28,7 @@ public struct RankDTO: Codable, Hashable { } public extension RankDTO { - static func toRankEntity(type: RankType, data: RankDTO) -> RankEntity { + static func toRankEntity(type: LOLGameType, data: RankDTO) -> RankEntity { return RankEntity( type: type, tier: LOLTier.stringToLOLTier(tier: data.tier),