diff --git a/Projects/App/Resources/Pokit-info.plist b/Projects/App/Resources/Pokit-info.plist index 98d454b2..ff684a8a 100644 --- a/Projects/App/Resources/Pokit-info.plist +++ b/Projects/App/Resources/Pokit-info.plist @@ -21,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0.0 + 2.0.1 CFBundleURLTypes diff --git a/Projects/App/ShareExtension/Info.plist b/Projects/App/ShareExtension/Info.plist index 8a334c06..c2ade449 100644 --- a/Projects/App/ShareExtension/Info.plist +++ b/Projects/App/ShareExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleName Pokit CFBundleShortVersionString - 1.0.9 + 2.0.1 CFBundleURLTypes diff --git a/Projects/App/Sources/MainTab/MainTabFeatureView.swift b/Projects/App/Sources/MainTab/MainTabFeatureView.swift index 0fbfd373..4dcee06a 100644 --- a/Projects/App/Sources/MainTab/MainTabFeatureView.swift +++ b/Projects/App/Sources/MainTab/MainTabFeatureView.swift @@ -74,10 +74,8 @@ public extension MainTabView { } if self.store.linkPopup != nil { - PokitLinkPopup( - type: $store.linkPopup, - action: { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } - ) + PokitLinkPopup(type: $store.linkPopup) + .onAction { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } } } } @@ -93,11 +91,9 @@ private extension MainTabView { .overlay(alignment: .bottom) { VStack(spacing: 0) { if store.linkPopup != nil { - PokitLinkPopup( - type: $store.linkPopup, - action: { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } - ) - .padding(.bottom, 20) + PokitLinkPopup(type: $store.linkPopup) + .onAction { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } + .padding(.bottom, 20) } bottomTabBar diff --git a/Projects/App/Sources/MainTab/MainTabPath.swift b/Projects/App/Sources/MainTab/MainTabPath.swift index 68d1e33c..fbd1782d 100644 --- a/Projects/App/Sources/MainTab/MainTabPath.swift +++ b/Projects/App/Sources/MainTab/MainTabPath.swift @@ -194,13 +194,13 @@ public extension MainTabFeature { case .검색: return .merge( .send(.path(.element(id: stackElementId, action: .검색(.delegate(.컨텐츠_검색))))), - .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구))), animation: .pokitSpring) + .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구, until: 4))), animation: .pokitSpring) ) default: - return .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구))), animation: .pokitSpring) + return .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구, until: 4))), animation: .pokitSpring) } case .recommend(.delegate(.저장하기_완료)): - return .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구))), animation: .pokitSpring) + return .send(.inner(.링크팝업_활성화(.success(title: Constants.링크_저장_완료_문구, until: 4))), animation: .pokitSpring) /// - 각 화면에서 링크 복사 감지했을 때 (링크 추가 및 수정 화면 제외) case let .path(.element(_, action: .알림함(.delegate(.linkCopyDetected(url))))), let .path(.element(_, action: .검색(.delegate(.linkCopyDetected(url))))), diff --git a/Projects/DSKit/Sources/Components/PokitCaution.swift b/Projects/DSKit/Sources/Components/PokitCaution.swift index e2ced148..82baabdd 100644 --- a/Projects/DSKit/Sources/Components/PokitCaution.swift +++ b/Projects/DSKit/Sources/Components/PokitCaution.swift @@ -84,9 +84,14 @@ public struct PokitCaution: View { private let type: CautionType private let action: (() -> Void)? - public init( + public init(type: CautionType) { + self.type = type + self.action = nil + } + + private init( type: CautionType, - action: (() -> Void)? = nil + action: (() -> Void)? ) { self.type = type self.action = action @@ -132,11 +137,15 @@ public struct PokitCaution: View { .frame(maxHeight: .infinity) .padding(.bottom, 92) } + + public func onAction(_ action: @escaping () -> Void) -> Self { + PokitCaution(type: self.type, action: action) + } } #Preview { - PokitCaution( - type: .미분류_링크없음, - action: {} - ) + PokitCaution(type: .미분류_링크없음) + .onAction { + + } } diff --git a/Projects/DSKit/Sources/Components/PokitLinkPopup.swift b/Projects/DSKit/Sources/Components/PokitLinkPopup.swift index 866acb2d..84057cc3 100644 --- a/Projects/DSKit/Sources/Components/PokitLinkPopup.swift +++ b/Projects/DSKit/Sources/Components/PokitLinkPopup.swift @@ -15,17 +15,36 @@ public struct PokitLinkPopup: View { @State private var second: Int = 0 private let action: (() -> Void)? + private let until: Int private let timer = Timer.publish( every: 1, on: .main, in: .common ).autoconnect() - public init( + public init(type: Binding) { + self._type = type + switch type.wrappedValue { + case let .link(_, _, until), + let .text(_, until), + let .success(_, until), + let .error(_, until), + let .warning(_, until), + let .report(_, until): + self.until = until + default: + self.until = 2 + } + self.action = nil + } + + private init( type: Binding, - action: (() -> Void)? = nil + until: Int, + action: (() -> Void)? ) { self._type = type + self.until = until self.action = action } @@ -40,7 +59,7 @@ public struct PokitLinkPopup: View { .frame(width: 335, height: 60) .transition(.move(edge: .bottom).combined(with: .opacity)) .onReceive(timer) { _ in - guard second < 2 else { + guard second < until else { closedPopup() return } @@ -61,7 +80,7 @@ public struct PokitLinkPopup: View { .multilineTextAlignment(.leading) .foregroundStyle(textColor) - if case let .link(_, url) = type { + if case let .link(_, url, _) = type { Text(url) .lineLimit(1) .pokitFont(.detail2) @@ -167,26 +186,34 @@ public struct PokitLinkPopup: View { private var title: String { switch type { - case let .link(title, _), - let .text(title), - let .success(title), - let .error(title), - let .warning(title), - let .report(title): + case let .link(title, _, _), + let .text(title, _), + let .success(title, _), + let .error(title, _), + let .warning(title, _), + let .report(title, _): return title default: return "" } } + + public func onAction(_ action: @escaping () -> Void) -> Self { + PokitLinkPopup( + type: self.$type, + until: self.until, + action: action + ) + } } public extension PokitLinkPopup { enum PopupType: Equatable { - case link(title: String, url: String) - case text(title: String) - case success(title: String) - case error(title: String) - case warning(title: String) - case report(title: String) + case link(title: String, url: String, until: Int = 2) + case text(title: String, until: Int = 2) + case success(title: String, until: Int = 2) + case error(title: String, until: Int = 2) + case warning(title: String, until: Int = 2) + case report(title: String, until: Int = 2) } } diff --git a/Projects/Domain/Sources/Base/BaseContentItem.swift b/Projects/Domain/Sources/Base/BaseContentItem.swift index 27ebd387..bddcb66d 100644 --- a/Projects/Domain/Sources/Base/BaseContentItem.swift +++ b/Projects/Domain/Sources/Base/BaseContentItem.swift @@ -19,7 +19,7 @@ public struct BaseContentItem: Identifiable, Equatable, PokitLinkCardItem, Sorta public let data: String public let domain: String public let createdAt: String - public let isRead: Bool? + public var isRead: Bool? public var isFavorite: Bool? public let keyword: String? diff --git a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailFeature.swift b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailFeature.swift index 0425f105..9b3a9c24 100644 --- a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailFeature.swift +++ b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailFeature.swift @@ -65,9 +65,6 @@ public struct CategoryDetailFeature { domain.contentList.hasNext } var isLoading: Bool = true - var isContentsNotEmpty: Bool { - (isFavoriteCategory && contents.contains { $0.content.isFavorite == true }) || (!isFavoriteCategory && !contents.isEmpty) - } public init(category: BaseCategoryItem) { self.domain = .init(categpry: category) @@ -199,11 +196,14 @@ private extension CategoryDetailFeature { ) case let .분류_버튼_눌렀을때(type): - if type == .즐겨찾기 { + switch type { + case .즐겨찾기: state.domain.condition.isFavoriteFlitered.toggle() + guard state.domain.condition.isFavoriteFlitered else { break } state.domain.condition.isUnreadFlitered = !state.domain.condition.isFavoriteFlitered - } else { + case .안읽음: state.domain.condition.isUnreadFlitered.toggle() + guard state.domain.condition.isUnreadFlitered else { break } state.domain.condition.isFavoriteFlitered = !state.domain.condition.isUnreadFlitered } return .concatenate( diff --git a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift index 5d0d80f6..7e319ed7 100644 --- a/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift +++ b/Projects/Feature/FeatureCategoryDetail/Sources/CategoryDetailView.swift @@ -65,7 +65,7 @@ public extension CategoryDetailView { .padding(.top, 12) .pokitNavigationBar { navigationBar } .overlay( - if: store.isContentsNotEmpty, + if: !store.isFavoriteCategory, alignment: .bottomTrailing ) { Button(action: { send(.링크_추가_버튼_눌렀을때) }) { @@ -215,30 +215,32 @@ private extension CategoryDetailView { var filterHeader: some View { let isFavoriteCategory = store.isFavoriteCategory let favoriteContentsCount = store.contents.filter { $0.content.isFavorite ?? false }.count - if store.isContentsNotEmpty { - HStack(spacing: isFavoriteCategory ? 2 : 8) { - if isFavoriteCategory { - Image(.icon(.link)) - .resizable() - .frame(width: 16, height: 16) - .foregroundStyle(.pokit(.icon(.secondary))) - Text("\(favoriteContentsCount)개") - .foregroundStyle(.pokit(.text(.tertiary))) - .pokitFont(.b2(.m)) - } else { - favoriteButton - - unreadButton - } + + HStack(spacing: isFavoriteCategory ? 2 : 8) { + if isFavoriteCategory { + Image(.icon(.link)) + .resizable() + .frame(width: 16, height: 16) + .foregroundStyle(.pokit(.icon(.secondary))) - Spacer() - PokitIconLTextLink( - store.sortType.title, - icon: .icon(.align), - action: { send(.정렬_버튼_눌렀을때) } - ) - .contentTransition(.numericText()) + Text("\(favoriteContentsCount)개") + .foregroundStyle(.pokit(.text(.tertiary))) + .pokitFont(.b2(.m)) + + } else { + favoriteButton + + unreadButton } + + Spacer() + + PokitIconLTextLink( + store.sortType.title, + icon: .icon(.align), + action: { send(.정렬_버튼_눌렀을때) } + ) + .contentTransition(.numericText()) } } @@ -286,53 +288,47 @@ private extension CategoryDetailView { } } + @ViewBuilder var contentScrollView: some View { - Group { - if !store.isLoading { - if store.contents.isEmpty { - PokitCaution( - type: .포킷상세_링크없음, - action: { send(.링크_추가_버튼_눌렀을때) } - ) - } else { - LazyVStack(spacing: 0) { - ForEach( - Array(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 - - if !self.store.isFavoriteCategory { - ContentCardView( - store: store, - type: .linkList, - isFirst: isFirst, - isLast: isLast - ) - } else { - if store.content.isFavorite == true { - ContentCardView( - store: store, - type: .linkList, - isFirst: isFirst, - isLast: isLast - ) - } - } - } + if !store.isLoading { + if store.contents.isEmpty { + PokitCaution(type: .포킷상세_링크없음) + } else { + LazyVStack(spacing: 0) { + ForEach( + Array(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 - if store.hasNext { - PokitLoading() - .task { await send(.pagenation).finish() } + if !self.store.isFavoriteCategory { + ContentCardView( + store: store, + type: .linkList, + isFirst: isFirst, + isLast: isLast + ) + } else if store.content.isFavorite == true { + ContentCardView( + store: store, + type: .linkList, + isFirst: isFirst, + isLast: isLast + ) } - - Spacer() } - .padding(.bottom, 36) + + if store.hasNext { + PokitLoading() + .task { await send(.pagenation).finish() } + } + + Spacer() } - } else { - PokitLoading() + .padding(.bottom, 36) } + } else { + PokitLoading() } } diff --git a/Projects/Feature/FeatureContentCard/Sources/ContentCard/ContentCardFeature.swift b/Projects/Feature/FeatureContentCard/Sources/ContentCard/ContentCardFeature.swift index d5bfae8c..12fd5eb3 100644 --- a/Projects/Feature/FeatureContentCard/Sources/ContentCard/ContentCardFeature.swift +++ b/Projects/Feature/FeatureContentCard/Sources/ContentCard/ContentCardFeature.swift @@ -52,6 +52,7 @@ public struct ContentCardFeature { public enum InnerAction: Equatable { case 메타데이터_조회_수행_반영(String) case 즐겨찾기_API_반영(Bool) + case 컨텐츠_상세_조회_API_반영 } @CasePathable @@ -60,6 +61,7 @@ public struct ContentCardFeature { case 즐겨찾기_API case 즐겨찾기_취소_API case 썸네일_수정_API + case 컨텐츠_상세_조회_API } public enum ScopeAction: Equatable { case doNothing } @@ -111,7 +113,10 @@ private extension ContentCardFeature { guard let url = URL(string: state.content.data) else { return .none } - return .run { _ in await openURL(url) } + return .run { send in + await send(.async(.컨텐츠_상세_조회_API)) + await openURL(url) + } case .컨텐츠_항목_케밥_버튼_눌렀을때: return .send(.delegate(.컨텐츠_항목_케밥_버튼_눌렀을때(content: state.content))) case .메타데이터_조회: @@ -137,6 +142,9 @@ private extension ContentCardFeature { case .즐겨찾기_API_반영(let favorite): state.content.isFavorite = favorite return .none + case .컨텐츠_상세_조회_API_반영: + state.content.isRead = true + return .none } } @@ -167,6 +175,11 @@ private extension ContentCardFeature { try await contentClient.썸네일_수정("\(content.id)", request) } + case .컨텐츠_상세_조회_API: + return .run { [id = state.content.id] send in + let _ = try await contentClient.컨텐츠_상세_조회("\(id)") + await send(.inner(.컨텐츠_상세_조회_API_반영)) + } } } diff --git a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift index e8d33455..76c032e9 100644 --- a/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift +++ b/Projects/Feature/FeatureContentSetting/Sources/ContentSetting/ContentSettingView.swift @@ -46,10 +46,9 @@ public extension ContentSettingView { } .overlay(alignment: .bottom) { if store.linkPopup != nil { - PokitLinkPopup( - type: $store.linkPopup, - action: { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } - ) + PokitLinkPopup(type: $store.linkPopup) + .onAction { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } + } } .pokitMaxWidth() diff --git a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift index 61a291ce..2b9df4b5 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditFeature.swift @@ -32,7 +32,7 @@ public struct PokitLinkEditFeature { var list = IdentifiedArrayOf() /// 선택한 링크 목록 var selectedItems = IdentifiedArrayOf() - var isActive: Bool = false + var isActive: Bool { !selectedItems.isEmpty } /// 포킷 이동 눌렀을 때 sheet var categorySelectSheetPresetend: Bool = false var linkDeleteSheetPresented: Bool = false @@ -160,8 +160,6 @@ private extension PokitLinkEditFeature { } else { state.selectedItems.append(item) } - - state.isActive = !state.selectedItems.isEmpty return .none case let .카테고리_선택했을때(pokit): @@ -257,12 +255,10 @@ private extension PokitLinkEditFeature { case .전체선택_버튼_눌렀을때: state.selectedItems = state.list - state.isActive = !state.selectedItems.isEmpty return .none case .전체해제_버튼_눌렀을때: state.selectedItems.removeAll() - state.isActive = !state.selectedItems.isEmpty return .none case .포킷이동_버튼_눌렀을때: diff --git a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift index 1c6b7e56..26307a7c 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitLinkEditView.swift @@ -63,11 +63,9 @@ public extension PokitLinkEditView { } .overlay(alignment: .bottom) { if store.linkPopup != nil { - PokitLinkPopup( - type: $store.linkPopup, - action: { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } - ) - .pokitMaxWidth() + PokitLinkPopup(type: $store.linkPopup) + .onAction { send(.링크팝업_버튼_눌렀을때, animation: .pokitSpring) } + .pokitMaxWidth() } } /// fullScreenCover를 통해 새로운 Destination을 만들었음 @@ -123,7 +121,7 @@ private extension PokitLinkEditView { var actionFloatButtonView: some View { PokitLinkEditFloatView( - isActive: $store.isActive, + isActive: store.isActive, delegateSend: { store.send(.scope(.floatButtonAction($0))) } ) } diff --git a/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift b/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift index f5771274..91e46d4f 100644 --- a/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift +++ b/Projects/Feature/FeaturePokit/Sources/PokitRootView.swift @@ -134,10 +134,8 @@ private extension PokitRootView { var pokitView: some View { if let categories = store.categories { if categories.isEmpty { - PokitCaution( - type: .카테고리없음, - action: { send(.포킷추가_버튼_눌렀을때) } - ) + PokitCaution(type: .카테고리없음) + .onAction { send(.포킷추가_버튼_눌렀을때) } } else { pokitList(categories) } @@ -181,10 +179,8 @@ private extension PokitRootView { var unclassifiedView: some View { if !store.isLoading { if store.contents.isEmpty { - PokitCaution( - type: .미분류_링크없음, - action: { send(.링크추가_버튼_눌렀을때) } - ) + PokitCaution(type: .미분류_링크없음) + .onAction { send(.링크추가_버튼_눌렀을때) } } else { unclassifiedList .padding(.top, 20) diff --git a/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift b/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift index 5b94da51..db0bc79b 100644 --- a/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift +++ b/Projects/Feature/FeaturePokit/Sources/Sheet/PokitLinkEditFloatView.swift @@ -11,14 +11,14 @@ import SwiftUI public struct PokitLinkEditFloatView: View { /// 전체 선택/해제 toggle @State private var isChecked: Bool = false - @Binding private var isActive: Bool + private let isActive: Bool private let delegateSend: ((PokitLinkEditFloatView.Delegate) -> Void)? public init( - isActive: Binding, + isActive: Bool, delegateSend: ((PokitLinkEditFloatView.Delegate) -> Void)? ) { - self._isActive = isActive + self.isActive = isActive self.delegateSend = delegateSend } @@ -114,7 +114,7 @@ public extension PokitLinkEditFloatView { } #Preview { PokitLinkEditFloatView( - isActive: .constant(true), + isActive: true, delegateSend: {_ in } ).padding(20) } diff --git a/Projects/Feature/FeatureRecommend/Sources/Recommend/RecommendFeature.swift b/Projects/Feature/FeatureRecommend/Sources/Recommend/RecommendFeature.swift index 9f3376db..df1ba34b 100644 --- a/Projects/Feature/FeatureRecommend/Sources/Recommend/RecommendFeature.swift +++ b/Projects/Feature/FeatureRecommend/Sources/Recommend/RecommendFeature.swift @@ -168,7 +168,7 @@ private extension RecommendFeature { case .onAppear: return .merge( shared(.async(.추천_조회_API), state: &state), - shared(.async(.유저_관심사_조회_API), state: &state) + shared(.async(.관심사_조회_API), state: &state) ) case .pagination: return shared(.async(.추천_조회_페이징_API), state: &state) @@ -215,7 +215,8 @@ private extension RecommendFeature { guard let url = URL(string: urlString) else { return .none } return .run { _ in await openURL(url) } case .관심사_편집_버튼_눌렀을때: - return shared(.async(.관심사_조회_API), state: &state) + state.showKeywordSheet = true + return .none case let .키워드_선택_버튼_눌렀을때(interests): state.showKeywordSheet = false state.selectedInterest = nil @@ -255,14 +256,18 @@ private extension RecommendFeature { state.isLoading = false return .none case let .유저_관심사_조회_API_반영(interests): - state.domain.myInterests = interests - interests.forEach { state.selectedInterestList.insert($0) } + state.domain.myInterests = interests.filter { interest in + state.interests.contains(interest) + } + interests.forEach { + guard state.interests.contains($0) else { return } + state.selectedInterestList.insert($0) + } return .none case let .관심사_조회_API_반영(interests): state.domain.interests = interests.filter({ interest in interest.code != "default" }) - state.showKeywordSheet = true return .none case let .컨텐츠_신고_API_반영(contentId): state.domain.contentList.data?.removeAll(where: { $0.id == contentId }) @@ -319,13 +324,20 @@ private extension RecommendFeature { return contentListFetch(state: &state) case .유저_관심사_조회_API: return .run { send in - let interests = try await userClient.유저_관심사_목록_조회().map { $0.toDomian() } + let interests = try await userClient.유저_관심사_목록_조회() + .map { $0.toDomian() } + .sorted { $0.description < $1.description } + await send(.inner(.유저_관심사_조회_API_반영(interests))) } case .관심사_조회_API: return .run { send in - let interests = try await userClient.관심사_목록_조회().map { $0.toDomian() } + let interests = try await userClient.관심사_목록_조회() + .map { $0.toDomian() } + .sorted { $0.description < $1.description } + await send(.inner(.관심사_조회_API_반영(interests))) + await send(.async(.유저_관심사_조회_API)) } case let .컨텐츠_신고_API(contentId): return .run { send in diff --git a/Projects/Feature/FeatureSetting/Sources/Alert/PokitAlertBoxView.swift b/Projects/Feature/FeatureSetting/Sources/Alert/PokitAlertBoxView.swift index f0e1e0ce..d658ebca 100644 --- a/Projects/Feature/FeatureSetting/Sources/Alert/PokitAlertBoxView.swift +++ b/Projects/Feature/FeatureSetting/Sources/Alert/PokitAlertBoxView.swift @@ -30,7 +30,7 @@ public extension PokitAlertBoxView { if alertContents.isEmpty { VStack { PokitCaution(type: .알림없음) - .padding(.top, 84) + .padding(.top, 84) Spacer() } } else { diff --git a/Projects/Feature/FeatureSetting/Sources/Search/PokitSearchView.swift b/Projects/Feature/FeatureSetting/Sources/Search/PokitSearchView.swift index 6a819894..2225fda2 100644 --- a/Projects/Feature/FeatureSetting/Sources/Search/PokitSearchView.swift +++ b/Projects/Feature/FeatureSetting/Sources/Search/PokitSearchView.swift @@ -265,30 +265,21 @@ private extension PokitSearchView { var resultList: some View { VStack(alignment: .leading, spacing: 20) { + if store.isSearching { + PokitIconLTextLink( + store.isResultAscending ? "오래된순" : "최신순", + icon: .icon(.align), + action: { send(.정렬_버튼_눌렀을때) } + ) + .contentTransition(.numericText()) + .padding(.horizontal, 20) + } + if !store.isLoading { - ScrollView { - LazyVStack(spacing: 0) { - ForEach( - Array(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 - - ContentCardView( - store: store, - type: .linkList, - isFirst: isFirst, - isLast: isLast - ) - } - - if store.hasNext { - PokitLoading() - .task { await send(.로딩중일때, animation: .pokitDissolve).finish() } - } - } - .padding(.horizontal, 20) - .padding(.bottom, 36) + if store.contents.isEmpty && store.isSearching { + resultEmptyLabel + } else { + resultListContent } } else { PokitLoading() @@ -296,6 +287,47 @@ private extension PokitSearchView { } .padding(.top, 24) } + + var resultListContent: some View { + ScrollView { + LazyVStack(spacing: 0) { + ForEach( + Array(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 + + ContentCardView( + store: store, + type: .linkList, + isFirst: isFirst, + isLast: isLast + ) + } + + if store.hasNext { + PokitLoading() + .task { await send(.로딩중일때, animation: .pokitDissolve).finish() } + } + } + .padding(.horizontal, 20) + .padding(.bottom, 36) + } + } + + var resultEmptyLabel: some View { + VStack(spacing: 8) { + Text("검색어가 없어요") + .pokitFont(.title2) + + Text("링크 제목, 포킷으로 검색해주세요") + .pokitFont(.b2(.m)) + } + .padding(.top, 100) + .padding(.bottom, 80) + .frame(maxWidth: .infinity) + .foregroundStyle(.pokit(.text(.tertiary))) + } } //MARK: - Preview #Preview { diff --git a/Projects/Util/Sources/Constants.swift b/Projects/Util/Sources/Constants.swift index 4c12153f..a5ff72ed 100644 --- a/Projects/Util/Sources/Constants.swift +++ b/Projects/Util/Sources/Constants.swift @@ -28,7 +28,7 @@ public enum Constants { public static let 포킷_최대_갯수_문구: String = "최대 30개의 포킷을 생성할 수 있습니다.\n포킷을 삭제한 뒤에 추가해주세요." public static let 복사한_링크_저장하기_문구: String = "복사한 링크 저장하기" public static let 제목을_입력해주세요_문구: String = "제목을 입력해주세요" - public static let 링크_저장_완료_문구: String = "링크 저장 완료" + public static let 링크_저장_완료_문구: String = "저정한 링크 보러가기" public static let 메모_수정_완료_문구: String = "메모 수정 완료" public static let 한글_영어_숫자_입력_문구: String = "한글, 영어, 숫자로만 입력이 가능합니다." diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 164214f1..04ed08e4 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -41,6 +41,7 @@ platform :ios do workspace: "Pokit.xcworkspace", scheme: "App", configuration: "Debug", + destination: "platform=iOS Simulator,name=iPhone 15,OS=17.5", export_method: "development", export_options: { provisioningProfiles: { @@ -72,6 +73,7 @@ platform :ios do workspace: "Pokit.xcworkspace", scheme: "App", configuration: "Release", + destination: "generic/platform=iOS", export_method: "app-store", export_options: { provisioningProfiles: {