refactor(navigation): 전역 경로 기반 단일 내비게이션 흐름으로 전환한다

This commit is contained in:
Yu Sung
2026-03-06 16:34:44 +09:00
parent f145de87aa
commit 42ce09d927
34 changed files with 1181 additions and 873 deletions

View File

@@ -9,11 +9,12 @@ import SwiftUI
struct ContentAllByThemeView: View {
@StateObject var viewModel = ContentAllByThemeViewModel()
@State private var isInitialized = false
let themeId: Int
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(alignment: .leading, spacing: 0) {
DetailNavigationBar(title: viewModel.theme)
@@ -111,8 +112,11 @@ struct ContentAllByThemeView: View {
}
}
.onAppear {
viewModel.themeId = themeId
viewModel.getContentList()
if !isInitialized || viewModel.themeId != themeId {
viewModel.themeId = themeId
viewModel.getContentList()
isInitialized = true
}
}
}
}

View File

@@ -10,12 +10,13 @@ import SwiftUI
struct ContentAllView: View {
@StateObject var viewModel = ContentAllViewModel()
@State private var isInitialized = false
var isFree: Bool = false
var isPointAvailableOnly: Bool = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
DetailNavigationBar(title: isFree ? String(localized: "무료 콘텐츠 전체") : isPointAvailableOnly ? String(localized: "포인트 대여 전체") : String(localized: "콘텐츠 전체"))
@@ -78,63 +79,63 @@ struct ContentAllView: View {
ForEach(viewModel.contentList.indices, id: \.self) { idx in
let item = viewModel.contentList[idx]
NavigationLink {
ContentDetailView(contentId: item.contentId)
} label: {
VStack(alignment: .leading, spacing: 0) {
ZStack(alignment: .top) {
DownsampledKFImage(
url: URL(string: item.coverImageUrl),
size: CGSize(width: itemSize, height: itemSize)
)
.cornerRadius(16)
VStack(alignment: .leading, spacing: 0) {
ZStack(alignment: .top) {
DownsampledKFImage(
url: URL(string: item.coverImageUrl),
size: CGSize(width: itemSize, height: itemSize)
)
.cornerRadius(16)
HStack(alignment: .top, spacing: 0) {
Spacer()
HStack(alignment: .top, spacing: 0) {
Spacer()
if item.isPointAvailable {
Image("ic_point")
.padding(.top, 6)
.padding(.trailing, 6)
}
if item.isPointAvailable {
Image("ic_point")
.padding(.top, 6)
.padding(.trailing, 6)
}
}
Text(item.title)
.appFont(size: 18, weight: .regular)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(1)
.padding(.horizontal, 6)
.padding(.top, 8)
Text(item.creatorNickname)
.appFont(size: 14, weight: .regular)
.foregroundColor(Color(hex: "78909C"))
.lineLimit(1)
.padding(.horizontal, 6)
.padding(.top, 4)
}
.frame(width: itemSize)
.contentShape(Rectangle())
.onAppear {
if idx == viewModel.contentList.count - 1 {
viewModel.fetchData()
}
Text(item.title)
.appFont(size: 18, weight: .regular)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(1)
.padding(.horizontal, 6)
.padding(.top, 8)
Text(item.creatorNickname)
.appFont(size: 14, weight: .regular)
.foregroundColor(Color(hex: "78909C"))
.lineLimit(1)
.padding(.horizontal, 6)
.padding(.top, 4)
}
.frame(width: itemSize)
.contentShape(Rectangle())
.onAppear {
if idx == viewModel.contentList.count - 1 {
viewModel.fetchData()
}
}
.onTapGesture { AppState.shared.setAppStep(step: .contentDetail(contentId: item.contentId)) }
}
}
.padding(horizontalPadding)
}
}
.onAppear {
viewModel.isFree = isFree
viewModel.isPointAvailableOnly = isPointAvailableOnly
viewModel.getThemeList()
viewModel.fetchData()
if !isInitialized || viewModel.isFree != isFree || viewModel.isPointAvailableOnly != isPointAvailableOnly {
viewModel.isFree = isFree
viewModel.isPointAvailableOnly = isPointAvailableOnly
viewModel.getThemeList()
viewModel.fetchData()
isInitialized = true
}
}
}
}

View File

@@ -14,95 +14,92 @@ struct ContentNewAllItemView: View {
let item: GetAudioContentMainItem
var body: some View {
NavigationLink {
ContentDetailView(contentId: item.contentId)
} label: {
VStack(alignment: .leading, spacing: 8) {
ZStack(alignment: .bottom) {
KFImage(URL(string: item.coverImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: width,
height: width
)
VStack(alignment: .leading, spacing: 8) {
ZStack(alignment: .bottom) {
KFImage(URL(string: item.coverImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: width,
height: width
)
.resizable()
.scaledToFill()
.frame(width: width, height: width, alignment: .top)
.cornerRadius(2.7)
)
.resizable()
.scaledToFill()
.frame(width: width, height: width, alignment: .top)
.cornerRadius(2.7)
VStack(spacing: 0) {
Spacer()
VStack(spacing: 0) {
Spacer()
HStack(spacing: 0) {
HStack(spacing: 2) {
if item.price > 0 {
Image("ic_card_can_gray")
Text("\(item.price)")
.appFont(size: 8.5, weight: .medium)
.foregroundColor(Color.white)
} else {
Text("무료")
.appFont(size: 8.5, weight: .medium)
.foregroundColor(Color.white)
}
}
.padding(3)
.background(Color(hex: "333333").opacity(0.7))
.cornerRadius(10)
.padding(.leading, 2.7)
.padding(.bottom, 2.7)
Spacer()
HStack(spacing: 2) {
Text(item.duration)
HStack(spacing: 0) {
HStack(spacing: 2) {
if item.price > 0 {
Image("ic_card_can_gray")
Text("\(item.price)")
.appFont(size: 8.5, weight: .medium)
.foregroundColor(Color.white)
} else {
Text("무료")
.appFont(size: 8.5, weight: .medium)
.foregroundColor(Color.white)
}
.padding(3)
.background(Color(hex: "333333").opacity(0.7))
.cornerRadius(10)
.padding(.trailing, 2.7)
.padding(.bottom, 2.7)
}
.padding(3)
.background(Color(hex: "333333").opacity(0.7))
.cornerRadius(10)
.padding(.leading, 2.7)
.padding(.bottom, 2.7)
Spacer()
HStack(spacing: 2) {
Text(item.duration)
.appFont(size: 8.5, weight: .medium)
.foregroundColor(Color.white)
}
.padding(3)
.background(Color(hex: "333333").opacity(0.7))
.cornerRadius(10)
.padding(.trailing, 2.7)
.padding(.bottom, 2.7)
}
}
.frame(width: width, height: width)
Text(item.title)
.appFont(size: 13.3, weight: .medium)
.foregroundColor(Color(hex: "d2d2d2"))
.frame(width: width, alignment: .leading)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(2)
HStack(spacing: 5.3) {
KFImage(URL(string: item.creatorProfileImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: 21.3,
height: 21.3
)
)
.resizable()
.scaledToFill()
.frame(width: 21.3, height: 21.3)
.clipShape(Circle())
.onTapGesture { AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId)) }
Text(item.creatorNickname)
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.lineLimit(1)
}
.padding(.bottom, 10)
}
.frame(width: width)
.frame(width: width, height: width)
Text(item.title)
.appFont(size: 13.3, weight: .medium)
.foregroundColor(Color(hex: "d2d2d2"))
.frame(width: width, alignment: .leading)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(2)
HStack(spacing: 5.3) {
KFImage(URL(string: item.creatorProfileImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: 21.3,
height: 21.3
)
)
.resizable()
.scaledToFill()
.frame(width: 21.3, height: 21.3)
.clipShape(Circle())
.onTapGesture { AppState.shared.setAppStep(step: .creatorDetail(userId: item.creatorId)) }
Text(item.creatorNickname)
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.lineLimit(1)
}
.padding(.bottom, 10)
}
.frame(width: width)
.onTapGesture { AppState.shared.setAppStep(step: .contentDetail(contentId: item.contentId)) }
}
}

View File

@@ -10,11 +10,12 @@ import SwiftUI
struct ContentNewAllView: View {
@StateObject var viewModel = ContentNewAllViewModel()
@State private var isInitialized = false
let isFree: Bool
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(alignment: .leading, spacing: 13.3) {
DetailNavigationBar(title: isFree ? "최신 무료 콘텐츠" : "최신 콘텐츠")
@@ -82,9 +83,12 @@ struct ContentNewAllView: View {
}
}
.onAppear {
viewModel.isFree = isFree
viewModel.getThemeList()
viewModel.getNewContentList()
if !isInitialized || viewModel.isFree != isFree {
viewModel.isFree = isFree
viewModel.getThemeList()
viewModel.getNewContentList()
isInitialized = true
}
}
}
.navigationBarHidden(true)

View File

@@ -11,9 +11,10 @@ import Kingfisher
struct ContentRankingAllView: View {
@StateObject var viewModel = ContentRankingAllViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
DetailNavigationBar(title: "인기 콘텐츠")
@@ -44,97 +45,94 @@ struct ContentRankingAllView: View {
LazyVStack(spacing: 20) {
ForEach(0..<viewModel.contentRankingItemList.count, id: \.self) { index in
let item = viewModel.contentRankingItemList[index]
NavigationLink {
ContentDetailView(contentId: item.contentId)
} label: {
HStack(spacing: 0) {
KFImage(URL(string: item.coverImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: 66.7,
height: 66.7
)
HStack(spacing: 0) {
KFImage(URL(string: item.coverImageUrl))
.cancelOnDisappear(true)
.downsampling(
size: CGSize(
width: 66.7,
height: 66.7
)
.resizable()
.scaledToFill()
.frame(width: 66.7, height: 66.7, alignment: .top)
.clipped()
.cornerRadius(5.3)
Text("\(index + 1)")
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "3bb9f1"))
.padding(.horizontal, 12)
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 8) {
Text(item.themeStr)
.appFont(size: 8, weight: .medium)
.foregroundColor(Color(hex: "3bac6a"))
.padding(2.6)
.background(Color(hex: "28312b"))
.cornerRadius(2.6)
Text(item.duration)
.appFont(size: 8, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.padding(2.6)
.background(Color(hex: "222222"))
.cornerRadius(2.6)
if item.isPointAvailable {
Text("포인트")
.appFont(size: 8, weight: .medium)
.foregroundColor(.white)
.padding(2.6)
.background(Color(hex: "7849bc"))
.cornerRadius(2.6)
}
}
Text(item.creatorNickname)
.appFont(size: 10.7, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.padding(.vertical, 8)
Text(item.title)
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "d2d2d2"))
.lineLimit(2)
.padding(.top, 2.7)
}
Spacer()
if item.price > 0 {
HStack(spacing: 8) {
Image("ic_can")
.resizable()
.frame(width: 17, height: 17)
Text("\(item.price)")
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "909090"))
}
} else {
Text("무료")
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "ffffff"))
.padding(.horizontal, 5.3)
.padding(.vertical, 2.7)
.background(Color(hex: "cf5c37"))
)
.resizable()
.scaledToFill()
.frame(width: 66.7, height: 66.7, alignment: .top)
.clipped()
.cornerRadius(5.3)
Text("\(index + 1)")
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "3bb9f1"))
.padding(.horizontal, 12)
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 8) {
Text(item.themeStr)
.appFont(size: 8, weight: .medium)
.foregroundColor(Color(hex: "3bac6a"))
.padding(2.6)
.background(Color(hex: "28312b"))
.cornerRadius(2.6)
Text(item.duration)
.appFont(size: 8, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.padding(2.6)
.background(Color(hex: "222222"))
.cornerRadius(2.6)
if item.isPointAvailable {
Text("포인트")
.appFont(size: 8, weight: .medium)
.foregroundColor(.white)
.padding(2.6)
.background(Color(hex: "7849bc"))
.cornerRadius(2.6)
}
}
Text(item.creatorNickname)
.appFont(size: 10.7, weight: .medium)
.foregroundColor(Color(hex: "777777"))
.padding(.vertical, 8)
Text(item.title)
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "d2d2d2"))
.lineLimit(2)
.padding(.top, 2.7)
}
.frame(height: 66.7)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.contentRankingItemList.count - 1 {
viewModel.getContentRanking()
Spacer()
if item.price > 0 {
HStack(spacing: 8) {
Image("ic_can")
.resizable()
.frame(width: 17, height: 17)
Text("\(item.price)")
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "909090"))
}
} else {
Text("무료")
.appFont(size: 12, weight: .medium)
.foregroundColor(Color(hex: "ffffff"))
.padding(.horizontal, 5.3)
.padding(.vertical, 2.7)
.background(Color(hex: "cf5c37"))
.cornerRadius(2.6)
}
}
.frame(height: 66.7)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.contentRankingItemList.count - 1 {
viewModel.getContentRanking()
}
}
.onTapGesture { AppState.shared.setAppStep(step: .contentDetail(contentId: item.contentId)) }
}
}
}
@@ -165,8 +163,11 @@ struct ContentRankingAllView: View {
}
}
.onAppear {
viewModel.getContentRankingSortType()
viewModel.getContentRanking()
if !isInitialized {
viewModel.getContentRankingSortType()
viewModel.getContentRanking()
isInitialized = true
}
}
}
}

View File

@@ -21,7 +21,7 @@ struct ContentBoxView: View {
var body: some View {
ZStack {
NavigationView {
Group {
VStack(spacing: 13.3) {
DetailNavigationBar(title: I18n.ContentBox.title)

View File

@@ -11,9 +11,10 @@ struct ContentListView: View {
let userId: Int
@StateObject var viewModel = ContentListViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
HStack(spacing: 0) {
@@ -128,17 +129,14 @@ struct ContentListView: View {
ForEach(0..<viewModel.audioContentList.count, id: \.self) { index in
let audioContent = viewModel.audioContentList[index]
NavigationLink {
ContentDetailView(contentId: audioContent.contentId)
} label: {
ContentListItemView(item: audioContent)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.audioContentList.count - 1 {
viewModel.getAudioContentList()
}
ContentListItemView(item: audioContent)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.audioContentList.count - 1 {
viewModel.getAudioContentList()
}
}
}
.onTapGesture { AppState.shared.setAppStep(step: .contentDetail(contentId: audioContent.contentId)) }
}
}
.padding(.horizontal, 13.3)
@@ -147,9 +145,12 @@ struct ContentListView: View {
.padding(.top, 13.3)
}
.onAppear {
viewModel.userId = userId
viewModel.getCategoryList()
viewModel.getAudioContentList()
if !isInitialized || viewModel.userId != userId {
viewModel.userId = userId
viewModel.getCategoryList()
viewModel.getAudioContentList()
isInitialized = true
}
}
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .bottom, autohideIn: 2) {
HStack {

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct ContentCurationView: View {
@StateObject var viewModel = ContentCurationViewModel()
@State private var isInitialized = false
let title: String
let curationId: Int
@@ -21,7 +22,7 @@ struct ContentCurationView: View {
]
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
DetailNavigationBar(title: title)
@@ -119,8 +120,11 @@ struct ContentCurationView: View {
}
}
.onAppear {
viewModel.curationId = curationId
viewModel.getContentList()
if !isInitialized || viewModel.curationId != curationId {
viewModel.curationId = curationId
viewModel.getContentList()
isInitialized = true
}
}
}
}

View File

@@ -25,7 +25,7 @@ struct AudioContentCommentListView: View {
@State private var isShowMemberProfilePopup: Bool = false
var body: some View {
NavigationView {
Group {
ZStack {
VStack(spacing: 0) {
HStack(spacing: 0) {

View File

@@ -422,12 +422,15 @@ struct ContentDetailView: View {
.sheet(
isPresented: $isShowCommentListView,
content: {
AudioContentCommentListView(
isPresented: $isShowCommentListView,
creatorId: viewModel.audioContent!.creator.creatorId,
audioContentId: viewModel.audioContent!.contentId,
isShowSecret: viewModel.audioContent!.existOrdered
)
NavigationStack {
AudioContentCommentListView(
isPresented: $isShowCommentListView,
creatorId: viewModel.audioContent!.creator.creatorId,
audioContentId: viewModel.audioContent!.contentId,
isShowSecret: viewModel.audioContent!.existOrdered
)
}
.toolbar(.hidden, for: .navigationBar)
}
)
.popup(isPresented: $viewModel.isShowPopup, type: .toast, position: .top, autohideIn: 2) {

View File

@@ -10,9 +10,10 @@ import SwiftUI
struct ContentMainAlarmAllView: View {
@StateObject var viewModel = ContentMainAlarmAllViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(alignment: .leading, spacing: 13.3) {
DetailNavigationBar(title: "새로운 알람")
@@ -81,7 +82,10 @@ struct ContentMainAlarmAllView: View {
}
}
.onAppear {
viewModel.getContentMainAlarmAll()
if !isInitialized {
viewModel.getContentMainAlarmAll()
isInitialized = true
}
}
}
.navigationBarHidden(true)

View File

@@ -10,9 +10,10 @@ import SwiftUI
struct ContentMainAsmrAllView: View {
@StateObject var viewModel = ContentNewAllViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(alignment: .leading, spacing: 13.3) {
DetailNavigationBar(title: "새로운 ASMR")
@@ -72,7 +73,14 @@ struct ContentMainAsmrAllView: View {
}
}
.onAppear {
viewModel.selectedTheme = "ASMR"
if !isInitialized {
if viewModel.selectedTheme != "ASMR" {
viewModel.selectedTheme = "ASMR"
} else if viewModel.newContentList.isEmpty {
viewModel.getNewContentList()
}
isInitialized = true
}
}
}
.navigationBarHidden(true)

View File

@@ -46,7 +46,7 @@ struct ContentMainViewV2: View {
}
var body: some View {
NavigationView {
Group {
ZStack {
Color.black.ignoresSafeArea()

View File

@@ -10,9 +10,10 @@ import SwiftUI
struct ContentMainIntroduceCreatorAllView: View {
@StateObject var viewModel = ContentMainIntroduceCreatorAllViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 13.3) {
DetailNavigationBar(title: "크리에이터 소개")
@@ -48,7 +49,10 @@ struct ContentMainIntroduceCreatorAllView: View {
}
}
.onAppear {
viewModel.getIntroduceCreatorList()
if !isInitialized {
viewModel.getIntroduceCreatorList()
isInitialized = true
}
}
}
.navigationBarHidden(true)

View File

@@ -10,9 +10,10 @@ import SwiftUI
struct ContentMainReplayAllView: View {
@StateObject var viewModel = ContentNewAllViewModel()
@State private var isInitialized = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(alignment: .leading, spacing: 13.3) {
DetailNavigationBar(title: "새로운 라이브 다시듣기")
@@ -72,7 +73,14 @@ struct ContentMainReplayAllView: View {
}
}
.onAppear {
viewModel.selectedTheme = "다시듣기"
if !isInitialized {
if viewModel.selectedTheme != "다시듣기" {
viewModel.selectedTheme = "다시듣기"
} else if viewModel.newContentList.isEmpty {
viewModel.getNewContentList()
}
isInitialized = true
}
}
}
.navigationBarHidden(true)

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct SeriesMainByGenreView: View {
@StateObject var viewModel = SeriesMainByGenreViewModel()
@State private var isInitialized = false
var body: some View {
ZStack {
@@ -41,17 +42,16 @@ struct SeriesMainByGenreView: View {
) {
ForEach(viewModel.seriesList.indices, id: \.self) { index in
let item = viewModel.seriesList[index]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getSeriesListByGenre()
}
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getSeriesListByGenre()
}
}
}
.onTapGesture {
AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
}
}
}
.padding(.horizontal, horizontalPadding)
@@ -73,7 +73,10 @@ struct SeriesMainByGenreView: View {
}
}
.onAppear {
viewModel.getGenreList()
if !isInitialized {
viewModel.getGenreList()
isInitialized = true
}
}
if viewModel.isLoading {

View File

@@ -75,17 +75,14 @@ struct SeriesMainDayOfWeekView: View {
) {
ForEach(viewModel.seriesList.indices, id: \.self) { index in
let item = viewModel.seriesList[index]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getDayOfWeekSeriesList(dayOfWeek: dayOfWeek)
}
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getDayOfWeekSeriesList(dayOfWeek: dayOfWeek)
}
}
}
.onTapGesture { AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId)) }
}
}
.padding(.horizontal, horizontalPadding)

View File

@@ -22,11 +22,8 @@ struct SeriesMainHomeBannerView: View {
ForEach(0..<bannerList.count, id: \.self) { index in
let item = bannerList[index]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainHomeBannerImageView(url: item.imagePath, width: width, height: height)
}
SeriesMainHomeBannerImageView(url: item.imagePath, width: width, height: height)
.onTapGesture { AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId)) }
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))

View File

@@ -10,6 +10,7 @@ import SwiftUI
struct SeriesMainHomeView: View {
@StateObject var viewModel = SeriesMainHomeViewModel()
@State private var isInitialized = false
var body: some View {
ZStack {
@@ -43,11 +44,10 @@ struct SeriesMainHomeView: View {
LazyHStack(spacing: 16) {
ForEach(0..<viewModel.completedSeriesList.count, id: \.self) {
let item = viewModel.completedSeriesList[$0]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainItemView(item: item)
}
SeriesMainItemView(item: item)
.onTapGesture {
AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
}
}
}
.padding(.horizontal, 24)
@@ -89,11 +89,10 @@ struct SeriesMainHomeView: View {
) {
ForEach(viewModel.recommendSeriesList.indices, id: \.self) {
let item = viewModel.recommendSeriesList[$0]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
}
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.onTapGesture {
AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
}
}
}
.padding(.horizontal, horizontalPadding)
@@ -117,7 +116,10 @@ struct SeriesMainHomeView: View {
}
}
.onAppear {
viewModel.fetchHome()
if !isInitialized {
viewModel.fetchHome()
isInitialized = true
}
}
if viewModel.isLoading {

View File

@@ -25,7 +25,7 @@ struct SeriesMainView: View {
@State private var selectedTab: InnerTab = .home
var body: some View {
NavigationView {
Group {
BaseView {
VStack(spacing: 0) {
DetailNavigationBar(title: "시리즈 전체보기")

View File

@@ -9,7 +9,8 @@ import SwiftUI
struct SeriesListAllView: View {
@ObservedObject var viewModel = SeriesListAllViewModel()
@StateObject var viewModel = SeriesListAllViewModel()
@State private var isInitialized = false
var creatorId: Int? = nil
var creatorNickname: String? = nil
@@ -18,7 +19,7 @@ struct SeriesListAllView: View {
var isCompleted = false
var body: some View {
NavigationView {
Group {
BaseView(isLoading: $viewModel.isLoading) {
VStack(spacing: 0) {
if isCompleted {
@@ -48,17 +49,16 @@ struct SeriesListAllView: View {
) {
ForEach(0..<viewModel.seriesList.count, id: \.self) { index in
let item = viewModel.seriesList[index]
NavigationLink {
SeriesDetailView(seriesId: item.seriesId)
} label: {
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getSeriesList()
}
SeriesMainItemView(item: item, width: width, height: width * 227 / 160)
.contentShape(Rectangle())
.onAppear {
if index == viewModel.seriesList.count - 1 {
viewModel.getSeriesList()
}
}
}
.onTapGesture {
AppState.shared.setAppStep(step: .seriesDetail(seriesId: item.seriesId))
}
}
}
.padding(horizontalPadding)
@@ -67,10 +67,24 @@ struct SeriesListAllView: View {
}
}
.onAppear {
viewModel.creatorId = creatorId
viewModel.isOriginal = isOriginal
viewModel.isCompleted = isCompleted
viewModel.getSeriesList()
let hasFilterChanged =
viewModel.creatorId != creatorId ||
viewModel.isOriginal != isOriginal ||
viewModel.isCompleted != isCompleted
if !isInitialized || hasFilterChanged {
if hasFilterChanged {
viewModel.page = 1
viewModel.isLast = false
viewModel.seriesList.removeAll()
}
viewModel.creatorId = creatorId
viewModel.isOriginal = isOriginal
viewModel.isCompleted = isCompleted
viewModel.getSeriesList()
isInitialized = true
}
}
}
}