Skip to content

Instantly share code, notes, and snippets.

@azamsharpschool
Created August 14, 2024 14:07
Show Gist options
  • Save azamsharpschool/9e7732f85f85353de069425454d0e8dc to your computer and use it in GitHub Desktop.
Save azamsharpschool/9e7732f85f85353de069425454d0e8dc to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// Learn
//
// Created by Mohammad Azam on 8/14/24.
//
import SwiftUI
enum Sheet: Identifiable, Hashable {
case settings
case contact(String)
var id: Self { self }
}
struct SheetAction {
typealias Action = (Sheet, (() -> Void)?) -> Void
let action: Action
func callAsFunction(_ sheet: Sheet, _ dismiss: (() -> Void)? = nil) {
action(sheet, dismiss)
}
}
struct ShowSheetKey: EnvironmentKey {
static var defaultValue: SheetAction = SheetAction { _, _ in }
}
extension EnvironmentValues {
var showSheet: (SheetAction) {
get { self[ShowSheetKey.self] }
set { self[ShowSheetKey.self] = newValue }
}
}
struct SheetView: View {
let sheet: Sheet
var body: some View {
switch sheet {
case .settings:
Text("Settings")
case .contact(let name):
Text("Contacting \(name)")
}
}
}
// THIS IS JUST FOR THE PREVIEWS
struct ContentViewContainer: View {
@State private var selectedSheet: Sheet?
@State private var onSheetDismiss: (() -> Void)?
var body: some View {
ContentView()
.environment(\.showSheet, SheetAction(action: { sheet, dismiss in
selectedSheet = sheet
onSheetDismiss = dismiss
}))
.sheet(item: $selectedSheet, onDismiss: onSheetDismiss) { sheet in
SheetView(sheet: sheet)
}
}
}
struct ContentView: View {
@Environment(\.showSheet) private var showSheet
private func settingsScreenDismissed() {
print("settingsScreenDismissed")
}
var body: some View {
VStack {
Button("Show Settings Screen") {
showSheet(.settings, settingsScreenDismissed)
}
Button("Show Contact Screen") {
showSheet(.contact("John Doe"))
}
}
.padding()
}
}
#Preview {
ContentViewContainer()
}
//
// LearnApp.swift
// Learn
//
// Created by Mohammad Azam on 8/14/24.
//
import SwiftUI
@main
struct LearnApp: App {
@State private var selectedSheet: Sheet?
@State private var onSheetDismiss: (() -> Void)?
var body: some Scene {
WindowGroup {
NavigationStack {
ContentView()
.environment(\.showSheet, SheetAction(action: { sheet, dismiss in
selectedSheet = sheet
onSheetDismiss = dismiss
}))
.sheet(item: $selectedSheet, onDismiss: onSheetDismiss) { sheet in
SheetView(sheet: sheet)
}
}
}
}
}
@abinhho
Copy link

abinhho commented Sep 6, 2024

  • How to know there is any sheet opening?
  • How to close sheet from sheet content (sheet close button)

@rursache
Copy link

rursache commented Sep 23, 2024

@abinhho

import SwiftUI

enum Sheet: Identifiable {
    case settings
    case contact(String)
    
    var id: String {
        switch self {
            case .settings:
                return "settings"
            case .contact(let name):
                return "contact_\(name)"
        }
    }
}

struct SheetManager: ViewModifier {
    @Binding var activeSheet: Sheet?
    
    func body(content: Content) -> some View {
        content
            .sheet(item: $activeSheet) { sheet in
                SheetView(sheet: sheet, dismiss: { activeSheet = nil })
            }
    }
}

extension View {
    func managedSheet(activeSheet: Binding<Sheet?>) -> some View {
        self.modifier(SheetManager(activeSheet: activeSheet))
    }
}

struct SheetView: View {
    let sheet: Sheet
    let dismiss: () -> Void
    
    var body: some View {
        VStack {
            sheetContent
            Button("Close", action: dismiss)
        }
    }
    
    @ViewBuilder
    private var sheetContent: some View {
        switch sheet {
            case .settings:
                Text("Settings")
            case .contact(let name):
                Text("Contacting \(name)")
        }
    }
}

struct ContentView: View {
    @State private var activeSheet: Sheet?
    
    var body: some View {
        VStack {
            Button("Show Settings") {
                activeSheet = .settings
            }
            Button("Show Contact") {
                activeSheet = .contact("John Doe")
            }
        }
        .managedSheet(activeSheet: $activeSheet)
    }
}

#Preview {
    ContentView()
}

@berlin2
Copy link

berlin2 commented Oct 14, 2024

Swift 6 compiler generates "Static property 'defaultValue' is not concurrency-safe because it is nonisolated global shared mutable state" at

static var defaultValue: SheetAction = SheetAction { _, _ in }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment