Skip to content

Instantly share code, notes, and snippets.

@aheze
Created April 30, 2022 03:28
Show Gist options
  • Save aheze/8ce478b7eae189b76f28d6073d67b81b to your computer and use it in GitHub Desktop.
Save aheze/8ce478b7eae189b76f28d6073d67b81b to your computer and use it in GitHub Desktop.
//
// ContentView.swift
// Paywall
//
// Created by A. Zheng (github.com/aheze) on 4/29/22.
// Copyright © 2022 A. Zheng. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@State var presentingPaywall = false
var body: some View {
Button {
presentingPaywall = true
} label: {
Text("Present Paywall")
}
.buttonStyle(.borderedProminent)
.sheet(isPresented: $presentingPaywall) {
PaywallView(presentingPaywall: $presentingPaywall)
}
}
}
struct PaywallView: View {
@Binding var presentingPaywall: Bool
var body: some View {
NavigationView {
ScrollView {
VStack(spacing: 20) {
RowView(
color: .red,
imageName: "menucard.fill",
title: "Better Results",
description: "Swipe through specific types of restaurants in your area!"
)
RowView(
color: .red.offset(by: 0.03),
imageName: "map.fill",
title: "Place Filters",
description: "Coffee shops, bars, brunch, ice cream & more!"
)
RowView(
color: .red.offset(by: 0.06),
imageName: "fork.knife",
title: "Cuisine Filters",
description: "Chinese, American, Japanese, Indian & More!"
)
RowView(
color: .red.offset(by: 0.09),
imageName: "heart.fill",
title: "Dietary Filters",
description: "Vegan, Gluten-Free, Vegetarian & Halal!"
)
}
.padding(.top, 16)
.padding(.horizontal, 20)
.padding(.bottom, 160) /// make space for the bottom blur
}
.overlay(alignment: .bottom) {
VStack {
Text("One-time purchase of $0.99!")
Button {
print("Unlock Swipe Filters")
} label: {
Text("Unlock Swipe Filters")
.font(.title2.bold())
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(EdgeInsets(top: 16, leading: 20, bottom: 16, trailing: 20))
.background(.black)
.cornerRadius(20)
}
Button {
print("Restore Purchase")
} label: {
Text("Restore Purchase")
.foregroundColor(.secondary)
}
}
.padding(20)
.background(
VisualEffectView(.systemChromeMaterial)
.mask(
LinearGradient(
stops: [
.init(color: .clear, location: 0),
.init(color: .black, location: 0.2),
],
startPoint: .top,
endPoint: .bottom
)
)
.edgesIgnoringSafeArea(.all)
.padding(.top, -30) /// extend out top
)
}
.navigationTitle("Unlock Swipe Filters")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
presentingPaywall = false
} label: {
Image(systemName: "xmark")
.font(.system(size: 13, weight: .bold))
.foregroundColor(.secondary)
.padding(8)
.background {
Circle()
.fill(
Color(UIColor.secondarySystemBackground)
)
}
}
}
}
}
}
}
struct RowView: View {
let color: UIColor
let imageName: String
let title: String
let description: String
var body: some View {
HStack(spacing: 20) {
Color.white.opacity(0.4)
.frame(width: 60, height: 60)
.overlay {
Image(systemName: imageName)
.font(.title)
}
.cornerRadius(16)
.overlay {
RoundedRectangle(cornerRadius: 16)
.strokeBorder(Color.white.opacity(0.75), lineWidth: 1)
}
VStack(alignment: .leading, spacing: 6) {
Text(title)
.fontWeight(.bold)
Text(description)
.opacity(0.9)
}
.font(.title2)
}
.foregroundColor(.white)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(20)
.background(
LinearGradient(
colors: [
Color(color),
Color(color.offset(by: 0.06)),
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.cornerRadius(20)
}
}
extension UIColor {
var hsba: (h: CGFloat, s: CGFloat, b: CGFloat, a: CGFloat) {
var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
self.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
return (h: h, s: s, b: b, a: a)
}
func offset(by offset: CGFloat) -> UIColor {
let (h, s, b, a) = hsba
var newHue = h - offset
/// make it go back to positive
while newHue <= 0 {
newHue += 1
}
let normalizedHue = newHue.truncatingRemainder(dividingBy: 1)
return UIColor(hue: normalizedHue, saturation: s, brightness: b, alpha: a)
}
}
/// Use UIKit blurs in SwiftUI.
struct VisualEffectView: UIViewRepresentable {
/// The blur's style.
public var style: UIBlurEffect.Style
/// Use UIKit blurs in SwiftUI.
public init(_ style: UIBlurEffect.Style) {
self.style = style
}
public func makeUIView(context _: UIViewRepresentableContext<Self>) -> UIVisualEffectView {
UIVisualEffectView()
}
public func updateUIView(_ uiView: UIVisualEffectView, context _: UIViewRepresentableContext<Self>) {
uiView.effect = UIBlurEffect(style: style)
}
}
@aheze
Copy link
Author

aheze commented Apr 30, 2022

Result

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