From cab719c774c773c4335206446c7793590253a6a6 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Sat, 11 May 2024 02:56:52 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A3=B0=EB=A0=9B=20=EB=B3=80=EA=B2=BD=20-=20?= =?UTF-8?q?=ED=99=95=EB=A5=A0=20=EC=88=98=EB=8F=99=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?-=20=EC=97=AC=EB=9F=AC=EA=B0=9C=EC=9D=98=20=EB=A3=B0=EB=A0=9B?= =?UTF-8?q?=EC=9D=B4=20=EC=BC=9C=EC=A0=B8=EC=9E=88=EC=9D=84=20=EB=95=8C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=98=EC=97=AC=20=EB=8F=8C=EB=A6=AC?= =?UTF-8?q?=EA=B8=B0=20-=20=ED=9B=84=EC=9B=90=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=EC=97=90=20=EB=A3=B0=EB=A0=9B=20=ED=9E=88?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../btn_minus_round_rect.png | Bin 2438 -> 0 bytes .../Contents.json | 21 --- .../btn_plus_round_rect.png | Bin 2874 -> 0 bytes .../ic_donation_message_list.png | Bin 3606 -> 996 bytes .../Contents.json | 2 +- .../ic_select_check_black.png | Bin 0 -> 418 bytes .../LiveRoomDonationMessageDialog.swift | 34 +---- .../LiveRoomDonationMessageItemView.swift | 68 ++++++++++ .../Sources/Live/Room/LiveRoomViewModel.swift | 49 +++---- .../Routlette/Config/RouletteOption.swift | 7 +- .../Config/RouletteSettingsOptionView.swift | 40 +++--- .../Config/RouletteSettingsView.swift | 6 +- .../Config/RouletteSettingsViewModel.swift | 105 ++++++--------- .../Room/Routlette/GetRouletteResponse.swift | 3 +- .../Live/Room/Routlette/RouletteApi.swift | 8 +- .../Live/Room/Routlette/RoulettePreview.swift | 1 + .../Routlette/RoulettePreviewDialog.swift | 121 +++++++++++++++--- .../Room/Routlette/SpinRouletteRequest.swift | 1 + .../Room/Routlette/SpinRouletteResponse.swift | 12 ++ .../Sources/Live/Room/V2/LiveRoomViewV2.swift | 88 +++++-------- .../UI/Component/SelectedButtonView.swift | 38 +++++- 21 files changed, 339 insertions(+), 265 deletions(-) delete mode 100644 SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png delete mode 100644 SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json delete mode 100644 SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png rename SodaLive/Resources/Assets.xcassets/{btn_minus_round_rect.imageset => ic_select_check_black.imageset}/Contents.json (84%) create mode 100644 SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png create mode 100644 SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift create mode 100644 SodaLive/Sources/Live/Room/Routlette/SpinRouletteResponse.swift diff --git a/SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png b/SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png deleted file mode 100644 index ae6a88e2742f1e865ea57bc318cef43ca38bb04d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2438 zcmb7G`9Bkm8=uL2tuf?Il24bTXvo;iRm?dohVo_Q3Y#NGCR>h3j>d=22TO8Ixe~&J z5IH{1+?3fY9cag>@d^2^vv)q4K@vgwPMKFm)AOkdbUf zdgaiKyC;K`x$Kaw{5%5Pr$zZ-mqSsi3um5!Zzk}kyC&#rI!DP>YAMK`%Fw`$l>f@k z3Ej6$?HZmjnYEU2ata9v2|Hq=o6FXAG@Q?D=3U$iByxE)rE1o@0|-5p;-tfArS8bf zTAfL4;4H83sypcZhqcW%ByA#GNH{r5@6AkYfV%V8WsHp&2rfY;W>6|kT~7L=5qs7Y zUZg4>K#~p|rWNrxA1-nq1pUC*>+C-l#uZf8strpmm{JQFI;;kHozVM_{Ijy7Y#d3 znUIqe_Rq%lau*C*Yjl&{)|{*BP$E*x?aX+=q9>%W-MyQ~v0kf6AYZ;)PWu^M*!aTN z&ev%m?8}Lj&@^-Z)(V$m*;V}7^=C%Zby(?n@SfR5yZRVq-(lvB2iayHMG2*TBSwQ0 zCBy>8ABBigzJv|DFN*$kT^q3g6@VHNr~ZXLGvA5D_J(~k8`Z%b5{D3lrX|8FXP^)V z*fsbp7MO{mQy&|qqx!FCTNRwkESyJ8=jB2Lky`W8kX$3)JN(6K(*$d^T2*0N6(43g zH$wpz4bskED?lV{Z8Pp!6hzhh)2IvR{$D3TI};DyM0m6??5$&x^n0>+5+f zI@yo}XB|R8s~$VUVh-KJa>`TBn)p10Ti{FRmwY1#?HD`Rw@oi817~~PABrLyIlVWA zyfAg0bW}8bn9Y(-AnX+C)6Z+CKSVC0rrq+Ifyl;ICmB#D>&R8(pSUyzeh!d!dHYD5 z?22C5oHAad6pMBJX{4tMDlM{$RwR?Oc)&d%b2Vcns&Fhx>%{*K(xsB__xD`lwd*)bmCF*2q;pA*=MXg7YQfbQ zOy9a^NKYp;ZXU0C+RYC^o{@7z?ul0_zOZ*P_g8#!OGl`#%v8)$KVjg7;{!bHxYJ9yOrRW$3GA?>|_j~MyK0Q(2)|NKWmBM0G= zR&VN%$iKJd+tunYn|_pua(x=zn|1?7TR6BWuyNCq7U34XsDfZNJU~AR^^=R6P^+~n>AdD- zZ|s)R0Mv}m&-J$E4rfIbg?DiV>D}8=;pK;A`0zH(Pd>1d1oDS4P$AJ@ysWft65Gok z5iv6vf)gFFf4#x&PS&ij#h=*i8I;P)cA>PW6=9!+CEpEC4dSPO_g%}4)JyB=%&)KC zj&xA#M4qf&$ZpT|yQiXxlQjs__#-r`OBtpRa@U*<03mpk}EOQPUtg7gU^C#`p7IDrTN5L#1cTe?nBow!@2{2GIDgg3Dj&_#sE)mOKIG76INzb$d0F`# z;FU)3E;fcs8Cx%jt~!rnnN10q#Qy#K`_Jm;+*otI67sM-#P&?2oEOGZdYUlq&f!?> z#|~=I2^rGosblv^w!-@C_`BDi0|%#i_r=QnZ+@9nqrR$>T!vTvA+bvNAaA7dq&SxN z?aTVYt83&Acvd(-b;G}{Jj0}p!Gb$>y>i;8k)s!;I8<=D+RqFXELh0iDnJsJ4 zzy1huqj&y3C%*SiE_bH3jSin9-i4^j$H$}dJ2pa$&JK+P-i93}@PDVf$Uu^}K5j5s zL1(44$>rP?E1V($5o6%kU#%=YA-1f%6w7z!_sQT|;alV~kk03<`6c`}6=&qZ8+=dF zb|EbRZt*l;)XLCVIwd&DevVF$tRBhWl1_WHK^Puv>se9txVH=h>HRQt>Y1&=ph6Aj zKNpsHi_)zPZ)3g+(1m6TYL^AT!p-eV6Q>RqdU#H`+3t*BTx5^cPl)2Qm^BMwxgO1g zCLO{Yb?hK~4=ZsP!)I@qU&IyGVgn1)MTv=nADc z*O*x*s>+)@@QO~Z(dUU%;HB{m!P#^L_2O9)X!oG{SxG{T*27ay1G)ER*LJQX+{zZb U%?eiMyiEWL6BP0_!sF3@0sU->DF6Tf diff --git a/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json b/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json deleted file mode 100644 index 6fc7e4e..0000000 --- a/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "btn_plus_round_rect.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png b/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png deleted file mode 100644 index a22155e15cc787c862ac41799a63c67a8745b371..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2874 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 M07*qoM6N<$f}oYNRsaA1 diff --git a/SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/Contents.json b/SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/Contents.json similarity index 84% rename from SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/Contents.json rename to SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/Contents.json index b214365..553d11b 100644 --- a/SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/Contents.json +++ b/SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/Contents.json @@ -9,7 +9,7 @@ "scale" : "2x" }, { - "filename" : "btn_minus_round_rect.png", + "filename" : "ic_select_check_black.png", "idiom" : "universal", "scale" : "3x" } diff --git a/SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png b/SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png new file mode 100644 index 0000000000000000000000000000000000000000..c9b4901c36875144f7a2ef5e8a8233fbae93703b GIT binary patch literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIde}J$B+ufw>Qt`9&!+9d#LZp=*j8FZuxA6 zP*79;PBmE{cFlvb3Ktnv1DFb)GAv?B2-_g!6ery{{jTgj_gS+qzB2t6d6Gd81Y#ev zmhE}@=S9scol-M{H?isKHd~+LX%|koRJmsM+H?8051!YU-97h3NCiXg|2HpHV-E@( zYuflUSw|w;?wC?hPOC|}p=VC)ID?VZi;CBG3oARp$L<-l1uDY!V?}wOfMJn ze=PMd<6yz2s;?Z6+|qx}6Ft&-t}0kj!faQE?39EVFBWa5F=BT`ce^QWjEmp0GGe{ Void + + var body: some View { + HStack(alignment: .top, spacing: 0) { + VStack(alignment: .leading, spacing: 8) { + Text("\(message.nickname)님이") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.white) + + if !message.canMessage.trimmingCharacters(in: .whitespaces).isEmpty { + Text("\(message.canMessage)") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.white) + } + + Text("'\(message.donationMessage)'") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(.white) + } + + Spacer() + + Image("ic_close_white") + .resizable() + .frame(width: 13.3, height: 13.3) + .onTapGesture { deleteDonationMessage(message.uuid) } + } + .padding(13.3) + .background(message.canMessage.trimmingCharacters(in: .whitespaces).isEmpty ? Color(hex: "c25264").opacity(0.8) : Color.gray33) + .cornerRadius(5.3) + } +} + +#Preview("일반후원 메시지") { + LiveRoomDonationMessageItemView( + message: LiveRoomDonationMessage( + uuid: "", + nickname: "유저2님이", + canMessage: "10캔을 후원하셨습니다", + donationMessage: "ㅅㅅㅅ" + ), + deleteDonationMessage: { _ in } + ) +} + +#Preview("룰렛후원 메시지") { + LiveRoomDonationMessageItemView( + message: LiveRoomDonationMessage( + uuid: "", + nickname: "유저2님의 룰렛 결과?", + canMessage: "", + donationMessage: "[테스트] 당첨!" + ), + deleteDonationMessage: { _ in } + ) +} diff --git a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift index 9d06313..29f62b8 100644 --- a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift +++ b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift @@ -151,7 +151,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { @Published var isShowRouletteSettings = false @Published var isShowRoulettePreview = false - @Published var roulettePreview: RoulettePreview? = nil + @Published var roulettePreviewList = [RoulettePreview]() @Published var isShowRoulette = false @Published var rouletteItems = [String]() @@ -1456,6 +1456,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { func showRoulette() { if let liveRoomInfo = liveRoomInfo, !isLoading { + self.roulettePreviewList.removeAll() isLoading = true rouletteRepository.getRoulette(creatorId: liveRoomInfo.creatorId) @@ -1472,10 +1473,14 @@ final class LiveRoomViewModel: NSObject, ObservableObject { do { let jsonDecoder = JSONDecoder() - let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) + let decoded = try jsonDecoder.decode(ApiResponse<[GetRouletteResponse]>.self, from: responseData) - if let data = decoded.data, decoded.success, !data.items.isEmpty { - self.roulettePreview = RoulettePreview(can: data.can, items: calculatePercentages(options: data.items)) + if let data = decoded.data, decoded.success, !data.isEmpty { + let roulettePreviewList = data + .filter { $0.isActive } + .filter { !$0.items.isEmpty} + .map { RoulettePreview(id: $0.id, can: $0.can, items: calculatePercentages(options: $0.items)) } + self.roulettePreviewList.append(contentsOf: roulettePreviewList) self.isShowRoulettePreview = true } else { if let message = decoded.message { @@ -1494,10 +1499,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject { } } - func spinRoulette() { + func spinRoulette(rouletteId: Int) { if !isLoading { isLoading = true - rouletteRepository.spinRoulette(request: SpinRouletteRequest(roomId: AppState.shared.roomId)) + rouletteRepository.spinRoulette(request: SpinRouletteRequest(roomId: AppState.shared.roomId, rouletteId: rouletteId)) .sink { result in switch result { case .finished: @@ -1511,11 +1516,15 @@ final class LiveRoomViewModel: NSObject, ObservableObject { do { let jsonDecoder = JSONDecoder() - let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) + let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success, !data.items.isEmpty { UserDefaults.set(UserDefaults.int(forKey: .can) - data.can, forKey: .can) - randomSelectRouletteItem(can: data.can, items: data.items) + self.rouletteItems.removeAll() + self.rouletteItems.append(contentsOf: data.items.map { $0.title }) + self.rouletteSelectedItem = data.result + self.rouletteCan = data.can + self.isShowRoulette = true } else { if let message = decoded.message { self.errorMessage = message @@ -1574,35 +1583,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject { } private func calculatePercentages(options: [RouletteItem]) -> [RoulettePreviewItem] { - let totalWeight = options.reduce(0) { $0 + $1.weight } let updatedOptions = options.map { option in - let percent = floor(Double(option.weight) / Double(totalWeight) * 10000) / 100 - return RoulettePreviewItem(title: option.title, percent: "\(String(format: "%.2f", percent))%") + return RoulettePreviewItem(title: option.title, percent: "\(String(format: "%.2f", option.percentage))%") } return updatedOptions } - private func randomSelectRouletteItem(can: Int, items: [RouletteItem]) { - isLoading = true - - var rouletteItems = [String]() - items.forEach { - var i = 1 - while (i < $0.weight * 10) { - rouletteItems.append($0.title) - i += 1 - } - } - - isLoading = false - self.rouletteItems.removeAll() - self.rouletteItems.append(contentsOf: items.map { $0.title }) - self.rouletteSelectedItem = rouletteItems.randomElement()! - self.rouletteCan = can - self.isShowRoulette = true - } - private func refundRouletteDonation() { isLoading = true diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteOption.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteOption.swift index e238003..d7312f0 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteOption.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteOption.swift @@ -9,11 +9,10 @@ import SwiftUI class RouletteOption: ObservableObject { var title: String - var weight: Int - var percentage: String = "50.00" + var percentage: String = "" - init(title: String, weight: Int) { + init(title: String, percentage: String) { self.title = title - self.weight = weight + self.percentage = percentage } } diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift index fa42339..961738a 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift @@ -12,10 +12,7 @@ struct RouletteSettingsOptionView: View { @ObservedObject var option: RouletteOption let index: Int - - let onClickPlus: () -> Void let onClickDelete: () -> Void - let onClickSubstract: () -> Void var body: some View { VStack(spacing: 6.7) { @@ -47,19 +44,28 @@ struct RouletteSettingsOptionView: View { .background(Color(hex: "222222")) .cornerRadius(6.7) - Text("\(option.percentage)%") + HStack(spacing: 0) { + TextField("0.00", text: $option.percentage) + .autocapitalization(.none) + .disableAutocorrection(true) .font(.custom(Font.medium.rawValue, size: 13.3)) .foregroundColor(Color(hex: "eeeeee")) - .padding(.horizontal, 13.3) - .padding(.vertical, 16.7) - .background(Color(hex: "222222")) - .cornerRadius(6.7) - - Image("btn_minus_round_rect") - .onTapGesture { onClickSubstract() } - - Image("btn_plus_round_rect") - .onTapGesture { onClickPlus() } + .keyboardType(.decimalPad) + .onChange(of: option.percentage) { newValue in + if newValue.count > 5 { + option.percentage = String(newValue.prefix(5)) + } + } + + Text("%") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + } + .padding(.horizontal, 13.3) + .padding(.vertical, 16.7) + .frame(maxWidth: 85) + .background(Color(hex: "222222")) + .cornerRadius(6.7) } } } @@ -68,11 +74,9 @@ struct RouletteSettingsOptionView: View { struct RouletteSettingsOptionView_Previews: PreviewProvider { static var previews: some View { RouletteSettingsOptionView( - option: RouletteOption(title: "옵션1", weight: 1), + option: RouletteOption(title: "옵션1", percentage: ""), index: 2, - onClickPlus: {}, - onClickDelete: {}, - onClickSubstract: {} + onClickDelete: {} ) } } diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift index 39b9f8b..ce836c5 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift @@ -128,9 +128,7 @@ struct RouletteSettingsView: View { RouletteSettingsOptionView( option: viewModel.options[index], index: index, - onClickPlus: { viewModel.plusWeight(index: index) }, - onClickDelete: { viewModel.deleteOption(index: index) }, - onClickSubstract: { viewModel.subtractWeight(index: index) } + onClickDelete: { viewModel.deleteOption(index: index) } ) } } @@ -190,7 +188,7 @@ struct RouletteSettingsView: View { isShowing: $viewModel.isShowPreview, title: "룰렛 미리보기", onClickSpin: nil, - preview: preview + previewList: [preview] ) } } diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift index c714b77..839b5b8 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift @@ -46,47 +46,15 @@ final class RouletteSettingsViewModel: ObservableObject { private var rouletteId = 0 @Published var rouletteList = [GetNewRouletteResponse]() - func plusWeight(index: Int) { - options[index].weight += 1 - recalculatePercentages() - } - - func subtractWeight(index: Int) { - if options[index].weight > 1 { - options[index].weight -= 1 - recalculatePercentages() - } - } - func addOption() { if (options.count >= 10) { return } - options.append(RouletteOption(title: "", weight: 1)) - recalculatePercentages() + options.append(RouletteOption(title: "", percentage: "")) } func deleteOption(index: Int) { options.remove(at: index) - recalculatePercentages() - } - - private func recalculatePercentages() { - let options = options - - var totalWeight = 0 - for option in options { - totalWeight += option.weight - } - - guard totalWeight > 0 else { return } - - for i in 0.. 0 { - updateRoulette(onSuccess: onSuccess) - } else { - createRoulette(onSuccess: onSuccess) + if validationOptions() { + if rouletteId > 0 { + updateRoulette(onSuccess: onSuccess) + } else { + createRoulette(onSuccess: onSuccess) + } } } } - private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) { - var items = [RouletteItem]() + private func validationOptions() -> Bool { + var totalPercentage = Float(0) + for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false errorMessage = "옵션은 빈칸일 수 없습니다." isShowErrorPopup = true - return + return false } - items.append(RouletteItem(title: option.title, weight: option.weight)) + if let percentage = Float(option.percentage) { + totalPercentage += percentage + } + } + + if totalPercentage != Float(100) { + isLoading = false + errorMessage = "확률이 100%가 아닙니다" + isShowErrorPopup = true + return false + } + + return true + } + + private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) { + var items = [RouletteItem]() + for option in options { + if let percentage = Float(option.percentage) { + items.append(RouletteItem(title: option.title, percentage: percentage)) + } } let selectedRouletteTitle: String @@ -227,14 +218,9 @@ final class RouletteSettingsViewModel: ObservableObject { private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) { var items = [RouletteItem]() for option in options { - if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { - isLoading = false - errorMessage = "옵션은 빈칸일 수 없습니다." - isShowErrorPopup = true - return + if let percentage = Float(option.percentage) { + items.append(RouletteItem(title: option.title, percentage: percentage)) } - - items.append(RouletteItem(title: option.title, weight: option.weight)) } let selectedRoulette = rouletteList[selectedRoulette!.rawValue] @@ -259,24 +245,10 @@ final class RouletteSettingsViewModel: ObservableObject { selectedRouletteTitle = "룰렛 1" } - var isAllActive = false - - rouletteList - .filter { - $0.id != selectedRoulette.id - } - .forEach { - if $0.isActive { - isAllActive = true - } - } - if isActive { - successMessage = "\(selectedRouletteTitle)로 설정하였습니다." - } else if !isAllActive { - successMessage = "\(selectedRouletteTitle)이 비활성화 되었습니다." + successMessage = "\(selectedRouletteTitle)을 활성화 했습니다." } else { - successMessage = "\(selectedRouletteTitle)을 설정했습니다." + successMessage = "\(selectedRouletteTitle)을 비활성화 했습니다." } let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items) @@ -337,10 +309,9 @@ final class RouletteSettingsViewModel: ObservableObject { self.rouletteId = roulette.id self.isActive = roulette.isActive let options = roulette.items.map { - RouletteOption(title: $0.title, weight: $0.weight) + RouletteOption(title: $0.title, percentage: String($0.percentage)) } removeAllAndAddOptions(options: options) - recalculatePercentages() } else { self.canText = "" self.isActive = false diff --git a/SodaLive/Sources/Live/Room/Routlette/GetRouletteResponse.swift b/SodaLive/Sources/Live/Room/Routlette/GetRouletteResponse.swift index 02a61ec..7ef94ad 100644 --- a/SodaLive/Sources/Live/Room/Routlette/GetRouletteResponse.swift +++ b/SodaLive/Sources/Live/Room/Routlette/GetRouletteResponse.swift @@ -6,6 +6,7 @@ // struct GetRouletteResponse: Decodable { + let id: Int let can: Int let isActive: Bool let items: [RouletteItem] @@ -13,5 +14,5 @@ struct GetRouletteResponse: Decodable { struct RouletteItem: Codable, Equatable { let title: String - let weight: Int + let percentage: Float } diff --git a/SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift b/SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift index 79399fa..e6d5b04 100644 --- a/SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift +++ b/SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift @@ -25,16 +25,16 @@ extension RouletteApi: TargetType { var path: String { switch self { case .getRoulette, .createRoulette, .updateRoulette: - return "/new-roulette" + return "/v2/roulette" case .getAllRoulette: - return "/new-roulette/creator" + return "/v2/roulette/creator" case .spinRoulette: - return "/new-roulette/spin" + return "/v2/roulette/spin" case .refundRouletteDonation(let roomId): - return "/new-roulette/refund/\(roomId)" + return "/v2/roulette/refund/\(roomId)" } } diff --git a/SodaLive/Sources/Live/Room/Routlette/RoulettePreview.swift b/SodaLive/Sources/Live/Room/Routlette/RoulettePreview.swift index 4066f31..6e14872 100644 --- a/SodaLive/Sources/Live/Room/Routlette/RoulettePreview.swift +++ b/SodaLive/Sources/Live/Room/Routlette/RoulettePreview.swift @@ -8,6 +8,7 @@ import Foundation struct RoulettePreview { + let id: Int let can: Int let items: [RoulettePreviewItem] } diff --git a/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift b/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift index 1984040..26c45a6 100644 --- a/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift +++ b/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift @@ -12,13 +12,61 @@ struct RoulettePreviewDialog: View { @Binding var isShowing: Bool let title: String? - let onClickSpin: (() -> Void)? - let preview: RoulettePreview + let onClickSpin: ((Int) -> Void)? + let previewList: [RoulettePreview] + + @State var selectedRoulette = SelectedRoulette.ROULETTE_1 var body: some View { GeometryReader { geo in ZStack { - VStack(spacing: 0) { + VStack(spacing: 16.7) { + if previewList.count > 1 { + HStack(spacing: 13.3) { + SelectedButtonView( + title: "룰렛 1", + isActive: true, + isSelected: selectedRoulette == .ROULETTE_1 + ) + .onTapGesture { + if selectedRoulette != .ROULETTE_1 { + selectedRoulette = .ROULETTE_1 + } + } + + SelectedButtonView( + title: "룰렛 2", + isActive: true, + isSelected: selectedRoulette == .ROULETTE_2, + checkImage: "ic_select_check_black", + bgSelectedColor: Color(hex: "ffcb14"), + textSelectedColor: Color.black, + textDefaultColor: Color(hex: "ffcb14") + ) + .onTapGesture { + if selectedRoulette != .ROULETTE_2 { + selectedRoulette = .ROULETTE_2 + } + } + + if previewList.count > 2 { + SelectedButtonView( + title: "룰렛 3", + isActive: true, + isSelected: selectedRoulette == .ROULETTE_3, + bgSelectedColor: Color(hex: "ff14d9"), + textDefaultColor: Color(hex: "ff14d9") + ) + .onTapGesture { + if selectedRoulette != .ROULETTE_3 { + selectedRoulette = .ROULETTE_3 + } + } + } + } + .padding(.top, 16.7) + } + HStack(spacing: 0) { Text(title ?? "룰렛") .font(.custom(Font.bold.rawValue, size: 18.3)) @@ -42,54 +90,66 @@ struct RoulettePreviewDialog: View { } } } - .padding(.top, 16.7) + .padding(.top, previewList.count > 1 ? 0 : 16.7) .padding(.horizontal, 13.3) LazyVStack(alignment: .leading, spacing: 13.3) { - ForEach(preview.items.indices, id: \.self) { index in + ForEach(previewList[selectedRoulette.rawValue].items.indices, id: \.self) { index in HStack(spacing:13.3) { Text("\(index + 1)") .font(.custom(Font.bold.rawValue, size: 14.7)) .foregroundColor(Color(hex: "e2e2e2")) - Text("\(preview.items[index].title) (\(preview.items[index].percent))") + Text("\(previewList[selectedRoulette.rawValue].items[index].title) (\(previewList[selectedRoulette.rawValue].items[index].percent))") .font(.custom(Font.medium.rawValue, size: 14.7)) .foregroundColor(Color(hex: "e2e2e2")) } } } - .padding(.top, 13.3) .padding(.horizontal, 13.3) HStack(spacing: 13.3) { Text("취소") .font(.custom(Font.bold.rawValue, size: 16)) - .foregroundColor(Color(hex: "3bb9f1")) + .foregroundColor( + selectedRoulette == .ROULETTE_2 ? Color(hex: "ffcb14") : + selectedRoulette == .ROULETTE_3 ? Color(hex: "ff14d9") : + Color.button + ) .padding(.horizontal, 18) .padding(.vertical, 16) .overlay( RoundedRectangle(cornerRadius: 10) - .stroke(Color(hex: "3bb9f1"), lineWidth: 1) + .stroke( + selectedRoulette == .ROULETTE_2 ? Color(hex: "ffcb14") : + selectedRoulette == .ROULETTE_3 ? Color(hex: "ff14d9") : + Color.button, + lineWidth: 1 + ) ) .onTapGesture { isShowing = false } - Text("\(preview.can)캔으로 룰렛 돌리기") + Text("\(previewList[selectedRoulette.rawValue].can)캔으로 룰렛 돌리기") .font(.custom(Font.bold.rawValue, size: 16)) - .foregroundColor(.white) + .foregroundColor(selectedRoulette == .ROULETTE_2 ? .black : .white) .padding(.vertical, 16) .frame(maxWidth: .infinity) - .background(Color(hex: "3bb9f1")) + .background( + selectedRoulette == .ROULETTE_2 ? Color(hex: "ffcb14") : + selectedRoulette == .ROULETTE_3 ? Color(hex: "ff14d9") : + Color.button + ) .cornerRadius(10) .onTapGesture { if let onClickSpin = onClickSpin { - onClickSpin() + onClickSpin(previewList[selectedRoulette.rawValue].id) } isShowing = false } } - .padding(.top, 26.7) + .padding(.top, 6.7) } .padding(13.3) .background(Color(hex: "222222")) @@ -108,13 +168,32 @@ struct RoulettePreviewDialog_Previews: PreviewProvider { isShowing: .constant(true), title: nil, onClickSpin: nil, - preview: RoulettePreview( - can: 100, - items: [ - RoulettePreviewItem(title: "옵션1", percent: "10%"), - RoulettePreviewItem(title: "옵션2", percent: "90%"), - ] - ) + previewList: [ + RoulettePreview( + id: 0, + can: 100, + items: [ + RoulettePreviewItem(title: "옵션1", percent: "33.40%"), + RoulettePreviewItem(title: "옵션2", percent: "66.60%"), + ] + ), + RoulettePreview( + id: 1, + can: 10, + items: [ + RoulettePreviewItem(title: "옵션3", percent: "10.8%"), + RoulettePreviewItem(title: "옵션4", percent: "89.2%"), + ] + ), + RoulettePreview( + id: 2, + can: 1000, + items: [ + RoulettePreviewItem(title: "옵션5", percent: "10%"), + RoulettePreviewItem(title: "옵션6", percent: "90%"), + ] + ) + ] ) } } diff --git a/SodaLive/Sources/Live/Room/Routlette/SpinRouletteRequest.swift b/SodaLive/Sources/Live/Room/Routlette/SpinRouletteRequest.swift index 89685c1..84bdce3 100644 --- a/SodaLive/Sources/Live/Room/Routlette/SpinRouletteRequest.swift +++ b/SodaLive/Sources/Live/Room/Routlette/SpinRouletteRequest.swift @@ -9,5 +9,6 @@ import Foundation struct SpinRouletteRequest: Encodable { let roomId: Int + let rouletteId: Int let container: String = "ios" } diff --git a/SodaLive/Sources/Live/Room/Routlette/SpinRouletteResponse.swift b/SodaLive/Sources/Live/Room/Routlette/SpinRouletteResponse.swift new file mode 100644 index 0000000..587944c --- /dev/null +++ b/SodaLive/Sources/Live/Room/Routlette/SpinRouletteResponse.swift @@ -0,0 +1,12 @@ +// +// SpinRouletteResponse.swift +// SodaLive +// +// Created by klaus on 5/11/24. +// + +struct SpinRouletteResponse: Decodable { + let can: Int + let result: String + let items: [RouletteItem] +} diff --git a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift index e94c983..359fe4d 100644 --- a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift +++ b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift @@ -168,76 +168,46 @@ struct LiveRoomViewV2: View { .padding(.top, 16) VStack(alignment: .trailing, spacing: 0) { - Image(viewModel.isSpeakerMute ? "ic_speaker_off" : "ic_speaker_on") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.toggleSpeakerMute() - } - .padding(.top, 26.7) - .padding(.trailing, 13.3) + LiveRoomRightBottomButton( + imageName: viewModel.isSpeakerMute ? "ic_speaker_off" : "ic_speaker_on", + onClick: { viewModel.toggleSpeakerMute() } + ) + .padding(.top, 26.7) + .padding(.trailing, 13.3) Spacer() VStack(spacing: 13.3) { if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) { - Image("ic_roulette_settings") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.isShowRouletteSettings = true - } + LiveRoomRightBottomButton( + imageName: "ic_roulette_settings", + onClick: { viewModel.isShowRouletteSettings = true } + ) } else if liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) && viewModel.isActiveRoulette { - Image("ic_roulette") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.showRoulette() - } + LiveRoomRightBottomButton( + imageName: "ic_roulette", + onClick: { viewModel.showRoulette() } + ) } if viewModel.role == .SPEAKER { - Image(viewModel.isMute ? "ic_mic_off" : "ic_mic_on") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.toggleMute() - } + LiveRoomRightBottomButton( + imageName: viewModel.isMute ? "ic_mic_off" : "ic_mic_on", + onClick: { viewModel.toggleMute() } + ) } if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) && UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue { - Image("ic_donation_message_list") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.isShowDonationMessagePopup = true - } + LiveRoomRightBottomButton( + imageName: "ic_donation_message_list", + onClick: { viewModel.isShowDonationMessagePopup = true } + ) } else { - Image("ic_donation") - .resizable() - .frame(width: 26.7, height: 26.7) - .padding(11) - .background(Color(hex: "525252").opacity(0.6)) - .cornerRadius(10) - .onTapGesture { - viewModel.isShowDonationPopup = true - } + LiveRoomRightBottomButton( + imageName: "ic_donation", + onClick: { viewModel.isShowDonationPopup = true } + ) } } .padding(.trailing, 13.3) @@ -629,12 +599,12 @@ struct LiveRoomViewV2: View { } } - if let preview = viewModel.roulettePreview, viewModel.isShowRoulettePreview { + if !viewModel.roulettePreviewList.isEmpty && viewModel.isShowRoulettePreview { RoulettePreviewDialog( isShowing: $viewModel.isShowRoulettePreview, title: nil, - onClickSpin: { viewModel.spinRoulette() }, - preview: preview + onClickSpin: { viewModel.spinRoulette(rouletteId: $0) }, + previewList: viewModel.roulettePreviewList ) } diff --git a/SodaLive/Sources/UI/Component/SelectedButtonView.swift b/SodaLive/Sources/UI/Component/SelectedButtonView.swift index fd11235..069ee01 100644 --- a/SodaLive/Sources/UI/Component/SelectedButtonView.swift +++ b/SodaLive/Sources/UI/Component/SelectedButtonView.swift @@ -13,23 +13,51 @@ struct SelectedButtonView: View { let isActive: Bool let isSelected: Bool + var checkImage = "ic_select_check" + var bgDisabledColor = Color.gray55 + var bgSelectedColor = Color.button + var bgDefaultColor = Color.bg + var textDisabledColor = Color.gray77 + var textSelectedColor = Color.white + var textDefaultColor = Color.button + var body: some View { HStack(spacing: 6.7) { if isSelected { - Image("ic_select_check") + Image(checkImage) } Text(title) .font(.custom(Font.bold.rawValue, size: 14.7)) - .foregroundColor(!isActive ? Color.gray77 : isSelected ? .white : Color.button) + .foregroundColor(!isActive ? textDisabledColor : isSelected ? textSelectedColor : textDefaultColor) } - .padding(.vertical, 14.3) + .padding(.vertical, isSelected ? 14.3 : 17) .frame(maxWidth: .infinity) - .background(!isActive ? Color.gray55 : isSelected ? Color.button : Color.bg) + .background(!isActive ? bgDisabledColor : isSelected ? bgSelectedColor : bgDefaultColor) .cornerRadius(6.7) } } -#Preview { +#Preview("기본") { SelectedButtonView(title: "테스트", isActive: true, isSelected: true) } + +#Preview("이미지와 컬러 수정 - selected") { + SelectedButtonView( + title: "테스트", + isActive: true, + isSelected: true, + bgSelectedColor: Color(hex: "ff14d9"), + textDefaultColor: Color(hex: "ff14d9") + ) +} + +#Preview("이미지와 컬러 수정 - unselected") { + SelectedButtonView( + title: "테스트", + isActive: true, + isSelected: false, + textDefaultColor: Color(hex: "ff14d9") + ) +} +