콘텐츠 메인, 라이브 메인, 오디션 메인, 마이페이지

- 로그인 하지 않고 페이지 조회가 되도록 수정
This commit is contained in:
Yu Sung 2025-03-24 18:32:27 +09:00
parent fa94c5447f
commit 80cb19a1c7
32 changed files with 874 additions and 595 deletions

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_logo_circle_gray.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -12,6 +12,8 @@ enum AppStep {
case main
case login
case signUp
case findPassword

View File

@ -89,6 +89,12 @@ extension AuditionApi: TargetType {
}
var headers: [String : String]? {
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
switch self {
case .getAuditionList:
return nil
default:
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
}
}
}

View File

@ -11,15 +11,18 @@ struct AuditionView: View {
@StateObject var viewModel = AuditionViewModel()
@AppStorage("isAuditionNotification") private var isAuditionNotification: Bool = UserDefaults.bool(forKey: .isAuditionNotification)
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
HomeNavigationBar(title: "오디션") {
Image(isAuditionNotification ? "btn_audition_notification_selected" : "btn_audition_notification_normal")
.onTapGesture {
viewModel.updateNotificationSettings()
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image(isAuditionNotification ? "btn_audition_notification_selected" : "btn_audition_notification_normal")
.onTapGesture {
viewModel.updateNotificationSettings()
}
}
}
HStack(spacing: 0) {
@ -70,11 +73,16 @@ struct AuditionView: View {
AuditionItemView(item: item)
.onTapGesture {
if !item.isOff {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if !item.isOff {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
}
} else {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
.setAppStep(step: .login)
}
}
}
@ -104,23 +112,20 @@ struct AuditionView: View {
AuditionItemView(item: item)
.padding(.top, 25)
.onTapGesture {
}
} else {
AuditionItemView(item: item)
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if !item.isOff {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
}
}
}
} else {
AuditionItemView(item: item)
.onTapGesture {
if !item.isOff {
} else {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
.setAppStep(step: .login)
}
}
}

View File

@ -41,6 +41,7 @@ enum ContentApi {
case getContentMainHome(isAdultContentVisible: Bool, contentType: ContentType)
case getPopularContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainHomeContentRanking(isAdultContentVisible: Bool, contentType: ContentType, sortType: String)
case getContentMainSeries(isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendSeriesListByGenre(genreId: Int, isAdultContentVisible: Bool, contentType: ContentType)
@ -168,6 +169,9 @@ extension ContentApi: TargetType {
case .getPopularContentByCreator:
return "/v2/audio-content/main/home/popular-content-by-creator"
case .getContentMainHomeContentRanking:
return "/v2/audio-content/main/home/content/ranking"
case .getContentMainSeries:
return "/v2/audio-content/main/series"
@ -238,7 +242,7 @@ extension ContentApi: TargetType {
case .getMainBannerList, .getMainOrderList, .getNewContentUploadCreatorList, .getCurationList, .getAudioContentByTheme:
return .get
case .getContentMainHome, .getPopularContentByCreator, .getContentMainSeries, .getRecommendSeriesListByGenre, .getRecommendSeriesByCreator, .getContentMainContent,
case .getContentMainHome, .getPopularContentByCreator, .getContentMainHomeContentRanking, .getContentMainSeries, .getRecommendSeriesListByGenre, .getRecommendSeriesByCreator, .getContentMainContent,
.getContentMainNewContentOfTheme, .getDailyContentRanking, .getRecommendContentByTag, .getContentMainAlarm, .getContentMainAlarmAll,
.getContentMainAsmr, .getPopularAsmrContentByCreator, .getContentMainReplay, .getPopularReplayContentByCreator,
.getContentMainFree, .getIntroduceCreatorList, .getNewFreeContentOfTheme, .getPopularFreeContentByCreator, .getCompletedSeries, .getContentMainContentPopularContentByCreator:
@ -439,6 +443,15 @@ extension ContentApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainHomeContentRanking(let isAdultContentVisible, let contentType, let sortType):
let parameters = [
"sort-type": sortType,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendSeriesByCreator(let creatorId, let isAdultContentVisible, let contentType):
let parameters = [
"creatorId": creatorId,

View File

@ -11,6 +11,8 @@ import Kingfisher
struct ContentMainTabRankContentView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let rows = [
GridItem(.fixed(60), alignment: .leading),
GridItem(.fixed(60), alignment: .leading),
@ -92,9 +94,13 @@ struct ContentMainTabRankContentView: View {
.frame(width: screenSize().width * 0.66, alignment: .leading)
.contentShape(Rectangle())
.onTapGesture {
AppState
.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}

View File

@ -10,6 +10,8 @@ import Kingfisher
struct ContentByChannelView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let title: String
let creatorList: [ContentCreatorResponse]
let contentList: [GetAudioContentRankingItem]
@ -111,15 +113,23 @@ struct ContentByChannelView: View {
.foregroundColor(.gray77)
}
.onTapGesture {
AppState
.shared
.setAppStep(step: .creatorDetail(userId: content.creatorId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: content.creatorId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
.onTapGesture {
AppState
.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .contentDetail(contentId: content.contentId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}

View File

@ -31,4 +31,14 @@ class ContentMainTabHomeRepository {
)
)
}
func getContentRanking(sortType: String = "매출") -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getContentMainHomeContentRanking(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
sortType: sortType
)
)
}
}

View File

@ -10,6 +10,7 @@ import SwiftUI
struct ContentMainTabHomeView: View {
@StateObject var viewModel = ContentMainTabHomeViewModel()
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
@ -29,10 +30,12 @@ struct ContentMainTabHomeView: View {
Spacer()
Image("ic_content_keep")
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_content_keep")
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
}
}
.padding(.horizontal, 13.3)
@ -45,153 +48,156 @@ struct ContentMainTabHomeView: View {
.padding(.horizontal, 13.3)
}
if viewModel.bannerList.count > 0 {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
viewModel.bannerList.count > 0 {
ContentMainBannerViewV2(bannerList: viewModel.bannerList)
.padding(.top, 30)
.padding(.horizontal, 13.3)
}
HStack(spacing: 0) {
Image("ic_title_search_black")
Text("채널명을 입력해 보세요")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.gray55)
.keyboardType(.default)
.padding(.horizontal, 13.3)
Spacer()
}
.padding(.horizontal, 21.3)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color.gray22)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.strokeBorder(lineWidth: 1)
.foregroundColor(Color.graybb)
)
.padding(.top, 30)
.padding(.horizontal, 13.3)
.onTapGesture {
UserDefaults.set("", forKey: .searchChannel)
AppState.shared.setAppStep(step: .searchChannel)
}
VStack(spacing: 13.3) {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_series",
title: "시리즈",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .SERIES
)
)
}
)
.frame(maxWidth: .infinity)
Image("ic_title_search_black")
ContentMainTabCategoryView(
imageName: "ic_category_content",
title: "단편",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .CONTENT
)
)
}
)
.frame(maxWidth: .infinity)
Text("채널명을 입력해 보세요")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.gray55)
.keyboardType(.default)
.padding(.horizontal, 13.3)
ContentMainTabCategoryView(
imageName: "ic_category_alarm",
title: "모닝콜",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ALARM
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_asmr",
title: "ASMR",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ASMR
)
)
}
)
.frame(maxWidth: .infinity)
Spacer()
}
.padding(.horizontal, 21.3)
.frame(height: 50)
.frame(maxWidth: .infinity)
.background(Color.gray22)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.strokeBorder(lineWidth: 1)
.foregroundColor(Color.graybb)
)
.padding(.top, 30)
.padding(.horizontal, 13.3)
.onTapGesture {
UserDefaults.set("", forKey: .searchChannel)
AppState.shared.setAppStep(step: .searchChannel)
}
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_replay",
title: "다시듣기",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .REPLAY
VStack(spacing: 13.3) {
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_series",
title: "시리즈",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .SERIES
)
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_free",
title: "무료",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .FREE
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_content",
title: "단편",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .CONTENT
)
)
)
}
)
.frame(maxWidth: .infinity)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_alarm",
title: "모닝콜",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ALARM
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_asmr",
title: "ASMR",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .ASMR
)
)
}
)
.frame(maxWidth: .infinity)
}
ContentMainTabCategoryView(
imageName: "ic_category_audio_book",
title: "오디오북",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_toon",
title: "오디오툰",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
HStack(spacing: 0) {
ContentMainTabCategoryView(
imageName: "ic_category_replay",
title: "다시듣기",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .REPLAY
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_free",
title: "무료",
onClick: {
AppState.shared
.setAppStep(
step: .contentMain(
startTab: .FREE
)
)
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_book",
title: "오디오북",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
ContentMainTabCategoryView(
imageName: "ic_category_audio_toon",
title: "오디오툰",
onClick: {
viewModel.errorMessage = "준비중입니다."
viewModel.isShowPopup = true
}
)
.frame(maxWidth: .infinity)
}
}
.padding(.vertical, 13.3)
.background(Color.gray22)
.cornerRadius(5.3)
.padding(.top, 30)
.padding(.horizontal, 13.3)
}
.padding(.vertical, 13.3)
.background(Color.gray22)
.cornerRadius(5.3)
.padding(.top, 30)
.padding(.horizontal, 13.3)
if let response = viewModel.rankCreatorResponse {
ContentMainTabHomeRankCreatorView(response: response)
@ -210,7 +216,11 @@ struct ContentMainTabHomeView: View {
title: "인기 단편",
isMore: true,
onClickMore: {
AppState.shared.setAppStep(step: .contentRankingAll)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .contentRankingAll)
} else {
AppState.shared.setAppStep(step: .login)
}
},
sortList: !viewModel.rankSortTypeList.isEmpty ?
viewModel.rankSortTypeList :
@ -221,7 +231,8 @@ struct ContentMainTabHomeView: View {
.padding(.top, 30)
}
if viewModel.eventBannerList.count > 0 {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
viewModel.eventBannerList.count > 0 {
SectionEventBannerView(items: viewModel.eventBannerList)
.padding(.top, 30)
}

View File

@ -11,7 +11,6 @@ import Combine
final class ContentMainTabHomeViewModel: ObservableObject {
private let repository = ContentMainTabHomeRepository()
private let contentRepository = ContentRepository()
private var subscription = Set<AnyCancellable>()
@Published var errorMessage = ""
@ -77,7 +76,7 @@ final class ContentMainTabHomeViewModel: ObservableObject {
func getContentRanking(sort: String = "매출") {
isLoading = true
contentRepository.getContentRanking(page: 1, size: 12, sortType: sort)
repository.getContentRanking(sortType: sort)
.sink { result in
switch result {
case .finished:
@ -90,10 +89,10 @@ final class ContentMainTabHomeViewModel: ObservableObject {
do {
let jsonDecoder = JSONDecoder()
let decoded = try jsonDecoder.decode(ApiResponse<GetAudioContentRanking>.self, from: responseData)
let decoded = try jsonDecoder.decode(ApiResponse<[GetAudioContentRankingItem]>.self, from: responseData)
if let data = decoded.data, decoded.success {
self.rankContentList = data.items
self.rankContentList = data
} else {
if let message = decoded.message {
self.errorMessage = message

View File

@ -10,6 +10,8 @@ import Kingfisher
struct ContentMainTabHomeRankCreatorView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let response: GetExplorerSectionResponse
let rankingCrawns = ["ic_crown_1", "ic_crown_2", "ic_crown_3"]
@ -121,8 +123,13 @@ struct ContentMainTabHomeRankCreatorView: View {
}
.contentShape(Rectangle())
.onTapGesture {
AppState.shared
.setAppStep(step: .creatorDetail(userId: creator.id))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: creator.id))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
}

View File

@ -17,13 +17,16 @@ struct ContentView: View {
if appState.isChangeAdultContentVisible {
EmptyView()
} else {
MainView()
HomeView()
}
switch appState.appStep {
case .splash:
SplashView()
case .login:
LoginView()
case .signUp:
SignUpView()

View File

@ -12,6 +12,7 @@ struct SectionEventBannerView: View {
@State private var currentIndex = 0
@State private var timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let items: [EventItem]
@ -38,10 +39,14 @@ struct SectionEventBannerView: View {
)
.tag(index)
.onTapGesture {
if let _ = item.detailImageUrl {
AppState.shared.setAppStep(step: .eventDetail(event: item))
} else if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if let _ = item.detailImageUrl {
AppState.shared.setAppStep(step: .eventDetail(event: item))
} else if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
} else {
AppState.shared.setAppStep(step: .login)
}
}
} else {
@ -62,10 +67,14 @@ struct SectionEventBannerView: View {
)
.tag(index)
.onTapGesture {
if let _ = item.detailImageUrl {
AppState.shared.setAppStep(step: .eventDetail(event: item))
} else if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if let _ = item.detailImageUrl {
AppState.shared.setAppStep(step: .eventDetail(event: item))
} else if let link = item.link, link.trimmingCharacters(in: .whitespaces).count > 0, let url = URL(string: link), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
} else {
AppState.shared.setAppStep(step: .login)
}
}
}

View File

@ -12,6 +12,7 @@ struct LiveView: View {
@StateObject var viewModel = LiveViewModel()
@StateObject var appState = AppState.shared
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
ZStack {
@ -44,9 +45,13 @@ struct LiveView: View {
}
.padding(.horizontal, 13.3)
.onTapGesture {
AppState.shared.setAppStep(
step: .contentAllByTheme(themeId: 7)
)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .contentAllByTheme(themeId: 7)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
if viewModel.recommendChannelItems.count > 0 {
@ -61,10 +66,18 @@ struct LiveView: View {
SectionLiveNowView(
items: viewModel.liveNowItems,
onClickParticipant: {
viewModel.enterLiveRoom(roomId: $0)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.enterLiveRoom(roomId: $0)
} else {
AppState.shared.setAppStep(step: .login)
}
},
onTapCreateLive: {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: onCreateSuccess))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: onCreateSuccess))
} else {
AppState.shared.setAppStep(step: .login)
}
},
onClickRefresh: {
viewModel.getSummary()
@ -82,12 +95,26 @@ struct LiveView: View {
SectionLiveReservationView(
items: viewModel.liveReservationItems,
onClickCancel: { viewModel.getSummary() },
onClickStart: { roomId in processStart(roomId: roomId) },
onClickStart: { roomId in
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
processStart(roomId: roomId)
} else {
AppState.shared.setAppStep(step: .login)
}
},
onClickReservation: { roomId in
viewModel.reservationLiveRoom(roomId: roomId)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.reservationLiveRoom(roomId: roomId)
} else {
AppState.shared.setAppStep(step: .login)
}
},
onTapCreateLive: {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .RESERVATION, onSuccess: onCreateSuccess))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .RESERVATION, onSuccess: onCreateSuccess))
} else {
AppState.shared.setAppStep(step: .login)
}
}
)
}
@ -102,7 +129,11 @@ struct LiveView: View {
.padding(.trailing, 16)
.padding(.bottom, 16)
.onTapGesture {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: onCreateSuccess))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: onCreateSuccess))
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}

View File

@ -84,10 +84,17 @@ final class LiveViewModel: ObservableObject {
}
func getSummary() {
getFollowedChannelList()
if !UserDefaults.string(forKey: UserDefaultsKey.token).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
getFollowedChannelList()
}
getRecommendChannelList()
getRecommendLive()
getLatestPostListFromCreatorsYouFollow()
if !UserDefaults.string(forKey: UserDefaultsKey.token).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
getLatestPostListFromCreatorsYouFollow()
}
isLoading = true
eventBannerItems.removeAll()

View File

@ -15,6 +15,8 @@ struct SectionLiveNowView: View {
let onTapCreateLive: () -> Void
let onClickRefresh: () -> Void
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
LazyVStack(spacing: 13.3) {
HStack(spacing: 0) {
@ -45,20 +47,24 @@ struct SectionLiveNowView: View {
LiveNowItemView(item: item)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {
AppState.shared.isShowPlayer = false
onClickParticipant(item.roomId)
},
onClickReservation: {},
onClickStart: {
},
onClickCancel: {
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {
AppState.shared.isShowPlayer = false
onClickParticipant(item.roomId)
},
onClickReservation: {},
onClickStart: {
},
onClickCancel: {
}
)
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}

View File

@ -13,6 +13,7 @@ struct SectionRecommendLiveView: View {
let items: [GetRecommendLiveResponse]
@State private var currentIndex = 0
@State private var timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect()
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
VStack(spacing: 0) {
@ -27,10 +28,12 @@ struct SectionRecommendLiveView: View {
Spacer()
Image("ic_message")
.onTapGesture {
AppState.shared.setAppStep(step: .message)
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_message")
.onTapGesture {
AppState.shared.setAppStep(step: .message)
}
}
}
.frame(width: screenSize().width - 26.7, alignment: .leading)
@ -53,7 +56,11 @@ struct SectionRecommendLiveView: View {
height: (screenSize().width - 26.7) * 0.53
)
.onTapGesture {
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId))
} else {
AppState.shared.setAppStep(step: .login)
}
}
.cornerRadius(4.7)
} else {
@ -72,7 +79,11 @@ struct SectionRecommendLiveView: View {
height: (screenSize().width - 26.7) * 0.53
)
.onTapGesture {
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId))
} else {
AppState.shared.setAppStep(step: .login)
}
}
.cornerRadius(4.7)
}

View File

@ -13,6 +13,7 @@ struct SectionRecommendChannelView: View {
let items: [GetRecommendChannelResponse]
@Binding var isFollowingList: Bool
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
VStack(spacing: 21.3) {
@ -20,30 +21,32 @@ struct SectionRecommendChannelView: View {
if isFollowingList {
Text("팔로잉 ")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color(hex: "eeeeee"))
.foregroundColor(.grayee)
} else {
Text("추천 ")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color(hex: "eeeeee"))
.foregroundColor(.grayee)
}
Text("채널")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color(hex: "3bb9f1"))
.foregroundColor(.button)
Spacer()
Text("팔로잉 채널")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color(hex: "777777"))
Image(isFollowingList ? "btn_toggle_on_big" : "btn_toggle_off_big")
.resizable()
.frame(width: 33.3, height: 20)
.padding(.leading, 6.7)
.onTapGesture {
isFollowingList.toggle()
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Text("팔로잉 채널")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(.gray77)
Image(isFollowingList ? "btn_toggle_on_big" : "btn_toggle_off_big")
.resizable()
.frame(width: 33.3, height: 20)
.padding(.leading, 6.7)
.onTapGesture {
isFollowingList.toggle()
}
}
}
.frame(width: screenSize().width - 26.7, alignment: .leading)
@ -70,7 +73,7 @@ struct SectionRecommendChannelView: View {
Circle()
.strokeBorder(lineWidth: 3)
.foregroundColor(
Color(hex: "3bb9f1")
.button
.opacity(item.isOnAir ? 1 : 0)
)
)
@ -81,21 +84,25 @@ struct SectionRecommendChannelView: View {
.foregroundColor(.white)
.padding(.vertical, 2.7)
.padding(.horizontal, 5.7)
.background(Color(hex: "3bb9f1"))
.background(Color.button)
.cornerRadius(6.7)
}
}
Text(item.nickname)
.font(.custom(Font.medium.rawValue, size: 11.3))
.foregroundColor(Color(hex: "bbbbbb"))
.foregroundColor(Color.graybb)
.frame(width: screenSize().width * 0.18)
.lineLimit(1)
}
.onTapGesture {
AppState.shared.setAppStep(
step: .creatorDetail(userId: item.creatorId)
)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .creatorDetail(userId: item.creatorId)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
@ -112,10 +119,15 @@ struct SectionRecommendChannelView: View {
.lineLimit(1)
}
.onTapGesture {
AppState.shared.setAppStep(step: .followingList)
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(step: .followingList)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}
.padding(.horizontal, 13.3)
}
}
}

View File

@ -15,6 +15,7 @@ struct SectionLiveReservationView: View {
let onClickStart: (Int) -> Void
let onClickReservation: (Int) -> Void
let onTapCreateLive: () -> Void
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
VStack(spacing: 13.3) {
@ -34,14 +35,18 @@ struct SectionLiveReservationView: View {
.font(.custom(Font.light.rawValue, size: 11.3))
.foregroundColor(Color(hex: "bbbbbb"))
.onTapGesture {
AppState.shared.setAppStep(
step: .liveReservationAll(
onClickReservation: onClickReservation,
onClickStart: onClickStart,
onClickCancel: onClickCancel,
onTapCreateLive: onTapCreateLive
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveReservationAll(
onClickReservation: onClickReservation,
onClickStart: onClickStart,
onClickCancel: onClickCancel,
onTapCreateLive: onTapCreateLive
)
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}
@ -57,29 +62,37 @@ struct SectionLiveReservationView: View {
MyLiveReservationItemView(item: item, index: index)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {},
onClickReservation: {},
onClickStart: { onClickStart(item.roomId) },
onClickCancel: onClickCancel
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {},
onClickReservation: {},
onClickStart: { onClickStart(item.roomId) },
onClickCancel: onClickCancel
)
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
} else {
LiveReservationItemView(item: item)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {},
onClickReservation: { onClickReservation(item.roomId) },
onClickStart: { onClickStart(item.roomId) },
onClickCancel: onClickCancel
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
onClickParticipant: {},
onClickReservation: { onClickReservation(item.roomId) },
onClickStart: { onClickStart(item.roomId) },
onClickCancel: onClickCancel
)
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}

View File

@ -25,6 +25,7 @@ struct HomeView: View {
private let contentView = ContentMainTabHomeView()
@State private var isShowPlayer = false
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
GeometryReader { proxy in
@ -168,10 +169,12 @@ struct HomeView: View {
}
}
.onAppear {
pushTokenUpdate()
viewModel.getMemberInfo()
viewModel.getEventPopup()
viewModel.addAllPlaybackTracking()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
pushTokenUpdate()
viewModel.getMemberInfo()
viewModel.getEventPopup()
viewModel.addAllPlaybackTracking()
}
}
if appState.isShowPlayer {

View File

@ -1,27 +0,0 @@
//
// MainView.swift
// SodaLive
//
// Created by klaus on 2023/08/09.
//
import SwiftUI
struct MainView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
if token.count > 0 {
HomeView()
} else {
LoginView()
}
}
}
struct MainView_Previews: PreviewProvider {
static var previews: some View {
MainView()
}
}

View File

@ -17,10 +17,12 @@ struct MyPageView: View {
@StateObject var viewModel = MyPageViewModel()
@State private var payload = Payload()
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
if viewModel.isShowAuthView {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty &&
viewModel.isShowAuthView {
BootpayUI(payload: payload, requestType: BootpayRequest.TYPE_AUTHENTICATION)
.onConfirm {
DEBUG_LOG("onConfirm: \($0)")
@ -47,100 +49,45 @@ struct MyPageView: View {
GeometryReader { geo in
VStack {
HomeNavigationBar(title: "마이 페이지") {
Image("ic_settings")
.resizable()
.frame(width: 20, height: 20)
.onTapGesture {
AppState.shared.setAppStep(step: .settings)
}
}
RefreshableScrollView(
refreshing: $viewModel.isLoading,
action: {
viewModel.getMypage()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_settings")
.resizable()
.frame(width: 20, height: 20)
.onTapGesture {
AppState.shared.setAppStep(step: .settings)
}
}
) {
VStack(spacing: 0) {
if let data = viewModel.myPageResponse {
MyInfoCardView(data: data) {
viewModel.getMypage()
}
.frame(width: screenSize().width - 26.7)
.padding(.top, 13.3)
if UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue {
Text("내 채널 보기")
.frame(width: screenSize().width - 26.7, height: 46.7)
.font(.custom(Font.bold.rawValue, size: 15.3))
.foregroundColor(Color.grayee)
.background(Color.button)
.cornerRadius(6.7)
.padding(.top, 26.7)
.onTapGesture {
AppState.shared.setAppStep(step: .creatorDetail(userId: UserDefaults.int(forKey: .userId)))
}
}
HStack(spacing: 10.7) {
Text("팔로잉 리스트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
.padding(.vertical, 13.3)
.background(Color.bg)
.cornerRadius(6.7)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.stroke(Color.button, lineWidth: 1.3)
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .followingList)
}
Text("차단 리스트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
.padding(.vertical, 13.3)
.background(Color.bg)
.cornerRadius(6.7)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.stroke(Color.button, lineWidth: 1.3)
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .blockList)
}
}
.padding(.top, 26.7)
.padding(.horizontal, 13.3)
if UserDefaults.int(forKey: .userId) != 17958 {
CanCardView(data: data) {
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
RefreshableScrollView(
refreshing: $viewModel.isLoading,
action: {
viewModel.getMypage()
}
) {
VStack(spacing: 0) {
if let data = viewModel.myPageResponse {
MyInfoCardView(data: data) {
viewModel.getMypage()
}
.frame(width: screenSize().width - 26.7)
.padding(.top, 26.7)
}
if data.isAuth {
CanChargeCouponButtonView()
.frame(width: screenSize().width - 26.7)
.padding(.top, 13.3)
.onTapGesture {
AppState.shared.setAppStep(step: .canCoupon)
}
}
VStack(alignment: .leading, spacing: 13.3) {
Text("내 보관함")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color.grayee)
.padding(.top, 13.3)
if UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue {
Text("내 채널 보기")
.frame(width: screenSize().width - 26.7, height: 46.7)
.font(.custom(Font.bold.rawValue, size: 15.3))
.foregroundColor(Color.grayee)
.background(Color.button)
.cornerRadius(6.7)
.padding(.top, 26.7)
.onTapGesture {
AppState.shared.setAppStep(step: .creatorDetail(userId: UserDefaults.int(forKey: .userId)))
}
}
HStack(spacing: 10.7) {
Text("구매목록")
Text("팔로잉 리스트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
@ -153,10 +100,10 @@ struct MyPageView: View {
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
AppState.shared.setAppStep(step: .followingList)
}
Text("재생목록")
Text("차단 리스트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
@ -169,26 +116,175 @@ struct MyPageView: View {
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .playlist))
AppState.shared.setAppStep(step: .blockList)
}
}
.padding(.top, 26.7)
.padding(.horizontal, 13.3)
if UserDefaults.int(forKey: .userId) != 17958 {
CanCardView(data: data) {
viewModel.getMypage()
}
.frame(width: screenSize().width - 26.7)
.padding(.top, 26.7)
}
if data.isAuth {
CanChargeCouponButtonView()
.frame(width: screenSize().width - 26.7)
.padding(.top, 13.3)
.onTapGesture {
AppState.shared.setAppStep(step: .canCoupon)
}
}
VStack(alignment: .leading, spacing: 13.3) {
Text("내 보관함")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color.grayee)
HStack(spacing: 10.7) {
Text("구매목록")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
.padding(.vertical, 13.3)
.background(Color.bg)
.cornerRadius(6.7)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.stroke(Color.button, lineWidth: 1.3)
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
Text("재생목록")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.button)
.frame(maxWidth: .infinity)
.padding(.vertical, 13.3)
.background(Color.bg)
.cornerRadius(6.7)
.overlay(
RoundedRectangle(cornerRadius: 6.7)
.stroke(Color.button, lineWidth: 1.3)
)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .playlist))
}
}
}
.padding(.top, 33)
.padding(.horizontal, 13.3)
ReservationStatusView(data: data)
.padding(.top, 40)
ServiceCenterButtonView()
.padding(.top, 40)
if !data.isAuth {
AuthButtonView()
.padding(.top, 40)
.onTapGesture {
viewModel.isShowAuthView = true
}
}
if let url = URL(string: "https://blog.naver.com/sodalive_official"),
UIApplication.shared.canOpenURL(url) {
Image("img_how_to_use")
.resizable()
.frame(
width: screenSize().width,
height: (200 * screenSize().width) / 1080
)
.padding(.vertical, 40)
.onTapGesture {
UIApplication.shared.open(url)
}
}
}
.padding(.top, 33)
}
}
} else {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 24) {
HStack(spacing: 6.7) {
Image("ic_logo_circle_gray")
Text("Login")
.font(.custom(Font.medium.rawValue, size: 32))
.foregroundColor(.gray90)
}
.padding(20)
.frame(maxWidth: .infinity)
.background(Color.bg)
.cornerRadius(6.7)
.contentShape(Rectangle())
.padding(.horizontal, 13.3)
.padding(.top, 24)
.onTapGesture {
AppState.shared
.setAppStep(step: .login)
}
HStack(spacing: 0) {
HStack(spacing: 6.7) {
Text("0")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(.grayee)
Image("ic_can")
.resizable()
.frame(width: 20, height: 20)
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.onTapGesture {
AppState.shared
.setAppStep(step: .login)
}
Spacer()
HStack(spacing: 7) {
Image("ic_coin_w")
.resizable()
.frame(width: 26.7, height: 26.7)
Text("충전")
.font(.custom(Font.bold.rawValue, size: 12))
.foregroundColor(Color(hex: "b38fff"))
}
.padding(.horizontal, 11.3)
.padding(.vertical, 7)
.overlay(
RoundedRectangle(cornerRadius: CGFloat(16.7))
.stroke(lineWidth: 1)
.foregroundColor(Color(hex: "b38fff"))
)
.cornerRadius(16.7)
.onTapGesture {
AppState.shared
.setAppStep(step: .login)
}
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 13.3)
.padding(.vertical, 10)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.horizontal, 13.3)
ReservationStatusView(data: data)
.padding(.top, 40)
ServiceCenterButtonView()
.padding(.top, 40)
if !data.isAuth {
AuthButtonView()
.padding(.top, 40)
.onTapGesture {
viewModel.isShowAuthView = true
}
}
.padding(.horizontal, 13.3)
if let url = URL(string: "https://blog.naver.com/sodalive_official"),
UIApplication.shared.canOpenURL(url) {
@ -198,7 +294,6 @@ struct MyPageView: View {
width: screenSize().width,
height: (200 * screenSize().width) / 1080
)
.padding(.vertical, 40)
.onTapGesture {
UIApplication.shared.open(url)
}
@ -210,7 +305,9 @@ struct MyPageView: View {
.frame(width: geo.size.width, height: geo.size.height)
}
.onAppear {
viewModel.getMypage()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.getMypage()
}
}
}
}

View File

@ -43,6 +43,6 @@ extension FaqApi: TargetType {
}
var headers: [String : String]? {
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
return nil
}
}

View File

@ -25,8 +25,9 @@ struct ServiceCenterButtonView: View {
.frame(width: 20, height: 20)
}
.padding(.horizontal, 13.3)
.frame(width: screenSize().width - 26.7, height: 66.7)
.background(Color(hex: "13181b"))
.frame(height: 66.7)
.frame(maxWidth: .infinity)
.background(Color.bg)
.cornerRadius(6.7)
.onTapGesture {
AppState.shared.setAppStep(step: .serviceCenter)

View File

@ -25,7 +25,7 @@ struct ServiceCenterView: View {
Text("고객센터")
.font(.custom(Font.bold.rawValue, size: 20))
.foregroundColor(Color(hex: "eeeeee"))
.foregroundColor(.grayee)
HStack(spacing: 13.3) {
Image("ic_service_center_kakao")
@ -48,13 +48,14 @@ struct ServiceCenterView: View {
Rectangle()
.frame(width: screenSize().width, height: 6.7)
.foregroundColor(Color(hex: "232323"))
.foregroundColor(.gray23)
.padding(.vertical, 20)
Text("자주 묻는 질문")
.font(.custom(Font.bold.rawValue, size: 18.3))
.foregroundColor(Color(hex: "eeeeee"))
.frame(width: screenSize().width - 26.7, alignment: .leading)
.foregroundColor(.grayee)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, 13.3)
ServiceCenterCategoryView(
categories: viewModel.categories,

View File

@ -20,165 +20,168 @@ struct SettingsView: View {
GeometryReader { geo in
VStack(spacing: 0) {
DetailNavigationBar(title: "설정")
VStack(spacing: 0) {
HStack(spacing: 0) {
Text("공지사항")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .notices)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("이벤트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .events)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("알림 설정")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .notificationSettings)
}
}
.padding(.horizontal, 13.3)
.frame(width: cardWidth)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 26.7)
if UserDefaults.bool(forKey: .auth) {
HStack(spacing: 0) {
Text("콘텐츠 보기 설정")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
VStack(spacing: 0) {
HStack(spacing: 0) {
Text("공지사항")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .notices)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("이벤트")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .events)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("알림 설정")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .notificationSettings)
}
}
.padding(.horizontal, 13.3)
.frame(width: cardWidth)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 26.7)
Spacer()
if UserDefaults.bool(forKey: .auth) {
HStack(spacing: 0) {
Text("콘텐츠 보기 설정")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 16.7)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.contentShape(Rectangle())
.padding(.top, 13.3)
.onTapGesture {
AppState.shared.setAppStep(step: .contentViewSettings)
}
}
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 16.7)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.contentShape(Rectangle())
.padding(.top, 13.3)
.onTapGesture {
AppState.shared.setAppStep(step: .contentViewSettings)
}
}
VStack(spacing: 0) {
HStack(spacing: 0) {
Text("이용약관")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
VStack(spacing: 0) {
HStack(spacing: 0) {
Text("이용약관")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .terms)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("개인정보처리방침")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .privacy)
}
}
.padding(.horizontal, 13.3)
.frame(width: cardWidth)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 13.3)
Spacer()
HStack(spacing: 0) {
Text("앱 버전 정보")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
Text("Ver \(version!)")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.grayee)
}
.padding(.horizontal, 16.7)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 13.3)
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .terms)
}
Rectangle()
.frame(width: cardWidth - 26.7, height: 0.3)
.foregroundColor(Color.gray90)
HStack(spacing: 0) {
Text("개인정보처리방침")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
Image("ic_forward")
.resizable()
.frame(width: 20, height: 20)
}
.padding(.horizontal, 3.3)
.frame(width: cardWidth - 26.7, height: 50)
.contentShape(Rectangle())
.onTapGesture {
AppState.shared.setAppStep(step: .privacy)
}
}
.padding(.horizontal, 13.3)
.frame(width: cardWidth)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 13.3)
HStack(spacing: 0) {
Text("앱 버전 정보")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
Spacer()
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
Text("Ver \(version!)")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color.grayee)
}
.padding(.horizontal, 16.7)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.padding(.top, 13.3)
Text("""
Text("""
- :
- :
@ -193,39 +196,40 @@ struct SettingsView: View {
- : sodalive.official@gmail.com
""")
.font(.custom(Font.medium.rawValue, size: 11))
.foregroundColor(Color.gray77)
.frame(width: cardWidth, alignment: .leading)
.padding(.top, 13.3)
Spacer()
Text("로그아웃")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.onTapGesture {
isShowLogoutDialog = true
}
Text("모든 기기에서 로그아웃")
.font(.custom(Font.medium.rawValue, size: 14.7))
.foregroundColor(Color.gray77)
.padding(.top, 13.3)
.onTapGesture {
isShowLogoutAllDeviceDialog = true
}
Text("회원탈퇴")
.font(.custom(Font.medium.rawValue, size: 14.7))
.foregroundColor(Color.gray77)
.underline()
.padding(.vertical, 26.7)
.onTapGesture {
AppState.shared.setAppStep(step: .signOut)
.font(.custom(Font.medium.rawValue, size: 11))
.foregroundColor(Color.gray77)
.frame(width: cardWidth, alignment: .leading)
.padding(.top, 13.3)
Text("로그아웃")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
.frame(width: cardWidth, height: 50)
.background(Color.gray22)
.cornerRadius(6.7)
.onTapGesture {
isShowLogoutDialog = true
}
.padding(.top, 46.7)
Text("모든 기기에서 로그아웃")
.font(.custom(Font.medium.rawValue, size: 14.7))
.foregroundColor(Color.gray77)
.padding(.top, 13.3)
.onTapGesture {
isShowLogoutAllDeviceDialog = true
}
Text("회원탈퇴")
.font(.custom(Font.medium.rawValue, size: 14.7))
.foregroundColor(Color.gray77)
.underline()
.padding(.vertical, 26.7)
.onTapGesture {
AppState.shared.setAppStep(step: .signOut)
}
}
}
}
}
@ -239,8 +243,9 @@ struct SettingsView: View {
ContentPlayerPlayManager.shared.resetPlayer()
viewModel.logout {
self.isShowLogoutDialog = false
AppState.shared.setAppStep(step: .main)
UserDefaults.reset()
AppState.shared.isChangeAdultContentVisible = true
AppState.shared.setAppStep(step: .splash)
}
},
cancelButtonTitle: "취소",
@ -260,8 +265,9 @@ struct SettingsView: View {
ContentPlayerPlayManager.shared.resetPlayer()
viewModel.logoutAllDevice {
self.isShowLogoutAllDeviceDialog = false
AppState.shared.setAppStep(step: .main)
UserDefaults.reset()
AppState.shared.isChangeAdultContentVisible = true
AppState.shared.setAppStep(step: .splash)
}
},
cancelButtonTitle: "취소",

View File

@ -56,6 +56,7 @@ final class SignOutViewModel: ObservableObject {
if decoded.success {
UserDefaults.reset()
AppState.shared.isChangeAdultContentVisible = true
AppState.shared.setAppStep(step: .splash)
} else {
if let message = decoded.message {

View File

@ -11,6 +11,8 @@ import Kingfisher
struct SeriesListBigItemView: View {
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
let item: SeriesListItem
let isVisibleCreator: Bool
@ -26,8 +28,13 @@ struct SeriesListBigItemView: View {
.cornerRadius(5)
.clipped()
.onTapGesture {
AppState.shared
.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
VStack(alignment: .leading, spacing: 0) {
@ -80,8 +87,13 @@ struct SeriesListBigItemView: View {
.lineLimit(1)
}
.onTapGesture {
AppState.shared
.setAppStep(step: .creatorDetail(userId: item.creator.creatorId))
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: item.creator.creatorId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}

View File

@ -17,7 +17,7 @@ struct LoginView: View {
var body: some View {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
HomeNavigationBar(title: "로그인") {}
DetailNavigationBar(title: "로그인")
Spacer()

View File

@ -55,6 +55,8 @@ final class LoginViewModel: ObservableObject {
UserDefaults.set(data.userId, forKey: .userId)
UserDefaults.set(data.email, forKey: .email)
UserDefaults.set(data.token, forKey: .token)
AppState.shared.isChangeAdultContentVisible = true
AppState.shared.setAppStep(step: .splash)
} else {
if let message = decoded.message {
self.errorMessage = message

View File

@ -58,7 +58,8 @@ final class SignUpViewModel: ObservableObject {
UserDefaults.set(data.userId, forKey: .userId)
UserDefaults.set(data.email, forKey: .email)
UserDefaults.set(data.token, forKey: .token)
AppState.shared.back()
AppState.shared.isChangeAdultContentVisible = true
AppState.shared.setAppStep(step: .splash)
} else {
if let message = decoded.message {
self.errorMessage = message