-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d3fdf25
commit 1164e36
Showing
7 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
116
Source/DDS/Component/Modal/Dialog/DodamDialogPresenter.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import Foundation | ||
|
||
protocol ModalProvider: ObservableObject { | ||
var isPresent: Bool { get } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |