diff --git a/SodaLive/Sources/I18n/I18n.swift b/SodaLive/Sources/I18n/I18n.swift index b90954f..3f06722 100644 --- a/SodaLive/Sources/I18n/I18n.swift +++ b/SodaLive/Sources/I18n/I18n.swift @@ -672,6 +672,12 @@ enum I18n { static var allAges: String { pick(ko: "전체 연령", en: "All ages", ja: "全年齢") } static var over19: String { pick(ko: "19세 이상", en: "19+", ja: "R-18") } + // 성별 제한 + static var genderRestrictionTitle: String { pick(ko: "성별 제한", en: "Gender restriction", ja: "性別制限") } + static var genderAll: String { pick(ko: "전체", en: "All", ja: "全体") } + static var genderMaleOnly: String { pick(ko: "남자만", en: "Male only", ja: "男性のみ") } + static var genderFemaleOnly: String { pick(ko: "여자만", en: "Female only", ja: "女性のみ") } + // 최근 데이터 관련 토스트/알림 static var recentDataLoaded: String { pick(ko: "최근데이터를 불러왔습니다.", en: "Recent data has been loaded.", ja: "最新データを読み込みました。") } static var recentDataLoadFailed: String { pick(ko: "최근데이터를 불러오지 못했습니다.\n다시 시도해 주세요.", en: "Failed to load recent data.\ntry again.", ja: "最近のデータを読み込めませんでした。\n恐れ入りますが、もう一度お試しください。") } diff --git a/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift b/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift index c70f97b..6903bb9 100644 --- a/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift +++ b/SodaLive/Sources/Live/Room/Create/CreateLiveRoomRequest.swift @@ -14,6 +14,7 @@ struct CreateLiveRoomRequest: Encodable { let tags: [String] let numberOfPeople: Int var isAdult: Bool = false + var genderRestriction: LiveRoomCreateViewModel.GenderRestriction = .ALL var price = 0 var type: LiveRoomCreateViewModel.LiveRoomType = .OPEN var password: String? = nil diff --git a/SodaLive/Sources/Live/Room/Create/GetRecentRoomInfoResponse.swift b/SodaLive/Sources/Live/Room/Create/GetRecentRoomInfoResponse.swift index 32b038b..b2032f4 100644 --- a/SodaLive/Sources/Live/Room/Create/GetRecentRoomInfoResponse.swift +++ b/SodaLive/Sources/Live/Room/Create/GetRecentRoomInfoResponse.swift @@ -13,4 +13,5 @@ struct GetRecentRoomInfoResponse: Decodable { let coverImageUrl: String let coverImagePath: String let numberOfPeople: Int + let genderRestriction: LiveRoomCreateViewModel.GenderRestriction } diff --git a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift index 54398de..2058ea4 100644 --- a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift +++ b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift @@ -175,6 +175,10 @@ struct LiveRoomCreateView: View { AdultSettingView() .frame(width: screenSize().width - 26.7) .padding(.top, 33.3) + + GenderRestrictionView() + .frame(width: screenSize().width - 26.7) + .padding(.top, 33.3) } PriceSettingView() @@ -698,6 +702,56 @@ struct LiveRoomCreateView: View { } } } + + @ViewBuilder + func GenderRestrictionView() -> some View { + VStack(spacing: 13.3) { + Text(I18n.CreateLive.genderRestrictionTitle) + .appFont(size: 16.7, weight: .bold) + .foregroundColor(Color.grayee) + .frame(width: screenSize().width - 26.7, alignment: .leading) + + HStack(spacing: 13.3) { + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderAll, + restriction: .ALL, + buttonWidth: (screenSize().width - 53) / 3 + ) + + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderMaleOnly, + restriction: .MALE_ONLY, + buttonWidth: (screenSize().width - 53) / 3 + ) + + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderFemaleOnly, + restriction: .FEMALE_ONLY, + buttonWidth: (screenSize().width - 53) / 3 + ) + } + } + } + + @ViewBuilder + func GenderRestrictionSelectButton( + title: String, + restriction: LiveRoomCreateViewModel.GenderRestriction, + buttonWidth: CGFloat + ) -> some View { + SelectedButtonView( + title: title, + isActive: true, + isSelected: viewModel.genderRestriction == restriction + ) + .frame(width: buttonWidth) + .onTapGesture { + hideKeyboard() + if viewModel.genderRestriction != restriction { + viewModel.genderRestriction = restriction + } + } + } @ViewBuilder func PriceSettingView() -> some View { diff --git a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift index 2974f09..2427ced 100644 --- a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift +++ b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateViewModel.swift @@ -23,6 +23,10 @@ final class LiveRoomCreateViewModel: ObservableObject { enum LiveRoomType: String, Codable { case OPEN, PRIVATE } + + enum GenderRestriction: String, Codable { + case ALL, MALE_ONLY, FEMALE_ONLY + } let prices = [0, 100, 300, 500, 1000, 2000] @@ -61,6 +65,7 @@ final class LiveRoomCreateViewModel: ObservableObject { } @Published var isAdult = false + @Published var genderRestriction: GenderRestriction = .ALL @Published var priceString = "0" { didSet { if priceString.count > 5 { @@ -134,6 +139,7 @@ final class LiveRoomCreateViewModel: ObservableObject { self.coverImageUrl = data.coverImageUrl self.coverImagePath = data.coverImagePath self.numberOfPeople = String(data.numberOfPeople) + self.genderRestriction = data.genderRestriction self.errorMessage = I18n.CreateLive.recentDataLoaded self.isShowPopup = true @@ -173,6 +179,7 @@ final class LiveRoomCreateViewModel: ObservableObject { tags: tags, numberOfPeople: Int(numberOfPeople)!, isAdult: isAdult, + genderRestriction: genderRestriction, price: price, type: roomType, password: (roomType == .PRIVATE && !password.trimmingCharacters(in: .whitespaces).isEmpty) ? password : nil, diff --git a/SodaLive/Sources/Live/Room/Detail/GetRoomDetailResponse.swift b/SodaLive/Sources/Live/Room/Detail/GetRoomDetailResponse.swift index 08348f4..0459146 100644 --- a/SodaLive/Sources/Live/Room/Detail/GetRoomDetailResponse.swift +++ b/SodaLive/Sources/Live/Room/Detail/GetRoomDetailResponse.swift @@ -14,6 +14,7 @@ struct GetRoomDetailResponse: Decodable { let notice: String let isPaid: Bool let isAdult: Bool + let genderRestriction: LiveRoomCreateViewModel.GenderRestriction? let isPrivateRoom: Bool let password: String? let tags: [String] diff --git a/SodaLive/Sources/Live/Room/Edit/EditLiveRoomInfoRequest.swift b/SodaLive/Sources/Live/Room/Edit/EditLiveRoomInfoRequest.swift index 4e0a521..f7a8ff1 100644 --- a/SodaLive/Sources/Live/Room/Edit/EditLiveRoomInfoRequest.swift +++ b/SodaLive/Sources/Live/Room/Edit/EditLiveRoomInfoRequest.swift @@ -17,4 +17,5 @@ struct EditLiveRoomInfoRequest: Encodable { var menuPan: String = "" var isActiveMenuPan: Bool? = nil var isAdult: Bool? = nil + var genderRestriction: LiveRoomCreateViewModel.GenderRestriction? = nil } diff --git a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift index 7f7f568..c7d6c54 100644 --- a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift +++ b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift @@ -45,13 +45,17 @@ struct LiveRoomEditView: View { NumberOfPeopleLimitView() .frame(width: screenSize().width - 26.7) .padding(.top, 33.3) + + GenderRestrictionView() + .frame(width: screenSize().width - 26.7) + .padding(.top, 33.3) if !viewModel.isLoading { Text("라이브 수정") .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .frame(width: screenSize().width - 26.7, height: 50) - .background(Color(hex: "9970ff")) + .background(Color.button) .cornerRadius(10) .padding(.top, 30) .onTapGesture { @@ -87,7 +91,7 @@ struct LiveRoomEditView: View { .padding(.vertical, 13.3) .frame(width: geo.size.width - 66.7, alignment: .center) .appFont(size: 12, weight: .medium) - .background(Color(hex: "9970ff")) + .background(Color.button) .foregroundColor(Color.white) .multilineTextAlignment(.center) .cornerRadius(20) @@ -175,7 +179,7 @@ struct LiveRoomEditView: View { .frame(width: buttonWidth, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) - .stroke(Color(hex: "9970ff"), lineWidth: 1.3) + .stroke(Color.button, lineWidth: 1.3) ) } } @@ -195,7 +199,7 @@ struct LiveRoomEditView: View { .frame(width: buttonWidth, height: 48.7) .overlay( RoundedRectangle(cornerRadius: 6.7) - .stroke(Color(hex: "9970ff"), lineWidth: 1.3) + .stroke(Color.button, lineWidth: 1.3) ) } } @@ -227,6 +231,56 @@ struct LiveRoomEditView: View { .cornerRadius(6.7) } } + + @ViewBuilder + func GenderRestrictionView() -> some View { + VStack(spacing: 13.3) { + Text(I18n.CreateLive.genderRestrictionTitle) + .appFont(size: 16.7, weight: .bold) + .foregroundColor(Color(hex: "eeeeee")) + .frame(width: screenSize().width - 26.7, alignment: .leading) + + HStack(spacing: 13.3) { + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderAll, + restriction: .ALL, + buttonWidth: (screenSize().width - 53) / 3 + ) + + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderMaleOnly, + restriction: .MALE_ONLY, + buttonWidth: (screenSize().width - 53) / 3 + ) + + GenderRestrictionSelectButton( + title: I18n.CreateLive.genderFemaleOnly, + restriction: .FEMALE_ONLY, + buttonWidth: (screenSize().width - 53) / 3 + ) + } + } + } + + @ViewBuilder + func GenderRestrictionSelectButton( + title: String, + restriction: LiveRoomCreateViewModel.GenderRestriction, + buttonWidth: CGFloat + ) -> some View { + SelectedButtonView( + title: title, + isActive: true, + isSelected: viewModel.genderRestriction == restriction + ) + .frame(width: buttonWidth) + .onTapGesture { + hideKeyboard() + if viewModel.genderRestriction != restriction { + viewModel.genderRestriction = restriction + } + } + } @ViewBuilder func SelectDateView() -> some View { diff --git a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift index 5ca4aae..d772aba 100644 --- a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift +++ b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift @@ -24,6 +24,7 @@ final class LiveRoomEditViewModel: ObservableObject { @Published var numberOfPeople = "" @Published var reservationDateString: String = "" @Published var reservationTimeString: String = "" + @Published var genderRestriction: LiveRoomCreateViewModel.GenderRestriction = .ALL @Published var errorMessage = "" @Published var isShowPopup = false @@ -51,6 +52,7 @@ final class LiveRoomEditViewModel: ObservableObject { title = room!.title notice = room!.notice numberOfPeople = String(room!.numberOfParticipantsTotal) + genderRestriction = room!.genderRestriction ?? .ALL if let beginDate = room!.beginDateTimeUtc.parseUtcIsoDate() { reservationDate = beginDate @@ -80,14 +82,16 @@ final class LiveRoomEditViewModel: ObservableObject { notice: room.notice != notice ? notice : nil, numberOfPeople: room.numberOfParticipantsTotal != Int(numberOfPeople)! ? Int(numberOfPeople)! : nil, beginDateTimeString: beginDateTimeStr != beginDateTime ? beginDateTime : nil, - timezone: TimeZone.current.identifier + timezone: TimeZone.current.identifier, + genderRestriction: (room.genderRestriction ?? .ALL) != genderRestriction ? genderRestriction : nil ) if ( request.title == nil && request.notice == nil && request.numberOfPeople == nil && - request.beginDateTimeString == nil + request.beginDateTimeString == nil && + request.genderRestriction == nil ) { self.errorMessage = "변경사항이 없습니다." self.isShowPopup = true