Skip to content

Commit

Permalink
Merge pull request #145 from SOPT-all/refactor/#141-mvi-juri
Browse files Browse the repository at this point in the history
Refactor/#141 Explore MVI
  • Loading branch information
juri123123 authored Jan 23, 2025
2 parents 32de116 + 7357e30 commit e9eeb3f
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 89 deletions.
4 changes: 1 addition & 3 deletions Spoony-iOS/Spoony-iOS/Network/Service/ExploreService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,7 @@ final class MockExploreService: ExploreProtocol {
sort: FilterType
) async throws -> FeedListResponse {
return .init(feedResponseList: [
FeedResponse.sample,
FeedResponse.sample,
FeedResponse.sample

])
}

Expand Down
1 change: 0 additions & 1 deletion Spoony-iOS/Spoony-iOS/Resource/Tab/Model/ViewType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import Foundation

enum ViewType: Hashable {
case test
case searchView // 검색 화면
case locationView(title: String) // 위치 선택 화면
case detailView(postId: Int) // 상세 화면
Expand Down
2 changes: 0 additions & 2 deletions Spoony-iOS/Spoony-iOS/Resource/Tab/NavigationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ final class NavigationManager: ObservableObject {
@ViewBuilder
func build(_ view: ViewType) -> some View {
switch view {
case .test:
Explore()
case .searchView:
SearchView()
case .locationView:
Expand Down
64 changes: 25 additions & 39 deletions Spoony-iOS/Spoony-iOS/Source/Feature/Explore/Explore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,51 @@ import Lottie

struct Explore: View {
@EnvironmentObject private var navigationManager: NavigationManager
@StateObject private var store = ExploreStore()

@State private var isPresentedLocation: Bool = false
@State private var isPresentedFilter: Bool = false

@State private var spoonCount: Int = 0
@StateObject private var store: ExploreStore = ExploreStore()

var body: some View {
VStack(spacing: 0) {
Spacer()
CustomNavigationBar(
style: .locationDetail,
title: store.navigationTitle,
spoonCount: spoonCount,
title: "서울특별시 \(store.state.selectedLocation.rawValue)",
spoonCount: store.state.spoonCount,
tappedAction: {
isPresentedLocation = true
store.dispatch(.navigationLocationTapped)
})

categoryList

if store.exploreList.isEmpty {
if store.state.exploreList.isEmpty {
emptyView
} else {
filterButton
.onTapGesture {
isPresentedFilter = true
store.dispatch(.filterButtontapped)
}
listView
}
}
.sheet(isPresented: $isPresentedFilter) {
FilterBottomSheet(
isPresented: $isPresentedFilter,
store: store
)
.sheet(isPresented: Binding(get: {
store.state.isPresentedFilter
}, set: { newValue in
store.dispatch(.isPresentedFilterChanged(newValue))
})) {
FilterBottomSheet(store: store)
.presentationDetents([.height(250.adjustedH)])
.presentationCornerRadius(16)
}
.sheet(isPresented: $isPresentedLocation) {
LocationPickerBottomSheet(
isPresented: $isPresentedLocation,
store: store
)
.sheet(isPresented: Binding(get: {
store.state.isPresentedLocation
}, set: { newValue in
store.dispatch(.isPresentedLocationChanged(newValue))
})) {
LocationPickerBottomSheet(store: store)
.presentationDetents([.height(542.adjustedH)])
.presentationCornerRadius(16)
}
.task {
store.getCategoryList()
//TODO: 추후 수정 예정
Task {
do {
spoonCount = try await DefaultHomeService().fetchSpoonCount(userId: Config.userId)
} catch {
print("Failed to fetch spoon count:", error)
}
}
store.dispatch(.onAppear)
}
}
}
Expand All @@ -76,10 +66,10 @@ extension Explore {
HStack {
Spacer()
.frame(width: 20.adjusted)
ForEach(store.categoryList) { item in
ExploreCategoryChip(category: item, selected: store.isSelectedCategory(category: item))
ForEach(store.state.categoryList) { item in
ExploreCategoryChip(category: item, selected: item == store.state.selectedCategory)
.onTapGesture {
store.changeCategory(category: item)
store.dispatch(.categoryTapped(item))
}
}
Spacer()
Expand All @@ -92,7 +82,7 @@ extension Explore {
private var filterButton: some View {
HStack(spacing: 2) {
Spacer()
Text(store.selectedFilter.title)
Text(store.state.selectedFilter.title)
.customFont(.caption1m)
.foregroundStyle(.gray700)
Image(.icFilterGray700)
Expand Down Expand Up @@ -135,7 +125,7 @@ extension Explore {
private var listView: some View {
ScrollView {
VStack(spacing: 0) {
ForEach(store.exploreList) { list in
ForEach(store.state.exploreList) { list in
ExploreCell(feed: list)
.padding(.bottom, 12)
.padding(.horizontal, 20)
Expand All @@ -149,7 +139,3 @@ extension Explore {
.padding(.top, 16)
}
}

#Preview {
Explore()
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,18 @@ enum FilterType: String, CaseIterable {
}

struct FilterBottomSheet: View {
@Binding var isPresented: Bool

@ObservedObject var store: ExploreStore

var body: some View {
VStack(spacing: 12) {
ForEach(FilterType.allCases, id: \.self) { filter in
SpoonyButton(
style: store.selectedFilter == filter ? .activate : .deactivate,
style: store.state.selectedFilter == filter ? .activate : .deactivate,
size: .xlarge,
title: filter.title,
disabled: .constant(false)
) {
store.changeFilter(filter: filter)
isPresented = false
store.dispatch(.filterTapped(filter))
}
}
SpoonyButton(
Expand All @@ -45,7 +42,7 @@ struct FilterBottomSheet: View {
title: "취소",
disabled: .constant(false)
) {
isPresented = false
store.dispatch(.closeFilterTapped)
}
Spacer()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ enum SeoulType: String, CaseIterable {
}

struct LocationPickerBottomSheet: View {
@Binding var isPresented: Bool
@State private var isDisabled: Bool = true
@State private var selectedRegion: SeoulType = .mapo

@ObservedObject var store: ExploreStore

var body: some View {
Expand All @@ -65,7 +61,7 @@ struct LocationPickerBottomSheet: View {

Image(.icCloseGray400)
.onTapGesture {
isPresented = false
store.dispatch(.closeLocationTapped)
}
}
.padding(.trailing, 20)
Expand Down Expand Up @@ -99,16 +95,15 @@ struct LocationPickerBottomSheet: View {
Text(type.rawValue)
.customFont(.body2m)
.foregroundStyle(
selectedRegion.rawValue != type.rawValue ? .gray400 : .spoonBlack
store.state.tempLocation?.rawValue != type.rawValue ? .gray400 : .spoonBlack
)
.frame(width: 240.adjusted, height: 44.adjustedH)
.background(
Rectangle()
.stroke(Color.gray0, lineWidth: 1)
)
.onTapGesture {
selectedRegion = type
isDisabled = false
store.dispatch(.locationTapped(type))
}
}
}
Expand All @@ -121,10 +116,12 @@ struct LocationPickerBottomSheet: View {
style: .secondary,
size: .xlarge,
title: "선택하기",
disabled: $isDisabled
disabled: Binding(get: {
return store.state.tempLocation == nil
}, set: { _ in
})
) {
store.changeLocation(location: selectedRegion)
isPresented = false
store.dispatch(.selectLocationTapped)
}
.padding(.top, 12)
.padding(.bottom, 22)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ExploreIntent.swift
// Spoony-iOS
//
// Created by 최주리 on 1/23/25.
//

import Foundation

enum ExploreIntent {
case onAppear

// Location Bottom Sheet
case navigationLocationTapped
case locationTapped(SeoulType)
case selectLocationTapped
case closeLocationTapped
case isPresentedLocationChanged(Bool)

// Filter Bottom Sheet
case filterButtontapped
case filterTapped(FilterType)
case closeFilterTapped
case isPresentedFilterChanged(Bool)

// Main
case categoryTapped(CategoryChip)
case cellTapped(FeedEntity)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// ExploreState.swift
// Spoony-iOS
//
// Created by 최주리 on 1/23/25.
//

import Foundation

struct ExploreState {
var exploreList: [FeedEntity] = []
var spoonCount: Int = 0

//TODO: 현재 위치 받아와서 바꾸기
var selectedLocation: SeoulType = .gangnam
var tempLocation: SeoulType?

var selectedFilter: FilterType = .latest

var categoryList: [CategoryChip] = []
var selectedCategory: CategoryChip?

var isPresentedLocation: Bool = false
var isPresentedFilter: Bool = false
}
Loading

0 comments on commit e9eeb3f

Please sign in to comment.