Skip to content

Commit

Permalink
Merge pull request #185 from YAPP-Github/feat/#180-recommend
Browse files Browse the repository at this point in the history
feat: [2.0.0] ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ์— ๋”ฐ๋ฅธ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋ฐ ์ˆ˜์ •(๋งํฌ ์ถ”์ฒœ)
  • Loading branch information
ShapeKim98 authored Feb 4, 2025
2 parents dbcbb18 + a2ce3f0 commit 9aca4aa
Show file tree
Hide file tree
Showing 35 changed files with 883 additions and 739 deletions.
4 changes: 2 additions & 2 deletions Projects/App/Sources/MainTab/MainTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import DSKit

public enum MainTab: String, CaseIterable {
case pokit = "ํฌํ‚ท"
case remind = "๋ฆฌ๋งˆ์ธ๋“œ"
case recommend = "๋งํฌ์ถ”์ฒœ"

var title: String { return self.rawValue }

var icon: PokitImage {
switch self {
case .pokit: return .icon(.folderFill)
case .remind: return .icon(.remind)
case .recommend: return .icon(.remind)
}
}
}
41 changes: 36 additions & 5 deletions Projects/App/Sources/MainTab/MainTabFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SwiftUI

import ComposableArchitecture
import FeaturePokit
import FeatureRemind
import FeatureRecommend
import FeatureContentDetail
import Domain
import DSKit
Expand Down Expand Up @@ -37,7 +37,7 @@ public struct MainTabFeature {

var path: StackState<MainTabPath.State> = .init()
var pokit: PokitRootFeature.State
var remind: RemindFeature.State = .init()
var recommend: RecommendFeature.State = .init()
@Presents var contentDetail: ContentDetailFeature.State?
@Shared(.inMemory("SelectCategory")) var categoryId: Int?
@Shared(.inMemory("PushTapped")) var isPushTapped: Bool = false
Expand All @@ -59,7 +59,7 @@ public struct MainTabFeature {
/// Todo: scope๋กœ ์ด๋™
case path(StackAction<MainTabPath.State, MainTabPath.Action>)
case pokit(PokitRootFeature.Action)
case remind(RemindFeature.Action)
case recommend(RecommendFeature.Action)
case contentDetail(PresentationAction<ContentDetailFeature.Action>)

@CasePathable
Expand All @@ -70,6 +70,8 @@ public struct MainTabFeature {
case onAppear
case onOpenURL(url: URL)
case ๊ฒฝ๊ณ _ํ™•์ธ๋ฒ„ํŠผ_ํด๋ฆญ
case ๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ
case ์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ
}
public enum InnerAction: Equatable {
case ๋งํฌ์ถ”๊ฐ€๋ฐ์ˆ˜์ •์ด๋™(contentId: Int)
Expand Down Expand Up @@ -129,7 +131,7 @@ public struct MainTabFeature {
return .none
case .pokit:
return .none
case .remind:
case .recommend:
return .none
case .contentDetail:
return .none
Expand All @@ -138,7 +140,14 @@ public struct MainTabFeature {
/// - Reducer body
public var body: some ReducerOf<Self> {
Scope(state: \.pokit, action: \.pokit) { PokitRootFeature() }
Scope(state: \.remind, action: \.remind) { RemindFeature() }
Scope(state: \.recommend, action: \.recommend) {
withDependencies {
$0[UserClient.self] = .testValue
$0[ContentClient.self] = .testValue
} operation: {
RecommendFeature()
}
}

BindingReducer()
navigationReducer
Expand Down Expand Up @@ -198,6 +207,28 @@ private extension MainTabFeature {
case .๊ฒฝ๊ณ _ํ™•์ธ๋ฒ„ํŠผ_ํด๋ฆญ:
state.error = nil
return .run { send in await send(.inner(.errorSheetPresented(false))) }
case .๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ:
switch state.selectedTab {
case .pokit: return .none
case .recommend:
return RecommendFeature()
.reduce(
into: &state.recommend,
action: .view(.๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ)
)
.map(Action.recommend)
}
case .์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ:
switch state.selectedTab {
case .pokit: return .none
case .recommend:
return RecommendFeature()
.reduce(
into: &state.recommend,
action: .view(.์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ)
)
.map(Action.recommend)
}
}
}
/// - Inner Effect
Expand Down
18 changes: 9 additions & 9 deletions Projects/App/Sources/MainTab/MainTabFeatureView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI
import ComposableArchitecture
import DSKit
import FeaturePokit
import FeatureRemind
import FeatureRecommend
import FeatureSetting
import FeatureCategorySetting
import FeatureContentDetail
Expand Down Expand Up @@ -135,8 +135,8 @@ private extension MainTabView {
.pokitNavigationBar { pokitNavigationBar }
.toolbarBackground(.hidden, for: .tabBar)

case .remind:
RemindView(store: store.scope(state: \.remind, action: \.remind))
case .recommend:
RecommendView(store: store.scope(state: \.recommend, action: \.recommend))
.pokitNavigationBar { remindNavigationBar }
.toolbarBackground(.hidden, for: .tabBar)
}
Expand Down Expand Up @@ -173,19 +173,19 @@ private extension MainTabView {
var remindNavigationBar: some View {
PokitHeader {
PokitHeaderItems(placement: .leading) {
Text("Remind")
.font(.system(size: 32, weight: .heavy))
.foregroundStyle(.pokit(.text(.brand)))
Text("๋งํฌ์ถ”์ฒœ")
.pokitFont(.title2)
.foregroundStyle(.pokit(.text(.primary)))
}

PokitHeaderItems(placement: .trailing) {
PokitToolbarButton(
.icon(.search),
action: { store.send(.remind(.view(.๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ))) }
action: { send(.๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ) }
)
PokitToolbarButton(
.icon(.bell),
action: { store.send(.remind(.view(.์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ))) }
action: { send(.์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ) }
)
}
}
Expand All @@ -198,7 +198,7 @@ private extension MainTabView {

Spacer()

bottomTabBarItem(.remind)
bottomTabBarItem(.recommend)
}
.padding(.horizontal, 48)
.padding(.top, 12)
Expand Down
19 changes: 5 additions & 14 deletions Projects/App/Sources/MainTab/MainTabPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ public extension MainTabFeature {
switch action {
/// - ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” `์•Œ๋ฆผ`๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ
case .pokit(.delegate(.alertButtonTapped)),
.remind(.delegate(.alertButtonTapped)),
.recommend(.delegate(.์•Œ๋ฆผ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ)),
.delegate(.์•Œ๋ฆผํ•จ์ด๋™):
state.isPushTapped = false
state.path.append(.์•Œ๋ฆผํ•จ(PokitAlertBoxFeature.State()))
return .none

/// - ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” `๊ฒ€์ƒ‰`๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ
case .pokit(.delegate(.searchButtonTapped)),
.remind(.delegate(.searchButtonTapped)):
.recommend(.delegate(.๊ฒ€์ƒ‰_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ)):
state.path.append(.๊ฒ€์ƒ‰(PokitSearchFeature.State()))
return .none

Expand Down Expand Up @@ -118,7 +118,6 @@ public extension MainTabFeature {
/// - ๋งํฌ ์ƒ์„ธ
case let .path(.element(_, action: .์นดํ…Œ๊ณ ๋ฆฌ์ƒ์„ธ(.delegate(.contentItemTapped(content))))),
let .pokit(.delegate(.contentDetailTapped(content))),
let .remind(.delegate(.๋งํฌ์ƒ์„ธ(content))),
let .path(.element(_, action: .๋งํฌ๋ชฉ๋ก(.delegate(.๋งํฌ์ƒ์„ธ(content: content))))),
let .path(.element(_, action: .๊ฒ€์ƒ‰(.delegate(.linkCardTapped(content: content))))):

Expand All @@ -128,7 +127,7 @@ public extension MainTabFeature {
/// - ๋งํฌ์ƒ์„ธ ๋ฐ”ํ…€์‹œํŠธ์—์„œ ๋งํฌ์ˆ˜์ •์œผ๋กœ ์ด๋™
case let .contentDetail(.presented(.delegate(.editButtonTapped(id)))),
let .pokit(.delegate(.๋งํฌ์ˆ˜์ •ํ•˜๊ธฐ(id))),
let .remind(.delegate(.๋งํฌ์ˆ˜์ •(id))),
let .recommend(.delegate(.์ถ”๊ฐ€ํ•˜๊ธฐ_๋ฒ„ํŠผ_๋ˆŒ๋ €์„๋•Œ(id))),
let .path(.element(_, action: .์นดํ…Œ๊ณ ๋ฆฌ์ƒ์„ธ(.delegate(.๋งํฌ์ˆ˜์ •(id))))),
let .path(.element(_, action: .๋งํฌ๋ชฉ๋ก(.delegate(.๋งํฌ์ˆ˜์ •(id))))),
let .path(.element(_, action: .๊ฒ€์ƒ‰(.delegate(.๋งํฌ์ˆ˜์ •(id))))),
Expand All @@ -146,8 +145,8 @@ public extension MainTabFeature {
switch state.selectedTab {
case .pokit:
return .send(.pokit(.delegate(.๋ฏธ๋ถ„๋ฅ˜_์นดํ…Œ๊ณ ๋ฆฌ_์ปจํ…์ธ _์กฐํšŒ)))
case .remind:
return .send(.remind(.delegate(.์ปจํ…์ธ _์ƒ์„ธ๋ณด๊ธฐ_delegate_์œ„์ž„)))
case .recommend:
return .none
}
}
switch lastPath {
Expand Down Expand Up @@ -198,14 +197,6 @@ public extension MainTabFeature {
case let .pokit(.delegate(.linkPopup(text))):
state.linkPopup = .text(title: text)
return .none
/// ๋งํฌ๋ชฉ๋ก `์•ˆ์ฝ์Œ`
case .remind(.delegate(.๋งํฌ๋ชฉ๋ก_์•ˆ์ฝ์Œ)):
state.path.append(.๋งํฌ๋ชฉ๋ก(ContentListFeature.State(contentType: .unread)))
return .none
/// ๋งํฌ๋ชฉ๋ก `์ฆ๊ฒจ์ฐพ๊ธฐ`
case .remind(.delegate(.๋งํฌ๋ชฉ๋ก_์ฆ๊ฒจ์ฐพ๊ธฐ)):
state.path.append(.๋งํฌ๋ชฉ๋ก(ContentListFeature.State(contentType: .favorite)))
return .none

case .path(.element(_, action: .์„ค์ •(.delegate(.๋กœ๊ทธ์•„์›ƒ)))):
return .send(.delegate(.๋กœ๊ทธ์•„์›ƒ))
Expand Down
16 changes: 9 additions & 7 deletions Projects/CoreKit/Sources/Data/DTO/Base/ContentBaseResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,26 @@ public struct ContentBaseResponse: Decodable {
public let createdAt: String
public let isRead: Bool?
public let isFavorite: Bool?
public let keyword: String?
}

extension ContentBaseResponse {
public static func mock(id: Int) -> Self {
Self(
contentId: id,
category: .init(
categoryId: 992,
categoryName: "๋ฏธ๋ถ„๋ฅ˜"
categoryId: 567,
categoryName: "์‹ ์„œ์œ ๊ธฐ"
),
data: "https://www.youtube.com/watch?v=wtSwdGJzQCQ",
data: "https://youtu.be/CIzKDrN7IpU?si=B0-7X7I_54VHAfkk",
domain: "youtube",
title: "์‹ ์„œ์œ ๊ธฐ",
title: "[#์ƒท์ถ”๊ฐ€] ๊ฑฐ๋ฆฌ ๋‘๊ธฐ ์ฒ ์ €ํ•˜๊ฒŒ ์ง€ํ‚ค๊ฒŒ ๋งŒ๋“œ๋Š” ์ธ๋ฌผ ํ€ด์ฆˆใ…‹ใ…‹ใ…‹์–ด๋–ค ์Œ์‹์„ ๋บ„์ง€ ๊ณ ๋ฏผํ•˜์ง€ ๋งˆ์š”..์–ด์ฐจํ”ผ ๋‹ค ๋ชป ๋จน์œผ๋‹ˆ๊นŒ์š”๐Ÿคฃ | #์‹ ์„œ์œ ๊ธฐ5 #Diggle",
memo: nil,
thumbNail: "https://i.ytimg.com/vi/NnOC4_kH0ok/hqdefault.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLDN6u6mTjbaVmRZ4biJS_aDq4uvAQ",
createdAt: "2024.08.08",
thumbNail: "https://i.ytimg.com/vi/CIzKDrN7IpU/maxresdefault.jpg",
createdAt: "2024.12.03",
isRead: false,
isFavorite: true
isFavorite: true,
keyword: "์˜ˆ๋Šฅ"
)
}
}
Expand Down
10 changes: 9 additions & 1 deletion Projects/CoreKit/Sources/Data/DTO/User/InterestResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ extension InterestResponse {
Self(code: "code2", description: "์‚ฐ์ฑ…"),
Self(code: "code3", description: "ํ”„๋กœ๊ทธ๋ž˜๋ฐ"),
Self(code: "code4", description: "์—ฌํ–‰"),
Self(code: "code5", description: "์š”๋ฆฌ")
Self(code: "code5", description: "์š”๋ฆฌ"),
Self(code: "code6", description: "์Šคํฌ์ธ /๋ ˆ์ €"),
Self(code: "code7", description: "๊ธฐํš/๋งˆ์ผ€ํŒ…"),
Self(code: "code8", description: "์‡ผํ•‘"),
Self(code: "code9", description: "๊ฒฝ์ œ/์‹œ์‚ฌ"),
Self(code: "code10", description: "์˜ํ™”/๋“œ๋ผ๋งˆ"),
Self(code: "code11", description: "์žฅ์†Œ"),
Self(code: "code12", description: "์ธํ…Œ๋ฆฌ์–ด"),
Self(code: "code13", description: "IT"),
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ extension ContentClient: DependencyKey {
},
๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ: { model in
try await provider.requestNoBody(.๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ(model: model))
},
์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ: { pageable, keyword in
try await provider.request(.์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ(pageable: pageable, keyword: keyword))
}
)
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ extension ContentClient: TestDependencyKey {
์ปจํ…์ธ _๊ฒ€์ƒ‰: { _, _ in .mock },
์ธ๋„ค์ผ_์ˆ˜์ •: { _, _ in },
๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_ํฌํ‚ท_์ด๋™: { _ in },
๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ: { _ in }
๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ: { _ in },
์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ: { _, _ in .mock }
)
}()
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,9 @@ public struct ContentClient {
public var ๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ: @Sendable (
_ model: ContentDeleteRequest
) async throws -> Void
public var ์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ: @Sendable (
_ pageable: BasePageableRequest,
_ keyword: String?
) async throws -> ContentListInquiryResponse
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public enum ContentEndpoint {
case ์ธ๋„ค์ผ_์ˆ˜์ •(contentId: String, model: ThumbnailRequest)
case ๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_ํฌํ‚ท_์ด๋™(model: ContentMoveRequest)
case ๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ(model: ContentDeleteRequest)
case ์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ(
pageable: BasePageableRequest,
keyword: String?
)
}

extension ContentEndpoint: TargetType {
Expand Down Expand Up @@ -63,6 +67,8 @@ extension ContentEndpoint: TargetType {
return ""
case .๋ฏธ๋ถ„๋ฅ˜_๋งํฌ_์‚ญ์ œ:
return "/uncategorized"
case .์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ:
return "/recommended"
}
}

Expand All @@ -85,7 +91,8 @@ extension ContentEndpoint: TargetType {

case .์นดํƒœ๊ณ ๋ฆฌ_๋‚ด_์ปจํ…์ธ _๋ชฉ๋ก_์กฐํšŒ,
.๋ฏธ๋ถ„๋ฅ˜_์นดํ…Œ๊ณ ๋ฆฌ_์ปจํ…์ธ _์กฐํšŒ,
.์ปจํ…์ธ _๊ฒ€์ƒ‰:
.์ปจํ…์ธ _๊ฒ€์ƒ‰,
.์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ:
return .get
}
}
Expand Down Expand Up @@ -126,6 +133,19 @@ extension ContentEndpoint: TargetType {
],
encoding: URLEncoding.default
)
case let .์ถ”์ฒœ_์ปจํ…์ธ _์กฐํšŒ(pageable, keyword):
var parameters: [String: Any] = [
"page": pageable.page,
"size": pageable.size,
"sort": pageable.sort.map { String($0) }.joined(separator: ",")
]
if let keyword {
parameters["keyword"] = keyword
}
return .requestParameters(
parameters: parameters,
encoding: URLEncoding.default
)
case let .์ปจํ…์ธ _๊ฒ€์ƒ‰(pageable, condition):
return .requestParameters(
parameters: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ extension UserClient: DependencyKey {
},
fcm_ํ† ํฐ_์ €์žฅ: { model in
try await provider.request(.fcm_ํ† ํฐ_์ €์žฅ(model: model))
},
์œ ์ €_๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ: {
try await provider.request(.์œ ์ €_๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ)
}
)
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ extension UserClient: TestDependencyKey {
๋‹‰๋„ค์ž„_์ค‘๋ณต_์ฒดํฌ: { _ in .mock },
๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ: { InterestResponse.mock },
๋‹‰๋„ค์ž„_์กฐํšŒ: { .mock },
fcm_ํ† ํฐ_์ €์žฅ: { _ in .mock }
fcm_ํ† ํฐ_์ €์žฅ: { _ in .mock },
์œ ์ €_๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ: { InterestResponse.mock }
)
}()
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public struct UserClient {
public var ๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ: @Sendable () async throws -> [InterestResponse]
public var ๋‹‰๋„ค์ž„_์กฐํšŒ: @Sendable () async throws -> BaseUserResponse
public var fcm_ํ† ํฐ_์ €์žฅ: @Sendable (_ model: FCMRequest) async throws -> FCMResponse
public var ์œ ์ €_๊ด€์‹ฌ์‚ฌ_๋ชฉ๋ก_์กฐํšŒ: @Sendable () async throws -> [InterestResponse]
}
Loading

0 comments on commit 9aca4aa

Please sign in to comment.