Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

๐Ÿ”€ :: ์ •๋ณด ์ž…๋ ฅ - ์™ธ๊ตญ์–ด ์ •๋ณด ์ž…๋ ฅ ํŽ˜์ด์ง€ #81

Merged
merged 8 commits into from
May 18, 2023
4 changes: 4 additions & 0 deletions Projects/App/Sources/Application/NeedleGenerated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ private class InputInformationDependency7b32a8e7e8a8f0ab5466Provider: InputInfor
var inputCertificateInfoBuildable: any InputCertificateInfoBuildable {
return appComponent.inputCertificateInfoBuildable
}
var inputLanguageInfoBuildable: any InputLanguageInfoBuildable {
return appComponent.inputLanguageInfoBuildable
}
private let appComponent: AppComponent
init(appComponent: AppComponent) {
self.appComponent = appComponent
Expand Down Expand Up @@ -243,6 +246,7 @@ extension InputInformationComponent: Registration {
keyPathToName[\InputInformationDependency.inputWorkInfoBuildable] = "inputWorkInfoBuildable-any InputWorkInfoBuildable"
keyPathToName[\InputInformationDependency.inputMilitaryInfoBuildable] = "inputMilitaryInfoBuildable-any InputMilitaryInfoBuildable"
keyPathToName[\InputInformationDependency.inputCertificateInfoBuildable] = "inputCertificateInfoBuildable-any InputCertificateInfoBuildable"
keyPathToName[\InputInformationDependency.inputLanguageInfoBuildable] = "inputLanguageInfoBuildable-any InputLanguageInfoBuildable"
}
}
extension InputCertificateInfoComponent: Registration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import InputSchoolLifeInfoFeatureInterface
import InputWorkInfoFeatureInterface
import InputMilitaryInfoFeatureInterface
import InputCertificateInfoFeatureInterface
import InputLanguageInfoFeatureInterface
import NeedleFoundation
import SwiftUI

Expand All @@ -14,6 +15,7 @@ public protocol InputInformationDependency: Dependency {
var inputWorkInfoBuildable: any InputWorkInfoBuildable { get }
var inputMilitaryInfoBuildable: any InputMilitaryInfoBuildable { get }
var inputCertificateInfoBuildable: any InputCertificateInfoBuildable { get }
var inputLanguageInfoBuildable: any InputLanguageInfoBuildable { get }
}

public final class InputInformationComponent:
Expand All @@ -34,6 +36,7 @@ public final class InputInformationComponent:
inputWorkInfoBuildable: dependency.inputWorkInfoBuildable,
inputMilitaryInfoBuildable: dependency.inputMilitaryInfoBuildable,
inputCertificateInfoBuildable: dependency.inputCertificateInfoBuildable,
inputLanguageInfoBuildable: dependency.inputLanguageInfoBuildable,
container: container
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import InputMilitaryInfoFeatureInterface
import InputProfileInfoFeatureInterface
import InputSchoolLifeInfoFeatureInterface
import InputWorkInfoFeatureInterface
import InputLanguageInfoFeatureInterface

final class InputInformationIntent: InputInformationIntentProtocol {
private weak var model: (any InputInformationActionProtocol)?
Expand Down Expand Up @@ -58,3 +59,13 @@ extension InputInformationIntent: InputCertificateDelegate {
model?.nextButtonDidTap()
}
}

extension InputInformationIntent: InputLanguageDelegate {
func languagePrevButtonDidTap() {
model?.prevButtonDidTap()
}

func completeToInputLanguage() {
// TODO: ์ „์ฒด ๋ฐ์ดํ„ฐ ์„œ๋ฒ„์— ์†ก์‹ 
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import InputSchoolLifeInfoFeatureInterface
import InputWorkInfoFeatureInterface
import InputMilitaryInfoFeatureInterface
import InputCertificateInfoFeatureInterface
import InputLanguageInfoFeatureInterface

protocol InputInformationIntentProtocol:
InputProfileDelegate,
InputSchoolLifeDelegate,
InputWorkDelegate,
InputMilitaryDelegate,
InputCertificateDelegate {}
InputCertificateDelegate,
InputLanguageDelegate {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import InputSchoolLifeInfoFeatureInterface
import InputWorkInfoFeatureInterface
import InputMilitaryInfoFeatureInterface
import InputCertificateInfoFeatureInterface
import InputLanguageInfoFeatureInterface
import SwiftUI
import ViewUtil

Expand All @@ -18,20 +19,23 @@ struct InputInformationView: View {
private let inputWorkInfoBuildable: any InputWorkInfoBuildable
private let inputMilitaryInfoBuildable: any InputMilitaryInfoBuildable
private let inputCertificateInfoBuildable: any InputCertificateInfoBuildable
private let inputLanguageInfoBuildable: any InputLanguageInfoBuildable

init(
inputProfileInfoBuildable: any InputProfileInfoBuildable,
inputSchoolLifeInfoBuildable: any InputSchoolListInfoBuildable,
inputWorkInfoBuildable: any InputWorkInfoBuildable,
inputMilitaryInfoBuildable: any InputMilitaryInfoBuildable,
inputCertificateInfoBuildable: any InputCertificateInfoBuildable,
inputLanguageInfoBuildable: any InputLanguageInfoBuildable,
container: MVIContainer<InputInformationIntentProtocol, InputInformationStateProtocol>
) {
self.inputProfileInfoBuildable = inputProfileInfoBuildable
self.inputSchoolLifeInfoBuildable = inputSchoolLifeInfoBuildable
self.inputWorkInfoBuildable = inputWorkInfoBuildable
self.inputMilitaryInfoBuildable = inputMilitaryInfoBuildable
self.inputCertificateInfoBuildable = inputCertificateInfoBuildable
self.inputLanguageInfoBuildable = inputLanguageInfoBuildable
self._container = StateObject(wrappedValue: container)
}

Expand Down Expand Up @@ -62,7 +66,8 @@ struct InputInformationView: View {
.eraseToAnyView()
.tag(InformationPhase.certificate)

Text("B")
inputLanguageInfoBuildable.makeView(delegate: intent)
.eraseToAnyView()
.tag(InformationPhase.language)
}
.animation(.default, value: state.phase)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public protocol InputLanguageDelegate: AnyObject {
func languagePrevButtonDidTap()
func completeToInputLanguage()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import SwiftUI

public protocol InputLanguageInfoBuildable {
associatedtype ViewType: View
func makeView() -> ViewType
func makeView(delegate: InputLanguageDelegate) -> ViewType
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ public final class InputLanguageInfoComponent:
Component<InputLanguageInfoDependency>,
InputLanguageInfoBuildable {

public func makeView() -> some View {
EmptyView()
public func makeView(delegate: InputLanguageDelegate) -> some View {
let model = InputLanguageInfoModel()
let intent = InputLanguageInfoIntent(model: model, languageDelegate: delegate)
let container = MVIContainer(
intent: intent as InputLanguageInfoIntentProtocol,
model: model as InputLanguageInfoStateProtocol,
modelChangePublisher: model.objectWillChange
)
return InputLanguageInfoView(container: container)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
import Foundation
import InputLanguageInfoFeatureInterface

final class InputLanguageInfoIntent: InputLanguageInfoIntentProtocol {}
final class InputLanguageInfoIntent: InputLanguageInfoIntentProtocol {
private weak var model: (any InputLanguageInfoActionProtocol)?
private weak var languageDelegate: (any InputLanguageDelegate)?

init(
model: any InputLanguageInfoActionProtocol,
languageDelegate: any InputLanguageDelegate
) {
self.model = model
self.languageDelegate = languageDelegate
}

func updateLanguageName(name: String, at index: Int) {
model?.updateLanguageName(name: name, at: index)
}

func updateLanguageScore(score: String, at index: Int) {
model?.updateLanguageScore(score: score, at: index)
}

func deleteLanguage(at index: Int) {
model?.deleteLanguage(at: index)
}

func languageAppendButtonDidTap() {
model?.appendLanguage()
}

func prevButtonDidTap() {
languageDelegate?.languagePrevButtonDidTap()
}

func completeButtonDidTap() {
languageDelegate?.completeToInputLanguage()
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import Foundation

protocol InputLanguageInfoIntentProtocol {}
protocol InputLanguageInfoIntentProtocol {
func updateLanguageName(name: String, at index: Int)
func updateLanguageScore(score: String, at index: Int)
func deleteLanguage(at index: Int)
func languageAppendButtonDidTap()
func prevButtonDidTap()
func completeButtonDidTap()
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
import Foundation
import FoundationUtil

final class InputLanguageInfoModel: ObservableObject, InputLanguageInfoStateProtocol {}
final class InputLanguageInfoModel: ObservableObject, InputLanguageInfoStateProtocol {
@Published var languageList: [LanguageInputModel] = [
.init(languageName: "", languageScore: "")
]
}

extension InputLanguageInfoModel: InputLanguageInfoActionProtocol {}
extension InputLanguageInfoModel: InputLanguageInfoActionProtocol {
func updateLanguageName(name: String, at index: Int) {
guard let indexedLanguage = languageList[safe: index] else { return }
let newLanuageInputModel = LanguageInputModel(
languageName: name,
languageScore: indexedLanguage.languageScore
)
languageList[index] = newLanuageInputModel
}

func updateLanguageScore(score: String, at index: Int) {
guard let indexedLanguage = languageList[safe: index] else { return }
let newLanuageInputModel = LanguageInputModel(
languageName: indexedLanguage.languageName,
languageScore: score
)
languageList[index] = newLanuageInputModel
}

func deleteLanguage(at index: Int) {
languageList.remove(at: index)
}

func appendLanguage() {
languageList.append(
.init(languageName: "", languageScore: "")
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import Foundation

protocol InputLanguageInfoStateProtocol {}
protocol InputLanguageInfoStateProtocol {
var languageList: [LanguageInputModel] { get }
}

protocol InputLanguageInfoActionProtocol: AnyObject {}
protocol InputLanguageInfoActionProtocol: AnyObject {
func updateLanguageName(name: String, at index: Int)
func updateLanguageScore(score: String, at index: Int)
func deleteLanguage(at index: Int)
func appendLanguage()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

struct LanguageInputModel: Equatable {
let languageName: String
let languageScore: String

init(languageName: String, languageScore: String) {
self.languageName = languageName
self.languageScore = languageScore
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,103 @@
import BaseFeature
import DesignSystem
import FoundationUtil
import SwiftUI
import ViewUtil

struct InputLanguageInfoView: View {
@StateObject var container: MVIContainer<InputLanguageInfoIntentProtocol, InputLanguageInfoStateProtocol>
var intent: any InputLanguageInfoIntentProtocol { container.intent }
var state: any InputLanguageInfoStateProtocol { container.model }

var body: some View {
Text("Hello, World!")
GeometryReader { proxy in
SMSNavigationTitleView(title: "์ •๋ณด์ž…๋ ฅ") {
Rectangle()
.fill(Color.sms(.neutral(.n10)))
.frame(maxWidth: .infinity)
.frame(height: 16)

VStack(spacing: 32) {
pageTitleView()

VStack(spacing: 8) {
languageListView(proxy: proxy)
.titleWrapper("์™ธ๊ตญ์–ด")
.aligned(.leading)

SMSChip("์ถ”๊ฐ€") {
intent.languageAppendButtonDidTap()
}
.aligned(.leading)
}
.animation(.default, value: state.languageList.count)

Spacer()

HStack(spacing: 8) {
CTAButton(text: "์ด์ „", style: .outline) {
intent.prevButtonDidTap()
}
.frame(maxWidth: proxy.size.width / 3)

CTAButton(text: "์ž…๋ ฅ ์™„๋ฃŒ") {
intent.completeButtonDidTap()
}
.frame(maxWidth: .infinity)
}
.padding(.bottom, 32)
}
.padding([.top, .horizontal], 20)
}
}
}

@ViewBuilder
func pageTitleView() -> some View {
HStack(spacing: 4) {
Text("์™ธ๊ตญ์–ด")
.foregroundColor(.sms(.system(.black)))

Text("*")
.foregroundColor(.sms(.sub(.s2)))

Spacer()

SMSPageControl(pageCount: 6, selectedPage: 5)
}
.smsFont(.title1)
}

@ViewBuilder
func languageListView(proxy: GeometryProxy) -> some View {
VStack(spacing: 12) {
ForEach(state.languageList.indices, id: \.self) { index in
HStack(spacing: 16) {
SMSTextField(
"์˜ˆ) ํ† ์ต",
text: Binding(
get: { state.languageList[safe: index]?.languageName ?? "" },
set: { intent.updateLanguageName(name: $0, at: index) }
)
)
.frame(maxWidth: .infinity)

SMSTextField(
"900",
text: Binding(
get: { state.languageList[safe: index]?.languageScore ?? "" },
set: { intent.updateLanguageScore(score: $0, at: index) }
)
)
.frame(maxWidth: proxy.size.width / 4)

Button {
intent.deleteLanguage(at: index)
} label: {
SMSIcon(.trash)
}
}
}
}
}
}