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

- 로그인 하지 않고 페이지 조회가 되도록 수정
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]? {
switch self {
case .getAuditionList:
return nil
default:
return ["Authorization": "Bearer \(UserDefaults.string(forKey: UserDefaultsKey.token))"]
}
}
}

View File

@ -11,16 +11,19 @@ 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: "오디션") {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image(isAuditionNotification ? "btn_audition_notification_selected" : "btn_audition_notification_normal")
.onTapGesture {
viewModel.updateNotificationSettings()
}
}
}
HStack(spacing: 0) {
Text("보이스온 오디션 이용방법")
@ -70,12 +73,17 @@ struct AuditionView: View {
AuditionItemView(item: item)
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if !item.isOff {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
}
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
} else if $0 == viewModel.firstIsOffIndex {
@ -104,24 +112,21 @@ struct AuditionView: View {
AuditionItemView(item: item)
.padding(.top, 25)
.onTapGesture {
if !item.isOff {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
}
}
}
} else {
AuditionItemView(item: item)
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if !item.isOff {
AppState.shared
.setAppStep(
step: .auditionDetail(auditionId: item.id)
)
}
} else {
AppState.shared
.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
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
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared
.setAppStep(step: .creatorDetail(userId: content.creatorId))
} else {
AppState.shared
.setAppStep(step: .login)
}
}
}
.onTapGesture {
AppState
.shared
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,11 +30,13 @@ struct ContentMainTabHomeView: View {
Spacer()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_content_keep")
.onTapGesture {
AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))
}
}
}
.padding(.horizontal, 13.3)
if let notice = viewModel.noticeItem {
@ -45,12 +48,14 @@ 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)
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
HStack(spacing: 0) {
Image("ic_title_search_black")
@ -192,6 +197,7 @@ struct ContentMainTabHomeView: View {
.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: {
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 {
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,11 +39,15 @@ struct SectionEventBannerView: View {
)
.tag(index)
.onTapGesture {
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 {
KFImage(URL(string: item.thumbnailImageUrl))
@ -62,11 +67,15 @@ struct SectionEventBannerView: View {
)
.tag(index)
.onTapGesture {
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 {
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: {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.enterLiveRoom(roomId: $0)
} else {
AppState.shared.setAppStep(step: .login)
}
},
onTapCreateLive: {
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
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.reservationLiveRoom(roomId: roomId)
} else {
AppState.shared.setAppStep(step: .login)
}
},
onTapCreateLive: {
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 {
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() {
if !UserDefaults.string(forKey: UserDefaultsKey.token).trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
getFollowedChannelList()
}
getRecommendChannelList()
getRecommendLive()
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,6 +47,7 @@ struct SectionLiveNowView: View {
LiveNowItemView(item: item)
.contentShape(Rectangle())
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
@ -59,6 +62,9 @@ struct SectionLiveNowView: View {
}
)
)
} 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,11 +28,13 @@ struct SectionRecommendLiveView: View {
Spacer()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_message")
.onTapGesture {
AppState.shared.setAppStep(step: .message)
}
}
}
.frame(width: screenSize().width - 26.7, alignment: .leading)
TabView(selection: $currentIndex) {
@ -53,7 +56,11 @@ struct SectionRecommendLiveView: View {
height: (screenSize().width - 26.7) * 0.53
)
.onTapGesture {
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 {
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,22 +21,23 @@ 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()
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Text("팔로잉 채널")
.font(.custom(Font.medium.rawValue, size: 13.3))
.foregroundColor(Color(hex: "777777"))
.foregroundColor(.gray77)
Image(isFollowingList ? "btn_toggle_on_big" : "btn_toggle_off_big")
.resizable()
@ -45,6 +47,7 @@ struct SectionRecommendChannelView: View {
isFollowingList.toggle()
}
}
}
.frame(width: screenSize().width - 26.7, alignment: .leading)
ScrollView(.horizontal, showsIndicators: false) {
@ -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 {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .creatorDetail(userId: item.creatorId)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
@ -112,11 +119,16 @@ struct SectionRecommendChannelView: View {
.lineLimit(1)
}
.onTapGesture {
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,6 +35,7 @@ struct SectionLiveReservationView: View {
.font(.custom(Font.light.rawValue, size: 11.3))
.foregroundColor(Color(hex: "bbbbbb"))
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveReservationAll(
onClickReservation: onClickReservation,
@ -42,6 +44,9 @@ struct SectionLiveReservationView: View {
onTapCreateLive: onTapCreateLive
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
}
}
@ -57,6 +62,7 @@ struct SectionLiveReservationView: View {
MyLiveReservationItemView(item: item, index: index)
.contentShape(Rectangle())
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
@ -66,11 +72,15 @@ struct SectionLiveReservationView: View {
onClickCancel: onClickCancel
)
)
} else {
AppState.shared.setAppStep(step: .login)
}
}
} else {
LiveReservationItemView(item: item)
.contentShape(Rectangle())
.onTapGesture {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
AppState.shared.setAppStep(
step: .liveDetail(
roomId: item.roomId,
@ -80,6 +90,9 @@ struct SectionLiveReservationView: View {
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,11 +169,13 @@ struct HomeView: View {
}
}
.onAppear {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
pushTokenUpdate()
viewModel.getMemberInfo()
viewModel.getEventPopup()
viewModel.addAllPlaybackTracking()
}
}
if appState.isShowPlayer {
LiveRoomViewV2()

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,6 +49,7 @@ struct MyPageView: View {
GeometryReader { geo in
VStack {
HomeNavigationBar(title: "마이 페이지") {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Image("ic_settings")
.resizable()
.frame(width: 20, height: 20)
@ -54,6 +57,8 @@ struct MyPageView: View {
AppState.shared.setAppStep(step: .settings)
}
}
}
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
RefreshableScrollView(
refreshing: $viewModel.isLoading,
action: {
@ -206,14 +211,106 @@ struct MyPageView: View {
}
}
}
} 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)
ServiceCenterButtonView()
.padding(.horizontal, 13.3)
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
)
.onTapGesture {
UIApplication.shared.open(url)
}
}
}
}
}
}
.frame(width: geo.size.width, height: geo.size.height)
}
.onAppear {
if !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
viewModel.getMypage()
}
}
}
}
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) {
GeometryReader { geo in
HStack {

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,6 +20,9 @@ struct SettingsView: View {
GeometryReader { geo in
VStack(spacing: 0) {
DetailNavigationBar(title: "설정")
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
VStack(spacing: 0) {
HStack(spacing: 0) {
Text("공지사항")
@ -198,8 +201,6 @@ struct SettingsView: View {
.frame(width: cardWidth, alignment: .leading)
.padding(.top, 13.3)
Spacer()
Text("로그아웃")
.font(.custom(Font.bold.rawValue, size: 14.7))
.foregroundColor(Color.grayee)
@ -209,6 +210,7 @@ struct SettingsView: View {
.onTapGesture {
isShowLogoutDialog = true
}
.padding(.top, 46.7)
Text("모든 기기에서 로그아웃")
.font(.custom(Font.medium.rawValue, size: 14.7))
@ -228,6 +230,8 @@ struct SettingsView: View {
}
}
}
}
}
if isShowLogoutDialog {
SodaDialog(
@ -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 {
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 {
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