Skip to content

Instantly share code, notes, and snippets.

@aheze
aheze / Saved.swift
Created May 27, 2022 15:35
App Storage with `objectWillChange` support
/// based on https://github.com/xavierLowmiller/AppStorage
/// A property wrapper type that reflects a value from `UserDefaults` and
/// invalidates a view on a change in value in that user default.
@frozen @propertyWrapper public struct Saved<Value>: DynamicProperty {
@ObservedObject private var _value: Storage<Value>
let saveValue: (Value) -> Void
let key: String
var valueChanged: (() -> Void)?
private init(value: Value, store: UserDefaults, key: String, transform: @escaping (Any?) -> Value?, saveValue: @escaping (Value) -> Void) {
//
// ContentView.swift
// Paywall
//
// Created by A. Zheng (github.com/aheze) on 4/29/22.
// Copyright © 2022 A. Zheng. All rights reserved.
//
import SwiftUI
Templates.Menu {
Templates.MenuButton(title: "How do I make this button green?", systemImage: "questionmark.circle.fill") { print("Button 1 pressed") }
.foregroundColor(.green)
Templates.MenuButton(title: "Easy.", systemImage: "face.smiling") { print("Button 2 pressed") }
} label: { fade in
Text("Present Menu!")
.opacity(fade ? 0.5 : 1)
}
struct ContentView: View {
@State var present = false
var body: some View {
Button("Present popover!") {
present = true
}
.frameTag("Button")
.popover(present: $present) {
Text("Hi, I'm a popover.")
struct ContentView: View {
@State var selection: String?
var body: some View {
HStack {
Button("1st") { selection = "1" }
.popover(selection: $selection, tag: "1") {
Text("1st Popover")
.padding()
.foregroundColor(.white)
/// https://github.com/aheze/Popovers/blob/main/Sources/Popover%2BLifecycle.swift#L130-L131
/// Use same ID so that SwiftUI animates the change.
newPopover.context.id = oldContext.id
Button("Present popover!") {
present = true
}
.popover(
present: $present,
attributes: {
$0.presentation.animation = .spring(response: 0.6, dampingFraction: 0.4, blendDuration: 1)
$0.presentation.transition = .offset(x: 0, y: 30).combined(with: .opacity)
$0.dismissal.transition = .offset(x: 0, y: 30).combined(with: .opacity)
$0.rubberBandingMode = .yAxis
Button("Present popover!") {
present = true
}
.padding()
.border(.green)
.popover(
present: $present,
attributes: {
$0.position = .absolute(
originAnchor: .top,
import Popovers
import SwiftUI
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
@IBAction func buttonPressed(_ sender: Any) {
var popover = Popover { PopoverView() }
popover.attributes.sourceFrame = { [weak button] in
button.windowFrame()
}
import Popovers
import SwiftUI
struct ContentView: View {
@State var present = false
var body: some View {
Button("Present popover!") {
present = true
}