Skip to content

Instantly share code, notes, and snippets.

@diegoventura
Last active December 27, 2020 18:12
Show Gist options
  • Save diegoventura/3168871fec9c6ef471d56a612681b8fa to your computer and use it in GitHub Desktop.
Save diegoventura/3168871fec9c6ef471d56a612681b8fa to your computer and use it in GitHub Desktop.
import SwiftUI
struct DialogButton {
enum ButtonType {
case destructive
case cancel
case `default`
}
let title: String
let type: ButtonType
let action: () -> Void
public init(title: String, type: ButtonType, action: @escaping () -> Void) {
self.title = title
self.type = type
self.action = action
}
}
struct ConfirmationDialog: ViewModifier {
@Binding var isPresented: Bool
let title: String
let message: String?
let buttons: [DialogButton]
let horizontalSizeClass: UserInterfaceSizeClass?
let onDismiss: () -> Void
func body(content: Content) -> some View {
content.if(horizontalSizeClass == .some(.regular)) { content in
content.popover(isPresented: $isPresented, content: popoverContent)
}.if(horizontalSizeClass == .some(.compact)) { content in
content.actionSheet(isPresented: $isPresented) {
ActionSheet(title: Text(self.title), message: Text(self.message ?? ""), buttons: sheetButtons)
}
}
}
private var sheetButtons: [ActionSheet.Button] {
UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .teal
return buttons.map { button -> ActionSheet.Button in
switch button.type {
case .cancel:
return .cancel(button.action)
case .`default`:
return .default(Text(button.title), action: button.action)
case .destructive:
return .destructive(Text(button.title), action: button.action)
}
}
}
private var popoverButtons: [Button<Text>] {
return buttons.map { button in
switch button.type {
case .cancel:
return Button(action: {
button.action()
}, label: {
Text(button.title)
.bold()
.foregroundColor(Color.teal)
})
case .`default`:
return Button(action: {
button.action()
}, label: {
Text(button.title)
.foregroundColor(Color.teal)
})
case .destructive:
return Button(action: {
button.action()
}, label: {
Text(button.title)
.foregroundColor(Color(UIColor.systemRed))
})
}
}
}
private func popoverContent() -> some View {
return VStack(alignment: .center, spacing: 10) {
Text(title)
.font(.footnote)
.foregroundColor(Color.secondary)
.bold()
.padding(.top)
if message != nil {
Text(message ?? "")
.font(.footnote)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
}
ForEach((0 ..< popoverButtons.count), id: \.self) { index in
Group {
Divider()
self.popoverButtons[index]
}
}
}
.buttonStyle(PlainButtonStyle())
.frame(width: 200)
.padding(10)
.onDisappear {
self.onDismiss()
}
}
}
import SwiftUI
struct MainView: View {
@State var isPresentingConfirmation: Bool
@Environment(\.horizontalSizeClass) private var horizontalSizeClass: UserInterfaceSizeClass?
var body: some View {
NavigationView {
Text("Hello world")
.navigationBarTitle("Welcome")
}
.navigationViewStyle(StackNavigationViewStyle())
}
private var logoutButton: some View {
Button(action: {
self.isPresentingConfirmation = true
}, label: {
Text("Press me")
})
.confirmationDialog(presented: $isPresentingConfirmation, title: "did you tap the button?", buttons: [
DialogButton(title: "No", type: .default) {
self.isPresentingConfirmation = false
},
DialogButton(title: "Yes", type: .destructive) {
self.isPresentingConfirmation = false
},
DialogButton(title: "Cancel", type: .cancel) {
self.isPresentingConfirmation = false
}
], horizontalSizeClass: horizontalSizeClass) {
self.isPresentingConfirmation = false
}
}
}
import SwiftUI
extension View {
func confirmationDialog(presented: Binding<Bool>, title: String, message: String? = nil, buttons: [DialogButton], horizontalSizeClass: UserInterfaceSizeClass?, onDismiss: @escaping () -> Void) -> some View {
self.modifier(ConfirmationDialog(isPresented: presented,
title: title,
message: message,
buttons: buttons,
horizontalSizeClass: horizontalSizeClass,
onDismiss: onDismiss))
}
func `if`<Content: View>(_ conditional: Bool, content: (Self) -> Content) -> some View {
if conditional {
return AnyView(content(self))
} else {
return AnyView(self)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment