Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MovieBooking/Domain/Entity/Movie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

public struct Movie: Identifiable, Equatable {
public struct Movie: Identifiable, Equatable, Hashable {
public let id: Int
public let title: String
public let overview: String
Expand Down
60 changes: 60 additions & 0 deletions MovieBooking/Feature/Search/MovieSearchFeature.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// MovieSearchFeature.swift
// MovieBooking
//
// Created by 김민희 on 10/16/25.
//

import ComposableArchitecture
import Foundation

@Reducer
struct MovieSearchFeature {
@ObservableState
struct State: Equatable {
var nowPlayingMovies: [Movie] = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@minneee 이걸 하나로 합치는거 어떨까요 ??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하나로 합치는게 어떻게 하는걸 말씀하시는거에요??

var upcomingMovies: [Movie] = []
var popularMovies: [Movie] = []
var searchText: String = ""
}

enum Action: BindableAction {
case updateMovieLists(nowPlaying: [Movie], upcoming: [Movie], popular: [Movie])
case binding(BindingAction<State>)
}

var body: some Reducer<State, Action> {
BindingReducer()
Reduce { state, action in
switch action {
case let .updateMovieLists(nowPlaying, upcoming, popular):
state.nowPlayingMovies = nowPlaying
state.upcomingMovies = upcoming
state.popularMovies = popular
return .none

case .binding:
return .none
}
}
}
}


extension MovieSearchFeature.State {
var trimmedKeyword: String {
searchText.trimmingCharacters(in: .whitespacesAndNewlines)
}

var aggregatedMovies: [Movie] {
Array(Set(nowPlayingMovies + upcomingMovies + popularMovies))
}
Comment on lines +49 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 동작인지 잘 모르겠어요
주석을 달아주시면 좋을 것 같습니다 ~!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

영화 목록들이 배열 여러개로 있어서 하나로 합친 로직입니다! 복잡한 것 같아서 간단하게 수정했습니당


var filteredMovies: [Movie] {
guard !trimmedKeyword.isEmpty else { return [] }

return aggregatedMovies.filter {
$0.title.localizedCaseInsensitiveContains(trimmedKeyword)
}
}
}
34 changes: 28 additions & 6 deletions MovieBooking/Feature/Search/MovieSearchView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,42 @@
//

import SwiftUI
import ComposableArchitecture

struct MovieSearchView: View {
@State private var searchText = ""
@Perception.Bindable var store: StoreOf<MovieSearchFeature>

var body: some View {
VStack(spacing: 20) {
SearchBar(text: $searchText)
WithPerceptionTracking {
VStack(spacing: 0) {
SearchBar(text: $store.searchText)
.padding(.bottom, 20)

SearchView(movies: Movie.mockData)
Group {
if store.trimmedKeyword.isEmpty {
EmptySearchView()
} else {
SearchView(movies: store.filteredMovies)
}
}
.frame(maxHeight: .infinity)
}
.padding(.top, 20)
.padding(.horizontal, 20)
}
.padding(.horizontal, 20)
}
}

#Preview {
MovieSearchView()
MovieSearchView(
store: Store(
initialState: MovieSearchFeature.State(
nowPlayingMovies: Movie.mockData,
upcomingMovies: Movie.mockData,
popularMovies: Movie.mockData
)
) {
MovieSearchFeature()
}
)
}