룰렛 변경
- 확률 수동 설정 - 여러개의 룰렛이 켜져있을 때 선택하여 돌리기 - 후원 히스토리에 룰렛 히스토리
This commit is contained in:
parent
57abeea432
commit
cab719c774
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 996 B |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "btn_minus_round_rect.png",
|
"filename" : "ic_select_check_black.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png
vendored
Normal file
BIN
SodaLive/Resources/Assets.xcassets/ic_select_check_black.imageset/ic_select_check_black.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 418 B |
|
@ -23,7 +23,7 @@ struct LiveRoomDonationMessageDialog: View {
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Text("후원메시지")
|
Text("후원 히스토리")
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
|
@ -45,43 +45,19 @@ struct LiveRoomDonationMessageDialog: View {
|
||||||
ForEach(0..<viewModel.donationMessageList.count, id: \.self) { index in
|
ForEach(0..<viewModel.donationMessageList.count, id: \.self) { index in
|
||||||
let donationMessage = viewModel.donationMessageList[index]
|
let donationMessage = viewModel.donationMessageList[index]
|
||||||
|
|
||||||
HStack(alignment: .top, spacing: 0) {
|
LiveRoomDonationMessageItemView(message: donationMessage) {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
viewModel.deleteDonationMessage(uuid: $0)
|
||||||
Text("\(donationMessage.nickname)님이")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(.white)
|
|
||||||
|
|
||||||
Text("\(donationMessage.canMessage)")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(.white)
|
|
||||||
|
|
||||||
Text("'\(donationMessage.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 {
|
|
||||||
viewModel.deleteDonationMessage(uuid: donationMessage.uuid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.padding(13.3)
|
|
||||||
.background(Color(hex: "333333"))
|
|
||||||
.cornerRadius(5.3)
|
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
UIPasteboard.general.string = donationMessage.donationMessage
|
UIPasteboard.general.string = donationMessage.donationMessage
|
||||||
self.viewModel.errorMessage = "후원 메시지가 복사되었습니다."
|
self.viewModel.errorMessage = "후원 히스토리가 복사되었습니다."
|
||||||
self.viewModel.isShowPopup = true
|
self.viewModel.isShowPopup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 18.7)
|
.padding(.top, 18.7)
|
||||||
} else {
|
} else {
|
||||||
Text("후원메시지가 없습니다.")
|
Text("후원 히스토리가 없습니다.")
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.top, 30)
|
.padding(.top, 30)
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// LiveRoomDonationMessageItemView.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by klaus on 5/11/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct LiveRoomDonationMessageItemView: View {
|
||||||
|
|
||||||
|
let message: LiveRoomDonationMessage
|
||||||
|
let deleteDonationMessage: (String) -> 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 }
|
||||||
|
)
|
||||||
|
}
|
|
@ -151,7 +151,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
@Published var isShowRouletteSettings = false
|
@Published var isShowRouletteSettings = false
|
||||||
|
|
||||||
@Published var isShowRoulettePreview = false
|
@Published var isShowRoulettePreview = false
|
||||||
@Published var roulettePreview: RoulettePreview? = nil
|
@Published var roulettePreviewList = [RoulettePreview]()
|
||||||
|
|
||||||
@Published var isShowRoulette = false
|
@Published var isShowRoulette = false
|
||||||
@Published var rouletteItems = [String]()
|
@Published var rouletteItems = [String]()
|
||||||
|
@ -1456,6 +1456,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
func showRoulette() {
|
func showRoulette() {
|
||||||
if let liveRoomInfo = liveRoomInfo, !isLoading {
|
if let liveRoomInfo = liveRoomInfo, !isLoading {
|
||||||
|
self.roulettePreviewList.removeAll()
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
rouletteRepository.getRoulette(creatorId: liveRoomInfo.creatorId)
|
rouletteRepository.getRoulette(creatorId: liveRoomInfo.creatorId)
|
||||||
|
@ -1472,10 +1473,14 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let jsonDecoder = JSONDecoder()
|
let jsonDecoder = JSONDecoder()
|
||||||
let decoded = try jsonDecoder.decode(ApiResponse<GetRouletteResponse>.self, from: responseData)
|
let decoded = try jsonDecoder.decode(ApiResponse<[GetRouletteResponse]>.self, from: responseData)
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success, !data.items.isEmpty {
|
if let data = decoded.data, decoded.success, !data.isEmpty {
|
||||||
self.roulettePreview = RoulettePreview(can: data.can, items: calculatePercentages(options: data.items))
|
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
|
self.isShowRoulettePreview = true
|
||||||
} else {
|
} else {
|
||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
|
@ -1494,10 +1499,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func spinRoulette() {
|
func spinRoulette(rouletteId: Int) {
|
||||||
if !isLoading {
|
if !isLoading {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
rouletteRepository.spinRoulette(request: SpinRouletteRequest(roomId: AppState.shared.roomId))
|
rouletteRepository.spinRoulette(request: SpinRouletteRequest(roomId: AppState.shared.roomId, rouletteId: rouletteId))
|
||||||
.sink { result in
|
.sink { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .finished:
|
case .finished:
|
||||||
|
@ -1511,11 +1516,15 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let jsonDecoder = JSONDecoder()
|
let jsonDecoder = JSONDecoder()
|
||||||
let decoded = try jsonDecoder.decode(ApiResponse<GetRouletteResponse>.self, from: responseData)
|
let decoded = try jsonDecoder.decode(ApiResponse<SpinRouletteResponse>.self, from: responseData)
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success, !data.items.isEmpty {
|
if let data = decoded.data, decoded.success, !data.items.isEmpty {
|
||||||
UserDefaults.set(UserDefaults.int(forKey: .can) - data.can, forKey: .can)
|
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 {
|
} else {
|
||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
|
@ -1574,35 +1583,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func calculatePercentages(options: [RouletteItem]) -> [RoulettePreviewItem] {
|
private func calculatePercentages(options: [RouletteItem]) -> [RoulettePreviewItem] {
|
||||||
let totalWeight = options.reduce(0) { $0 + $1.weight }
|
|
||||||
let updatedOptions = options.map { option in
|
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", option.percentage))%")
|
||||||
return RoulettePreviewItem(title: option.title, percent: "\(String(format: "%.2f", percent))%")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedOptions
|
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() {
|
private func refundRouletteDonation() {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,10 @@ import SwiftUI
|
||||||
|
|
||||||
class RouletteOption: ObservableObject {
|
class RouletteOption: ObservableObject {
|
||||||
var title: String
|
var title: String
|
||||||
var weight: Int
|
var percentage: String = ""
|
||||||
var percentage: String = "50.00"
|
|
||||||
|
|
||||||
init(title: String, weight: Int) {
|
init(title: String, percentage: String) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.weight = weight
|
self.percentage = percentage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,7 @@ struct RouletteSettingsOptionView: View {
|
||||||
@ObservedObject var option: RouletteOption
|
@ObservedObject var option: RouletteOption
|
||||||
|
|
||||||
let index: Int
|
let index: Int
|
||||||
|
|
||||||
let onClickPlus: () -> Void
|
|
||||||
let onClickDelete: () -> Void
|
let onClickDelete: () -> Void
|
||||||
let onClickSubstract: () -> Void
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 6.7) {
|
VStack(spacing: 6.7) {
|
||||||
|
@ -47,19 +44,28 @@ struct RouletteSettingsOptionView: View {
|
||||||
.background(Color(hex: "222222"))
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.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))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.horizontal, 13.3)
|
.keyboardType(.decimalPad)
|
||||||
.padding(.vertical, 16.7)
|
.onChange(of: option.percentage) { newValue in
|
||||||
.background(Color(hex: "222222"))
|
if newValue.count > 5 {
|
||||||
.cornerRadius(6.7)
|
option.percentage = String(newValue.prefix(5))
|
||||||
|
}
|
||||||
Image("btn_minus_round_rect")
|
}
|
||||||
.onTapGesture { onClickSubstract() }
|
|
||||||
|
Text("%")
|
||||||
Image("btn_plus_round_rect")
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.onTapGesture { onClickPlus() }
|
.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 {
|
struct RouletteSettingsOptionView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
RouletteSettingsOptionView(
|
RouletteSettingsOptionView(
|
||||||
option: RouletteOption(title: "옵션1", weight: 1),
|
option: RouletteOption(title: "옵션1", percentage: ""),
|
||||||
index: 2,
|
index: 2,
|
||||||
onClickPlus: {},
|
onClickDelete: {}
|
||||||
onClickDelete: {},
|
|
||||||
onClickSubstract: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,9 +128,7 @@ struct RouletteSettingsView: View {
|
||||||
RouletteSettingsOptionView(
|
RouletteSettingsOptionView(
|
||||||
option: viewModel.options[index],
|
option: viewModel.options[index],
|
||||||
index: index,
|
index: index,
|
||||||
onClickPlus: { viewModel.plusWeight(index: index) },
|
onClickDelete: { viewModel.deleteOption(index: index) }
|
||||||
onClickDelete: { viewModel.deleteOption(index: index) },
|
|
||||||
onClickSubstract: { viewModel.subtractWeight(index: index) }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +188,7 @@ struct RouletteSettingsView: View {
|
||||||
isShowing: $viewModel.isShowPreview,
|
isShowing: $viewModel.isShowPreview,
|
||||||
title: "룰렛 미리보기",
|
title: "룰렛 미리보기",
|
||||||
onClickSpin: nil,
|
onClickSpin: nil,
|
||||||
preview: preview
|
previewList: [preview]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,47 +46,15 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
private var rouletteId = 0
|
private var rouletteId = 0
|
||||||
@Published var rouletteList = [GetNewRouletteResponse]()
|
@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() {
|
func addOption() {
|
||||||
if (options.count >= 10) {
|
if (options.count >= 10) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
options.append(RouletteOption(title: "", weight: 1))
|
options.append(RouletteOption(title: "", percentage: ""))
|
||||||
recalculatePercentages()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteOption(index: Int) {
|
func deleteOption(index: Int) {
|
||||||
options.remove(at: index)
|
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 {
|
|
||||||
let percent = floor(Double(options[i].weight) / Double(totalWeight) * 10000) / 100
|
|
||||||
options[i].percentage = String(format: "%.2f", percent)
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllAndAddOptions(options: options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeAllAndAddOptions(options: [RouletteOption]) {
|
private func removeAllAndAddOptions(options: [RouletteOption]) {
|
||||||
|
@ -143,7 +111,7 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
items.append(RoulettePreviewItem(title: option.title, percent: "\(option.percentage)%"))
|
items.append(RoulettePreviewItem(title: option.title, percent: "\(option.percentage)%"))
|
||||||
}
|
}
|
||||||
|
|
||||||
previewData = RoulettePreview(can: self.can, items: items)
|
previewData = RoulettePreview(id: 0, can: self.can, items: items)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
isShowPreview = true
|
isShowPreview = true
|
||||||
}
|
}
|
||||||
|
@ -152,25 +120,48 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
if !isLoading {
|
if !isLoading {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
if rouletteId > 0 {
|
if validationOptions() {
|
||||||
updateRoulette(onSuccess: onSuccess)
|
if rouletteId > 0 {
|
||||||
} else {
|
updateRoulette(onSuccess: onSuccess)
|
||||||
createRoulette(onSuccess: onSuccess)
|
} else {
|
||||||
|
createRoulette(onSuccess: onSuccess)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
private func validationOptions() -> Bool {
|
||||||
var items = [RouletteItem]()
|
var totalPercentage = Float(0)
|
||||||
|
|
||||||
for option in options {
|
for option in options {
|
||||||
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
isLoading = false
|
isLoading = false
|
||||||
errorMessage = "옵션은 빈칸일 수 없습니다."
|
errorMessage = "옵션은 빈칸일 수 없습니다."
|
||||||
isShowErrorPopup = true
|
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
|
let selectedRouletteTitle: String
|
||||||
|
@ -227,14 +218,9 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
||||||
var items = [RouletteItem]()
|
var items = [RouletteItem]()
|
||||||
for option in options {
|
for option in options {
|
||||||
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
if let percentage = Float(option.percentage) {
|
||||||
isLoading = false
|
items.append(RouletteItem(title: option.title, percentage: percentage))
|
||||||
errorMessage = "옵션은 빈칸일 수 없습니다."
|
|
||||||
isShowErrorPopup = true
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(RouletteItem(title: option.title, weight: option.weight))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectedRoulette = rouletteList[selectedRoulette!.rawValue]
|
let selectedRoulette = rouletteList[selectedRoulette!.rawValue]
|
||||||
|
@ -259,24 +245,10 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
selectedRouletteTitle = "룰렛 1"
|
selectedRouletteTitle = "룰렛 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
var isAllActive = false
|
|
||||||
|
|
||||||
rouletteList
|
|
||||||
.filter {
|
|
||||||
$0.id != selectedRoulette.id
|
|
||||||
}
|
|
||||||
.forEach {
|
|
||||||
if $0.isActive {
|
|
||||||
isAllActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isActive {
|
if isActive {
|
||||||
successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
|
successMessage = "\(selectedRouletteTitle)을 활성화 했습니다."
|
||||||
} else if !isAllActive {
|
|
||||||
successMessage = "\(selectedRouletteTitle)이 비활성화 되었습니다."
|
|
||||||
} else {
|
} else {
|
||||||
successMessage = "\(selectedRouletteTitle)을 설정했습니다."
|
successMessage = "\(selectedRouletteTitle)을 비활성화 했습니다."
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items)
|
let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items)
|
||||||
|
@ -337,10 +309,9 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
self.rouletteId = roulette.id
|
self.rouletteId = roulette.id
|
||||||
self.isActive = roulette.isActive
|
self.isActive = roulette.isActive
|
||||||
let options = roulette.items.map {
|
let options = roulette.items.map {
|
||||||
RouletteOption(title: $0.title, weight: $0.weight)
|
RouletteOption(title: $0.title, percentage: String($0.percentage))
|
||||||
}
|
}
|
||||||
removeAllAndAddOptions(options: options)
|
removeAllAndAddOptions(options: options)
|
||||||
recalculatePercentages()
|
|
||||||
} else {
|
} else {
|
||||||
self.canText = ""
|
self.canText = ""
|
||||||
self.isActive = false
|
self.isActive = false
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
struct GetRouletteResponse: Decodable {
|
struct GetRouletteResponse: Decodable {
|
||||||
|
let id: Int
|
||||||
let can: Int
|
let can: Int
|
||||||
let isActive: Bool
|
let isActive: Bool
|
||||||
let items: [RouletteItem]
|
let items: [RouletteItem]
|
||||||
|
@ -13,5 +14,5 @@ struct GetRouletteResponse: Decodable {
|
||||||
|
|
||||||
struct RouletteItem: Codable, Equatable {
|
struct RouletteItem: Codable, Equatable {
|
||||||
let title: String
|
let title: String
|
||||||
let weight: Int
|
let percentage: Float
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,16 @@ extension RouletteApi: TargetType {
|
||||||
var path: String {
|
var path: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .getRoulette, .createRoulette, .updateRoulette:
|
case .getRoulette, .createRoulette, .updateRoulette:
|
||||||
return "/new-roulette"
|
return "/v2/roulette"
|
||||||
|
|
||||||
case .getAllRoulette:
|
case .getAllRoulette:
|
||||||
return "/new-roulette/creator"
|
return "/v2/roulette/creator"
|
||||||
|
|
||||||
case .spinRoulette:
|
case .spinRoulette:
|
||||||
return "/new-roulette/spin"
|
return "/v2/roulette/spin"
|
||||||
|
|
||||||
case .refundRouletteDonation(let roomId):
|
case .refundRouletteDonation(let roomId):
|
||||||
return "/new-roulette/refund/\(roomId)"
|
return "/v2/roulette/refund/\(roomId)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct RoulettePreview {
|
struct RoulettePreview {
|
||||||
|
let id: Int
|
||||||
let can: Int
|
let can: Int
|
||||||
let items: [RoulettePreviewItem]
|
let items: [RoulettePreviewItem]
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,61 @@ struct RoulettePreviewDialog: View {
|
||||||
@Binding var isShowing: Bool
|
@Binding var isShowing: Bool
|
||||||
|
|
||||||
let title: String?
|
let title: String?
|
||||||
let onClickSpin: (() -> Void)?
|
let onClickSpin: ((Int) -> Void)?
|
||||||
let preview: RoulettePreview
|
let previewList: [RoulettePreview]
|
||||||
|
|
||||||
|
@State var selectedRoulette = SelectedRoulette.ROULETTE_1
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geo in
|
GeometryReader { geo in
|
||||||
ZStack {
|
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) {
|
HStack(spacing: 0) {
|
||||||
Text(title ?? "룰렛")
|
Text(title ?? "룰렛")
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
.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)
|
.padding(.horizontal, 13.3)
|
||||||
|
|
||||||
LazyVStack(alignment: .leading, spacing: 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) {
|
HStack(spacing:13.3) {
|
||||||
Text("\(index + 1)")
|
Text("\(index + 1)")
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "e2e2e2"))
|
.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))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "e2e2e2"))
|
.foregroundColor(Color(hex: "e2e2e2"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 13.3)
|
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
Text("취소")
|
Text("취소")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16))
|
.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(.horizontal, 18)
|
||||||
.padding(.vertical, 16)
|
.padding(.vertical, 16)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
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 {
|
.onTapGesture {
|
||||||
isShowing = false
|
isShowing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Text("\(preview.can)캔으로 룰렛 돌리기")
|
Text("\(previewList[selectedRoulette.rawValue].can)캔으로 룰렛 돌리기")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16))
|
.font(.custom(Font.bold.rawValue, size: 16))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(selectedRoulette == .ROULETTE_2 ? .black : .white)
|
||||||
.padding(.vertical, 16)
|
.padding(.vertical, 16)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.background(Color(hex: "3bb9f1"))
|
.background(
|
||||||
|
selectedRoulette == .ROULETTE_2 ? Color(hex: "ffcb14") :
|
||||||
|
selectedRoulette == .ROULETTE_3 ? Color(hex: "ff14d9") :
|
||||||
|
Color.button
|
||||||
|
)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if let onClickSpin = onClickSpin {
|
if let onClickSpin = onClickSpin {
|
||||||
onClickSpin()
|
onClickSpin(previewList[selectedRoulette.rawValue].id)
|
||||||
}
|
}
|
||||||
isShowing = false
|
isShowing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 26.7)
|
.padding(.top, 6.7)
|
||||||
}
|
}
|
||||||
.padding(13.3)
|
.padding(13.3)
|
||||||
.background(Color(hex: "222222"))
|
.background(Color(hex: "222222"))
|
||||||
|
@ -108,13 +168,32 @@ struct RoulettePreviewDialog_Previews: PreviewProvider {
|
||||||
isShowing: .constant(true),
|
isShowing: .constant(true),
|
||||||
title: nil,
|
title: nil,
|
||||||
onClickSpin: nil,
|
onClickSpin: nil,
|
||||||
preview: RoulettePreview(
|
previewList: [
|
||||||
can: 100,
|
RoulettePreview(
|
||||||
items: [
|
id: 0,
|
||||||
RoulettePreviewItem(title: "옵션1", percent: "10%"),
|
can: 100,
|
||||||
RoulettePreviewItem(title: "옵션2", percent: "90%"),
|
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%"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,6 @@ import Foundation
|
||||||
|
|
||||||
struct SpinRouletteRequest: Encodable {
|
struct SpinRouletteRequest: Encodable {
|
||||||
let roomId: Int
|
let roomId: Int
|
||||||
|
let rouletteId: Int
|
||||||
let container: String = "ios"
|
let container: String = "ios"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
}
|
|
@ -168,76 +168,46 @@ struct LiveRoomViewV2: View {
|
||||||
.padding(.top, 16)
|
.padding(.top, 16)
|
||||||
|
|
||||||
VStack(alignment: .trailing, spacing: 0) {
|
VStack(alignment: .trailing, spacing: 0) {
|
||||||
Image(viewModel.isSpeakerMute ? "ic_speaker_off" : "ic_speaker_on")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: viewModel.isSpeakerMute ? "ic_speaker_off" : "ic_speaker_on",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.toggleSpeakerMute() }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
.padding(.top, 26.7)
|
||||||
.cornerRadius(10)
|
.padding(.trailing, 13.3)
|
||||||
.onTapGesture {
|
|
||||||
viewModel.toggleSpeakerMute()
|
|
||||||
}
|
|
||||||
.padding(.top, 26.7)
|
|
||||||
.padding(.trailing, 13.3)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
VStack(spacing: 13.3) {
|
VStack(spacing: 13.3) {
|
||||||
if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) {
|
if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) {
|
||||||
Image("ic_roulette_settings")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: "ic_roulette_settings",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.isShowRouletteSettings = true }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.isShowRouletteSettings = true
|
|
||||||
}
|
|
||||||
} else if liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) && viewModel.isActiveRoulette {
|
} else if liveRoomInfo.creatorId != UserDefaults.int(forKey: .userId) && viewModel.isActiveRoulette {
|
||||||
Image("ic_roulette")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: "ic_roulette",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.showRoulette() }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.showRoulette()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.role == .SPEAKER {
|
if viewModel.role == .SPEAKER {
|
||||||
Image(viewModel.isMute ? "ic_mic_off" : "ic_mic_on")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: viewModel.isMute ? "ic_mic_off" : "ic_mic_on",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.toggleMute() }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.toggleMute()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) &&
|
if liveRoomInfo.creatorId == UserDefaults.int(forKey: .userId) &&
|
||||||
UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue {
|
UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue {
|
||||||
Image("ic_donation_message_list")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: "ic_donation_message_list",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.isShowDonationMessagePopup = true }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.isShowDonationMessagePopup = true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Image("ic_donation")
|
LiveRoomRightBottomButton(
|
||||||
.resizable()
|
imageName: "ic_donation",
|
||||||
.frame(width: 26.7, height: 26.7)
|
onClick: { viewModel.isShowDonationPopup = true }
|
||||||
.padding(11)
|
)
|
||||||
.background(Color(hex: "525252").opacity(0.6))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.isShowDonationPopup = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.trailing, 13.3)
|
.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(
|
RoulettePreviewDialog(
|
||||||
isShowing: $viewModel.isShowRoulettePreview,
|
isShowing: $viewModel.isShowRoulettePreview,
|
||||||
title: nil,
|
title: nil,
|
||||||
onClickSpin: { viewModel.spinRoulette() },
|
onClickSpin: { viewModel.spinRoulette(rouletteId: $0) },
|
||||||
preview: preview
|
previewList: viewModel.roulettePreviewList
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,23 +13,51 @@ struct SelectedButtonView: View {
|
||||||
let isActive: Bool
|
let isActive: Bool
|
||||||
let isSelected: 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 {
|
var body: some View {
|
||||||
HStack(spacing: 6.7) {
|
HStack(spacing: 6.7) {
|
||||||
if isSelected {
|
if isSelected {
|
||||||
Image("ic_select_check")
|
Image(checkImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.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)
|
.frame(maxWidth: .infinity)
|
||||||
.background(!isActive ? Color.gray55 : isSelected ? Color.button : Color.bg)
|
.background(!isActive ? bgDisabledColor : isSelected ? bgSelectedColor : bgDefaultColor)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview("기본") {
|
||||||
SelectedButtonView(title: "테스트", isActive: true, isSelected: true)
|
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")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue