Skip to content

Commit

Permalink
Merge pull request #156 from Nexters/feature/lgvv/present
Browse files Browse the repository at this point in the history
[Architecture] SwiftUI Presentation Layer 구조 개선
  • Loading branch information
lgvv authored Mar 12, 2024
2 parents c6b1b12 + 7aa5134 commit cb83d3f
Show file tree
Hide file tree
Showing 21 changed files with 176 additions and 98 deletions.
8 changes: 8 additions & 0 deletions FunchApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
1ACE49802B5BA46600024336 /* ProfileRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE497F2B5BA46600024336 /* ProfileRepositoryImpl.swift */; };
1ACE49862B5BAB5F00024336 /* DefaultFunchButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE49852B5BAB5F00024336 /* DefaultFunchButtonStyle.swift */; };
1ACE498D2B5C111500024336 /* ChipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE498C2B5C111500024336 /* ChipView.swift */; };
1AFB7D9C2B9D9387007E4D2F /* MultiProfileListDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFB7D9B2B9D9387007E4D2F /* MultiProfileListDelegate.swift */; };
1AFB7D9E2B9D9481007E4D2F /* ProfileViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFB7D9D2B9D9481007E4D2F /* ProfileViewDelegate.swift */; };
3E1E73EF2B7071030082386A /* SubwayStationRepositoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E1E73EE2B7071030082386A /* SubwayStationRepositoryTests.swift */; };
3E1E73F12B70B3570082386A /* ChipButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E1E73F02B70B3570082386A /* ChipButton.swift */; };
3E1E73F32B713B3A0082386A /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E1E73F22B713B3A0082386A /* String+.swift */; };
Expand Down Expand Up @@ -257,6 +259,8 @@
1ACE497F2B5BA46600024336 /* ProfileRepositoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileRepositoryImpl.swift; sourceTree = "<group>"; };
1ACE49852B5BAB5F00024336 /* DefaultFunchButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultFunchButtonStyle.swift; sourceTree = "<group>"; };
1ACE498C2B5C111500024336 /* ChipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipView.swift; sourceTree = "<group>"; };
1AFB7D9B2B9D9387007E4D2F /* MultiProfileListDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProfileListDelegate.swift; sourceTree = "<group>"; };
1AFB7D9D2B9D9481007E4D2F /* ProfileViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewDelegate.swift; sourceTree = "<group>"; };
3E1E73EE2B7071030082386A /* SubwayStationRepositoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubwayStationRepositoryTests.swift; sourceTree = "<group>"; };
3E1E73F02B70B3570082386A /* ChipButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipButton.swift; sourceTree = "<group>"; };
3E1E73F22B713B3A0082386A /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -488,6 +492,7 @@
1AC7812D2B91E6CC00E298E3 /* MultiProfileScene */ = {
isa = PBXGroup;
children = (
1AFB7D9B2B9D9387007E4D2F /* MultiProfileListDelegate.swift */,
1AC781362B923EEA00E298E3 /* MultiProfileListViewBuilder.swift */,
1AC7812B2B91E6C900E298E3 /* MultiProfileListView.swift */,
1AC781342B923EC800E298E3 /* MultiProfileListViewModel.swift */,
Expand Down Expand Up @@ -596,6 +601,7 @@
1ACE495E2B5B9EFF00024336 /* ProfileScene */ = {
isa = PBXGroup;
children = (
1AFB7D9D2B9D9481007E4D2F /* ProfileViewDelegate.swift */,
1A83F0302B80E6CB00E6EC89 /* ProfileViewBuilder.swift */,
1A83F0322B80E6E000E6EC89 /* ProfileViewModel.swift */,
1ACE49552B5B9E9300024336 /* ProfileView.swift */,
Expand Down Expand Up @@ -1037,6 +1043,7 @@
1A83F0382B80E8E200E6EC89 /* SplashViewBuilder.swift in Sources */,
1A44AAAC2B67EFCD006D8894 /* CreateProfile.Req.swift in Sources */,
1A8F13092B8B7DAB001E0237 /* LinkStringSet.swift in Sources */,
1AFB7D9E2B9D9481007E4D2F /* ProfileViewDelegate.swift in Sources */,
1AC781202B90E81500E298E3 /* RepositoryError.swift in Sources */,
1A8F12F12B87A33C001E0237 /* MBTIBoardUseCase.swift in Sources */,
1A7B069E2B5D702D0024356C /* APIEnvironment.swift in Sources */,
Expand All @@ -1053,6 +1060,7 @@
1A83F02C2B80E1BD00E6EC89 /* HomeViewModel.swift in Sources */,
3EA875682B86492B00713C64 /* DeleteProfile.Res.swift in Sources */,
1A7B06A22B5D8C710024356C /* MatchingInfo.swift in Sources */,
1AFB7D9C2B9D9387007E4D2F /* MultiProfileListDelegate.swift in Sources */,
1ACE497D2B5BA3B600024336 /* CreateProfile.Res.swift in Sources */,
1A83F02E2B80E26B00E6EC89 /* MatchResultViewBuilder.swift in Sources */,
1A8F12EA2B8784B8001E0237 /* ProfileEditorPresentation.swift in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions FunchApp/Application/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ final class DIContainer: ObservableObject {
let subwayStationRepository: SubwayStationRepository
}

struct Delegate {

// var ProfileViewDelegate: ProfileViewDelegate = ProfileDelegate
}

private(set) var dependency: Dependency

private(set) var openUrl: OpenURLProtocol
Expand Down
9 changes: 4 additions & 5 deletions FunchApp/Application/FunchApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@ struct FunchApp: App {
}
.overlay {
if isSplashing {
withAnimation(.easeOut) {
SplashViewBuilder().body
}

SplashViewBuilder().body
}
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.35) {
isSplashing.toggle()
withAnimation(.easeInOut) {
isSplashing.toggle()
}
}
}
.environmentObject(container)
Expand Down
5 changes: 2 additions & 3 deletions FunchApp/Presentation/EasterEggScene/EasterEggView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
import SwiftUI

struct EasterEggView: View {

@Environment(\.dismiss) var dismiss

@StateObject var viewModel: EasterEggViewModel

@Environment(\.dismiss) var dismiss

var body: some View {
ZStack {
Color.gray900
Expand Down
43 changes: 42 additions & 1 deletion FunchApp/Presentation/HomeScene/HomePresentation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Geon Woo lee on 2/22/24.
//

import Foundation
import SwiftUI

enum HomePresentation: Hashable, Identifiable {
var id: Int { hashValue }
Expand All @@ -16,3 +16,44 @@ enum HomePresentation: Hashable, Identifiable {
case easterEgg
case multiProfile
}

struct HomePresentationView: View {
@EnvironmentObject var container: DIContainer
@State var presentation: HomePresentation

var viewModel: HomeViewModel

var body: some View {
switch presentation {
case .profile:
NavigationStack {
ProfileViewBuilder(
container,
delegate: viewModel
).body
}
case let .matchResult(matchingInfo):
NavigationStack {
MatchResultViewBuilder(
container,
matchingInfo: matchingInfo
).body
}
case .mbtiCollection:
NavigationStack {
MBTIBoardViewBuilder(container).body
}
case .easterEgg:
NavigationStack {
EasterEggViewBuilder(container).body
}
case .multiProfile:
NavigationStack {
MultiProfileListViewBuilder(
container,
delegate: viewModel
).body
}
}
}
}
35 changes: 1 addition & 34 deletions FunchApp/Presentation/HomeScene/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
import SwiftUI

struct HomeView: View {

@EnvironmentObject var container: DIContainer

@StateObject var viewModel: HomeViewModel

var body: some View {
Expand Down Expand Up @@ -102,37 +99,7 @@ struct HomeView: View {
hideKeyboard()
}
.fullScreenCover(item: $viewModel.presentation) { presentation in
switch presentation {
case .profile:
NavigationStack {
ProfileViewBuilder(container).body
}
.onDisappear {
viewModel.send(action: .load)
}
case let .matchResult(matchingInfo):
NavigationStack {
MatchResultViewBuilder(
container,
matchingInfo: matchingInfo
).body
}
case .mbtiCollection:
NavigationStack {
MBTIBoardViewBuilder(container).body
}
case .easterEgg:
NavigationStack {
EasterEggViewBuilder(container).body
}
case .multiProfile:
NavigationStack {
MultiProfileListViewBuilder(container).body
}
.onDisappear {
viewModel.send(action: .load)
}
}
HomePresentationView(presentation: presentation, viewModel: self.viewModel)
}
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Expand Down
2 changes: 1 addition & 1 deletion FunchApp/Presentation/HomeScene/HomeViewBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import SwiftUI

final class HomeViewBuilder {
final class HomeViewBuilder{

private var container: DIContainer

Expand Down
15 changes: 13 additions & 2 deletions FunchApp/Presentation/HomeScene/HomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ final class HomeViewModel: ObservableObject {

private var useCase: UseCase
private var container: DIContainer
private var cancellables = Set<AnyCancellable>()

struct UseCase {
let fetchProfile: DefaultFetchProfileUseCase
Expand All @@ -71,8 +72,6 @@ final class HomeViewModel: ObservableObject {
self.container = container
}

var cancellables = Set<AnyCancellable>()

func send(action: Action) {
switch action {
case .load:
Expand Down Expand Up @@ -168,3 +167,15 @@ final class HomeViewModel: ObservableObject {
}.store(in: &cancellables)
}
}

extension HomeViewModel: ProfileViewDelegate {
func delete(profile: Profile) {
self.send(action: .load)
}
}

extension HomeViewModel: MultiProfileListDelegate {
func change(profile: Profile) {
self.send(action: .load)
}
}
4 changes: 1 addition & 3 deletions FunchApp/Presentation/MBTIBoardScene/MBTIBoardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
import SwiftUI

struct MBTIBoardView: View {

@Environment(\.dismiss) var dismiss

@StateObject var viewModel: MBTIBoardViewModel
@Environment(\.dismiss) var dismiss

var body: some View {
ZStack {
Expand Down
5 changes: 2 additions & 3 deletions FunchApp/Presentation/MatchResultScene/MatchResultView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import SwiftUI
import SwiftUIPager

struct MatchResultView: View {

@Environment(\.dismiss) var dismiss

@StateObject var viewModel: MatchResultViewModel
@StateObject var page: Page = .first()

@Environment(\.dismiss) var dismiss

var viewSize: CGSize = UIScreen.main.bounds.size

var body: some View {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// MultiProfileListDelegate.swift
// FunchApp
//
// Created by Geon Woo lee on 3/10/24.
//

import Foundation

protocol MultiProfileListDelegate: AnyObject {
/// 프로필 변경
func change(profile: Profile)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@
// Created by Geon Woo lee on 3/2/24.
//

import Foundation
import SwiftUI

enum MultiProfileListPresentation: Hashable, Identifiable {
var id: Int { hashValue }

case create
case home
}

struct MultiProfileListPresentationView: View {
@EnvironmentObject var container: DIContainer
@State var presentation: MultiProfileListPresentation

var body: some View {
switch presentation {
case .create:
NavigationStack {
ProfileEditorViewBuilder(container).body
}
}
}
}
28 changes: 5 additions & 23 deletions FunchApp/Presentation/MultiProfileScene/MultiProfileListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@
import SwiftUI

struct MultiProfileListView: View {
@StateObject var viewModel: MultiProfileListViewModel

@Environment(\.dismiss) var dismiss

@EnvironmentObject var container: DIContainer

@StateObject var viewModel: MultiProfileListViewModel

var body: some View {
ZStack {
Color.gray900
Expand Down Expand Up @@ -62,32 +59,17 @@ struct MultiProfileListView: View {
viewModel.send(action: .load)
}
.fullScreenCover(item: $viewModel.presentation) { presentation in
switch presentation {
case .create:
NavigationStack {
ProfileEditorViewBuilder(container).body
}
.onDisappear {
viewModel.send(action: .load)
}
case .home:
EmptyView()
}
MultiProfileListPresentationView(presentation: presentation)
}
.onReceive(viewModel.$presentation) {
switch $0 {
case .home:
container.paths.removeAll()
default:
break
}
.onReceive(viewModel.$dismiss) { isDismiss in
if isDismiss { dismiss() }
}
.toolbarBackground(Color.gray900, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button {
dismiss()
viewModel.send(action: .dismiss)
} label: {
Image(.iconX)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@

import SwiftUI

final class MultiProfileListViewBuilder {
struct MultiProfileListViewBuilder {

private var container: DIContainer
private var viewModel: MultiProfileListViewModel
private var delegate: MultiProfileListDelegate

init(_ container: DIContainer) {
init(
_ container: DIContainer,
delegate: MultiProfileListDelegate
) {
self.container = container
self.delegate = delegate

self.viewModel = .init(
container: container,
delegate: delegate
)
}

var body: some View {
let viewModel = MultiProfileListViewModel(container: container)
let view = MultiProfileListView(viewModel: viewModel)

return view
Expand Down
Loading

0 comments on commit cb83d3f

Please sign in to comment.