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 ae6a88e..0000000 Binary files a/SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png and /dev/null differ 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 a22155e..0000000 Binary files a/SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png and /dev/null differ diff --git a/SodaLive/Resources/Assets.xcassets/ic_donation_message_list.imageset/ic_donation_message_list.png b/SodaLive/Resources/Assets.xcassets/ic_donation_message_list.imageset/ic_donation_message_list.png index f7e7728..818c847 100644 Binary files a/SodaLive/Resources/Assets.xcassets/ic_donation_message_list.imageset/ic_donation_message_list.png and b/SodaLive/Resources/Assets.xcassets/ic_donation_message_list.imageset/ic_donation_message_list.png differ 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 0000000..c9b4901 Binary files /dev/null and b/SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png differ diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift index 746839c..eb87971 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift @@ -23,7 +23,7 @@ struct LiveRoomDonationMessageDialog: View { VStack(spacing: 0) { HStack(spacing: 0) { - Text("후원메시지") + Text("후원 히스토리") .font(.custom(Font.bold.rawValue, size: 14.7)) .foregroundColor(Color(hex: "eeeeee")) @@ -45,43 +45,19 @@ struct LiveRoomDonationMessageDialog: View { ForEach(0.. 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") + ) +} +