Compare commits
No commits in common. "3c6ac1c0607fc2a36702e6647c0555ab47fb35a8" and "27b87c9cbe36342dc665ff2177d11bb9597b3cac" have entirely different histories.
3c6ac1c060
...
27b87c9cbe
|
@ -36,22 +36,13 @@
|
||||||
"version" : "5.7.1"
|
"version" : "5.7.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"identity" : "app-check",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/google/app-check.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2",
|
|
||||||
"version" : "10.18.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "firebase-ios-sdk",
|
"identity" : "firebase-ios-sdk",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
|
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "be49849dcba96f2b5ee550d4eceb2c0fa27dade4",
|
"revision" : "df2171b0c6afb9e9d4f7e07669d558c510b9f6be",
|
||||||
"version" : "10.22.1"
|
"version" : "10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,8 +50,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "482cfa4e5880f0a29f66ecfd60c5a62af28bd1f0",
|
"revision" : "03b9beee1a61f62d32c521e172e192a1663a5e8b",
|
||||||
"version" : "10.22.1"
|
"version" : "10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -68,8 +59,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/GoogleDataTransport.git",
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
|
"revision" : "aae45a320fd0d11811820335b1eabc8753902a40",
|
||||||
"version" : "9.4.0"
|
"version" : "9.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -77,8 +68,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/GoogleUtilities.git",
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "26c898aed8bed13b8a63057ee26500abbbcb8d55",
|
"revision" : "c38ce365d77b04a9a300c31061c5227589e5597b",
|
||||||
"version" : "7.13.1"
|
"version" : "7.11.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -86,8 +77,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/google/grpc-binary.git",
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98",
|
"revision" : "f1b366129d1125be7db83247e003fc333104b569",
|
||||||
"version" : "1.49.1"
|
"version" : "1.50.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -99,15 +90,6 @@
|
||||||
"version" : "3.1.1"
|
"version" : "3.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"identity" : "interop-ios-for-google-sdks",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
|
|
||||||
"version" : "100.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "kingfisher",
|
"identity" : "kingfisher",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
|
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.5 KiB |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "btn_following_big.png",
|
"filename" : "btn_notification.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/btn_notification.imageset/btn_notification.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
21
SodaLive/Resources/Assets.xcassets/btn_notification_selected.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "btn_notification_selected.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/btn_notification_selected.imageset/btn_notification_selected.png
vendored
Normal file
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 563 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 772 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 554 KiB |
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 320 KiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 617 KiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 678 KiB |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "ic_can_white.png",
|
"filename" : "img_guide_5.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/onboarding/img_guide_5.imageset/img_guide_5.png
vendored
Normal file
After Width: | Height: | Size: 531 KiB |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "btn_follow_big.png",
|
"filename" : "img_guide_6.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/onboarding/img_guide_6.imageset/img_guide_6.png
vendored
Normal file
After Width: | Height: | Size: 252 KiB |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "img_bg_short_play.png",
|
"filename" : "splash_bg_2024.jpg",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/splash_bg_2024.imageset/splash_bg_2024.jpg
vendored
Normal file
After Width: | Height: | Size: 349 KiB |
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "splash_bg_2024_03.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 3.1 MiB |
21
SodaLive/Resources/Assets.xcassets/splash/splash_bubble.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "splash_bubble.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/splash_bubble.imageset/splash_bubble.png
vendored
Normal file
After Width: | Height: | Size: 11 KiB |
21
SodaLive/Resources/Assets.xcassets/splash/splash_logo.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "splash_logo.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/splash_logo.imageset/splash_logo.png
vendored
Normal file
After Width: | Height: | Size: 55 KiB |
21
SodaLive/Resources/Assets.xcassets/splash/splash_logo_2024.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "splash_logo_2024.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/splash_logo_2024.imageset/splash_logo_2024.png
vendored
Normal file
After Width: | Height: | Size: 40 KiB |
|
@ -9,7 +9,7 @@
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "img_bg_review_live.png",
|
"filename" : "splash_logo_dragon_2024.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
After Width: | Height: | Size: 82 KiB |
21
SodaLive/Resources/Assets.xcassets/splash/splash_text.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "splash_text.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/splash_text.imageset/splash_text.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "splash_text_2024_03.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 29 KiB |
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "splash_text_logo_2024_03.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 4.5 KiB |
21
SodaLive/Resources/Assets.xcassets/splash/vividnext_logo.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "vividnext_logo.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
SodaLive/Resources/Assets.xcassets/splash/vividnext_logo.imageset/vividnext_logo.png
vendored
Normal file
After Width: | Height: | Size: 6.6 KiB |
|
@ -1,41 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>CA92.1</string>
|
|
||||||
</array>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>C617.1</string>
|
|
||||||
</array>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>35F9.1</string>
|
|
||||||
</array>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>E174.1</string>
|
|
||||||
</array>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -89,7 +89,7 @@ struct ContentAllByThemeView: View {
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
LazyVGrid(columns: columns, spacing: 32) {
|
LazyVGrid(columns: columns, spacing: 13.3) {
|
||||||
ForEach(0..<viewModel.contentList.count, id: \.self) { index in
|
ForEach(0..<viewModel.contentList.count, id: \.self) { index in
|
||||||
ContentNewAllItemView(item: viewModel.contentList[index])
|
ContentNewAllItemView(item: viewModel.contentList[index])
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|
|
@ -35,11 +35,11 @@ struct ContentNewAllItemView: View {
|
||||||
Image("ic_card_can_gray")
|
Image("ic_card_can_gray")
|
||||||
|
|
||||||
Text("\(item.price)")
|
Text("\(item.price)")
|
||||||
.font(.custom(Font.medium.rawValue, size: 8.5))
|
.font(.custom(Font.medium.rawValue, size: 8.3))
|
||||||
.foregroundColor(Color.white)
|
.foregroundColor(Color.white)
|
||||||
} else {
|
} else {
|
||||||
Text("무료")
|
Text("무료")
|
||||||
.font(.custom(Font.medium.rawValue, size: 8.5))
|
.font(.custom(Font.medium.rawValue, size: 8.3))
|
||||||
.foregroundColor(Color.white)
|
.foregroundColor(Color.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,10 @@ struct ContentNewAllItemView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
HStack(spacing: 2) {
|
||||||
|
Image("ic_card_time_small_gray")
|
||||||
|
|
||||||
Text(item.duration)
|
Text(item.duration)
|
||||||
.font(.custom(Font.medium.rawValue, size: 8.5))
|
.font(.custom(Font.medium.rawValue, size: 8.3))
|
||||||
.foregroundColor(Color.white)
|
.foregroundColor(Color.white)
|
||||||
}
|
}
|
||||||
.padding(3)
|
.padding(3)
|
||||||
|
@ -91,7 +93,7 @@ struct ContentNewAllItemView: View {
|
||||||
}
|
}
|
||||||
.frame(width: width)
|
.frame(width: width)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
width = (screenSize().width - 42) / 3
|
width = (screenSize().width - 54) / 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct ContentNewAllView: View {
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
LazyVGrid(columns: columns, spacing: 32) {
|
LazyVGrid(columns: columns, spacing: 13.3) {
|
||||||
ForEach(0..<viewModel.newContentList.count, id: \.self) { index in
|
ForEach(0..<viewModel.newContentList.count, id: \.self) { index in
|
||||||
ContentNewAllItemView(item: viewModel.newContentList[index])
|
ContentNewAllItemView(item: viewModel.newContentList[index])
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|
|
@ -91,7 +91,7 @@ struct ContentCurationView: View {
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
LazyVGrid(columns: columns, spacing: 32) {
|
LazyVGrid(columns: columns, spacing: 13.3) {
|
||||||
ForEach(0..<viewModel.contentList.count, id: \.self) { index in
|
ForEach(0..<viewModel.contentList.count, id: \.self) { index in
|
||||||
ContentNewAllItemView(item: viewModel.contentList[index])
|
ContentNewAllItemView(item: viewModel.contentList[index])
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|
|
@ -33,8 +33,8 @@ struct AudioContentCommentItemView: View {
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Text(commentItem.nickname)
|
Text(commentItem.nickname)
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.gray90)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Text(commentItem.date)
|
Text(commentItem.date)
|
||||||
.font(.custom(Font.medium.rawValue, size: 10.3))
|
.font(.custom(Font.medium.rawValue, size: 10.3))
|
||||||
|
@ -107,15 +107,14 @@ struct AudioContentCommentItemView: View {
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.strokeBorder(lineWidth: 1)
|
.strokeBorder(lineWidth: 1)
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "3bb9f1"))
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
VStack(alignment: .leading, spacing: 13.3) {
|
VStack(alignment: .leading, spacing: 13.3) {
|
||||||
Text(commentItem.comment)
|
Text(commentItem.comment)
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "777777"))
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.lineSpacing(8)
|
|
||||||
.padding(.top, commentItem.donationCan > 0 ? 0 : 13.3)
|
.padding(.top, commentItem.donationCan > 0 ? 0 : 13.3)
|
||||||
|
|
||||||
if !isReplyComment {
|
if !isReplyComment {
|
||||||
|
@ -128,7 +127,7 @@ struct AudioContentCommentItemView: View {
|
||||||
) {
|
) {
|
||||||
Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기")
|
Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ struct ContentDetailCommentView: View {
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color(hex: "bbbbbb"))
|
.foregroundColor(Color(hex: "bbbbbb"))
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.lineSpacing(8)
|
|
||||||
.padding(.leading, 3)
|
.padding(.leading, 3)
|
||||||
} else {
|
} else {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct ContentDetailCreatorProfileView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if creator.creatorId != UserDefaults.int(forKey: .userId) {
|
if creator.creatorId != UserDefaults.int(forKey: .userId) {
|
||||||
Image(creator.isFollowing ? "btn_following_big" : "btn_follow_big")
|
Image(creator.isFollowing ? "btn_notification_selected" : "btn_notification")
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if creator.isFollowing {
|
if creator.isFollowing {
|
||||||
onClickUnFollow(creator.creatorId)
|
onClickUnFollow(creator.creatorId)
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
//
|
|
||||||
// ContentDetailInfoLimitedEditionView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 3/27/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentDetailInfoLimitedEditionView: View {
|
|
||||||
|
|
||||||
let totalContentCount: Int
|
|
||||||
let remainingContentCount: Int
|
|
||||||
let orderSequence: Int?
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
Text("한정판")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
if let orderSequence = orderSequence {
|
|
||||||
Text("\(orderSequence)")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
.padding(.leading, 5.3)
|
|
||||||
|
|
||||||
Text("/")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.grayd2)
|
|
||||||
.padding(.leading, 2.3)
|
|
||||||
|
|
||||||
Text("\(totalContentCount)")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.grayd2)
|
|
||||||
.padding(.leading, 2.3)
|
|
||||||
} else if (remainingContentCount <= 0) {
|
|
||||||
Text("Sold Out")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
|
||||||
.foregroundColor(Color.grayd2)
|
|
||||||
.padding(.horizontal, 5.3)
|
|
||||||
.padding(.vertical, 3.3)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 2.6)
|
|
||||||
.stroke(lineWidth: 1)
|
|
||||||
.foregroundColor(Color.grayd2)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Text("잔여수량")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.grayd2)
|
|
||||||
|
|
||||||
Text("\(remainingContentCount)")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
.padding(.leading, 5.3)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
.padding(.vertical, 8)
|
|
||||||
.padding(.horizontal, 10.3)
|
|
||||||
.background(Color(hex: "14262d"))
|
|
||||||
.cornerRadius(5.3)
|
|
||||||
.padding(.top, 13.3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
ContentDetailInfoLimitedEditionView(
|
|
||||||
totalContentCount: 10,
|
|
||||||
remainingContentCount: 0,
|
|
||||||
orderSequence: nil
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -142,14 +142,6 @@ struct ContentDetailInfoView: View {
|
||||||
}
|
}
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
|
|
||||||
if let totalContentCount = audioContent.totalContentCount, let remainingContentCount = audioContent.remainingContentCount {
|
|
||||||
ContentDetailInfoLimitedEditionView(
|
|
||||||
totalContentCount: totalContentCount,
|
|
||||||
remainingContentCount: remainingContentCount,
|
|
||||||
orderSequence: audioContent.orderSequence
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ZStack {
|
ZStack {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
if audioContent.tag.count > 0 {
|
if audioContent.tag.count > 0 {
|
||||||
|
|
|
@ -35,17 +35,7 @@ struct ContentDetailPlayView: View {
|
||||||
)
|
)
|
||||||
.cornerRadius(10.7, corners: [.topLeft, .topRight])
|
.cornerRadius(10.7, corners: [.topLeft, .topRight])
|
||||||
|
|
||||||
if let _ = audioContent.totalContentCount, let remainingContentCount = audioContent.remainingContentCount, remainingContentCount <= 0, audioContent.creator.creatorId != UserDefaults.int(forKey: .userId), !audioContent.existOrdered {
|
if audioContent.releaseDate == nil && !isAlertPreview || (isAlertPreview && audioContent.isActivePreview) {
|
||||||
Text("Sold Out")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 36.7))
|
|
||||||
.foregroundColor(.white)
|
|
||||||
.frame(
|
|
||||||
width: screenSize().width - 26.7,
|
|
||||||
height: screenSize().width - 26.7,
|
|
||||||
alignment: .center
|
|
||||||
)
|
|
||||||
.background(Color.black.opacity(0.6))
|
|
||||||
} else if audioContent.releaseDate == nil && !isAlertPreview || (audioContent.isActivePreview && !audioContent.contentUrl.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty) {
|
|
||||||
Image(isPlaying() ? "btn_audio_content_pause" : isAlertPreview ? "btn_audio_content_preview_play" : "btn_audio_content_play")
|
Image(isPlaying() ? "btn_audio_content_pause" : isAlertPreview ? "btn_audio_content_preview_play" : "btn_audio_content_play")
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if isPlaying() {
|
if isPlaying() {
|
||||||
|
@ -66,7 +56,7 @@ struct ContentDetailPlayView: View {
|
||||||
isShowPreviewAlert = true
|
isShowPreviewAlert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if audioContent.releaseDate == nil {
|
} else {
|
||||||
Text("해당 콘텐츠는 크리에이터의 요청으로\n미리듣기를 제공하지 않습니다.")
|
Text("해당 콘텐츠는 크리에이터의 요청으로\n미리듣기를 제공하지 않습니다.")
|
||||||
.font(.custom(Font.medium.rawValue, size: 16.7))
|
.font(.custom(Font.medium.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color.grayee)
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct ContentDetailPurchaseButton: View {
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 48.7)
|
.frame(height: 48.7)
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.cornerRadius(5.3)
|
.cornerRadius(5.3)
|
||||||
.padding(.top, 18.3)
|
.padding(.top, 18.3)
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,29 +107,10 @@ struct ContentDetailView: View {
|
||||||
!audioContent.existOrdered &&
|
!audioContent.existOrdered &&
|
||||||
audioContent.orderType == nil &&
|
audioContent.orderType == nil &&
|
||||||
audioContent.creator.creatorId != UserDefaults.int(forKey: .userId) {
|
audioContent.creator.creatorId != UserDefaults.int(forKey: .userId) {
|
||||||
if let _ = audioContent.totalContentCount, let remainingContentCount = audioContent.remainingContentCount, remainingContentCount <= 0 {
|
ContentDetailPurchaseButton(price: audioContent.price, isOnlyRental: audioContent.isOnlyRental)
|
||||||
Text("해당 콘텐츠가 매진되었습니다.")
|
.contentShape(Rectangle())
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
.padding(.horizontal, 13.3)
|
||||||
.foregroundColor(.white)
|
.onTapGesture { isShowOrderView = true }
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.frame(height: 48.7)
|
|
||||||
.background(Color(hex: "525252"))
|
|
||||||
.cornerRadius(5.3)
|
|
||||||
.padding(.top, 18.3)
|
|
||||||
.padding(.horizontal, 13.3)
|
|
||||||
} else {
|
|
||||||
ContentDetailPurchaseButton(price: audioContent.price, isOnlyRental: audioContent.isOnlyRental)
|
|
||||||
.contentShape(Rectangle())
|
|
||||||
.padding(.horizontal, 13.3)
|
|
||||||
.onTapGesture {
|
|
||||||
if let _ = audioContent.totalContentCount, let _ = audioContent.remainingContentCount {
|
|
||||||
viewModel.orderType = .KEEP
|
|
||||||
isShowOrderConfirmView = true
|
|
||||||
} else {
|
|
||||||
isShowOrderView = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if audioContent.isCommentAvailable {
|
if audioContent.isCommentAvailable {
|
||||||
|
|
|
@ -18,9 +18,6 @@ struct GetAudioContentDetailResponse: Decodable {
|
||||||
let price: Int
|
let price: Int
|
||||||
let duration: String
|
let duration: String
|
||||||
let releaseDate: String?
|
let releaseDate: String?
|
||||||
let totalContentCount: Int?
|
|
||||||
let remainingContentCount: Int?
|
|
||||||
let orderSequence: Int?
|
|
||||||
let isActivePreview: Bool
|
let isActivePreview: Bool
|
||||||
let isAdult: Bool
|
let isAdult: Bool
|
||||||
let isMosaic: Bool
|
let isMosaic: Bool
|
||||||
|
|
|
@ -38,45 +38,47 @@ struct ContentMainView: View {
|
||||||
.padding(.bottom, 26.7)
|
.padding(.bottom, 26.7)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 13.3) {
|
||||||
ZStack {
|
VStack(spacing: 2.7) {
|
||||||
Image("img_bg_short_play")
|
|
||||||
.resizable()
|
|
||||||
.frame(height: 53.3)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.cornerRadius(2.6)
|
|
||||||
|
|
||||||
HStack(spacing: 2.7) {
|
HStack(spacing: 2.7) {
|
||||||
Image("ic_short_play")
|
Image("ic_short_play")
|
||||||
|
|
||||||
Text("숏플")
|
Text("숏플")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "dd158d"))
|
.foregroundColor(Color(hex: "dd158d"))
|
||||||
}
|
}
|
||||||
.cornerRadius(2.6)
|
|
||||||
|
Text("짧지만 꼴릿한 이야기")
|
||||||
|
.font(.custom(Font.light.rawValue, size: 10))
|
||||||
|
.foregroundColor(Color(hex: "dd158d"))
|
||||||
}
|
}
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(Color(hex: "ffecf7"))
|
||||||
|
.cornerRadius(2.6)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
AppState.shared.setAppStep(
|
AppState.shared.setAppStep(
|
||||||
step: .contentAllByTheme(themeId: 11)
|
step: .contentAllByTheme(themeId: 11)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ZStack {
|
VStack(spacing: 2.7) {
|
||||||
Image("img_bg_review_live")
|
|
||||||
.resizable()
|
|
||||||
.frame(height: 53.3)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.cornerRadius(2.6)
|
|
||||||
|
|
||||||
HStack(spacing: 2.7) {
|
HStack(spacing: 2.7) {
|
||||||
Image("ic_thumb_play_blue")
|
Image("ic_thumb_play_blue")
|
||||||
|
|
||||||
Text("라이브 다시듣기")
|
Text("라이브 다시듣기")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color(hex: "0057ff"))
|
.foregroundColor(Color(hex: "0057ff"))
|
||||||
}
|
}
|
||||||
.cornerRadius(2.6)
|
|
||||||
|
Text("놓쳤던 라이브 다시듣기")
|
||||||
|
.font(.custom(Font.light.rawValue, size: 10))
|
||||||
|
.foregroundColor(Color(hex: "0057ff"))
|
||||||
}
|
}
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(Color(hex: "ecf9ff"))
|
||||||
|
.cornerRadius(2.6)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
AppState.shared.setAppStep(
|
AppState.shared.setAppStep(
|
||||||
step: .contentAllByTheme(themeId: 7)
|
step: .contentAllByTheme(themeId: 7)
|
||||||
|
|
|
@ -33,8 +33,8 @@ struct CreatorCommunityCommentItemView: View {
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Text(commentItem.nickname)
|
Text(commentItem.nickname)
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.gray90)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Text(commentItem.date)
|
Text(commentItem.date)
|
||||||
.font(.custom(Font.medium.rawValue, size: 10.3))
|
.font(.custom(Font.medium.rawValue, size: 10.3))
|
||||||
|
@ -86,10 +86,9 @@ struct CreatorCommunityCommentItemView: View {
|
||||||
} else {
|
} else {
|
||||||
VStack(alignment: .leading, spacing: 13.3) {
|
VStack(alignment: .leading, spacing: 13.3) {
|
||||||
Text(commentItem.comment)
|
Text(commentItem.comment)
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "777777"))
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.lineSpacing(8)
|
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
|
|
||||||
if !isReplyComment {
|
if !isReplyComment {
|
||||||
|
@ -102,7 +101,7 @@ struct CreatorCommunityCommentItemView: View {
|
||||||
) {
|
) {
|
||||||
Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기")
|
Text(commentItem.replyCount > 0 ? "답글 \(commentItem.replyCount)개" : "답글 쓰기")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,12 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Text("\(cheersItem.nickname)")
|
Text("\(cheersItem.nickname)")
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.gray90)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Text("\(cheersItem.date)")
|
Text("\(cheersItem.date)")
|
||||||
.font(.custom(Font.medium.rawValue, size: 10.7))
|
.font(.custom(Font.medium.rawValue, size: 10.7))
|
||||||
.foregroundColor(Color.gray55)
|
.foregroundColor(Color(hex: "525252"))
|
||||||
.padding(.top, 8.3)
|
.padding(.top, 8.3)
|
||||||
|
|
||||||
if isModeModify {
|
if isModeModify {
|
||||||
|
@ -60,14 +60,14 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.strokeBorder(lineWidth: 1)
|
.strokeBorder(lineWidth: 1)
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
)
|
)
|
||||||
|
|
||||||
Text("수정")
|
Text("수정")
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
.font(.custom(Font.bold.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color(hex: "ffffff"))
|
.foregroundColor(Color(hex: "ffffff"))
|
||||||
.padding(13.3)
|
.padding(13.3)
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
modifyCheer(cheersItem.cheersId, cheers)
|
modifyCheer(cheersItem.cheersId, cheers)
|
||||||
|
@ -76,7 +76,7 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
|
|
||||||
Text("취소")
|
Text("취소")
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
.font(.custom(Font.bold.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
.padding(13.3)
|
.padding(13.3)
|
||||||
.background(Color(hex: "222222"))
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
|
@ -87,10 +87,9 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
} else {
|
} else {
|
||||||
Text("\(cheersItem.content)")
|
Text("\(cheersItem.content)")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "777777"))
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.lineSpacing(8)
|
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
if userId == UserDefaults.int(forKey: .userId) {
|
if userId == UserDefaults.int(forKey: .userId) {
|
||||||
Text("답글쓰기")
|
Text("답글쓰기")
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
.padding(.top, 18.3)
|
.padding(.top, 18.3)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isShowInputReply = true
|
isShowInputReply = true
|
||||||
|
@ -147,7 +146,7 @@ struct UserProfileFanTalkCheersItemView: View {
|
||||||
.frame(minWidth: 100)
|
.frame(minWidth: 100)
|
||||||
.padding(.horizontal, 6.7)
|
.padding(.horizontal, 6.7)
|
||||||
.padding(.vertical, 6.7)
|
.padding(.vertical, 6.7)
|
||||||
.background(Color.button.opacity(0.3))
|
.background(Color(hex: "9970ff").opacity(0.3))
|
||||||
.cornerRadius(16.7)
|
.cornerRadius(16.7)
|
||||||
.padding(.top, 18.3)
|
.padding(.top, 18.3)
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct FollowerListItemView: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if let isFollow = item.isFollow {
|
if let isFollow = item.isFollow {
|
||||||
Image(isFollow ? "btn_following_big" : "btn_follow_big")
|
Image(isFollow ? "btn_notification_selected" : "btn_notification")
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isFollow ?
|
isFollow ?
|
||||||
creatorUnFollow(item.userId) :
|
creatorUnFollow(item.userId) :
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct UserProfileCreatorView: View {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VStack(alignment: .leading, spacing: 9.3) {
|
VStack(alignment: .leading, spacing: 9.3) {
|
||||||
Image(creator.isNotification ? "btn_following_big" : "btn_follow_big")
|
Image(creator.isNotification ? "btn_notification_selected" : "btn_notification")
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 83.3, height: 26.7)
|
.frame(width: 83.3, height: 26.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct FollowCreatorItemView: View {
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Image(isFollow ? "btn_following_big" : "btn_follow_big")
|
Image(isFollow ? "btn_notification_selected" : "btn_notification")
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if isFollow {
|
if isFollow {
|
||||||
onClickUnFollow(creator.creatorId)
|
onClickUnFollow(creator.creatorId)
|
||||||
|
|
|
@ -36,7 +36,6 @@ enum LiveApi {
|
||||||
case getDonationMessageList(roomId: Int)
|
case getDonationMessageList(roomId: Int)
|
||||||
case deleteDonationMessage(roomId: Int, messageUUID: String)
|
case deleteDonationMessage(roomId: Int, messageUUID: String)
|
||||||
case getUserProfile(roomId: Int, userId: Int)
|
case getUserProfile(roomId: Int, userId: Int)
|
||||||
case getAllMenuPreset(creatorId: Int)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LiveApi: TargetType {
|
extension LiveApi: TargetType {
|
||||||
|
@ -126,15 +125,12 @@ extension LiveApi: TargetType {
|
||||||
|
|
||||||
case .getUserProfile(let roomId, let userId):
|
case .getUserProfile(let roomId, let userId):
|
||||||
return "/live/room/\(roomId)/profile/\(userId)"
|
return "/live/room/\(roomId)/profile/\(userId)"
|
||||||
|
|
||||||
case .getAllMenuPreset:
|
|
||||||
return "/live/room/menu/all"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method: Moya.Method {
|
var method: Moya.Method {
|
||||||
switch self {
|
switch self {
|
||||||
case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile, .getAllMenuPreset:
|
case .roomList, .recentVisitRoomUsers, .getReservations, .getReservation, .getRoomDetail, .getTags, .getRecentRoomInfo, .getRoomInfo, .donationStatus, .donationTotal, .getDonationMessageList, .getUserProfile:
|
||||||
return .get
|
return .get
|
||||||
|
|
||||||
case .makeReservation, .enterRoom, .createRoom, .quitRoom, .donation, .refundDonation, .kickOut:
|
case .makeReservation, .enterRoom, .createRoom, .quitRoom, .donation, .refundDonation, .kickOut:
|
||||||
|
@ -230,9 +226,6 @@ extension LiveApi: TargetType {
|
||||||
|
|
||||||
case .deleteDonationMessage(let roomId, let messageUUID):
|
case .deleteDonationMessage(let roomId, let messageUUID):
|
||||||
return .requestJSONEncodable(DeleteLiveRoomDonationMessage(roomId: roomId, messageUUID: messageUUID))
|
return .requestJSONEncodable(DeleteLiveRoomDonationMessage(roomId: roomId, messageUUID: messageUUID))
|
||||||
|
|
||||||
case .getAllMenuPreset(let creatorId):
|
|
||||||
return .requestParameters(parameters: ["creatorId" : creatorId], encoding: URLEncoding.queryString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,8 +116,4 @@ final class LiveRepository {
|
||||||
func getUserProfile(roomId: Int, userId: Int) -> AnyPublisher<Response, MoyaError> {
|
func getUserProfile(roomId: Int, userId: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
api.requestPublisher(.getUserProfile(roomId: roomId, userId: userId))
|
api.requestPublisher(.getUserProfile(roomId: roomId, userId: userId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllMenuPreset(creatorId: Int) -> AnyPublisher<Response, MoyaError> {
|
|
||||||
api.requestPublisher(.getAllMenuPreset(creatorId: creatorId))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,39 +11,33 @@ import Kingfisher
|
||||||
struct LiveNowAllItemView: View {
|
struct LiveNowAllItemView: View {
|
||||||
|
|
||||||
let item: GetRoomListResponse
|
let item: GetRoomListResponse
|
||||||
let itemWidth: CGFloat
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(spacing: 13.3) {
|
||||||
ZStack {
|
HStack(spacing: 20) {
|
||||||
KFImage(URL(string: item.coverImageUrl))
|
ZStack(alignment: .topLeading) {
|
||||||
.resizable()
|
KFImage(URL(string: item.coverImageUrl))
|
||||||
.scaledToFill()
|
.resizable()
|
||||||
.frame(width: itemWidth, height: itemWidth * 144 / 102, alignment: .center)
|
.scaledToFill()
|
||||||
.cornerRadius(4.7)
|
.frame(width: 80, height: 116.7, alignment: .top)
|
||||||
.clipped()
|
.cornerRadius(4.7)
|
||||||
|
.clipped()
|
||||||
|
}
|
||||||
|
|
||||||
LinearGradient(
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
colors: [Color.black.opacity(0.1), Color.black.opacity(0.8)],
|
HStack(alignment: .top, spacing: 0) {
|
||||||
startPoint: .top,
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
endPoint: .bottom
|
Text(item.creatorNickname)
|
||||||
)
|
.font(.custom(Font.medium.rawValue, size: 11.3))
|
||||||
|
.foregroundColor(Color(hex: "bbbbbb"))
|
||||||
|
|
||||||
VStack(alignment: .trailing, spacing: 0) {
|
Text(item.title)
|
||||||
HStack(spacing: 0) {
|
.font(.custom(Font.medium.rawValue, size: 15.3))
|
||||||
HStack(spacing: 1) {
|
.foregroundColor(Color(hex: "e2e2e2"))
|
||||||
if item.price > 0 {
|
.lineLimit(2)
|
||||||
Image("ic_can_white")
|
.padding(.top, 4.3)
|
||||||
}
|
.padding(.trailing, 20)
|
||||||
|
|
||||||
Text(item.price > 0 ? "\(item.price)" : "무료")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
|
||||||
.foregroundColor(Color.white)
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 7.3)
|
|
||||||
.padding(.vertical, 4)
|
|
||||||
.background(item.price > 0 ? Color.mainRed3 : Color.gray11)
|
|
||||||
.cornerRadius(13.3)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
@ -51,92 +45,48 @@ struct LiveNowAllItemView: View {
|
||||||
Image("ic_lock")
|
Image("ic_lock")
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.padding(2.7)
|
|
||||||
.background(Color.gray33.opacity(0.7))
|
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 3.3)
|
.padding(.top, 13.3)
|
||||||
.padding(.top, 3.3)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if item.numberOfPeople - item.numberOfParticipate < 3 {
|
HStack(spacing: 0) {
|
||||||
HStack(spacing: 0) {
|
Text(item.numberOfPeople > item.numberOfParticipate ? "참여가능" : "Sold out")
|
||||||
Spacer()
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
|
.foregroundColor(
|
||||||
|
Color(
|
||||||
|
hex: item.numberOfPeople > item.numberOfParticipate ?
|
||||||
|
"3bb9f1" :
|
||||||
|
"ffd300"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
Spacer()
|
||||||
Text("잔여")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
|
||||||
.foregroundColor(Color.grayee)
|
|
||||||
|
|
||||||
Text("\(item.numberOfPeople - item.numberOfParticipate)")
|
if item.price > 0 {
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
Text("\(item.price)")
|
||||||
.foregroundColor(Color.button)
|
.font(.custom(Font.bold.rawValue, size: 15.3))
|
||||||
}
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.horizontal, 4)
|
|
||||||
.padding(.vertical, 3)
|
Image("ic_can")
|
||||||
.background(Color.gray33.opacity(0.7))
|
.resizable()
|
||||||
.cornerRadius(13.3)
|
.frame(width: 20, height: 20)
|
||||||
|
.padding(.leading, 6.7)
|
||||||
|
} else {
|
||||||
|
Text("무료")
|
||||||
|
.font(.custom(Font.bold.rawValue, size: 15.3))
|
||||||
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 3.3)
|
|
||||||
.padding(.bottom, 3.3)
|
|
||||||
}
|
}
|
||||||
|
.padding(.bottom, 3.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: itemWidth, height: itemWidth * 144 / 102)
|
|
||||||
|
|
||||||
Text("\(item.title)")
|
Rectangle()
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.foregroundColor(Color(hex: "909090").opacity(0.5))
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.frame(width: screenSize().width - 26.7, height: 1)
|
||||||
.lineLimit(2)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
|
|
||||||
if item.tags.count > 0 {
|
|
||||||
Text("\(item.tags.map { "#\($0)" }.joined(separator: " "))")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 11))
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack(spacing: 5.3) {
|
|
||||||
KFImage(URL(string: item.creatorProfileImage))
|
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 21.3, height: 21.3, alignment: .center)
|
|
||||||
.clipShape(Circle())
|
|
||||||
|
|
||||||
Text("\(item.creatorNickname)")
|
|
||||||
.font(.custom(Font.medium.rawValue, size: 10))
|
|
||||||
.foregroundColor(Color.gray77)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(width: itemWidth)
|
.frame(width: screenSize().width - 26.7, height: 130, alignment: .center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LiveNowAllItemView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
LiveNowAllItemView(
|
|
||||||
item: GetRoomListResponse(
|
|
||||||
roomId: 99,
|
|
||||||
title: "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest",
|
|
||||||
content: "testtest",
|
|
||||||
beginDateTime: "2022.05.23 Mon 03:00 PM",
|
|
||||||
numberOfParticipate: 3,
|
|
||||||
numberOfPeople: 5,
|
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
isAdult: true,
|
|
||||||
price: 20,
|
|
||||||
tags: ["팬미팅", "힐링"],
|
|
||||||
channelName: nil,
|
|
||||||
creatorProfileImage: "https://test-cf.sodalive.net/profile/default-profile.png",
|
|
||||||
creatorNickname: "user8",
|
|
||||||
creatorId: 19,
|
|
||||||
isReservation: false,
|
|
||||||
isPrivateRoom: true
|
|
||||||
),
|
|
||||||
itemWidth: 102
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,6 @@ struct LiveNowAllView: View {
|
||||||
@StateObject var viewModel = LiveViewModel()
|
@StateObject var viewModel = LiveViewModel()
|
||||||
@StateObject var liveAllViewModel = LiveAllViewModel()
|
@StateObject var liveAllViewModel = LiveAllViewModel()
|
||||||
|
|
||||||
let columns = [
|
|
||||||
GridItem(.flexible(), alignment: .top),
|
|
||||||
GridItem(.flexible(), alignment: .top),
|
|
||||||
GridItem(.flexible(), alignment: .top)
|
|
||||||
]
|
|
||||||
|
|
||||||
let spacing: CGFloat = 13.3
|
|
||||||
|
|
||||||
let onClickParticipant: (Int) -> Void
|
let onClickParticipant: (Int) -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -37,11 +29,11 @@ struct LiveNowAllView: View {
|
||||||
viewModel.getLiveNowList()
|
viewModel.getLiveNowList()
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
LazyVGrid(columns: columns, spacing: spacing) {
|
VStack(spacing: 13.3) {
|
||||||
ForEach(0..<viewModel.liveNowItems.count, id: \.self) { index in
|
ForEach(0..<viewModel.liveNowItems.count, id: \.self) { index in
|
||||||
let item = viewModel.liveNowItems[index]
|
let item = viewModel.liveNowItems[index]
|
||||||
|
|
||||||
LiveNowAllItemView(item: item, itemWidth: (screenSize().width - (spacing * (CGFloat(columns.count + 1)))) / 3)
|
LiveNowAllItemView(item: item)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
self.liveAllViewModel.selectedRoomId = item.roomId
|
self.liveAllViewModel.selectedRoomId = item.roomId
|
||||||
|
|
|
@ -12,8 +12,8 @@ struct LiveNowItemView: View {
|
||||||
|
|
||||||
let item: GetRoomListResponse
|
let item: GetRoomListResponse
|
||||||
|
|
||||||
let width: CGFloat = 128
|
let width: CGFloat = 133.3
|
||||||
let height: CGFloat = 179
|
let height: CGFloat = 176.7
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
@ -32,20 +32,14 @@ struct LiveNowItemView: View {
|
||||||
)
|
)
|
||||||
|
|
||||||
VStack(alignment: .trailing, spacing: 0) {
|
VStack(alignment: .trailing, spacing: 0) {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 3.3) {
|
||||||
HStack(spacing: 1) {
|
Text(item.price > 0 ? "유료" : "무료")
|
||||||
if item.price > 0 {
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
Image("ic_can_white")
|
.foregroundColor(Color.white)
|
||||||
}
|
.padding(.horizontal, 7.3)
|
||||||
|
.padding(.vertical, 4)
|
||||||
Text(item.price > 0 ? "\(item.price)" : "무료")
|
.background(Color(hex: item.price > 0 ? "881609" : "643bc8"))
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.cornerRadius(10)
|
||||||
.foregroundColor(Color.white)
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 7.3)
|
|
||||||
.padding(.vertical, 4)
|
|
||||||
.background(item.price > 0 ? Color.mainRed3 : Color.gray11)
|
|
||||||
.cornerRadius(13.3)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
|
@ -53,9 +47,6 @@ struct LiveNowItemView: View {
|
||||||
Image("ic_lock")
|
Image("ic_lock")
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
.padding(2.7)
|
|
||||||
.background(Color.gray33.opacity(0.7))
|
|
||||||
.clipShape(Circle())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 3.3)
|
.padding(.horizontal, 3.3)
|
||||||
|
@ -106,7 +97,7 @@ struct LiveNowItemView_Previews: PreviewProvider {
|
||||||
numberOfPeople: 5,
|
numberOfPeople: 5,
|
||||||
coverImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
coverImageUrl: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
isAdult: true,
|
isAdult: true,
|
||||||
price: 20,
|
price: 0,
|
||||||
tags: ["팬미팅", "힐링"],
|
tags: ["팬미팅", "힐링"],
|
||||||
channelName: nil,
|
channelName: nil,
|
||||||
creatorProfileImage: "https://test-cf.sodalive.net/profile/default-profile.png",
|
creatorProfileImage: "https://test-cf.sodalive.net/profile/default-profile.png",
|
||||||
|
|
|
@ -15,7 +15,6 @@ struct LiveRoomChatRawMessage: Codable {
|
||||||
let type: LiveRoomChatRawMessageType
|
let type: LiveRoomChatRawMessageType
|
||||||
let message: String
|
let message: String
|
||||||
let can: Int
|
let can: Int
|
||||||
var signatureImageUrl: String? = nil
|
|
||||||
let donationMessage: String?
|
let donationMessage: String?
|
||||||
var isActiveRoulette: Bool? = nil
|
var isActiveRoulette: Bool? = nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,4 @@ struct CreateLiveRoomRequest: Encodable {
|
||||||
var password: String? = nil
|
var password: String? = nil
|
||||||
let timezone: String = TimeZone.current.identifier
|
let timezone: String = TimeZone.current.identifier
|
||||||
var beginDateTimeString: String? = nil
|
var beginDateTimeString: String? = nil
|
||||||
var menuPanId: Int = 0
|
|
||||||
var menuPan: String = ""
|
|
||||||
var isActiveMenuPan: Bool = false
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ struct LiveRoomCreateView: View {
|
||||||
|
|
||||||
Text("라이브 만들기")
|
Text("라이브 만들기")
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
@ -49,13 +49,13 @@ struct LiveRoomCreateView: View {
|
||||||
if viewModel.isShowGetRecentInfoButton {
|
if viewModel.isShowGetRecentInfoButton {
|
||||||
Text("최근 데이터 가져오기")
|
Text("최근 데이터 가져오기")
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.padding(.horizontal, 10.7)
|
.padding(.horizontal, 10.7)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: 8)
|
||||||
.stroke()
|
.stroke()
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
)
|
)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
viewModel.getRecentInfo()
|
viewModel.getRecentInfo()
|
||||||
|
@ -71,7 +71,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Text("썸네일")
|
Text("썸네일")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
.frame(width: screenSize().width, alignment: .leading)
|
.frame(width: screenSize().width, alignment: .leading)
|
||||||
|
@ -95,13 +95,13 @@ struct LiveRoomCreateView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 80, height: 116.8)
|
.frame(width: 80, height: 116.8)
|
||||||
.background(Color.bg)
|
.background(Color(hex: "3e3358"))
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
Image("ic_camera")
|
Image("ic_camera")
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.cornerRadius(30)
|
.cornerRadius(30)
|
||||||
.offset(x: 40, y: 40)
|
.offset(x: 40, y: 40)
|
||||||
}
|
}
|
||||||
|
@ -115,32 +115,25 @@ struct LiveRoomCreateView: View {
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
.padding(.top, 33.3)
|
.padding(.top, 33.3)
|
||||||
|
|
||||||
ContentInputView()
|
TagSelectView()
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
.padding(.top, 33.3)
|
.padding(.top, 33.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(spacing: 33.3) {
|
VStack(spacing: 0) {
|
||||||
LiveRoomMenuSelectView(
|
ContentInputView()
|
||||||
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)
|
|
||||||
|
|
||||||
TagSelectView()
|
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
|
.padding(.top, 33.3)
|
||||||
|
|
||||||
TimeSettingView()
|
if viewModel.roomType != .SECRET {
|
||||||
|
TimeSettingView()
|
||||||
|
.padding(.top, 33.3)
|
||||||
|
}
|
||||||
|
|
||||||
NumberOfPeopleLimitView()
|
NumberOfPeopleLimitView()
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
|
.padding(.top, 33.3)
|
||||||
}
|
}
|
||||||
.padding(.top, 33.3)
|
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
RoomTypeSettingView()
|
RoomTypeSettingView()
|
||||||
|
@ -153,9 +146,11 @@ struct LiveRoomCreateView: View {
|
||||||
.padding(.top, 33.3)
|
.padding(.top, 33.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
PriceSettingView()
|
if UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue {
|
||||||
.frame(width: screenSize().width - 26.7)
|
PriceSettingView()
|
||||||
.padding(.top, 33.3)
|
.frame(width: screenSize().width - 26.7)
|
||||||
|
.padding(.top, 33.3)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(alignment: .top, spacing: 0) {
|
HStack(alignment: .top, spacing: 0) {
|
||||||
|
@ -172,23 +167,23 @@ struct LiveRoomCreateView: View {
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
.foregroundColor(Color.white)
|
.foregroundColor(Color.white)
|
||||||
.frame(width: screenSize().width - 26.7, height: 50)
|
.frame(width: screenSize().width - 26.7, height: 50)
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.padding(.vertical, 13.3)
|
.padding(.vertical, 13.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: screenSize().width)
|
.frame(width: screenSize().width)
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(16.7, corners: [.topLeft, .topRight])
|
.cornerRadius(16.7, corners: [.topLeft, .topRight])
|
||||||
.padding(.top, 30)
|
.padding(.top, 30)
|
||||||
|
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.foregroundColor(Color.gray22)
|
.foregroundColor(Color(hex: "222222"))
|
||||||
.frame(width: screenSize().width, height: keyboardHandler.keyboardHeight)
|
.frame(width: screenSize().width, height: keyboardHandler.keyboardHeight)
|
||||||
|
|
||||||
if proxy.safeAreaInsets.bottom > 0 {
|
if proxy.safeAreaInsets.bottom > 0 {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.foregroundColor(Color.gray22)
|
.foregroundColor(Color(hex: "222222"))
|
||||||
.frame(width: screenSize().width, height: 15.3)
|
.frame(width: screenSize().width, height: 15.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +234,7 @@ struct LiveRoomCreateView: View {
|
||||||
.padding(.vertical, 13.3)
|
.padding(.vertical, 13.3)
|
||||||
.frame(width: geo.size.width - 66.7, alignment: .center)
|
.frame(width: geo.size.width - 66.7, alignment: .center)
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.foregroundColor(Color.white)
|
.foregroundColor(Color.white)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.cornerRadius(20)
|
.cornerRadius(20)
|
||||||
|
@ -250,7 +245,6 @@ struct LiveRoomCreateView: View {
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.timeSettingMode = timeSettingMode
|
viewModel.timeSettingMode = timeSettingMode
|
||||||
viewModel.getAllMenuPreset()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +253,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Text("제목")
|
Text("제목")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.frame(width: screenSize().width, alignment: .leading)
|
.frame(width: screenSize().width, alignment: .leading)
|
||||||
|
|
||||||
|
@ -267,15 +261,15 @@ struct LiveRoomCreateView: View {
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.accentColor(Color.button)
|
.accentColor(Color(hex: "3bb9f1"))
|
||||||
.keyboardType(.default)
|
.keyboardType(.default)
|
||||||
.padding(.top, 12)
|
.padding(.top, 12)
|
||||||
.padding(.horizontal, 6.7)
|
.padding(.horizontal, 6.7)
|
||||||
|
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.frame(height: 1)
|
.frame(height: 1)
|
||||||
.foregroundColor(Color.gray90.opacity(0.7))
|
.foregroundColor(Color(hex: "909090").opacity(0.7))
|
||||||
.padding(.top, 8.3)
|
.padding(.top, 8.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,7 +279,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(alignment: .leading, spacing: 13.3) {
|
VStack(alignment: .leading, spacing: 13.3) {
|
||||||
Text("관심사")
|
Text("관심사")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -293,15 +287,15 @@ struct LiveRoomCreateView: View {
|
||||||
}) {
|
}) {
|
||||||
Text("관심사 선택")
|
Text("관심사 선택")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
.padding(.vertical, 13.7)
|
.padding(.vertical, 13.7)
|
||||||
.frame(width: screenSize().width - 26.7)
|
.frame(width: screenSize().width - 26.7)
|
||||||
.background(Color.button.opacity(0.2))
|
.background(Color(hex: "9970ff").opacity(0.2))
|
||||||
.cornerRadius(24.3)
|
.cornerRadius(24.3)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 24.3)
|
RoundedRectangle(cornerRadius: 24.3)
|
||||||
.stroke()
|
.stroke()
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +315,7 @@ struct LiveRoomCreateView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.background(Color.button)
|
.background(Color(hex: "9970ff"))
|
||||||
.cornerRadius(24.3)
|
.cornerRadius(24.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,25 +330,25 @@ struct LiveRoomCreateView: View {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Text("공지")
|
Text("공지")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("\(viewModel.content.count)자")
|
Text("\(viewModel.content.count)자")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.mainRed) +
|
.foregroundColor(Color(hex: "ff5c49")) +
|
||||||
Text(" / 1000자")
|
Text(" / 1000자")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.gray77)
|
.foregroundColor(Color(hex: "777777"))
|
||||||
}
|
}
|
||||||
|
|
||||||
TextViewWrapper(
|
TextViewWrapper(
|
||||||
text: $viewModel.content,
|
text: $viewModel.content,
|
||||||
placeholder: viewModel.placeholder,
|
placeholder: viewModel.placeholder,
|
||||||
textColorHex: "eeeeee",
|
textColorHex: "eeeeee",
|
||||||
backgroundColorHex: "303030"
|
backgroundColorHex: "222222"
|
||||||
)
|
)
|
||||||
.frame(width: screenSize().width - 26.7, height: 200)
|
.frame(width: screenSize().width - 26.7, height: 133.3)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
}
|
}
|
||||||
|
@ -365,7 +359,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Text("시간설정")
|
Text("시간설정")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
|
@ -406,11 +400,15 @@ struct LiveRoomCreateView: View {
|
||||||
.foregroundColor(
|
.foregroundColor(
|
||||||
viewModel.timeSettingMode == timeSettingMode ?
|
viewModel.timeSettingMode == timeSettingMode ?
|
||||||
.white :
|
.white :
|
||||||
Color.button
|
Color(hex: "9970ff")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.background(viewModel.timeSettingMode == timeSettingMode ? Color.button : Color.bg)
|
.background(
|
||||||
|
viewModel.timeSettingMode == timeSettingMode ?
|
||||||
|
Color(hex: "9970ff") :
|
||||||
|
Color(hex: "1f1734")
|
||||||
|
)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -426,7 +424,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(alignment: .leading, spacing: 6.7) {
|
VStack(alignment: .leading, spacing: 6.7) {
|
||||||
Text("예약 날짜")
|
Text("예약 날짜")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -434,11 +432,11 @@ struct LiveRoomCreateView: View {
|
||||||
}) {
|
}) {
|
||||||
Text(viewModel.reservationDateString)
|
Text(viewModel.reservationDateString)
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 6.7)
|
RoundedRectangle(cornerRadius: 6.7)
|
||||||
.stroke(Color.button, lineWidth: 1.3)
|
.stroke(Color(hex: "9970ff"), lineWidth: 1.3)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,7 +444,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(alignment: .leading, spacing: 6.7) {
|
VStack(alignment: .leading, spacing: 6.7) {
|
||||||
Text("예약 시간")
|
Text("예약 시간")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -454,18 +452,18 @@ struct LiveRoomCreateView: View {
|
||||||
}) {
|
}) {
|
||||||
Text(viewModel.reservationTimeString)
|
Text(viewModel.reservationTimeString)
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 6.7)
|
RoundedRectangle(cornerRadius: 6.7)
|
||||||
.stroke(Color.button, lineWidth: 1.3)
|
.stroke(Color(hex: "9970ff"), lineWidth: 1.3)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: screenSize().width)
|
.frame(width: screenSize().width)
|
||||||
.padding(.vertical, 13.3)
|
.padding(.vertical, 13.3)
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
@ -473,7 +471,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 13.3) {
|
VStack(spacing: 13.3) {
|
||||||
Text("참여인원 설정")
|
Text("참여인원 설정")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
TextField("최대 인원 999명", text: $viewModel.numberOfPeople)
|
TextField("최대 인원 999명", text: $viewModel.numberOfPeople)
|
||||||
|
@ -481,12 +479,12 @@ struct LiveRoomCreateView: View {
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.accentColor(Color.button)
|
.accentColor(Color(hex: "3bb9f1"))
|
||||||
.keyboardType(.numberPad)
|
.keyboardType(.numberPad)
|
||||||
.padding(.vertical, 15.7)
|
.padding(.vertical, 15.7)
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .center)
|
.frame(width: screenSize().width - 26.7, alignment: .center)
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,12 +508,12 @@ struct LiveRoomCreateView: View {
|
||||||
Button(action: { self.isShowSelectDateView = false }) {
|
Button(action: { self.isShowSelectDateView = false }) {
|
||||||
Text("확인")
|
Text("확인")
|
||||||
.font(.system(size: 16))
|
.font(.system(size: 16))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.frame(width: proxy.size.width - 53.4)
|
.frame(width: proxy.size.width - 53.4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
}
|
}
|
||||||
.frame(width: proxy.size.width)
|
.frame(width: proxy.size.width)
|
||||||
|
@ -541,12 +539,12 @@ struct LiveRoomCreateView: View {
|
||||||
Button(action: { self.isShowSelectTimeView = false }) {
|
Button(action: { self.isShowSelectTimeView = false }) {
|
||||||
Text("확인")
|
Text("확인")
|
||||||
.font(.system(size: 16))
|
.font(.system(size: 16))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.frame(width: proxy.size.width)
|
.frame(width: proxy.size.width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
}
|
}
|
||||||
.frame(width: proxy.size.width)
|
.frame(width: proxy.size.width)
|
||||||
|
@ -558,7 +556,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Text("공개 설정")
|
Text("공개 설정")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
|
@ -593,10 +591,18 @@ struct LiveRoomCreateView: View {
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(viewModel.roomType == type ? .white : Color.button)
|
.foregroundColor(
|
||||||
|
viewModel.roomType == type ?
|
||||||
|
.white :
|
||||||
|
Color(hex: "9970ff")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.background(viewModel.roomType == type ? Color.button : Color.bg)
|
.background(
|
||||||
|
viewModel.roomType == type ?
|
||||||
|
Color(hex: "9970ff") :
|
||||||
|
Color(hex: "1f1734")
|
||||||
|
)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -611,7 +617,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 13.3) {
|
VStack(spacing: 13.3) {
|
||||||
Text("방 비밀번호 입력")
|
Text("방 비밀번호 입력")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
TextField("방 입장 비밀번호 6자리를 입력해 주세요.", text: $viewModel.password)
|
TextField("방 입장 비밀번호 6자리를 입력해 주세요.", text: $viewModel.password)
|
||||||
|
@ -619,12 +625,12 @@ struct LiveRoomCreateView: View {
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.accentColor(Color.button)
|
.accentColor(Color(hex: "3bb9f1"))
|
||||||
.keyboardType(.numberPad)
|
.keyboardType(.numberPad)
|
||||||
.padding(.vertical, 15.7)
|
.padding(.vertical, 15.7)
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .center)
|
.frame(width: screenSize().width - 26.7, alignment: .center)
|
||||||
.background(Color.gray22)
|
.background(Color(hex: "222222"))
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,7 +640,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 13.3) {
|
VStack(spacing: 13.3) {
|
||||||
Text("연령 제한")
|
Text("연령 제한")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
|
@ -662,10 +668,18 @@ struct LiveRoomCreateView: View {
|
||||||
|
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
.font(.custom(Font.bold.rawValue, size: 14.7))
|
||||||
.foregroundColor(viewModel.isAdult == isAdult ? .white : Color.button)
|
.foregroundColor(
|
||||||
|
viewModel.isAdult == isAdult ?
|
||||||
|
.white :
|
||||||
|
Color(hex: "9970ff")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.background(viewModel.isAdult == isAdult ? Color.button : Color.bg)
|
.background(
|
||||||
|
viewModel.isAdult == isAdult ?
|
||||||
|
Color(hex: "9970ff") :
|
||||||
|
Color(hex: "1f1734")
|
||||||
|
)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
@ -680,7 +694,7 @@ struct LiveRoomCreateView: View {
|
||||||
VStack(spacing: 13.3) {
|
VStack(spacing: 13.3) {
|
||||||
Text("티켓 가격")
|
Text("티켓 가격")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
.frame(width: screenSize().width - 26.7, alignment: .leading)
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
|
@ -705,23 +719,35 @@ struct LiveRoomCreateView: View {
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.font(.custom(Font.bold.rawValue, size: 13.3))
|
.font(.custom(Font.bold.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
.accentColor(Color.button)
|
.accentColor(Color(hex: "3bb9f1"))
|
||||||
.keyboardType(.numberPad)
|
.keyboardType(.numberPad)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("캔")
|
Text("캔")
|
||||||
.font(.custom(Font.medium.rawValue, size: 14.7))
|
.font(.custom(Font.medium.rawValue, size: 14.7))
|
||||||
.foregroundColor(Color.button)
|
.foregroundColor(
|
||||||
|
Color(hex: "9970ff")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.frame(width: screenSize().width - 26.7, height: 48.7)
|
.frame(width: screenSize().width - 26.7, height: 48.7)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 6.7)
|
RoundedRectangle(cornerRadius: 6.7)
|
||||||
.stroke(!viewModel.prices.contains(viewModel.price) ? Color.button : Color.gray77, lineWidth: 1)
|
.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")
|
||||||
)
|
)
|
||||||
.background(!viewModel.prices.contains(viewModel.price) ? Color.button.opacity(0.3): Color.gray23)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,17 +761,23 @@ struct LiveRoomCreateView: View {
|
||||||
Font.medium.rawValue,
|
Font.medium.rawValue,
|
||||||
size: 14.7
|
size: 14.7
|
||||||
))
|
))
|
||||||
.foregroundColor(viewModel.price == price ? Color.button : Color.gray77)
|
.foregroundColor(
|
||||||
|
Color(hex: viewModel.price == price ? "9970ff" : "777777")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.frame(width: buttonWidth, height: 48.7)
|
.frame(width: buttonWidth, height: 48.7)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 6.7)
|
RoundedRectangle(cornerRadius: 6.7)
|
||||||
.stroke(
|
.stroke(
|
||||||
viewModel.price == price ? Color.button : Color.gray77,
|
Color(hex: viewModel.price == price ? "9970ff" : "777777"),
|
||||||
lineWidth: 1
|
lineWidth: 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.background(viewModel.price == price ? Color.button.opacity(0.3) : Color.gray23)
|
.background(
|
||||||
|
viewModel.price == price ?
|
||||||
|
Color(hex:"9970ff").opacity(0.3):
|
||||||
|
Color(hex: "232323")
|
||||||
|
)
|
||||||
.cornerRadius(6.7)
|
.cornerRadius(6.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
|
|
|
@ -9,19 +9,13 @@ import UIKit
|
||||||
import Moya
|
import Moya
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
enum SelectedMenu: Int {
|
|
||||||
case MENU_1 = 0
|
|
||||||
case MENU_2 = 1
|
|
||||||
case MENU_3 = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
final class LiveRoomCreateViewModel: ObservableObject {
|
final class LiveRoomCreateViewModel: ObservableObject {
|
||||||
enum TimeSettingMode: String {
|
enum TimeSettingMode: String {
|
||||||
case NOW, RESERVATION
|
case NOW, RESERVATION
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LiveRoomType: String, Codable {
|
enum LiveRoomType: String, Codable {
|
||||||
case OPEN, PRIVATE
|
case OPEN, PRIVATE, SECRET
|
||||||
}
|
}
|
||||||
|
|
||||||
let prices = [0, 100, 300, 500, 1000, 2000]
|
let prices = [0, 100, 300, 500, 1000, 2000]
|
||||||
|
@ -46,12 +40,15 @@ final class LiveRoomCreateViewModel: ObservableObject {
|
||||||
|
|
||||||
@Published var roomType: LiveRoomType = .OPEN {
|
@Published var roomType: LiveRoomType = .OPEN {
|
||||||
didSet {
|
didSet {
|
||||||
|
if roomType == .SECRET {
|
||||||
|
timeSettingMode = .NOW
|
||||||
|
}
|
||||||
|
|
||||||
if roomType != .PRIVATE {
|
if roomType != .PRIVATE {
|
||||||
password = ""
|
password = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var password = "" {
|
@Published var password = "" {
|
||||||
didSet {
|
didSet {
|
||||||
if password.count > 6 {
|
if password.count > 6 {
|
||||||
|
@ -80,14 +77,6 @@ final class LiveRoomCreateViewModel: ObservableObject {
|
||||||
@Published var isShowPopup = false
|
@Published var isShowPopup = false
|
||||||
@Published var isShowGetRecentInfoButton = true
|
@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 let repository = LiveRepository()
|
||||||
private var subscription = Set<AnyCancellable>()
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@ -175,13 +164,10 @@ final class LiveRoomCreateViewModel: ObservableObject {
|
||||||
isAdult: isAdult,
|
isAdult: isAdult,
|
||||||
price: price,
|
price: price,
|
||||||
type: roomType,
|
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 {
|
if timeSettingMode == .RESERVATION && roomType != .SECRET {
|
||||||
request.beginDateTimeString = "\(reservationDate.convertDateFormat(dateFormat: "yyyy-MM-dd")) \(reservationTime.convertDateFormat(dateFormat: "HH:mm"))"
|
request.beginDateTimeString = "\(reservationDate.convertDateFormat(dateFormat: "yyyy-MM-dd")) \(reservationTime.convertDateFormat(dateFormat: "HH:mm"))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,73 +233,6 @@ 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 {
|
private func validate() -> Bool {
|
||||||
if coverImage == nil && coverImagePath == nil {
|
if coverImage == nil && coverImagePath == nil {
|
||||||
self.errorMessage = "커버이미지를 선택해주세요."
|
self.errorMessage = "커버이미지를 선택해주세요."
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct LiveRoomInfoEditDialog: View {
|
||||||
|
|
||||||
let placeholder = "라이브 공지를 입력하세요"
|
let placeholder = "라이브 공지를 입력하세요"
|
||||||
|
|
||||||
@StateObject var viewModel: LiveRoomViewModel
|
let viewModel: LiveRoomViewModel
|
||||||
|
|
||||||
let isLoading: Bool
|
let isLoading: Bool
|
||||||
let coverImageUrl: String?
|
let coverImageUrl: String?
|
||||||
|
@ -39,7 +39,7 @@ struct LiveRoomInfoEditDialog: View {
|
||||||
self._isShowing = isShowing
|
self._isShowing = isShowing
|
||||||
self._isShowPhotoPicker = isShowPhotoPicker
|
self._isShowPhotoPicker = isShowPhotoPicker
|
||||||
|
|
||||||
self._viewModel = StateObject(wrappedValue: viewModel)
|
self.viewModel = viewModel
|
||||||
self.isLoading = isLoading
|
self.isLoading = isLoading
|
||||||
|
|
||||||
self.title = currentTitle
|
self.title = currentTitle
|
||||||
|
@ -53,123 +53,112 @@ struct LiveRoomInfoEditDialog: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
GeometryReader { proxy in
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
HStack(spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Text("라이브 수정")
|
HStack(spacing: 0) {
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
Text("라이브 수정")
|
||||||
.foregroundColor(Color.grayee)
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Image("ic_close_white")
|
Image("ic_close_white")
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isShowing = false
|
isShowing = false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
HStack {
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
ZStack {
|
|
||||||
if let coverImage = coverImage {
|
|
||||||
Image(uiImage: coverImage)
|
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 80, height: 116.8, alignment: .top)
|
|
||||||
.clipped()
|
|
||||||
.cornerRadius(10)
|
|
||||||
} else if let coverImageUrl = coverImageUrl {
|
|
||||||
KFImage(URL(string: coverImageUrl))
|
|
||||||
.resizable()
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(width: 80, height: 116.8, alignment: .top)
|
|
||||||
.clipped()
|
|
||||||
.cornerRadius(10)
|
|
||||||
} else {
|
|
||||||
Image("ic_logo")
|
|
||||||
.resizable()
|
|
||||||
.scaledToFit()
|
|
||||||
.frame(width: 80, height: 116.8)
|
|
||||||
.background(Color.bg)
|
|
||||||
.cornerRadius(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
Image("ic_camera")
|
|
||||||
.padding(10)
|
|
||||||
.background(Color.button)
|
|
||||||
.cornerRadius(30)
|
|
||||||
.offset(x: 40, y: 40)
|
|
||||||
}
|
|
||||||
.frame(alignment: .bottomTrailing)
|
|
||||||
.padding(.top, 13.3)
|
|
||||||
.onTapGesture {
|
|
||||||
isShowPhotoPicker = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
HStack {
|
||||||
}
|
Spacer()
|
||||||
|
|
||||||
TitleInputView()
|
ZStack {
|
||||||
.padding(.top, 40)
|
if let coverImage = coverImage {
|
||||||
|
Image(uiImage: coverImage)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
.frame(width: 80, height: 116.8, alignment: .top)
|
||||||
|
.clipped()
|
||||||
|
.cornerRadius(10)
|
||||||
|
} else if let coverImageUrl = coverImageUrl {
|
||||||
|
KFImage(URL(string: coverImageUrl))
|
||||||
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
.frame(width: 80, height: 116.8, alignment: .top)
|
||||||
|
.clipped()
|
||||||
|
.cornerRadius(10)
|
||||||
|
} else {
|
||||||
|
Image("ic_logo")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 80, height: 116.8)
|
||||||
|
.background(Color(hex: "3e3358"))
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
|
||||||
ContentInputView()
|
Image("ic_camera")
|
||||||
.padding(.top, 33.3)
|
.padding(10)
|
||||||
|
.background(Color(hex: "9970ff"))
|
||||||
LiveRoomMenuSelectView(
|
.cornerRadius(30)
|
||||||
menu: $viewModel.menu,
|
.offset(x: 40, y: 40)
|
||||||
isActivate: $viewModel.isActivateMenu,
|
}
|
||||||
menuCount: viewModel.menuList.count,
|
.frame(alignment: .bottomTrailing)
|
||||||
selectedMenu: viewModel.selectedMenu,
|
.padding(.top, 13.3)
|
||||||
selectMenu: { viewModel.selectMenuPreset(selectedMenuPreset: $0) }
|
|
||||||
)
|
|
||||||
.padding(.top, 33.3)
|
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
|
||||||
Text("취소")
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
.padding(.vertical, 16)
|
|
||||||
.frame(width: (screenSize().width - 40) / 2)
|
|
||||||
.background(Color.button.opacity(0.2))
|
|
||||||
.cornerRadius(10)
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 10)
|
|
||||||
.strokeBorder(lineWidth: 1)
|
|
||||||
.foregroundColor(Color.button)
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
isShowing = false
|
isShowPhotoPicker = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Text("수정하기")
|
Spacer()
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
}
|
||||||
.foregroundColor(.white)
|
|
||||||
.padding(.vertical, 16)
|
TitleInputView()
|
||||||
.frame(width: (screenSize().width - 40) / 2)
|
.padding(.top, 40)
|
||||||
.background(Color.button)
|
|
||||||
.cornerRadius(10)
|
ContentInputView()
|
||||||
.onTapGesture {
|
.padding(.top, 33.3)
|
||||||
confirmAction(
|
|
||||||
title,
|
HStack(spacing: 13.3) {
|
||||||
notice.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? notice : ""
|
Text("취소")
|
||||||
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
|
.padding(.vertical, 16)
|
||||||
|
.frame(width: (screenSize().width - 40) / 2)
|
||||||
|
.background(Color(hex: "9970ff").opacity(0.2))
|
||||||
|
.cornerRadius(10)
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.strokeBorder(lineWidth: 1)
|
||||||
|
.foregroundColor(Color(hex: "9970ff"))
|
||||||
)
|
)
|
||||||
isShowing = false
|
.onTapGesture {
|
||||||
}
|
isShowing = false
|
||||||
}
|
}
|
||||||
.padding(.top, 45)
|
|
||||||
|
|
||||||
Spacer()
|
Text("수정하기")
|
||||||
}
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
.padding(13.3)
|
.foregroundColor(.white)
|
||||||
.onTapGesture { hideKeyboard() }
|
.padding(.vertical, 16)
|
||||||
.onAppear {
|
.frame(width: (screenSize().width - 40) / 2)
|
||||||
viewModel.getAllMenuPreset {
|
.background(Color(hex: "9970ff"))
|
||||||
self.isShowing = false
|
.cornerRadius(10)
|
||||||
|
.onTapGesture {
|
||||||
|
confirmAction(
|
||||||
|
title,
|
||||||
|
notice.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? notice : ""
|
||||||
|
)
|
||||||
|
isShowing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.top, 45)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
|
.padding(13.3)
|
||||||
|
.frame(width: proxy.size.width, height: proxy.size.height)
|
||||||
|
.onTapGesture { hideKeyboard() }
|
||||||
}
|
}
|
||||||
|
.background(Color(hex: "222222").edgesIgnoringSafeArea(.all))
|
||||||
}
|
}
|
||||||
.background(Color(hex: "222222").edgesIgnoringSafeArea(.all))
|
|
||||||
|
|
||||||
if viewModel.isShowPopup {
|
if viewModel.isShowPopup {
|
||||||
LiveRoomDialogView(
|
LiveRoomDialogView(
|
||||||
|
@ -204,15 +193,15 @@ struct LiveRoomInfoEditDialog: View {
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.accentColor(Color.button)
|
.accentColor(Color(hex: "3bb9f1"))
|
||||||
.keyboardType(.default)
|
.keyboardType(.default)
|
||||||
.padding(.top, 12)
|
.padding(.top, 12)
|
||||||
.padding(.horizontal, 6.7)
|
.padding(.horizontal, 6.7)
|
||||||
|
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.frame(height: 1)
|
.frame(height: 1)
|
||||||
.foregroundColor(Color.gray90.opacity(0.7))
|
.foregroundColor(Color(hex: "909090").opacity(0.7))
|
||||||
.padding(.top, 8.3)
|
.padding(.top, 8.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,16 +212,16 @@ struct LiveRoomInfoEditDialog: View {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Text("공지")
|
Text("공지")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16.7))
|
.font(.custom(Font.bold.rawValue, size: 16.7))
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("\(notice.count)자")
|
Text("\(notice.count)자")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.mainRed) +
|
.foregroundColor(Color(hex: "ff5c49")) +
|
||||||
Text(" / 1000자")
|
Text(" / 1000자")
|
||||||
.font(.custom(Font.medium.rawValue, size: 13.3))
|
.font(.custom(Font.medium.rawValue, size: 13.3))
|
||||||
.foregroundColor(Color.gray77)
|
.foregroundColor(Color(hex: "777777"))
|
||||||
}
|
}
|
||||||
|
|
||||||
TextViewWrapper(
|
TextViewWrapper(
|
||||||
|
|
|
@ -13,7 +13,4 @@ struct EditLiveRoomInfoRequest: Encodable {
|
||||||
let numberOfPeople: Int?
|
let numberOfPeople: Int?
|
||||||
let beginDateTimeString: String?
|
let beginDateTimeString: String?
|
||||||
let timezone: String?
|
let timezone: String?
|
||||||
var menuPanId: Int = 0
|
|
||||||
var menuPan: String = ""
|
|
||||||
var isActiveMenuPan: Bool? = nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ struct GetRoomInfoResponse: Decodable {
|
||||||
let listenerList: [LiveRoomMember]
|
let listenerList: [LiveRoomMember]
|
||||||
let managerList: [LiveRoomMember]
|
let managerList: [LiveRoomMember]
|
||||||
let donationRankingTop3UserIds: [Int]
|
let donationRankingTop3UserIds: [Int]
|
||||||
let menuPan: String
|
|
||||||
let isActiveRoulette: Bool
|
let isActiveRoulette: Bool
|
||||||
let isPrivateRoom: Bool
|
let isPrivateRoom: Bool
|
||||||
let password: String?
|
let password: String?
|
||||||
|
|
|
@ -67,21 +67,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
@Published var selectedProfile: LiveRoomMember?
|
@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
|
@Published var isShowDonationPopup = false
|
||||||
|
|
||||||
|
@ -157,38 +143,6 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
@Published var rouletteSelectedItem = ""
|
@Published var rouletteSelectedItem = ""
|
||||||
var rouletteCan = 0
|
var rouletteCan = 0
|
||||||
|
|
||||||
@Published var signatureImageUrl = "" {
|
|
||||||
didSet {
|
|
||||||
if signatureImageUrl.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 {
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 7) {
|
|
||||||
if let imageUrl = self.signatureImageUrls.first {
|
|
||||||
self.signatureImageUrl = imageUrl
|
|
||||||
self.signatureImageUrls.removeFirst()
|
|
||||||
} else {
|
|
||||||
self.signatureImageUrl = ""
|
|
||||||
self.isShowSignatureImage = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var menuId = 0
|
|
||||||
@Published var menu = ""
|
|
||||||
@Published var menuList = [GetMenuPresetResponse]()
|
|
||||||
|
|
||||||
@Published var isActivateMenu = false {
|
|
||||||
didSet {
|
|
||||||
if !isActivateMenu {
|
|
||||||
menu = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Published var selectedMenu: SelectedMenu? = nil
|
|
||||||
|
|
||||||
var signatureImageUrls = [String]()
|
|
||||||
var isShowSignatureImage = false
|
|
||||||
|
|
||||||
var timer: DispatchSourceTimer?
|
var timer: DispatchSourceTimer?
|
||||||
|
|
||||||
func setOriginOffset(_ offset: CGFloat) {
|
func setOriginOffset(_ offset: CGFloat) {
|
||||||
|
@ -399,7 +353,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let jsonDecoder = JSONDecoder()
|
let jsonDecoder = JSONDecoder()
|
||||||
let decoded = try jsonDecoder.decode(ApiResponse<String>.self, from: responseData)
|
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||||
|
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
|
|
||||||
|
@ -409,7 +363,6 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
type: .DONATION,
|
type: .DONATION,
|
||||||
message: rawMessage,
|
message: rawMessage,
|
||||||
can: can,
|
can: can,
|
||||||
signatureImageUrl: decoded.data,
|
|
||||||
donationMessage: message
|
donationMessage: message
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -431,7 +384,6 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
)
|
)
|
||||||
|
|
||||||
totalDonationCan += can
|
totalDonationCan += can
|
||||||
showSignatureImage(imageUrl: decoded.data ?? "")
|
|
||||||
|
|
||||||
self.messageChangeFlag.toggle()
|
self.messageChangeFlag.toggle()
|
||||||
if self.messages.count > 100 {
|
if self.messages.count > 100 {
|
||||||
|
@ -647,13 +599,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
notice: liveRoomInfo!.notice != notice ? notice : nil,
|
notice: liveRoomInfo!.notice != notice ? notice : nil,
|
||||||
numberOfPeople: nil,
|
numberOfPeople: nil,
|
||||||
beginDateTimeString: nil,
|
beginDateTimeString: nil,
|
||||||
timezone: nil,
|
timezone: nil
|
||||||
menuPanId: isActivateMenu ? menuId : 0,
|
|
||||||
menuPan: isActivateMenu ? menu : "",
|
|
||||||
isActiveMenuPan: isActivateMenu
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (request.title == nil && request.notice == nil && coverImage == nil && menu == liveRoomInfo?.menuPan) {
|
if (request.title == nil && request.notice == nil && coverImage == nil) {
|
||||||
self.errorMessage = "변경사항이 없습니다."
|
self.errorMessage = "변경사항이 없습니다."
|
||||||
self.isShowErrorPopup = true
|
self.isShowErrorPopup = true
|
||||||
return
|
return
|
||||||
|
@ -664,7 +613,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
encoder.outputFormatting = .withoutEscapingSlashes
|
encoder.outputFormatting = .withoutEscapingSlashes
|
||||||
|
|
||||||
if (request.title != nil || request.notice != nil || menu != liveRoomInfo?.menuPan) {
|
if (request.title != nil || request.notice != nil) {
|
||||||
let jsonData = try? encoder.encode(request)
|
let jsonData = try? encoder.encode(request)
|
||||||
if let jsonData = jsonData {
|
if let jsonData = jsonData {
|
||||||
multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request"))
|
multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request"))
|
||||||
|
@ -681,6 +630,8 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
repository.editLiveRoomInfo(roomId: AppState.shared.roomId, parameters: multipartData)
|
repository.editLiveRoomInfo(roomId: AppState.shared.roomId, parameters: multipartData)
|
||||||
.sink { result in
|
.sink { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -698,11 +649,6 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
|
|
||||||
if decoded.success {
|
if decoded.success {
|
||||||
self.coverImage = nil
|
self.coverImage = nil
|
||||||
self.menuList.removeAll()
|
|
||||||
self.isActivateMenu = false
|
|
||||||
self.selectedMenu = nil
|
|
||||||
self.menu = ""
|
|
||||||
self.isShowMenuPan = false
|
|
||||||
self.getRoomInfo()
|
self.getRoomInfo()
|
||||||
|
|
||||||
let editRoomInfoMessage = LiveRoomChatRawMessage(
|
let editRoomInfoMessage = LiveRoomChatRawMessage(
|
||||||
|
@ -713,102 +659,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
)
|
)
|
||||||
|
|
||||||
self.agora.sendRawMessageToGroup(rawMessage: editRoomInfoMessage)
|
self.agora.sendRawMessageToGroup(rawMessage: editRoomInfoMessage)
|
||||||
self.errorMessage = "라이브 정보가 수정되었습니다."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = decoded.message ?? "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요."
|
self.errorMessage = decoded.message ?? "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요."
|
||||||
self.isShowErrorPopup = true
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
self.errorMessage = "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &subscription)
|
|
||||||
}
|
|
||||||
|
|
||||||
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(onFailure: @escaping () -> Void) {
|
|
||||||
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.isActivateMenu = false
|
|
||||||
self.selectedMenu = nil
|
|
||||||
|
|
||||||
for (index, menuPreset) in self.menuList.enumerated() {
|
|
||||||
if menuPreset.isActive {
|
|
||||||
switch index {
|
|
||||||
case 1:
|
|
||||||
self.selectMenuPreset(selectedMenuPreset: .MENU_2)
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
self.selectMenuPreset(selectedMenuPreset: .MENU_3)
|
|
||||||
|
|
||||||
default:
|
|
||||||
self.selectMenuPreset(selectedMenuPreset: .MENU_1)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.isActivateMenu = true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onFailure()
|
|
||||||
if let message = decoded.message {
|
|
||||||
self.errorMessage = message
|
|
||||||
} else {
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
}
|
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
onFailure()
|
self.errorMessage = "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요."
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1485,8 +1341,8 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setActiveRoulette(isActiveRoulette: Bool, message: String) {
|
func setActiveRoulette(isActiveRoulette: Bool) {
|
||||||
self.popupContent = message
|
self.popupContent = isActiveRoulette ? "룰렛을 활성화 했습니다." : "룰렛을 비활성화 했습니다."
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
self.agora.sendRawMessageToGroup(
|
self.agora.sendRawMessageToGroup(
|
||||||
rawMessage: LiveRoomChatRawMessage(
|
rawMessage: LiveRoomChatRawMessage(
|
||||||
|
@ -1688,17 +1544,6 @@ final class LiveRoomViewModel: NSObject, ObservableObject {
|
||||||
}
|
}
|
||||||
.store(in: &subscription)
|
.store(in: &subscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func showSignatureImage(imageUrl: String) {
|
|
||||||
if imageUrl.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 {
|
|
||||||
if !isShowSignatureImage {
|
|
||||||
isShowSignatureImage = true
|
|
||||||
signatureImageUrl = imageUrl
|
|
||||||
} else {
|
|
||||||
signatureImageUrls.append(imageUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LiveRoomViewModel: AgoraRtcEngineDelegate {
|
extension LiveRoomViewModel: AgoraRtcEngineDelegate {
|
||||||
|
@ -1863,7 +1708,6 @@ extension LiveRoomViewModel: AgoraRtmChannelDelegate {
|
||||||
)
|
)
|
||||||
|
|
||||||
self.totalDonationCan += decoded.can
|
self.totalDonationCan += decoded.can
|
||||||
self.showSignatureImage(imageUrl: decoded.signatureImageUrl ?? "")
|
|
||||||
} else if decoded.type == .ROULETTE_DONATION {
|
} else if decoded.type == .ROULETTE_DONATION {
|
||||||
self.messages.append(
|
self.messages.append(
|
||||||
LiveRoomRouletteDonationChat(
|
LiveRoomRouletteDonationChat(
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
//
|
|
||||||
// GetMenuPresetResponse.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 3/8/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
struct GetMenuPresetResponse: Decodable {
|
|
||||||
let id: Int
|
|
||||||
let menu: String
|
|
||||||
let isActive: Bool
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
//
|
|
||||||
// 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()
|
|
||||||
selectMenu(.MENU_1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.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: "303030"
|
|
||||||
)
|
|
||||||
.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 }
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -7,14 +7,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct CreateRouletteRequest: Encodable {
|
struct CreateOrUpdateRouletteRequest: Encodable {
|
||||||
let can: Int
|
|
||||||
let isActive: Bool
|
|
||||||
let items: [RouletteItem]
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UpdateRouletteRequest: Encodable {
|
|
||||||
let id: Int
|
|
||||||
let can: Int
|
let can: Int
|
||||||
let isActive: Bool
|
let isActive: Bool
|
||||||
let items: [RouletteItem]
|
let items: [RouletteItem]
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
//
|
|
||||||
// GetNewRouletteResponse.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2/23/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
struct GetNewRouletteResponse: Decodable {
|
|
||||||
let id: Int
|
|
||||||
let can: Int
|
|
||||||
let isActive: Bool
|
|
||||||
let items: [RouletteItem]
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ struct RouletteSettingsView: View {
|
||||||
@StateObject var viewModel = RouletteSettingsViewModel()
|
@StateObject var viewModel = RouletteSettingsViewModel()
|
||||||
|
|
||||||
@Binding var isShowing: Bool
|
@Binding var isShowing: Bool
|
||||||
let onComplete: (Bool, String) -> Void
|
let onComplete: (Bool) -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { proxy in
|
GeometryReader { proxy in
|
||||||
|
@ -25,36 +25,6 @@ struct RouletteSettingsView: View {
|
||||||
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
HStack(spacing: 13.3) {
|
|
||||||
SelectedButtonView(
|
|
||||||
title: "룰렛 1",
|
|
||||||
isActive: true,
|
|
||||||
isSelected: viewModel.selectedRoulette == .ROULETTE_1
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.selectRoulette(selectedRoulette: .ROULETTE_1)
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectedButtonView(
|
|
||||||
title: "룰렛 2",
|
|
||||||
isActive: viewModel.rouletteList.count > 0,
|
|
||||||
isSelected: viewModel.selectedRoulette == .ROULETTE_2
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.selectRoulette(selectedRoulette: .ROULETTE_2)
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectedButtonView(
|
|
||||||
title: "룰렛 3",
|
|
||||||
isActive: viewModel.rouletteList.count > 1,
|
|
||||||
isSelected: viewModel.selectedRoulette == .ROULETTE_3
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
|
||||||
viewModel.selectRoulette(selectedRoulette: .ROULETTE_3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(.top, 26.7)
|
|
||||||
|
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
Text("룰렛을 활성화 하시겠습니까?")
|
Text("룰렛을 활성화 하시겠습니까?")
|
||||||
.font(.custom(Font.bold.rawValue, size: 16))
|
.font(.custom(Font.bold.rawValue, size: 16))
|
||||||
|
@ -69,7 +39,6 @@ struct RouletteSettingsView: View {
|
||||||
viewModel.isActive.toggle()
|
viewModel.isActive.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 26.7)
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 13.3) {
|
VStack(alignment: .leading, spacing: 13.3) {
|
||||||
Text("룰렛 금액 설정")
|
Text("룰렛 금액 설정")
|
||||||
|
@ -166,7 +135,7 @@ struct RouletteSettingsView: View {
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
viewModel.createOrUpdateRoulette {
|
viewModel.createOrUpdateRoulette {
|
||||||
onComplete($0, $1)
|
onComplete($0)
|
||||||
isShowing = false
|
isShowing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +181,7 @@ struct RouletteSettingsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.getAllRoulette(creatorId: UserDefaults.int(forKey: .userId))
|
viewModel.getRoulette(creatorId: UserDefaults.int(forKey: .userId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +189,6 @@ struct RouletteSettingsView: View {
|
||||||
|
|
||||||
struct RouletteSettingsView_Previews: PreviewProvider {
|
struct RouletteSettingsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
RouletteSettingsView(isShowing: .constant(true)) { _, _ in }
|
RouletteSettingsView(isShowing: .constant(true)) { _ in }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
enum SelectedRoulette: Int {
|
|
||||||
case ROULETTE_1 = 0
|
|
||||||
case ROULETTE_2 = 1
|
|
||||||
case ROULETTE_3 = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
final class RouletteSettingsViewModel: ObservableObject {
|
final class RouletteSettingsViewModel: ObservableObject {
|
||||||
private let repository = RouletteRepository()
|
private let repository = RouletteRepository()
|
||||||
private var subscription = Set<AnyCancellable>()
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
@ -40,11 +34,7 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
@Published var previewData: RoulettePreview? = nil
|
@Published var previewData: RoulettePreview? = nil
|
||||||
|
|
||||||
@Published var selectedRoulette: SelectedRoulette? = nil
|
|
||||||
|
|
||||||
var can = 0
|
var can = 0
|
||||||
private var rouletteId = 0
|
|
||||||
@Published var rouletteList = [GetNewRouletteResponse]()
|
|
||||||
|
|
||||||
func plusWeight(index: Int) {
|
func plusWeight(index: Int) {
|
||||||
options[index].weight += 1
|
options[index].weight += 1
|
||||||
|
@ -94,9 +84,9 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
self.options.append(contentsOf: options)
|
self.options.append(contentsOf: options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllRoulette(creatorId: Int) {
|
func getRoulette(creatorId: Int) {
|
||||||
self.isLoading = true
|
self.isLoading = true
|
||||||
repository.getAllRoulette(creatorId: creatorId)
|
repository.getRoulette(creatorId: creatorId)
|
||||||
.sink { result in
|
.sink { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .finished:
|
case .finished:
|
||||||
|
@ -110,15 +100,32 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let jsonDecoder = JSONDecoder()
|
let jsonDecoder = JSONDecoder()
|
||||||
let decoded = try jsonDecoder.decode(ApiResponse<[GetNewRouletteResponse]>.self, from: responseData)
|
let decoded = try jsonDecoder.decode(ApiResponse<GetRouletteResponse>.self, from: responseData)
|
||||||
|
|
||||||
if let data = decoded.data, decoded.success {
|
if let data = decoded.data, decoded.success {
|
||||||
rouletteList.removeAll()
|
self.isActive = data.isActive
|
||||||
rouletteList.append(contentsOf: data)
|
|
||||||
selectRoulette(selectedRoulette: .ROULETTE_1)
|
if data.can > 0 {
|
||||||
|
self.canText = String(data.can)
|
||||||
|
} else {
|
||||||
|
self.canText = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.isActive = false
|
||||||
self.isShowErrorPopup = true
|
self.canText = ""
|
||||||
|
self.addOption()
|
||||||
|
self.addOption()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
@ -148,208 +155,51 @@ final class RouletteSettingsViewModel: ObservableObject {
|
||||||
isShowPreview = true
|
isShowPreview = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOrUpdateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
func createOrUpdateRoulette(onSuccess: @escaping (Bool) -> Void) {
|
||||||
if !isLoading {
|
if !isLoading {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
if rouletteId > 0 {
|
var items = [RouletteItem]()
|
||||||
updateRoulette(onSuccess: onSuccess)
|
for option in options {
|
||||||
} else {
|
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
createRoulette(onSuccess: onSuccess)
|
isLoading = false
|
||||||
}
|
errorMessage = "옵션은 빈칸일 수 없습니다."
|
||||||
}
|
isShowErrorPopup = true
|
||||||
}
|
return
|
||||||
|
|
||||||
private func createRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
|
||||||
var items = [RouletteItem]()
|
|
||||||
for option in options {
|
|
||||||
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
||||||
isLoading = false
|
|
||||||
errorMessage = "옵션은 빈칸일 수 없습니다."
|
|
||||||
isShowErrorPopup = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
items.append(RouletteItem(title: option.title, weight: option.weight))
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedRouletteTitle: String
|
|
||||||
let successMessage: String
|
|
||||||
|
|
||||||
switch (self.selectedRoulette) {
|
|
||||||
case .ROULETTE_2:
|
|
||||||
selectedRouletteTitle = "룰렛 2"
|
|
||||||
|
|
||||||
case .ROULETTE_3:
|
|
||||||
selectedRouletteTitle = "룰렛 3"
|
|
||||||
|
|
||||||
default:
|
|
||||||
selectedRouletteTitle = "룰렛 1"
|
|
||||||
}
|
|
||||||
|
|
||||||
if isActive {
|
|
||||||
successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
|
|
||||||
} else {
|
|
||||||
successMessage = "\(selectedRouletteTitle)을 설정했습니다."
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = CreateRouletteRequest(can: can, isActive: isActive, items: items)
|
|
||||||
repository.createRoulette(request: request)
|
|
||||||
.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 {
|
items.append(RouletteItem(title: option.title, weight: option.weight))
|
||||||
let jsonDecoder = JSONDecoder()
|
}
|
||||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
|
||||||
|
|
||||||
if decoded.success {
|
let request = CreateOrUpdateRouletteRequest(can: can, isActive: isActive, items: items)
|
||||||
onSuccess(isActive, successMessage)
|
repository.createOrUpdateRoulette(request: request)
|
||||||
} else {
|
.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(ApiResponseWithoutData.self, from: responseData)
|
||||||
|
|
||||||
|
if decoded.success {
|
||||||
|
onSuccess(isActive)
|
||||||
|
} else {
|
||||||
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
self.isShowErrorPopup = true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
self.isShowErrorPopup = true
|
self.isShowErrorPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
}
|
}
|
||||||
}
|
.store(in: &subscription)
|
||||||
.store(in: &subscription)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateRoulette(onSuccess: @escaping (Bool, String) -> Void) {
|
|
||||||
var items = [RouletteItem]()
|
|
||||||
for option in options {
|
|
||||||
if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
||||||
isLoading = false
|
|
||||||
errorMessage = "옵션은 빈칸일 수 없습니다."
|
|
||||||
isShowErrorPopup = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
items.append(RouletteItem(title: option.title, weight: option.weight))
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedRoulette = rouletteList[selectedRoulette!.rawValue]
|
|
||||||
if selectedRoulette.isActive == isActive && selectedRoulette.can == can && selectedRoulette.items == items {
|
|
||||||
self.errorMessage = "변동사항이 없습니다."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
self.isLoading = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedRouletteTitle: String
|
|
||||||
let successMessage: String
|
|
||||||
|
|
||||||
switch (self.selectedRoulette) {
|
|
||||||
case .ROULETTE_2:
|
|
||||||
selectedRouletteTitle = "룰렛 2"
|
|
||||||
|
|
||||||
case .ROULETTE_3:
|
|
||||||
selectedRouletteTitle = "룰렛 3"
|
|
||||||
|
|
||||||
default:
|
|
||||||
selectedRouletteTitle = "룰렛 1"
|
|
||||||
}
|
|
||||||
|
|
||||||
var isAllActive = false
|
|
||||||
|
|
||||||
rouletteList
|
|
||||||
.filter {
|
|
||||||
$0.id != selectedRoulette.id
|
|
||||||
}
|
|
||||||
.forEach {
|
|
||||||
if $0.isActive {
|
|
||||||
isAllActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isActive {
|
|
||||||
successMessage = "\(selectedRouletteTitle)로 설정하였습니다."
|
|
||||||
} else if !isAllActive {
|
|
||||||
successMessage = "\(selectedRouletteTitle)이 비활성화 되었습니다."
|
|
||||||
} else {
|
|
||||||
successMessage = "\(selectedRouletteTitle)을 설정했습니다."
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items)
|
|
||||||
repository.updateRoulette(request: request)
|
|
||||||
.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(ApiResponseWithoutData.self, from: responseData)
|
|
||||||
|
|
||||||
if decoded.success {
|
|
||||||
onSuccess(isActive, successMessage)
|
|
||||||
} else {
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
|
||||||
self.isShowErrorPopup = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.store(in: &subscription)
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectRoulette(selectedRoulette: SelectedRoulette) {
|
|
||||||
if rouletteList.isEmpty && (selectedRoulette == .ROULETTE_2 || selectedRoulette == .ROULETTE_3) {
|
|
||||||
errorMessage = "룰렛 1을 먼저 설정하세요"
|
|
||||||
isShowErrorPopup = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if rouletteList.count == 1 && selectedRoulette == .ROULETTE_3 {
|
|
||||||
errorMessage = "룰렛 1과 룰렛 2를 먼저 설정하세요"
|
|
||||||
isShowErrorPopup = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.selectedRoulette != selectedRoulette {
|
|
||||||
self.selectedRoulette = selectedRoulette
|
|
||||||
|
|
||||||
if rouletteList.count > selectedRoulette.rawValue {
|
|
||||||
let roulette = rouletteList[selectedRoulette.rawValue]
|
|
||||||
if roulette.can > 0 {
|
|
||||||
self.canText = String(roulette.can)
|
|
||||||
} else {
|
|
||||||
self.canText = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
self.rouletteId = roulette.id
|
|
||||||
self.isActive = roulette.isActive
|
|
||||||
let options = roulette.items.map {
|
|
||||||
RouletteOption(title: $0.title, weight: $0.weight)
|
|
||||||
}
|
|
||||||
removeAllAndAddOptions(options: options)
|
|
||||||
recalculatePercentages()
|
|
||||||
} else {
|
|
||||||
self.canText = ""
|
|
||||||
self.isActive = false
|
|
||||||
self.rouletteId = 0
|
|
||||||
|
|
||||||
options.removeAll()
|
|
||||||
self.addOption()
|
|
||||||
self.addOption()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct GetRouletteResponse: Decodable {
|
||||||
let items: [RouletteItem]
|
let items: [RouletteItem]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RouletteItem: Codable, Equatable {
|
struct RouletteItem: Codable {
|
||||||
let title: String
|
let title: String
|
||||||
let weight: Int
|
let weight: Int
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,7 @@ import Moya
|
||||||
|
|
||||||
enum RouletteApi {
|
enum RouletteApi {
|
||||||
case getRoulette(creatorId: Int)
|
case getRoulette(creatorId: Int)
|
||||||
case getAllRoulette(creatorId: Int)
|
case createOrUpdateRoulette(request: CreateOrUpdateRouletteRequest)
|
||||||
case createRoulette(request: CreateRouletteRequest)
|
|
||||||
case updateRoulette(request: UpdateRouletteRequest)
|
|
||||||
case spinRoulette(request: SpinRouletteRequest)
|
case spinRoulette(request: SpinRouletteRequest)
|
||||||
case refundRouletteDonation(roomId: Int)
|
case refundRouletteDonation(roomId: Int)
|
||||||
}
|
}
|
||||||
|
@ -24,30 +22,24 @@ extension RouletteApi: TargetType {
|
||||||
|
|
||||||
var path: String {
|
var path: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .getRoulette, .createRoulette, .updateRoulette:
|
case .getRoulette, .createOrUpdateRoulette:
|
||||||
return "/new-roulette"
|
return "/roulette"
|
||||||
|
|
||||||
case .getAllRoulette:
|
|
||||||
return "/new-roulette/creator"
|
|
||||||
|
|
||||||
case .spinRoulette:
|
case .spinRoulette:
|
||||||
return "/new-roulette/spin"
|
return "/roulette/spin"
|
||||||
|
|
||||||
case .refundRouletteDonation(let roomId):
|
case .refundRouletteDonation(let roomId):
|
||||||
return "/new-roulette/refund/\(roomId)"
|
return "/roulette/refund/\(roomId)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method: Moya.Method {
|
var method: Moya.Method {
|
||||||
switch self {
|
switch self {
|
||||||
case .getRoulette, .getAllRoulette:
|
case .getRoulette:
|
||||||
return .get
|
return .get
|
||||||
|
|
||||||
case .createRoulette, .spinRoulette, .refundRouletteDonation:
|
case .createOrUpdateRoulette, .spinRoulette, .refundRouletteDonation:
|
||||||
return .post
|
return .post
|
||||||
|
|
||||||
case .updateRoulette:
|
|
||||||
return .put
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +55,7 @@ extension RouletteApi: TargetType {
|
||||||
encoding: URLEncoding.queryString
|
encoding: URLEncoding.queryString
|
||||||
)
|
)
|
||||||
|
|
||||||
case .getAllRoulette(let creatorId):
|
case .createOrUpdateRoulette(let request):
|
||||||
let parameters = [
|
|
||||||
"creatorId": creatorId
|
|
||||||
] as [String : Any]
|
|
||||||
|
|
||||||
return .requestParameters(
|
|
||||||
parameters: parameters,
|
|
||||||
encoding: URLEncoding.queryString
|
|
||||||
)
|
|
||||||
|
|
||||||
case .createRoulette(let request):
|
|
||||||
return .requestJSONEncodable(request)
|
|
||||||
|
|
||||||
case .updateRoulette(let request):
|
|
||||||
return .requestJSONEncodable(request)
|
return .requestJSONEncodable(request)
|
||||||
|
|
||||||
case .spinRoulette(let request):
|
case .spinRoulette(let request):
|
||||||
|
|
|
@ -17,16 +17,8 @@ final class RouletteRepository {
|
||||||
return api.requestPublisher(.getRoulette(creatorId: creatorId))
|
return api.requestPublisher(.getRoulette(creatorId: creatorId))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllRoulette(creatorId: Int) -> AnyPublisher<Response, MoyaError> {
|
func createOrUpdateRoulette(request: CreateOrUpdateRouletteRequest) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.getAllRoulette(creatorId: creatorId))
|
return api.requestPublisher(.createOrUpdateRoulette(request: request))
|
||||||
}
|
|
||||||
|
|
||||||
func createRoulette(request: CreateRouletteRequest) -> AnyPublisher<Response, MoyaError> {
|
|
||||||
return api.requestPublisher(.createRoulette(request: request))
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRoulette(request: UpdateRouletteRequest) -> AnyPublisher<Response, MoyaError> {
|
|
||||||
return api.requestPublisher(.updateRoulette(request: request))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func spinRoulette(request: SpinRouletteRequest) -> AnyPublisher<Response, MoyaError> {
|
func spinRoulette(request: SpinRouletteRequest) -> AnyPublisher<Response, MoyaError> {
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct LiveRoomOverlayStrokeTextButton: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(text)
|
Text(text)
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.foregroundColor(textColor)
|
.foregroundColor(Color.red)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, 8)
|
||||||
.padding(.vertical, 6)
|
.padding(.vertical, 6)
|
||||||
.overlay(
|
.overlay(
|
||||||
|
|
|
@ -63,17 +63,18 @@ struct LiveRoomInfoCreatorView: View {
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(spacing: 5.3) {
|
Text(creatorNickname)
|
||||||
Text(creatorNickname)
|
.font(.custom(Font.medium.rawValue, size: 12))
|
||||||
.font(.custom(Font.medium.rawValue, size: 12))
|
.foregroundColor(.gray77)
|
||||||
.foregroundColor(.gray77)
|
|
||||||
|
|
||||||
if isShowFollowingButton {
|
|
||||||
Image(isFollowing ? "btn_following" : "btn_follow")
|
|
||||||
.onTapGesture { onClickFollow() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isShowFollowingButton {
|
||||||
|
Image(isFollowing ? "btn_select_checked" : "btn_plus_round")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.onTapGesture { onClickFollow() }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.padding(.horizontal, 5.3)
|
.padding(.horizontal, 5.3)
|
||||||
|
|
|
@ -14,8 +14,6 @@ struct LiveRoomInfoGuestView: View {
|
||||||
|
|
||||||
let isOnBg: Bool
|
let isOnBg: Bool
|
||||||
let isOnNotice: Bool
|
let isOnNotice: Bool
|
||||||
let isOnMenuPan: Bool
|
|
||||||
let isShowMenuPanButton: Bool
|
|
||||||
|
|
||||||
let creatorId: Int
|
let creatorId: Int
|
||||||
let creatorNickname: String
|
let creatorNickname: String
|
||||||
|
@ -33,9 +31,7 @@ struct LiveRoomInfoGuestView: View {
|
||||||
let onClickFollow: (Bool) -> Void
|
let onClickFollow: (Bool) -> Void
|
||||||
let onClickProfile: (Int) -> Void
|
let onClickProfile: (Int) -> Void
|
||||||
let onClickNotice: () -> Void
|
let onClickNotice: () -> Void
|
||||||
let onClickMenuPan: () -> Void
|
|
||||||
let onClickTotalDonation: () -> Void
|
let onClickTotalDonation: () -> Void
|
||||||
let onClickChangeListener: () -> Void
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
@ -51,16 +47,6 @@ struct LiveRoomInfoGuestView: View {
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
if speakerList.contains(where: { $0.id == UserDefaults.int(forKey: .userId)}) {
|
|
||||||
LiveRoomOverlayStrokeTextButton(
|
|
||||||
text: "리스너 변경",
|
|
||||||
textColor: Color.grayee,
|
|
||||||
strokeColor: Color.graybb,
|
|
||||||
strokeWidth: 1,
|
|
||||||
strokeCornerRadius: 5.3
|
|
||||||
) { onClickChangeListener() }
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveRoomOverlayStrokeTextToggleButton(
|
LiveRoomOverlayStrokeTextToggleButton(
|
||||||
isOn: isOnBg,
|
isOn: isOnBg,
|
||||||
onText: "배경 ON",
|
onText: "배경 ON",
|
||||||
|
@ -127,21 +113,6 @@ struct LiveRoomInfoGuestView: View {
|
||||||
onClick: { onClickNotice() }
|
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()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 2.7) {
|
HStack(spacing: 2.7) {
|
||||||
|
@ -180,8 +151,6 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider {
|
||||||
totalDonationCan: 123456,
|
totalDonationCan: 123456,
|
||||||
isOnBg: true,
|
isOnBg: true,
|
||||||
isOnNotice: false,
|
isOnNotice: false,
|
||||||
isOnMenuPan: false,
|
|
||||||
isShowMenuPanButton: false,
|
|
||||||
creatorId: 1,
|
creatorId: 1,
|
||||||
creatorNickname: "도화",
|
creatorNickname: "도화",
|
||||||
creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320",
|
creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320",
|
||||||
|
@ -215,9 +184,7 @@ struct LiveRoomInfoGuestView_Previews: PreviewProvider {
|
||||||
onClickFollow: { _ in },
|
onClickFollow: { _ in },
|
||||||
onClickProfile: { _ in },
|
onClickProfile: { _ in },
|
||||||
onClickNotice: {},
|
onClickNotice: {},
|
||||||
onClickMenuPan: {},
|
onClickTotalDonation: {}
|
||||||
onClickTotalDonation: {},
|
|
||||||
onClickChangeListener: {}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@ struct LiveRoomInfoHostView: View {
|
||||||
|
|
||||||
let isOnBg: Bool
|
let isOnBg: Bool
|
||||||
let isOnNotice: Bool
|
let isOnNotice: Bool
|
||||||
let isOnMenuPan: Bool
|
|
||||||
let isShowMenuPanButton: Bool
|
|
||||||
|
|
||||||
let creatorId: Int
|
let creatorId: Int
|
||||||
let creatorNickname: String
|
let creatorNickname: String
|
||||||
|
@ -34,7 +32,6 @@ struct LiveRoomInfoHostView: View {
|
||||||
let onClickEdit: () -> Void
|
let onClickEdit: () -> Void
|
||||||
let onClickProfile: (Int) -> Void
|
let onClickProfile: (Int) -> Void
|
||||||
let onClickNotice: () -> Void
|
let onClickNotice: () -> Void
|
||||||
let onClickMenuPan: () -> Void
|
|
||||||
let onClickTotalDonation: () -> Void
|
let onClickTotalDonation: () -> Void
|
||||||
let onClickParticipants: () -> Void
|
let onClickParticipants: () -> Void
|
||||||
|
|
||||||
|
@ -125,21 +122,6 @@ struct LiveRoomInfoHostView: View {
|
||||||
onClick: { onClickNotice() }
|
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()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 2.7) {
|
HStack(spacing: 2.7) {
|
||||||
|
@ -196,8 +178,6 @@ struct LiveRoomInfoHostView_Previews: PreviewProvider {
|
||||||
participantsCount: 18,
|
participantsCount: 18,
|
||||||
isOnBg: true,
|
isOnBg: true,
|
||||||
isOnNotice: true,
|
isOnNotice: true,
|
||||||
isOnMenuPan: false,
|
|
||||||
isShowMenuPanButton: false,
|
|
||||||
creatorId: 1,
|
creatorId: 1,
|
||||||
creatorNickname: "도화",
|
creatorNickname: "도화",
|
||||||
creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320",
|
creatorProfileUrl: "https://cf.sodalive.net/profile/26/26-profile-ddf78b4d-0300-4c50-9c84-5d8a95fd5fe2-4892-1705256364320",
|
||||||
|
@ -230,7 +210,6 @@ struct LiveRoomInfoHostView_Previews: PreviewProvider {
|
||||||
onClickEdit: {},
|
onClickEdit: {},
|
||||||
onClickProfile: { _ in },
|
onClickProfile: { _ in },
|
||||||
onClickNotice: {},
|
onClickNotice: {},
|
||||||
onClickMenuPan: {},
|
|
||||||
onClickTotalDonation: {},
|
onClickTotalDonation: {},
|
||||||
onClickParticipants: {}
|
onClickParticipants: {}
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
import SDWebImageSwiftUI
|
|
||||||
|
|
||||||
struct LiveRoomViewV2: View {
|
struct LiveRoomViewV2: View {
|
||||||
|
|
||||||
|
@ -29,8 +28,6 @@ struct LiveRoomViewV2: View {
|
||||||
participantsCount: liveRoomInfo.participantsCount,
|
participantsCount: liveRoomInfo.participantsCount,
|
||||||
isOnBg: viewModel.isBgOn,
|
isOnBg: viewModel.isBgOn,
|
||||||
isOnNotice: viewModel.isShowNotice,
|
isOnNotice: viewModel.isShowNotice,
|
||||||
isOnMenuPan: viewModel.isShowMenuPan,
|
|
||||||
isShowMenuPanButton: !liveRoomInfo.menuPan.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
|
|
||||||
creatorId: liveRoomInfo.creatorId,
|
creatorId: liveRoomInfo.creatorId,
|
||||||
creatorNickname: liveRoomInfo.creatorNickname,
|
creatorNickname: liveRoomInfo.creatorNickname,
|
||||||
creatorProfileUrl: liveRoomInfo.creatorProfileUrl,
|
creatorProfileUrl: liveRoomInfo.creatorProfileUrl,
|
||||||
|
@ -58,9 +55,6 @@ struct LiveRoomViewV2: View {
|
||||||
onClickNotice: {
|
onClickNotice: {
|
||||||
viewModel.isShowNotice.toggle()
|
viewModel.isShowNotice.toggle()
|
||||||
},
|
},
|
||||||
onClickMenuPan: {
|
|
||||||
viewModel.isShowMenuPan.toggle()
|
|
||||||
},
|
|
||||||
onClickTotalDonation: {
|
onClickTotalDonation: {
|
||||||
viewModel.isShowDonationRankingPopup = true
|
viewModel.isShowDonationRankingPopup = true
|
||||||
},
|
},
|
||||||
|
@ -74,8 +68,6 @@ struct LiveRoomViewV2: View {
|
||||||
totalDonationCan: viewModel.totalDonationCan,
|
totalDonationCan: viewModel.totalDonationCan,
|
||||||
isOnBg: viewModel.isBgOn,
|
isOnBg: viewModel.isBgOn,
|
||||||
isOnNotice: viewModel.isShowNotice,
|
isOnNotice: viewModel.isShowNotice,
|
||||||
isOnMenuPan: viewModel.isShowMenuPan,
|
|
||||||
isShowMenuPanButton: !liveRoomInfo.menuPan.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
|
|
||||||
creatorId: liveRoomInfo.creatorId,
|
creatorId: liveRoomInfo.creatorId,
|
||||||
creatorNickname: liveRoomInfo.creatorNickname,
|
creatorNickname: liveRoomInfo.creatorNickname,
|
||||||
creatorProfileUrl: liveRoomInfo.creatorProfileUrl,
|
creatorProfileUrl: liveRoomInfo.creatorProfileUrl,
|
||||||
|
@ -108,14 +100,8 @@ struct LiveRoomViewV2: View {
|
||||||
onClickNotice: {
|
onClickNotice: {
|
||||||
viewModel.isShowNotice.toggle()
|
viewModel.isShowNotice.toggle()
|
||||||
},
|
},
|
||||||
onClickMenuPan: {
|
|
||||||
viewModel.isShowMenuPan.toggle()
|
|
||||||
},
|
|
||||||
onClickTotalDonation: {
|
onClickTotalDonation: {
|
||||||
viewModel.isShowDonationRankingPopup = true
|
viewModel.isShowDonationRankingPopup = true
|
||||||
},
|
|
||||||
onClickChangeListener: {
|
|
||||||
viewModel.setListener()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -255,20 +241,6 @@ struct LiveRoomViewV2: View {
|
||||||
proxy.scrollTo(viewModel.messages.count - 1, anchor: .center)
|
proxy.scrollTo(viewModel.messages.count - 1, anchor: .center)
|
||||||
}.padding(.bottom, 70)
|
}.padding(.bottom, 70)
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.signatureImageUrl.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 {
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
AnimatedImage(url: URL(string: viewModel.signatureImageUrl))
|
|
||||||
.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(height: 300)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.padding(.horizontal, 20)
|
|
||||||
.padding(.bottom, 65)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,28 +278,6 @@ struct LiveRoomViewV2: View {
|
||||||
.padding(.bottom, 120)
|
.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,9 +297,7 @@ struct LiveRoomViewV2: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
if viewModel.liveRoomInfo == nil {
|
viewModel.quitRoom()
|
||||||
viewModel.quitRoom()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,11 +548,8 @@ struct LiveRoomViewV2: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.isShowRouletteSettings {
|
if viewModel.isShowRouletteSettings {
|
||||||
RouletteSettingsView(isShowing: $viewModel.isShowRouletteSettings) { isActiveRoulette, message in
|
RouletteSettingsView(isShowing: $viewModel.isShowRouletteSettings) { isActiveRoulette in
|
||||||
self.viewModel.setActiveRoulette(
|
self.viewModel.setActiveRoulette(isActiveRoulette: isActiveRoulette)
|
||||||
isActiveRoulette: isActiveRoulette,
|
|
||||||
message: message
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,6 @@ struct HomeView: View {
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
pushTokenUpdate()
|
pushTokenUpdate()
|
||||||
viewModel.fetchAndUpdateIdfa()
|
|
||||||
viewModel.getMemberInfo()
|
viewModel.getMemberInfo()
|
||||||
viewModel.getEventPopup()
|
viewModel.getEventPopup()
|
||||||
viewModel.addAllPlaybackTracking()
|
viewModel.addAllPlaybackTracking()
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
import AppTrackingTransparency
|
|
||||||
import AdSupport
|
|
||||||
|
|
||||||
final class HomeViewModel: ObservableObject {
|
final class HomeViewModel: ObservableObject {
|
||||||
|
|
||||||
private var subscription = Set<AnyCancellable>()
|
private var subscription = Set<AnyCancellable>()
|
||||||
|
@ -40,25 +37,6 @@ final class HomeViewModel: ObservableObject {
|
||||||
.store(in: &subscription)
|
.store(in: &subscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAndUpdateIdfa() {
|
|
||||||
ATTrackingManager.requestTrackingAuthorization { [unowned self] status in
|
|
||||||
if status == .authorized {
|
|
||||||
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
|
||||||
self.userRepository.updateIdfa(request: IdfaUpdateRequest(adid: idfa))
|
|
||||||
.sink { result in
|
|
||||||
switch result {
|
|
||||||
case .finished:
|
|
||||||
DEBUG_LOG("finish")
|
|
||||||
case .failure(let error):
|
|
||||||
ERROR_LOG(error.localizedDescription)
|
|
||||||
}
|
|
||||||
} receiveValue: { _ in
|
|
||||||
}
|
|
||||||
.store(in: &self.subscription)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMemberInfo() {
|
func getMemberInfo() {
|
||||||
userRepository.getMemberInfo()
|
userRepository.getMemberInfo()
|
||||||
.sink { result in
|
.sink { result in
|
||||||
|
|
|
@ -40,6 +40,16 @@ struct OnboardingView: View {
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.tag(4)
|
.tag(4)
|
||||||
|
|
||||||
|
Image("img_guide_5")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.tag(5)
|
||||||
|
|
||||||
|
Image("img_guide_6")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.tag(6)
|
||||||
}
|
}
|
||||||
.tabViewStyle(PageTabViewStyle())
|
.tabViewStyle(PageTabViewStyle())
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
@ -49,7 +59,7 @@ struct OnboardingView: View {
|
||||||
|
|
||||||
Text("시작하기")
|
Text("시작하기")
|
||||||
.font(.custom(Font.bold.rawValue, size: 18.3))
|
.font(.custom(Font.bold.rawValue, size: 18.3))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(Color(hex: "1313BC"))
|
||||||
.frame(width: screenSize().width, height: 60)
|
.frame(width: screenSize().width, height: 60)
|
||||||
.background(Color(hex: "80D8FF"))
|
.background(Color(hex: "80D8FF"))
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
|
|
|
@ -17,19 +17,23 @@ struct SplashView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
Image("splash_bg_2024_03")
|
Image("splash_bg_2024")
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Image("splash_text_2024_03")
|
|
||||||
.padding(.top, 262)
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Image("splash_text_logo_2024_03")
|
Image("splash_logo_2024")
|
||||||
.padding(.bottom, 35)
|
|
||||||
|
Image("splash_logo_dragon_2024")
|
||||||
|
.padding(.leading, 25)
|
||||||
|
.padding(.top, 50)
|
||||||
|
.padding(.bottom, 45)
|
||||||
|
|
||||||
|
Image("vividnext_logo")
|
||||||
|
.padding(.bottom, 45)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isShowUpdatePopup {
|
if isShowUpdatePopup {
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
//
|
|
||||||
// SelectedButtonView.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2/23/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct SelectedButtonView: View {
|
|
||||||
|
|
||||||
let title: String
|
|
||||||
let isActive: Bool
|
|
||||||
let isSelected: Bool
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack(spacing: 6.7) {
|
|
||||||
if isSelected {
|
|
||||||
Image("ic_select_check")
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(title)
|
|
||||||
.font(.custom(Font.bold.rawValue, size: 14.7))
|
|
||||||
.foregroundColor(!isActive ? Color.gray77 : isSelected ? .white : Color.button)
|
|
||||||
}
|
|
||||||
.padding(.vertical, 14.3)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.background(!isActive ? Color.gray55 : isSelected ? Color.button : Color.bg)
|
|
||||||
.cornerRadius(6.7)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
SelectedButtonView(title: "테스트", isActive: true, isSelected: true)
|
|
||||||
}
|
|
|
@ -15,7 +15,6 @@ extension Color {
|
||||||
static let bg = Color(hex: "13181B")
|
static let bg = Color(hex: "13181B")
|
||||||
static let gray11 = Color(hex: "111111")
|
static let gray11 = Color(hex: "111111")
|
||||||
static let gray22 = Color(hex: "222222")
|
static let gray22 = Color(hex: "222222")
|
||||||
static let gray23 = Color(hex: "232323")
|
|
||||||
static let gray30 = Color(hex: "303030")
|
static let gray30 = Color(hex: "303030")
|
||||||
static let gray33 = Color(hex: "333333")
|
static let gray33 = Color(hex: "333333")
|
||||||
static let gray52 = Color(hex: "525252")
|
static let gray52 = Color(hex: "525252")
|
||||||
|
@ -28,6 +27,5 @@ extension Color {
|
||||||
|
|
||||||
static let mainRed = Color(hex: "ff5c49")
|
static let mainRed = Color(hex: "ff5c49")
|
||||||
static let mainRed2 = Color(hex: "ea3a25")
|
static let mainRed2 = Color(hex: "ea3a25")
|
||||||
static let mainRed3 = Color(hex: "dd4500")
|
|
||||||
static let mainYellow = Color(hex: "ffdc00")
|
static let mainYellow = Color(hex: "ffdc00")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
//
|
|
||||||
// IdfaUpdateRequest.swift
|
|
||||||
// SodaLive
|
|
||||||
//
|
|
||||||
// Created by klaus on 2/26/24.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct IdfaUpdateRequest: Encodable {
|
|
||||||
let adid: String
|
|
||||||
}
|
|
|
@ -30,7 +30,6 @@ enum UserApi {
|
||||||
case getChangeNicknamePrice
|
case getChangeNicknamePrice
|
||||||
case checkNickname(nickname: String)
|
case checkNickname(nickname: String)
|
||||||
case changeNickname(request: ProfileUpdateRequest)
|
case changeNickname(request: ProfileUpdateRequest)
|
||||||
case updateIdfa(request: IdfaUpdateRequest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UserApi: TargetType {
|
extension UserApi: TargetType {
|
||||||
|
@ -99,9 +98,6 @@ extension UserApi: TargetType {
|
||||||
|
|
||||||
case .changeNickname:
|
case .changeNickname:
|
||||||
return "/member/change/nickname"
|
return "/member/change/nickname"
|
||||||
|
|
||||||
case .updateIdfa:
|
|
||||||
return "/member/adid/update"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +110,7 @@ extension UserApi: TargetType {
|
||||||
case .searchUser, .getMypage, .getMemberInfo, .getMyProfile, .getChangeNicknamePrice, .checkNickname:
|
case .searchUser, .getMypage, .getMemberInfo, .getMyProfile, .getChangeNicknamePrice, .checkNickname:
|
||||||
return .get
|
return .get
|
||||||
|
|
||||||
case .updatePushToken, .profileUpdate, .changeNickname, .updateIdfa:
|
case .updatePushToken, .profileUpdate, .changeNickname:
|
||||||
return .put
|
return .put
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,9 +167,6 @@ extension UserApi: TargetType {
|
||||||
|
|
||||||
case .changeNickname(let request):
|
case .changeNickname(let request):
|
||||||
return .requestJSONEncodable(request)
|
return .requestJSONEncodable(request)
|
||||||
|
|
||||||
case .updateIdfa(let request):
|
|
||||||
return .requestJSONEncodable(request)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,4 @@ final class UserRepository {
|
||||||
func changeNickname(request: ProfileUpdateRequest) -> AnyPublisher<Response, MoyaError> {
|
func changeNickname(request: ProfileUpdateRequest) -> AnyPublisher<Response, MoyaError> {
|
||||||
return api.requestPublisher(.changeNickname(request: request))
|
return api.requestPublisher(.changeNickname(request: request))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIdfa(request: IdfaUpdateRequest) -> AnyPublisher<Response, MoyaError> {
|
|
||||||
return api.requestPublisher(.updateIdfa(request: request))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|