diff --git a/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListFeature.swift b/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListFeature.swift index b5797db0..59c9738c 100644 --- a/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListFeature.swift +++ b/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListFeature.swift @@ -7,6 +7,7 @@ import Foundation import ComposableArchitecture +import FeatureContentCard import Domain import CoreKit import DSKit @@ -32,14 +33,7 @@ public struct ContentListFeature { let contentType: ContentType fileprivate var domain = ContentList() - var contents: IdentifiedArrayOf? { - guard let contentList = domain.contentList.data else { - return nil - } - var identifiedArray = IdentifiedArrayOf() - contentList.forEach { identifiedArray.append($0) } - return identifiedArray - } + var contents: IdentifiedArrayOf = [] var contentCount: Int { get { domain.contentCount } } @@ -52,6 +46,7 @@ public struct ContentListFeature { var hasNext: Bool { domain.contentList.hasNext } + var isLoading: Bool = true } /// - Action @@ -61,6 +56,7 @@ public struct ContentListFeature { case async(AsyncAction) case scope(ScopeAction) case delegate(DelegateAction) + case contents(IdentifiedActionOf) @CasePathable public enum View: Equatable, BindableAction { @@ -102,11 +98,12 @@ public struct ContentListFeature { case 클립보드_감지 } - public enum ScopeAction: Equatable { + public enum ScopeAction { case bottomSheet( delegate: PokitBottomSheet.Delegate, content: BaseContentItem ) + case contents(IdentifiedActionOf) } public enum DelegateAction: Equatable { @@ -142,12 +139,18 @@ public struct ContentListFeature { /// - Delegate case .delegate(let delegateAction): return handleDelegateAction(delegateAction, state: &state) + + case let .contents(contentAction): + return .send(.scope(.contents(contentAction))) } } /// - Reducer body public var body: some ReducerOf { Reduce(self.core) + .forEach(\.contents, action: \.contents) { + ContentCardFeature() + } ._printChanges() } } @@ -208,6 +211,8 @@ private extension ContentListFeature { state.domain.contentList = contentList state.domain.contentList.data = list + newList + + newList.forEach { state.contents.append(.init(content: $0)) } return .none case .컨텐츠_삭제_API_반영(id: let id): state.alertItem = nil @@ -215,10 +220,16 @@ private extension ContentListFeature { return .none case .컨텐츠_목록_조회_API_반영(let contentList): state.domain.contentList = contentList + var identifiedArray = IdentifiedArrayOf() + contentList.data?.forEach { identifiedArray.append(.init(content: $0)) } + state.contents = identifiedArray + state.isLoading = false return .none case .페이징_초기화: state.domain.pageable.page = 0 state.domain.contentList.data = nil + state.isLoading = true + state.contents.removeAll() return .send(.async(.컨텐츠_목록_조회_API), animation: .pokitDissolve) case let .컨텐츠_개수_업데이트(count): state.domain.contentCount = count @@ -303,6 +314,14 @@ private extension ContentListFeature { state.shareSheetItem = content return .none } + + case let .contents(.element(id: _, action: .delegate(.컨텐츠_항목_눌렀을때(content)))): + return .send(.delegate(.링크상세(content: content))) + case let .contents(.element(id: _, action: .delegate(.컨텐츠_항목_케밥_버튼_눌렀을때(content)))): + state.bottomSheetItem = content + return .none + case .contents: + return .none } } @@ -353,7 +372,7 @@ private extension ContentListFeature { contentItems?.data = items + newItems } guard let contentItems else { return } - await send(.inner(.컨텐츠_목록_조회_API_반영(contentItems))) + await send(.inner(.컨텐츠_목록_조회_API_반영(contentItems)), animation: .pokitDissolve) } } diff --git a/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListView.swift b/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListView.swift index 53b6de19..533c73a5 100644 --- a/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListView.swift +++ b/Projects/Feature/FeatureContentList/Sources/ContentList/ContentListView.swift @@ -7,6 +7,7 @@ import SwiftUI import ComposableArchitecture +import FeatureContentCard import DSKit @ViewAction(for: ContentListFeature.self) @@ -86,8 +87,8 @@ private extension ContentListView { var list: some View { Group { - if let contents = store.contents { - if contents.isEmpty { + if !store.isLoading { + if store.contents.isEmpty { PokitCaution( image: .empty, titleKey: "즐겨찾기 링크가 없어요!", @@ -99,16 +100,17 @@ private extension ContentListView { } else { ScrollView { LazyVStack(spacing: 0) { - ForEach(contents) { content in - let isFirst = content == contents.first - let isLast = content == contents.last + ForEachStore( + store.scope(state: \.contents, action: \.contents) + ) { store in + let isFirst = store.state.id == self.store.contents.first?.id + let isLast = store.state.id == self.store.contents.last?.id - PokitLinkCard( - link: content, - action: { send(.컨텐츠_항목_눌렀을때(content: content)) }, - kebabAction: { send(.컨텐츠_항목_케밥_버튼_눌렀을때(content: content)) } + ContentCardView( + store: store, + isFirst: isFirst, + isLast: isLast ) - .divider(isFirst: isFirst, isLast: isLast) } if store.hasNext {