refactor(navigation): 전역 경로 기반 단일 내비게이션 흐름으로 전환한다
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user