룰렛 설정 다이얼로그 뷰 추가
This commit is contained in:
		
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_add.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_add.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| { | ||||
|   "images" : [ | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "1x" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "2x" | ||||
|     }, | ||||
|     { | ||||
|       "filename" : "btn_add.png", | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "3x" | ||||
|     } | ||||
|   ], | ||||
|   "info" : { | ||||
|     "author" : "xcode", | ||||
|     "version" : 1 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_add.imageset/btn_add.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_add.imageset/btn_add.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| { | ||||
|   "images" : [ | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "1x" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "2x" | ||||
|     }, | ||||
|     { | ||||
|       "filename" : "btn_minus_round_rect.png", | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "3x" | ||||
|     } | ||||
|   ], | ||||
|   "info" : { | ||||
|     "author" : "xcode", | ||||
|     "version" : 1 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_minus_round_rect.imageset/btn_minus_round_rect.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.4 KiB | 
							
								
								
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/Contents.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| { | ||||
|   "images" : [ | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "1x" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "2x" | ||||
|     }, | ||||
|     { | ||||
|       "filename" : "btn_plus_round_rect.png", | ||||
|       "idiom" : "universal", | ||||
|       "scale" : "3x" | ||||
|     } | ||||
|   ], | ||||
|   "info" : { | ||||
|     "author" : "xcode", | ||||
|     "version" : 1 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								SodaLive/Resources/Assets.xcassets/btn_plus_round_rect.imageset/btn_plus_round_rect.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.8 KiB | 
| @@ -316,6 +316,9 @@ struct LiveRoomView: View { | ||||
|                                             .background(Color(hex: "525252").opacity(0.6)) | ||||
|                                             .cornerRadius(10) | ||||
|                                             .padding(.bottom, 13.3) | ||||
|                                             .onTapGesture { | ||||
|                                                 viewModel.isShowRouletteSettings = true | ||||
|                                             } | ||||
|                                     } else if liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) && viewModel.isActiveRoulette { | ||||
|                                         Image("ic_roulette") | ||||
|                                             .resizable() | ||||
| @@ -682,6 +685,10 @@ struct LiveRoomView: View { | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if viewModel.isShowRouletteSettings { | ||||
|                 RouletteSettingsView(isShowing: $viewModel.isShowRouletteSettings) | ||||
|             } | ||||
|              | ||||
|             if viewModel.isLoading && viewModel.liveRoomInfo == nil { | ||||
|                 LoadingView() | ||||
|             } | ||||
|   | ||||
| @@ -134,6 +134,8 @@ final class LiveRoomViewModel: NSObject, ObservableObject { | ||||
|      | ||||
|     @Published var isActiveRoulette = false | ||||
|      | ||||
|     @Published var isShowRouletteSettings = false | ||||
|      | ||||
|     var timer: DispatchSourceTimer? | ||||
|      | ||||
|     func setOriginOffset(_ offset: CGFloat) { | ||||
|   | ||||
| @@ -0,0 +1,19 @@ | ||||
| // | ||||
| //  RouletteOption.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/05. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
|  | ||||
| class RouletteOption: ObservableObject { | ||||
|     var title: String | ||||
|     var weight: Int | ||||
|     var percentage: Int = 50 | ||||
|      | ||||
|     init(title: String, weight: Int) { | ||||
|         self.title = title | ||||
|         self.weight = weight | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| // | ||||
| //  RouletteSettingsOptionView.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/05. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
|  | ||||
| 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) { | ||||
|             HStack(spacing: 0) { | ||||
|                 Text("옵션 \(index + 1)") | ||||
|                     .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||
|                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                  | ||||
|                 Spacer() | ||||
|                  | ||||
|                 if index > 1 { | ||||
|                     Text("삭제") | ||||
|                         .font(.custom(Font.medium.rawValue, size: 14.7)) | ||||
|                         .foregroundColor(Color(hex: "ff5c49")) | ||||
|                         .onTapGesture { onClickDelete() } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             HStack(spacing: 8) { | ||||
|                 TextField("옵션을 입력하세요", text: $option.title) | ||||
|                     .autocapitalization(.none) | ||||
|                     .disableAutocorrection(true) | ||||
|                     .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                     .keyboardType(.default) | ||||
|                     .padding(.horizontal, 13.3) | ||||
|                     .padding(.vertical, 16.7) | ||||
|                     .frame(maxWidth: .infinity) | ||||
|                     .background(Color(hex: "222222")) | ||||
|                     .cornerRadius(6.7) | ||||
|                  | ||||
|                 Text("\(option.percentage)%") | ||||
|                     .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() } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct RouletteSettingsOptionView_Previews: PreviewProvider { | ||||
|     static var previews: some View { | ||||
|         RouletteSettingsOptionView( | ||||
|             option: RouletteOption(title: "옵션1", weight: 1), | ||||
|             index: 2, | ||||
|             onClickPlus: {}, | ||||
|             onClickDelete: {}, | ||||
|             onClickSubstract: {} | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,158 @@ | ||||
| // | ||||
| //  RouletteSettingsView.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/05. | ||||
| // | ||||
|  | ||||
| import SwiftUI | ||||
|  | ||||
| struct RouletteSettingsView: View { | ||||
|      | ||||
|     @StateObject var keyboardHandler = KeyboardHandler() | ||||
|     @StateObject var viewModel = RouletteSettingsViewModel() | ||||
|      | ||||
|     @Binding var isShowing: Bool | ||||
|      | ||||
|     var body: some View { | ||||
|         GeometryReader { proxy in | ||||
|             BaseView(isLoading: $viewModel.isLoading) { | ||||
|                 VStack(spacing: 0) { | ||||
|                     DetailNavigationBar(title: "룰렛설정") { | ||||
|                         isShowing = false | ||||
|                     } | ||||
|                      | ||||
|                     ScrollView(.vertical, showsIndicators: false) { | ||||
|                         VStack(spacing: 0) { | ||||
|                             HStack(spacing: 0) { | ||||
|                                 Text("룰렛을 활성화 하시겠습니까?") | ||||
|                                     .font(.custom(Font.bold.rawValue, size: 16)) | ||||
|                                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                  | ||||
|                                 Spacer() | ||||
|                                  | ||||
|                                 Image(viewModel.isActive ? "btn_toggle_on_big" : "btn_toggle_off_big") | ||||
|                                     .resizable() | ||||
|                                     .frame(width: 44, height: 27) | ||||
|                                     .onTapGesture { | ||||
|                                         viewModel.isActive.toggle() | ||||
|                                     } | ||||
|                             } | ||||
|                              | ||||
|                             VStack(alignment: .leading, spacing: 13.3) { | ||||
|                                 Text("룰렛 금액 설정") | ||||
|                                     .font(.custom(Font.bold.rawValue, size: 16)) | ||||
|                                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                  | ||||
|                                 HStack(spacing: 8) { | ||||
|                                     TextField("룰렛 금액을 입력해 주세요 (최소 5캔)", text: Binding( | ||||
|                                         get: { | ||||
|                                             self.viewModel.canText | ||||
|                                         }, | ||||
|                                         set: { newValue in | ||||
|                                             self.viewModel.canText = newValue.filter { "0123456789".contains($0) } | ||||
|                                         } | ||||
|                                     )) | ||||
|                                     .autocapitalization(.none) | ||||
|                                     .disableAutocorrection(true) | ||||
|                                     .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                     .keyboardType(.numberPad) | ||||
|                                     .padding(.horizontal, 13.3) | ||||
|                                     .padding(.vertical, 16.7) | ||||
|                                     .frame(maxWidth: .infinity) | ||||
|                                     .background(Color(hex: "222222")) | ||||
|                                     .cornerRadius(6.7) | ||||
|                                      | ||||
|                                     Spacer() | ||||
|                                      | ||||
|                                     Text("캔") | ||||
|                                         .font(.custom(Font.bold.rawValue, size: 16.7)) | ||||
|                                         .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                 } | ||||
|                             } | ||||
|                             .padding(.top, 26.7) | ||||
|                              | ||||
|                             VStack(alignment: .leading, spacing: 21.3) { | ||||
|                                 Text("룰렛 옵션 설정") | ||||
|                                     .font(.custom(Font.bold.rawValue, size: 16)) | ||||
|                                     .foregroundColor(Color(hex: "eeeeee")) | ||||
|                                  | ||||
|                                 HStack(spacing: 0) { | ||||
|                                     Text("※ 룰렛 옵션은 최소 2개,\n최대 6개까지 설정할 수 있습니다.") | ||||
|                                         .font(.custom(Font.medium.rawValue, size: 13.3)) | ||||
|                                         .foregroundColor(Color(hex: "ff5c49")) | ||||
|                                      | ||||
|                                     Spacer() | ||||
|                                      | ||||
|                                     Image("btn_add") | ||||
|                                         .onTapGesture { viewModel.addOption() } | ||||
|                                 } | ||||
|                             } | ||||
|                             .padding(.top, 26.7) | ||||
|                              | ||||
|                             LazyVStack(spacing: 21.3) { | ||||
|                                 ForEach(viewModel.options.indices, id: \.self) { index in | ||||
|                                     RouletteSettingsOptionView( | ||||
|                                         option: viewModel.options[index], | ||||
|                                         index: index, | ||||
|                                         onClickPlus: { viewModel.plusWeight(index: index) }, | ||||
|                                         onClickDelete: { viewModel.deleteOption(index: index) }, | ||||
|                                         onClickSubstract: { viewModel.subtractWeight(index: index) } | ||||
|                                     ) | ||||
|                                 } | ||||
|                             } | ||||
|                             .padding(.top, 21.3) | ||||
|                         } | ||||
|                         .padding(.horizontal, 13.3) | ||||
|                     } | ||||
|                      | ||||
|                     Spacer() | ||||
|                      | ||||
|                     HStack(spacing: 13.3) { | ||||
|                         Text("미리보기") | ||||
|                             .font(.custom(Font.bold.rawValue, size: 18.3)) | ||||
|                             .foregroundColor(Color(hex: "3bb9f1")) | ||||
|                             .padding(.vertical, 16) | ||||
|                             .frame(maxWidth: .infinity) | ||||
|                             .overlay( | ||||
|                                 RoundedRectangle(cornerRadius: 10) | ||||
|                                     .strokeBorder(lineWidth: 1) | ||||
|                                     .foregroundColor(Color(hex: "3bb9f1")) | ||||
|                             ) | ||||
|                             .onTapGesture { | ||||
|                             } | ||||
|                          | ||||
|                         Text("설정완료") | ||||
|                             .font(.custom(Font.bold.rawValue, size: 18.3)) | ||||
|                             .foregroundColor(.white) | ||||
|                             .padding(.vertical, 16) | ||||
|                             .frame(maxWidth: .infinity) | ||||
|                             .background(Color(hex: "3bb9f1")) | ||||
|                             .cornerRadius(10) | ||||
|                             .onTapGesture { | ||||
|                             } | ||||
|                     } | ||||
|                     .padding(13.3) | ||||
|                     .background(Color(hex: "222222")) | ||||
|                     .cornerRadius(16.7, corners: [.topLeft, .topRight]) | ||||
|                      | ||||
|                     if proxy.safeAreaInsets.bottom > 0 { | ||||
|                         Rectangle() | ||||
|                             .foregroundColor(Color(hex: "222222")) | ||||
|                             .frame(width: screenSize().width, height: 15.3) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             .onAppear { | ||||
|                 viewModel.getRoulette(creatorId: UserDefaults.int(forKey: .userId)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct RouletteSettingsView_Previews: PreviewProvider { | ||||
|     static var previews: some View { | ||||
|         RouletteSettingsView(isShowing: .constant(true)) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,121 @@ | ||||
| // | ||||
| //  RouletteSettingsViewModel.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/05. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import Combine | ||||
|  | ||||
| final class RouletteSettingsViewModel: ObservableObject { | ||||
|     private let repository = RouletteRepository() | ||||
|     private var subscription = Set<AnyCancellable>() | ||||
|      | ||||
|     @Published var isLoading = false | ||||
|      | ||||
|     @Published var errorMessage = "" | ||||
|     @Published var isShowErrorPopup = false | ||||
|      | ||||
|     @Published var canText = ""{ | ||||
|         didSet { | ||||
|             can = Int(canText) ?? 0 | ||||
|         } | ||||
|     } | ||||
|     @Published var isActive = false | ||||
|     @Published var options = [RouletteOption]() | ||||
|      | ||||
|     var can = 5 | ||||
|      | ||||
|     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 >= 6) { | ||||
|             return | ||||
|         } | ||||
|         options.append(RouletteOption(title: "", weight: 1)) | ||||
|         recalculatePercentages() | ||||
|     } | ||||
|      | ||||
|     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..<options.count { | ||||
|             options[i].percentage = Int(Double(options[i].weight) / Double(totalWeight) * 100) | ||||
|         } | ||||
|          | ||||
|         removeAllAndAddOptions(options: options) | ||||
|     } | ||||
|      | ||||
|     private func removeAllAndAddOptions(options: [RouletteOption]) { | ||||
|         self.options.removeAll() | ||||
|         self.options.append(contentsOf: options) | ||||
|     } | ||||
|      | ||||
|     func getRoulette(creatorId: Int) { | ||||
|         self.isLoading = true | ||||
|         repository.getRoulette(creatorId: creatorId) | ||||
|             .sink { result in | ||||
|                 switch result { | ||||
|                 case .finished: | ||||
|                     DEBUG_LOG("finish") | ||||
|                 case .failure(let error): | ||||
|                     ERROR_LOG(error.localizedDescription) | ||||
|                 } | ||||
|             } receiveValue: { [unowned self] response in | ||||
|                 self.isLoading = false | ||||
|                 let responseData = response.data | ||||
|                  | ||||
|                 do { | ||||
|                     let jsonDecoder = JSONDecoder() | ||||
|                     let decoded = try jsonDecoder.decode(ApiResponse<GetRouletteResponse>.self, from: responseData) | ||||
|                      | ||||
|                     if let data = decoded.data, decoded.success { | ||||
|                         self.isActive = data.isActive | ||||
|                         self.canText = String(data.can) | ||||
|                         if !data.items.isEmpty { | ||||
|                             let options = data.items.map { | ||||
|                                 RouletteOption(title: $0.title, weight: $0.weight) | ||||
|                             } | ||||
|                             removeAllAndAddOptions(options: options) | ||||
|                             recalculatePercentages() | ||||
|                         } else { | ||||
|                             self.addOption() | ||||
|                             self.addOption() | ||||
|                         } | ||||
|                     } else { | ||||
|                         self.isActive = false | ||||
|                         self.canText = "5" | ||||
|                         self.addOption() | ||||
|                         self.addOption() | ||||
|                     } | ||||
|                 } catch { | ||||
|                     self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." | ||||
|                     self.isShowErrorPopup = true | ||||
|                 } | ||||
|             } | ||||
|             .store(in: &subscription) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| // | ||||
| //  GetRouletteResponse.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/06. | ||||
| // | ||||
|  | ||||
| struct GetRouletteResponse: Decodable { | ||||
|     let can: Int | ||||
|     let isActive: Bool | ||||
|     let items: [RouletteItem] | ||||
| } | ||||
|  | ||||
| struct RouletteItem: Decodable { | ||||
|     let title: String | ||||
|     let weight: Int | ||||
| } | ||||
							
								
								
									
										51
									
								
								SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								SodaLive/Sources/Live/Room/Routlette/RouletteApi.swift
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // | ||||
| //  RouletteApi.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/06. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import Moya | ||||
|  | ||||
| enum RouletteApi { | ||||
|     case getRoulette(creatorId: Int) | ||||
| } | ||||
|  | ||||
| extension RouletteApi: TargetType { | ||||
|     var baseURL: URL { | ||||
|         return URL(string: BASE_URL)! | ||||
|     } | ||||
|      | ||||
|     var path: String { | ||||
|         switch self { | ||||
|         case .getRoulette: | ||||
|             return "/roulette" | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     var method: Moya.Method { | ||||
|         switch self { | ||||
|         case .getRoulette: | ||||
|             return .get | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     var task: Moya.Task { | ||||
|         switch self { | ||||
|         case .getRoulette(let creatorId): | ||||
|             let parameters = [ | ||||
|                 "creatorId": creatorId | ||||
|             ] as [String : Any] | ||||
|              | ||||
|             return .requestParameters( | ||||
|                 parameters: parameters, | ||||
|                 encoding: URLEncoding.queryString | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     var headers: [String : String]? { | ||||
|         return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"] | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| // | ||||
| //  RouletteRepository.swift | ||||
| //  SodaLive | ||||
| // | ||||
| //  Created by klaus on 2023/12/06. | ||||
| // | ||||
|  | ||||
| import Foundation | ||||
| import CombineMoya | ||||
| import Combine | ||||
| import Moya | ||||
|  | ||||
| final class RouletteRepository { | ||||
|     private let api = MoyaProvider<RouletteApi>() | ||||
|      | ||||
|     func getRoulette(creatorId: Int) -> AnyPublisher<Response, MoyaError> { | ||||
|         return api.requestPublisher(.getRoulette(creatorId: creatorId)) | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Yu Sung
					Yu Sung