diff --git a/SodaLive/Sources/Live/LiveApi.swift b/SodaLive/Sources/Live/LiveApi.swift index edbf311..8ebaf7e 100644 --- a/SodaLive/Sources/Live/LiveApi.swift +++ b/SodaLive/Sources/Live/LiveApi.swift @@ -36,6 +36,7 @@ enum LiveApi { case getDonationMessageList(roomId: Int) case deleteDonationMessage(roomId: Int, messageUUID: String) case getUserProfile(roomId: Int, userId: Int) + case getAllMenuPreset(creatorId: Int) } extension LiveApi: TargetType { @@ -125,12 +126,15 @@ extension LiveApi: TargetType { case .getUserProfile(let roomId, let userId): return "/live/room/\(roomId)/profile/\(userId)" + + case .getAllMenuPreset: + return "/live/room/menu/all" } } var method: Moya.Method { switch self { - case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile: + case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile, .getAllMenuPreset: return .get case .makeReservation, .enterRoom, .createRoom, .quitRoom, .donation, .refundDonation, .kickOut: @@ -226,6 +230,9 @@ extension LiveApi: TargetType { case .deleteDonationMessage(let roomId, let messageUUID): return .requestJSONEncodable(DeleteLiveRoomDonationMessage(roomId: roomId, messageUUID: messageUUID)) + + case .getAllMenuPreset(let creatorId): + return .requestParameters(parameters: ["creatorId" : creatorId], encoding: URLEncoding.queryString) } } diff --git a/SodaLive/Sources/Live/LiveRepository.swift b/SodaLive/Sources/Live/LiveRepository.swift index d44af7b..1ef872f 100644 --- a/SodaLive/Sources/Live/LiveRepository.swift +++ b/SodaLive/Sources/Live/LiveRepository.swift @@ -116,4 +116,8 @@ final class LiveRepository { func getUserProfile(roomId: Int, userId: Int) -> AnyPublisher { api.requestPublisher(.getUserProfile(roomId: roomId, userId: userId)) } + + func getAllMenuPreset(creatorId: Int) -> AnyPublisher { + api.requestPublisher(.getAllMenuPreset(creatorId: creatorId)) + } } diff --git a/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift b/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift index 35b9524..2763b2b 100644 --- a/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift +++ b/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift @@ -19,4 +19,7 @@ struct CreateLiveRoomRequest: Encodable { var password: String? = nil let timezone: String = TimeZone.current.identifier var beginDateTimeString: String? = nil + var menuPanId: Int = 0 + var menuPan: String = "" + var isActiveMenuPan: Bool = false } diff --git a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift index 5d2c5c1..079bc12 100644 --- a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift +++ b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift @@ -41,7 +41,7 @@ struct LiveRoomCreateView: View { Text("라이브 만들기") .font(.custom(Font.bold.rawValue, size: 18.3)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) } Spacer() @@ -49,13 +49,13 @@ struct LiveRoomCreateView: View { if viewModel.isShowGetRecentInfoButton { Text("최근 데이터 가져오기") .font(.custom(Font.medium.rawValue, size: 12)) - .foregroundColor(Color(hex: "9970ff")) + .foregroundColor(Color.button) .padding(.vertical, 8) .padding(.horizontal, 10.7) .overlay( RoundedRectangle(cornerRadius: 8) .stroke() - .foregroundColor(Color(hex: "9970ff")) + .foregroundColor(Color.button) ) .onTapGesture { viewModel.getRecentInfo() @@ -71,7 +71,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 0) { Text("썸네일") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .padding(.horizontal, 13.3) .padding(.top, 13.3) .frame(width: screenSize().width, alignment: .leading) @@ -95,13 +95,13 @@ struct LiveRoomCreateView: View { .resizable() .scaledToFit() .frame(width: 80, height: 116.8) - .background(Color(hex: "3e3358")) + .background(Color.bg) .cornerRadius(10) } Image("ic_camera") .padding(10) - .background(Color(hex: "9970ff")) + .background(Color.button) .cornerRadius(30) .offset(x: 40, y: 40) } @@ -115,25 +115,32 @@ struct LiveRoomCreateView: View { .frame(width: screenSize().width - 26.7) .padding(.top, 33.3) - TagSelectView() + ContentInputView() .frame(width: screenSize().width - 26.7) .padding(.top, 33.3) } - VStack(spacing: 0) { - ContentInputView() - .frame(width: screenSize().width - 26.7) - .padding(.top, 33.3) + VStack(spacing: 33.3) { + LiveRoomMenuSelectView( + menu: $viewModel.menu, + isActivate: $viewModel.isActivateMenu, + menuCount: viewModel.menuList.count, + selectedMenu: viewModel.selectedMenu ?? .MENU_1, + selectMenu: { + viewModel.selectMenuPreset(selectedMenuPreset: $0) + } + ) + .frame(width: screenSize().width - 26.7) - if viewModel.roomType != .SECRET { - TimeSettingView() - .padding(.top, 33.3) - } + TagSelectView() + .frame(width: screenSize().width - 26.7) + + TimeSettingView() NumberOfPeopleLimitView() .frame(width: screenSize().width - 26.7) - .padding(.top, 33.3) } + .padding(.top, 33.3) VStack(spacing: 0) { RoomTypeSettingView() @@ -146,11 +153,9 @@ struct LiveRoomCreateView: View { .padding(.top, 33.3) } - if UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue { - PriceSettingView() - .frame(width: screenSize().width - 26.7) - .padding(.top, 33.3) - } + PriceSettingView() + .frame(width: screenSize().width - 26.7) + .padding(.top, 33.3) } HStack(alignment: .top, spacing: 0) { @@ -167,23 +172,23 @@ struct LiveRoomCreateView: View { .font(.custom(Font.bold.rawValue, size: 18.3)) .foregroundColor(Color.white) .frame(width: screenSize().width - 26.7, height: 50) - .background(Color(hex: "9970ff")) + .background(Color.button) .cornerRadius(10) .padding(.vertical, 13.3) } } .frame(width: screenSize().width) - .background(Color(hex: "222222")) + .background(Color.gray22) .cornerRadius(16.7, corners: [.topLeft, .topRight]) .padding(.top, 30) Rectangle() - .foregroundColor(Color(hex: "222222")) + .foregroundColor(Color.gray22) .frame(width: screenSize().width, height: keyboardHandler.keyboardHeight) if proxy.safeAreaInsets.bottom > 0 { Rectangle() - .foregroundColor(Color(hex: "222222")) + .foregroundColor(Color.gray22) .frame(width: screenSize().width, height: 15.3) } } @@ -234,7 +239,7 @@ struct LiveRoomCreateView: View { .padding(.vertical, 13.3) .frame(width: geo.size.width - 66.7, alignment: .center) .font(.custom(Font.medium.rawValue, size: 12)) - .background(Color(hex: "9970ff")) + .background(Color.button) .foregroundColor(Color.white) .multilineTextAlignment(.center) .cornerRadius(20) @@ -245,6 +250,7 @@ struct LiveRoomCreateView: View { } .onAppear { viewModel.timeSettingMode = timeSettingMode + viewModel.getAllMenuPreset() } } @@ -253,7 +259,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 0) { Text("제목") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .padding(.horizontal, 13.3) .frame(width: screenSize().width, alignment: .leading) @@ -261,15 +267,15 @@ struct LiveRoomCreateView: View { .autocapitalization(.none) .disableAutocorrection(true) .font(.custom(Font.medium.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "eeeeee")) - .accentColor(Color(hex: "3bb9f1")) + .foregroundColor(Color.grayee) + .accentColor(Color.button) .keyboardType(.default) .padding(.top, 12) .padding(.horizontal, 6.7) Rectangle() .frame(height: 1) - .foregroundColor(Color(hex: "909090").opacity(0.7)) + .foregroundColor(Color.gray90.opacity(0.7)) .padding(.top, 8.3) } } @@ -279,7 +285,7 @@ struct LiveRoomCreateView: View { VStack(alignment: .leading, spacing: 13.3) { Text("관심사") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) Button(action: { hideKeyboard() @@ -287,15 +293,15 @@ struct LiveRoomCreateView: View { }) { Text("관심사 선택") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "9970ff")) + .foregroundColor(Color.button) .padding(.vertical, 13.7) .frame(width: screenSize().width - 26.7) - .background(Color(hex: "9970ff").opacity(0.2)) + .background(Color.button.opacity(0.2)) .cornerRadius(24.3) .overlay( RoundedRectangle(cornerRadius: 24.3) .stroke() - .foregroundColor(Color(hex: "9970ff")) + .foregroundColor(Color.button) ) } @@ -315,7 +321,7 @@ struct LiveRoomCreateView: View { } } .padding(10) - .background(Color(hex: "9970ff")) + .background(Color.button) .cornerRadius(24.3) } } @@ -330,16 +336,16 @@ struct LiveRoomCreateView: View { HStack(spacing: 0) { Text("공지") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) Spacer() Text("\(viewModel.content.count)자") .font(.custom(Font.medium.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "ff5c49")) + + .foregroundColor(Color.mainRed) + Text(" / 1000자") .font(.custom(Font.medium.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "777777")) + .foregroundColor(Color.gray77) } TextViewWrapper( @@ -348,7 +354,7 @@ struct LiveRoomCreateView: View { textColorHex: "eeeeee", backgroundColorHex: "222222" ) - .frame(width: screenSize().width - 26.7, height: 133.3) + .frame(width: screenSize().width - 26.7, height: 200) .cornerRadius(6.7) .padding(.top, 13.3) } @@ -359,7 +365,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 0) { Text("시간설정") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) HStack(spacing: 13.3) { @@ -400,15 +406,11 @@ struct LiveRoomCreateView: View { .foregroundColor( viewModel.timeSettingMode == timeSettingMode ? .white : - Color(hex: "9970ff") + Color.button ) } .frame(width: buttonWidth, height: 48.7) - .background( - viewModel.timeSettingMode == timeSettingMode ? - Color(hex: "9970ff") : - Color(hex: "1f1734") - ) + .background(viewModel.timeSettingMode == timeSettingMode ? Color.button : Color.bg) .cornerRadius(6.7) .onTapGesture { hideKeyboard() @@ -424,7 +426,7 @@ struct LiveRoomCreateView: View { VStack(alignment: .leading, spacing: 6.7) { Text("예약 날짜") .font(.custom(Font.medium.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) Button(action: { hideKeyboard() @@ -432,11 +434,11 @@ struct LiveRoomCreateView: View { }) { Text(viewModel.reservationDateString) .font(.custom(Font.medium.rawValue, size: 14.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: buttonWidth, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) - .stroke(Color(hex: "9970ff"), lineWidth: 1.3) + .stroke(Color.button, lineWidth: 1.3) ) } } @@ -444,7 +446,7 @@ struct LiveRoomCreateView: View { VStack(alignment: .leading, spacing: 6.7) { Text("예약 시간") .font(.custom(Font.medium.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) Button(action: { hideKeyboard() @@ -452,18 +454,18 @@ struct LiveRoomCreateView: View { }) { Text(viewModel.reservationTimeString) .font(.custom(Font.medium.rawValue, size: 14.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: buttonWidth, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) - .stroke(Color(hex: "9970ff"), lineWidth: 1.3) + .stroke(Color.button, lineWidth: 1.3) ) } } } .frame(width: screenSize().width) .padding(.vertical, 13.3) - .background(Color(hex: "222222")) + .background(Color.gray22) } @ViewBuilder @@ -471,7 +473,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 13.3) { Text("참여인원 설정") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) TextField("최대 인원 999명", text: $viewModel.numberOfPeople) @@ -479,12 +481,12 @@ struct LiveRoomCreateView: View { .disableAutocorrection(true) .multilineTextAlignment(.center) .font(.custom(Font.medium.rawValue, size: 14.7)) - .foregroundColor(Color(hex: "eeeeee")) - .accentColor(Color(hex: "3bb9f1")) + .foregroundColor(Color.grayee) + .accentColor(Color.button) .keyboardType(.numberPad) .padding(.vertical, 15.7) .frame(width: screenSize().width - 26.7, alignment: .center) - .background(Color(hex: "222222")) + .background(Color.gray22) .cornerRadius(6.7) } } @@ -508,12 +510,12 @@ struct LiveRoomCreateView: View { Button(action: { self.isShowSelectDateView = false }) { Text("확인") .font(.system(size: 16)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .padding(.vertical, 10) .frame(width: proxy.size.width - 53.4) } } - .background(Color(hex: "222222")) + .background(Color.gray22) .cornerRadius(6.7) } .frame(width: proxy.size.width) @@ -539,12 +541,12 @@ struct LiveRoomCreateView: View { Button(action: { self.isShowSelectTimeView = false }) { Text("확인") .font(.system(size: 16)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .padding(.vertical, 10) .frame(width: proxy.size.width) } } - .background(Color(hex: "222222")) + .background(Color.gray22) .cornerRadius(6.7) } .frame(width: proxy.size.width) @@ -556,7 +558,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 0) { Text("공개 설정") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) HStack(spacing: 13.3) { @@ -591,18 +593,10 @@ struct LiveRoomCreateView: View { Text(title) .font(.custom(Font.bold.rawValue, size: 14.7)) - .foregroundColor( - viewModel.roomType == type ? - .white : - Color(hex: "9970ff") - ) + .foregroundColor(viewModel.roomType == type ? .white : Color.button) } .frame(width: buttonWidth, height: 48.7) - .background( - viewModel.roomType == type ? - Color(hex: "9970ff") : - Color(hex: "1f1734") - ) + .background(viewModel.roomType == type ? Color.button : Color.bg) .cornerRadius(6.7) .onTapGesture { hideKeyboard() @@ -617,7 +611,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 13.3) { Text("방 비밀번호 입력") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) TextField("방 입장 비밀번호 6자리를 입력해 주세요.", text: $viewModel.password) @@ -625,12 +619,12 @@ struct LiveRoomCreateView: View { .disableAutocorrection(true) .multilineTextAlignment(.center) .font(.custom(Font.medium.rawValue, size: 14.7)) - .foregroundColor(Color(hex: "eeeeee")) - .accentColor(Color(hex: "3bb9f1")) + .foregroundColor(Color.grayee) + .accentColor(Color.button) .keyboardType(.numberPad) .padding(.vertical, 15.7) .frame(width: screenSize().width - 26.7, alignment: .center) - .background(Color(hex: "222222")) + .background(Color.grayee) .cornerRadius(6.7) } } @@ -640,7 +634,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 13.3) { Text("연령 제한") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) HStack(spacing: 13.3) { @@ -668,18 +662,10 @@ struct LiveRoomCreateView: View { Text(title) .font(.custom(Font.bold.rawValue, size: 14.7)) - .foregroundColor( - viewModel.isAdult == isAdult ? - .white : - Color(hex: "9970ff") - ) + .foregroundColor(viewModel.isAdult == isAdult ? .white : Color.button) } .frame(width: buttonWidth, height: 48.7) - .background( - viewModel.isAdult == isAdult ? - Color(hex: "9970ff") : - Color(hex: "1f1734") - ) + .background(viewModel.isAdult == isAdult ? Color.button : Color.bg) .cornerRadius(6.7) .onTapGesture { hideKeyboard() @@ -694,7 +680,7 @@ struct LiveRoomCreateView: View { VStack(spacing: 13.3) { Text("티켓 가격") .font(.custom(Font.bold.rawValue, size: 16.7)) - .foregroundColor(Color(hex: "eeeeee")) + .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) HStack(spacing: 13.3) { @@ -719,35 +705,23 @@ struct LiveRoomCreateView: View { .disableAutocorrection(true) .multilineTextAlignment(.center) .font(.custom(Font.bold.rawValue, size: 13.3)) - .foregroundColor(Color(hex: "9970ff")) - .accentColor(Color(hex: "3bb9f1")) + .foregroundColor(Color.button) + .accentColor(Color.button) .keyboardType(.numberPad) Spacer() Text("캔") .font(.custom(Font.medium.rawValue, size: 14.7)) - .foregroundColor( - Color(hex: "9970ff") - ) + .foregroundColor(Color.button) } .padding(.horizontal, 13.3) .frame(width: screenSize().width - 26.7, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) - .stroke( - Color(hex: !viewModel.prices.contains(viewModel.price) ? - "9970ff" : - "777777" - ), - lineWidth: 1 - ) - ) - .background( - !viewModel.prices.contains(viewModel.price) ? - Color(hex:"9970ff").opacity(0.3): - Color(hex: "232323") + .stroke(!viewModel.prices.contains(viewModel.price) ? Color.button : Color.gray77, lineWidth: 1) ) + .background(!viewModel.prices.contains(viewModel.price) ? Color.button.opacity(0.3): Color.gray23) } } @@ -761,23 +735,17 @@ struct LiveRoomCreateView: View { Font.medium.rawValue, size: 14.7 )) - .foregroundColor( - Color(hex: viewModel.price == price ? "9970ff" : "777777") - ) + .foregroundColor(viewModel.price == price ? Color.button : Color.gray77) } .frame(width: buttonWidth, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) .stroke( - Color(hex: viewModel.price == price ? "9970ff" : "777777"), + viewModel.price == price ? Color.button : Color.gray77, lineWidth: 1 ) ) - .background( - viewModel.price == price ? - Color(hex:"9970ff").opacity(0.3): - Color(hex: "232323") - ) + .background(viewModel.price == price ? Color.button.opacity(0.3) : Color.gray23) .cornerRadius(6.7) .onTapGesture { hideKeyboard() diff --git a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift index 705fb9e..0f12412 100644 --- a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift +++ b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift @@ -9,13 +9,19 @@ import UIKit import Moya import Combine +enum SelectedMenu: Int { + case MENU_1 = 0 + case MENU_2 = 1 + case MENU_3 = 2 +} + final class LiveRoomCreateViewModel: ObservableObject { enum TimeSettingMode: String { case NOW, RESERVATION } enum LiveRoomType: String, Codable { - case OPEN, PRIVATE, SECRET + case OPEN, PRIVATE } let prices = [0, 100, 300, 500, 1000, 2000] @@ -40,15 +46,12 @@ final class LiveRoomCreateViewModel: ObservableObject { @Published var roomType: LiveRoomType = .OPEN { didSet { - if roomType == .SECRET { - timeSettingMode = .NOW - } - if roomType != .PRIVATE { password = "" } } } + @Published var password = "" { didSet { if password.count > 6 { @@ -77,6 +80,14 @@ final class LiveRoomCreateViewModel: ObservableObject { @Published var isShowPopup = false @Published var isShowGetRecentInfoButton = true + + private var menuId = 0 + @Published var menu = "" + @Published var menuList = [GetMenuPresetResponse]() + + @Published var isActivateMenu = false + @Published var selectedMenu: SelectedMenu? = nil + private let repository = LiveRepository() private var subscription = Set() @@ -164,10 +175,13 @@ final class LiveRoomCreateViewModel: ObservableObject { isAdult: isAdult, price: price, type: roomType, - password: (roomType == .PRIVATE && !password.trimmingCharacters(in: .whitespaces).isEmpty) ? password : nil + password: (roomType == .PRIVATE && !password.trimmingCharacters(in: .whitespaces).isEmpty) ? password : nil, + menuPanId: isActivateMenu ? menuId : 0, + menuPan: isActivateMenu ? menu : "", + isActiveMenuPan: isActivateMenu ) - if timeSettingMode == .RESERVATION && roomType != .SECRET { + if timeSettingMode == .RESERVATION { request.beginDateTimeString = "\(reservationDate.convertDateFormat(dateFormat: "yyyy-MM-dd")) \(reservationTime.convertDateFormat(dateFormat: "HH:mm"))" } @@ -233,6 +247,73 @@ final class LiveRoomCreateViewModel: ObservableObject { } } + func selectMenuPreset(selectedMenuPreset: SelectedMenu) { + if menuList.isEmpty && (selectedMenuPreset == .MENU_2 || selectedMenuPreset == .MENU_3) { + errorMessage = "메뉴 1을 먼저 설정하세요" + isShowPopup = true + return + } + + if menuList.count == 1 && selectedMenuPreset == .MENU_3 { + errorMessage = "메뉴 1과 메뉴 2를 먼저 설정하세요" + isShowPopup = true + return + } + + if self.selectedMenu != selectedMenuPreset { + self.selectedMenu = selectedMenuPreset + + if menuList.count > selectedMenuPreset.rawValue { + let menu = menuList[selectedMenuPreset.rawValue] + self.menu = menu.menu + self.menuId = menu.id + } else { + self.menu = "" + self.menuId = 0 + } + } + } + + func getAllMenuPreset() { + isLoading = true + + repository.getAllMenuPreset(creatorId: UserDefaults.int(forKey: .userId)) + .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<[GetMenuPresetResponse]>.self, from: responseData) + + if let data = decoded.data, decoded.success { + self.menuList.removeAll() + self.menuList.append(contentsOf: data) + self.selectMenuPreset(selectedMenuPreset: .MENU_1) + } else { + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + } + + self.isShowPopup = true + } + } catch { + self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.isShowPopup = true + } + } + .store(in: &subscription) + } + private func validate() -> Bool { if coverImage == nil && coverImagePath == nil { self.errorMessage = "커버이미지를 선택해주세요." diff --git a/SodaLive/Sources/Live/Room/GetRoomInfoResponse.swift b/SodaLive/Sources/Live/Room/GetRoomInfoResponse.swift index d2b3f45..80113be 100644 --- a/SodaLive/Sources/Live/Room/GetRoomInfoResponse.swift +++ b/SodaLive/Sources/Live/Room/GetRoomInfoResponse.swift @@ -24,6 +24,7 @@ struct GetRoomInfoResponse: Decodable { let listenerList: [LiveRoomMember] let managerList: [LiveRoomMember] let donationRankingTop3UserIds: [Int] + let menuPan: String let isActiveRoulette: Bool let isPrivateRoom: Bool let password: String? diff --git a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift index c61f82e..6bb799b 100644 --- a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift +++ b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift @@ -67,7 +67,21 @@ final class LiveRoomViewModel: NSObject, ObservableObject { } @Published var selectedProfile: LiveRoomMember? - @Published var isShowNotice = false + @Published var isShowNotice = false { + didSet { + if isShowNotice { + isShowMenuPan = false + } + } + } + + @Published var isShowMenuPan = false { + didSet { + if isShowMenuPan { + isShowNotice = false + } + } + } @Published var isShowDonationPopup = false diff --git a/SodaLive/Sources/Live/Room/Menu/GetMenuPresetResponse.swift b/SodaLive/Sources/Live/Room/Menu/GetMenuPresetResponse.swift new file mode 100644 index 0000000..329011f --- /dev/null +++ b/SodaLive/Sources/Live/Room/Menu/GetMenuPresetResponse.swift @@ -0,0 +1,12 @@ +// +// GetMenuPresetResponse.swift +// SodaLive +// +// Created by klaus on 3/8/24. +// + +struct GetMenuPresetResponse: Decodable { + let id: Int + let menu: String + let isActive: Bool +} diff --git a/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift b/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift new file mode 100644 index 0000000..8d4be52 --- /dev/null +++ b/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift @@ -0,0 +1,93 @@ +// +// LiveRoomMenuSelectView.swift +// SodaLive +// +// Created by klaus on 3/8/24. +// + +import SwiftUI + +struct LiveRoomMenuSelectView: View { + + @Binding var menu: String + @Binding var isActivate: Bool + + let menuCount: Int + let selectedMenu: SelectedMenu + let selectMenu: (SelectedMenu) -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + Text("메뉴") + .font(.custom(Font.bold.rawValue, size: 16.7)) + .foregroundColor(Color(hex: "eeeeee")) + + HStack(spacing: 0) { + Text("메뉴를 활성화 하시겠습니까?") + .font(.custom(Font.medium.rawValue, size: 13.3)) + .foregroundColor(Color(hex: "eeeeee")) + + Spacer() + + Image(isActivate ? "btn_toggle_on_big" : "btn_toggle_off_big") + .resizable() + .frame(width: 33.3, height: 20) + .onTapGesture { isActivate.toggle() } + } + .padding(.top, 8) + + if isActivate { + VStack(spacing: 13.3) { + HStack(spacing: 13.3) { + SelectedButtonView( + title: "메뉴 1", + isActive: true, + isSelected: selectedMenu == .MENU_1 + ) + .onTapGesture { + selectMenu(.MENU_1) + } + + SelectedButtonView( + title: "메뉴 2", + isActive: menuCount > 0, + isSelected: selectedMenu == .MENU_2 + ) + .onTapGesture { + selectMenu(.MENU_2) + } + + SelectedButtonView( + title: "메뉴 3", + isActive: menuCount > 1, + isSelected: selectedMenu == .MENU_3 + ) + .onTapGesture { + selectMenu(.MENU_3) + } + } + + TextViewWrapper( + text: $menu, + placeholder: "메뉴판을 작성해주세요.", + textColorHex: "eeeeee", + backgroundColorHex: "222222" + ) + .frame(height: 200) + .cornerRadius(6.7) + } + .padding(.top, 13.3) + } + } + } +} + +#Preview { + LiveRoomMenuSelectView( + menu: .constant("메뉴 1 입니다\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n테스트"), + isActivate: .constant(true), + menuCount: 2, + selectedMenu: .MENU_1, + selectMenu: { _ in } + ) +} diff --git a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift index 9ff4c76..da0bb02 100644 --- a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift +++ b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift @@ -14,6 +14,8 @@ struct LiveRoomInfoGuestView: View { let isOnBg: Bool let isOnNotice: Bool + let isOnMenuPan: Bool + let isShowMenuPanButton: Bool let creatorId: Int let creatorNickname: String @@ -31,6 +33,7 @@ struct LiveRoomInfoGuestView: View { let onClickFollow: (Bool) -> Void let onClickProfile: (Int) -> Void let onClickNotice: () -> Void + let onClickMenuPan: () -> Void let onClickTotalDonation: () -> Void var body: some View { @@ -113,6 +116,21 @@ struct LiveRoomInfoGuestView: View { onClick: { onClickNotice() } ) + if isShowMenuPanButton { + LiveRoomOverlayStrokeTextToggleButton( + isOn: isOnMenuPan, + onText: "메뉴판", + onTextColor: .button, + onStrokeColor: .button, + offText: nil, + offTextColor: .graybb, + offStrokeColor: .graybb, + strokeWidth: 1, + strokeCornerRadius: 5.3, + onClick: { onClickMenuPan() } + ) + } + Spacer() HStack(spacing: 2.7) { @@ -151,6 +169,8 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider { totalDonationCan: 123456, isOnBg: true, isOnNotice: false, + isOnMenuPan: false, + isShowMenuPanButton: false, creatorId: 1, creatorNickname: "도화", creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320", @@ -184,6 +204,7 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider { onClickFollow: { _ in }, onClickProfile: { _ in }, onClickNotice: {}, + onClickMenuPan: {}, onClickTotalDonation: {} ) } diff --git a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift index 805b1d1..3c0f892 100644 --- a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift +++ b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift @@ -16,6 +16,8 @@ struct LiveRoomInfoHostView: View { let isOnBg: Bool let isOnNotice: Bool + let isOnMenuPan: Bool + let isShowMenuPanButton: Bool let creatorId: Int let creatorNickname: String @@ -32,6 +34,7 @@ struct LiveRoomInfoHostView: View { let onClickEdit: () -> Void let onClickProfile: (Int) -> Void let onClickNotice: () -> Void + let onClickMenuPan: () -> Void let onClickTotalDonation: () -> Void let onClickParticipants: () -> Void @@ -122,6 +125,21 @@ struct LiveRoomInfoHostView: View { onClick: { onClickNotice() } ) + if isShowMenuPanButton { + LiveRoomOverlayStrokeTextToggleButton( + isOn: isOnMenuPan, + onText: "메뉴판", + onTextColor: .button, + onStrokeColor: .button, + offText: nil, + offTextColor: .graybb, + offStrokeColor: .graybb, + strokeWidth: 1, + strokeCornerRadius: 5.3, + onClick: { onClickMenuPan() } + ) + } + Spacer() HStack(spacing: 2.7) { @@ -178,6 +196,8 @@ struct LiveRoomInfoHostView_Previews: PreviewProvider { participantsCount: 18, isOnBg: true, isOnNotice: true, + isOnMenuPan: false, + isShowMenuPanButton: false, creatorId: 1, creatorNickname: "도화", creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320", @@ -210,6 +230,7 @@ struct LiveRoomInfoHostView_Previews: PreviewProvider { onClickEdit: {}, onClickProfile: { _ in }, onClickNotice: {}, + onClickMenuPan: {}, onClickTotalDonation: {}, onClickParticipants: {} ) diff --git a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift index 4df9b4c..210c3d0 100644 --- a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift +++ b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift @@ -29,6 +29,8 @@ struct LiveRoomViewV2: View { participantsCount: liveRoomInfo.participantsCount, isOnBg: viewModel.isBgOn, isOnNotice: viewModel.isShowNotice, + isOnMenuPan: viewModel.isShowMenuPan, + isShowMenuPanButton: !liveRoomInfo.menuPan.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, creatorId: liveRoomInfo.creatorId, creatorNickname: liveRoomInfo.creatorNickname, creatorProfileUrl: liveRoomInfo.creatorProfileUrl, @@ -56,6 +58,9 @@ struct LiveRoomViewV2: View { onClickNotice: { viewModel.isShowNotice.toggle() }, + onClickMenuPan: { + viewModel.isShowMenuPan.toggle() + }, onClickTotalDonation: { viewModel.isShowDonationRankingPopup = true }, @@ -69,6 +74,8 @@ struct LiveRoomViewV2: View { totalDonationCan: viewModel.totalDonationCan, isOnBg: viewModel.isBgOn, isOnNotice: viewModel.isShowNotice, + isOnMenuPan: viewModel.isShowMenuPan, + isShowMenuPanButton: !liveRoomInfo.menuPan.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, creatorId: liveRoomInfo.creatorId, creatorNickname: liveRoomInfo.creatorNickname, creatorProfileUrl: liveRoomInfo.creatorProfileUrl, @@ -101,6 +108,9 @@ struct LiveRoomViewV2: View { onClickNotice: { viewModel.isShowNotice.toggle() }, + onClickMenuPan: { + viewModel.isShowMenuPan.toggle() + }, onClickTotalDonation: { viewModel.isShowDonationRankingPopup = true } @@ -293,6 +303,28 @@ struct LiveRoomViewV2: View { .padding(.bottom, 120) } } + + if viewModel.isShowMenuPan { + VStack(alignment: .leading, spacing: 0) { + Image("ic_notice_triangle") + .padding(.leading, 60) + + VStack(alignment: .leading, spacing: 8) { + Text("[메뉴판]") + .font(.custom(Font.bold.rawValue, size: 11.3)) + .foregroundColor(.white) + + Text(liveRoomInfo.menuPan) + .font(.custom(Font.light.rawValue, size: 11.3)) + .foregroundColor(.white) + .lineSpacing(4) + } + .padding(8) + .background(Color.gray33) + .padding(.horizontal, 60) + .padding(.bottom, 120) + } + } } } } diff --git a/SodaLive/Sources/UI/Theme/Color.swift b/SodaLive/Sources/UI/Theme/Color.swift index 4ff5ce8..d97fa7d 100644 --- a/SodaLive/Sources/UI/Theme/Color.swift +++ b/SodaLive/Sources/UI/Theme/Color.swift @@ -15,6 +15,7 @@ extension Color { static let bg = Color(hex: "13181B") static let gray11 = Color(hex: "111111") static let gray22 = Color(hex: "222222") + static let gray23 = Color(hex: "232323") static let gray30 = Color(hex: "303030") static let gray33 = Color(hex: "333333") static let gray52 = Color(hex: "525252")