Skip to content

Commit

Permalink
feat: Create DodamDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
hhhello0507 committed Jul 26, 2024
1 parent d3fdf25 commit 1164e36
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 0 deletions.
49 changes: 49 additions & 0 deletions Source/DDS/Component/Modal/BaseModal.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Foundation
import SwiftUI

struct BaseModal<MC: View, C: View>: View {

@Namespace var animation
@State private var scaleEffect: CGFloat = 1.2
@Binding var isPresent: Bool
@State var opacity: Double = 0.0
let backgroundColor: DodamColorable = DodamColor.Background.normal
let cornerRadius: CGFloat = 16
// let shadow: SeugiShadowSystem = .evBlack(.ev1)
@ViewBuilder let modalContent: () -> MC
@ViewBuilder let content: () -> C

var body: some View {
ZStack {
content()
Color.black
.opacity(0.2 * opacity)
.ignoresSafeArea()
// MARK: - Modal Content
VStack {
Spacer()
if isPresent {
modalContent()
.background(backgroundColor)
.cornerRadius(cornerRadius)
// .shadow(shadow)
.scaleEffect(scaleEffect)
.opacity(opacity)
} else {
modalContent()
.background(backgroundColor)
.cornerRadius(cornerRadius)
// .shadow(shadow)
.opacity(opacity)
}
Spacer()
}
}
.onChange(of: isPresent) { isPresent in
withAnimation(.easeOut(duration: 0.2)) {
opacity = isPresent ? 1 : 0
scaleEffect = isPresent ? 1 : 1.1
}
}
}
}
14 changes: 14 additions & 0 deletions Source/DDS/Component/Modal/Dialog/DialogButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

public struct DialogButton {
let title: String
let action: () -> Void

public init(
_ title: String,
action: @escaping () -> Void
) {
self.title = title
self.action = action
}
}
71 changes: 71 additions & 0 deletions Source/DDS/Component/Modal/Dialog/DialogProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Foundation

public final class DialogProvider: ObservableObject, ModalProvider {

public struct Builder {
let title: String
let message: String?
let secondaryButton: DialogButton?
let primaryButton: DialogButton?
let provider: DialogProvider

public init(
title: String,
provider: DialogProvider
) {
self.title = title
self.message = nil
self.secondaryButton = nil
self.primaryButton = nil
self.provider = provider
}

private init(
title: String,
message: String?,
secondaryButton: DialogButton?,
primaryButton: DialogButton?,
provider: DialogProvider
) {
self.title = title
self.message = message
self.secondaryButton = secondaryButton
self.primaryButton = primaryButton
self.provider = provider
}

public func message(_ message: String?) -> Self {
.init(title: title, message: message, secondaryButton: secondaryButton, primaryButton: primaryButton, provider: provider)
}

public func secondaryButton(_ title: String, action: @escaping () -> Void) -> Self {
.init(title: self.title, message: message, secondaryButton: .init(title, action: action), primaryButton: primaryButton, provider: provider)
}

public func primaryButton(_ title: String, action: @escaping () -> Void) -> Self {
.init(title: self.title, message: message, secondaryButton: secondaryButton, primaryButton: .init(title, action: action), provider: provider)
}

public func show() {
provider.title = title
provider.message = message
provider.secondaryButton = secondaryButton
provider.primaryButton = primaryButton
provider.isPresent = true
}
}

@Published public var isPresent = false
@Published var title: String = ""
@Published var message: String?
@Published var secondaryButton: DialogButton?
@Published var primaryButton: DialogButton?

public init() {}

public func present(
_ title: String
) -> Builder {
.init(title: title, provider: self)
}
}
116 changes: 116 additions & 0 deletions Source/DDS/Component/Modal/Dialog/DodamDialogPresenter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import SwiftUI
import Combine

public struct DodamDialogPresenter<C: View>: ModalViewProtocol {

public typealias P = DialogProvider
@StateObject private var provider: DialogProvider

let content: () -> C

public init(
provider: DialogProvider,
@ViewBuilder content: @escaping () -> C
) {
self._provider = .init(wrappedValue: provider)
self.content = content
}

func dismiss() {
provider.isPresent = false
}

public var body: some View {
BaseModal(
isPresent: $provider.isPresent,
modalContent: {
VStack(spacing: 18) {
HStack {
VStack(alignment: .leading, spacing: 12) {
Text(provider.title)
.heading1(.bold)
.foreground(DodamColor.Label.strong)
if let message = provider.message {
Text(message)
.body1(.medium)
.foreground(DodamColor.Label.alternative)
}
}
Spacer()
}
.padding(6)
HStack(spacing: 8) {
if let secondaryButton = provider.secondaryButton {
if let primaryButton = provider.primaryButton {
DodamButton.fullWidth(title: secondaryButton.title) {
secondaryButton.action()
dismiss()
}
.role(.assistive)
DodamButton.fullWidth(title: primaryButton.title) {
primaryButton.action()
dismiss()
}
} else {
HStack {
Spacer()
DodamTextButton.large(title: secondaryButton.title) {
secondaryButton.action()
dismiss()
}
}
}
} else {
HStack {
Spacer()
if let primaryButton = provider.primaryButton {
DodamTextButton.large(title: primaryButton.title) {
primaryButton.action()
dismiss()
}
} else {
DodamTextButton.large(title: "닫기", color: DodamColor.Primary.normal) {
dismiss()
}
}
}
}
}
}
.padding(18)
.frame(width: 328)
},
content: content
)
}
}

#Preview {
struct DialogPreview: View {
@StateObject private var provider = DialogProvider()
var body: some View {
DodamDialogPresenter(provider: provider) {
VStack {
Button("Show 1") {
provider.present("제목을 입력해주세요")
.message("본문을 입력해주세요")
.primaryButton("확인") {
//
}
.secondaryButton("취소") {
//
}
.show()
}
Button("Show 2") {
provider.present("제목을 입력해주세요")
.message("본문을 입력해주세요")
.show()
}
}
}
.registerSUIT()
}
}
return DialogPreview()
}
29 changes: 29 additions & 0 deletions Source/DDS/Component/Modal/DodamModalPresenter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// DodamModalProvider.swift
//
//
// Created by hhhello0507 on 7/26/24.
//

import SwiftUI

public struct DodamModalProvider<C: View>: View {

private let dialogProvider: DialogProvider
private let content: () -> C

public init(
dialogProvider: DialogProvider,
@ViewBuilder content: @escaping () -> C
) {
self.dialogProvider = dialogProvider
self.content = content
}

public var body: some View {
DodamDialogPresenter(provider: dialogProvider) {
content()
.environmentObject(dialogProvider)
}
}
}
5 changes: 5 additions & 0 deletions Source/DDS/Component/Modal/ModalProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

protocol ModalProvider: ObservableObject {
var isPresent: Bool { get }
}
10 changes: 10 additions & 0 deletions Source/DDS/Component/Modal/ModalViewProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import SwiftUI

protocol ModalViewProtocol: View {
associatedtype P: ModalProvider
associatedtype C: View

var content: () -> C { get }

func dismiss()
}

0 comments on commit 1164e36

Please sign in to comment.