EasyApp

Shared Tools

Common tools, view modifiers, extensions, components, and public functions in EasyAppSwiftUI

Shared Tools

EasyAppSwiftUI provides a rich collection of utility tools, including view modifiers, extension methods, and utility functions to help you quickly build feature-complete SwiftUI applications.

We continuously update our utility toolkit to help you rapidly build fully-featured SwiftUI applications.

Overview

  • 12 Custom View Modifiers - For authentication, paywalls, loading states, etc.
  • Extension Methods - Enhance SwiftUI views and basic type functionality
  • Utility Functions - Validation, haptic feedback, app navigation, and other practical features
  • Cross-Version Compatibility - Support for compatibility across different iOS versions

View Modifiers

1. Authentication Modifier

Automatically manages user authentication state, displaying different content based on login status.

ContentView()
    .modifier(AuthViewModifier())

// Or use extension method
ContentView()
    .showAuthView()

Key Features:

  • Automatically checks user login status
  • Shows login/registration interface for unauthenticated users
  • Shows main app interface for authenticated users
  • Smooth state transition animations

2. Paywall Modifier

Locks content behind a paywall and manages subscription verification.

// Basic usage
PremiumContentView()
    .modifier(RequirePremiumViewModifier())

// Advanced usage
PremiumContentView()
    .requirePremium(
        subscriptionType: .revenueCat,
        sheetOrFullScreenCover: .sheet,
        onCancelPaywall: {
            print("User cancelled payment")
        },
        onPaySuccess: {
            print("Payment successful")
        }
    )

Core Implementation:

struct RequirePremiumViewModifier: ViewModifier {
    @EnvironmentObject private var authManager: AuthManager
    @State private var showPaywall = false
    
    let subscriptionType: SubscriptionType
    let sheetOrFullScreenCover: SheetOrFullScreenCover
    let onCancelPaywall: () -> Void
    let onPaySuccess: () -> Void
    
    func body(content: Content) -> some View {
        content
            .onAppear {
                showPaywall = !authManager.subscriptionActive
            }
            .sheet(isPresented: sheetOrFullScreenCover == .sheet ? $showPaywall : .constant(false)) {
                paywallContent()
            }
    }
}

3. Loading State Modifier

Displays full-screen loading indicator with optional message overlay.

@State private var isLoading = false

ContentView()
    .modifier(FullScreenToastViewModifier(
        isPresenting: $isLoading,
        message: "Processing your request...",
        backgroundColor: Color.black.opacity(0.7)
    ))

// Or use extension method
ContentView()
    .fullScreenLoading(isPresenting: $isLoading)

4. Shimmer Effect Modifier

Adds animated shimmer effect to views, commonly used for loading states.

LoadingView()
    .modifier(ShimmerViewModifier(duration: 2.0, autoreverse: true))

// Or use extension method
LoadingView()
    .shimmering(enable: true, duration: 1.5)

5. Keyboard Management Modifier

Automatically dismisses keyboard when user drags.

FormView()
    .modifier(ResignKeyboardOnDragGesture())

// Or use extension method
FormView()
    .dismissKeyboard()

Extension Methods

Color Extensions

Support for creating colors from hexadecimal strings.

extension Color {
    init(hex: String) {
        let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int: UInt64 = 0
        Scanner(string: hex).scanHexInt64(&int)
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            (a, r, g, b) = (1, 1, 1, 0)
        }
        
        self.init(
            .sRGB,
            red: Double(r) / 255,
            green: Double(g) / 255,
            blue: Double(b) / 255,
            opacity: Double(a) / 255
        )
    }
}

Usage Examples:

let primaryColor = Color(hex: "007AFF")     // 6-digit RGB
let redColor = Color(hex: "F00")            // 3-digit RGB
let transparentBlue = Color(hex: "80007AFF") // 8-digit ARGB

String Extensions

Provides string content validation functionality.

extension String {
    var containsLetter: Bool {
        let letterRegex = ".*[A-Za-z]+.*"
        let passwordTest = NSPredicate(format: "SELF MATCHES %@", letterRegex)
        return passwordTest.evaluate(with: self)
    }
    
    var containsNumber: Bool {
        let numberRegex = ".*[0-9]+.*"
        let passwordTest = NSPredicate(format: "SELF MATCHES %@", numberRegex)
        return passwordTest.evaluate(with: self)
    }
}

Usage Examples:

let password = "password123"
let hasLetters = password.containsLetter  // true
let hasNumbers = password.containsNumber  // true

Date Extensions

Provides user-friendly date formatting.

extension Date {
    var friendlyLocalFormat: String {
        return self.formatted(date: .abbreviated, time: .omitted)
    }
}

Usage Examples:

let now = Date()
let formattedDate = now.friendlyLocalFormat  // "Jan 15, 2024"

View Extensions

Provides rich view enhancement functionality.

Loading States

// Button loading state
Button("Submit") { }
    .loading($isLoading)

// Toast notifications
someView.showToast($showToast, message: "Operation successful", isSuccess: true)

// Full-screen loading
someView.fullScreenLoading(isPresenting: $isLoading, message: "Loading...")

Styling and Appearance

// Rounded corners
someView.roundedCorners(radius: 12)
someView.cardRoundedCorners()    // Predefined card corners
someView.circle()                // Circular clipping

// Shadow effects
someView.shadowCompat()
someView.colorSchemeShadow(
    light: Color.gray.opacity(0.3),
    dark: Color.white.opacity(0.1),
    radius: 4
)

// Background handling
someView.viewBackground()  // Adaptive system background

Interaction Enhancements

// Enhanced tap gesture
CustomView()
    .tappable { 
        // Tap action
    }

// Web view presentation
someView.webViewSheet(
    isPresented: $showWebView,
    url: URL(string: "https://example.com"),
    title: "Web Page Title"
)

Utility Functions

Haptic Feedback Engine

Provides simple haptic feedback functionality.

enum HapticsEngine {
    static func impact(style: UIImpactFeedbackGenerator.FeedbackStyle = .light) {
        UIImpactFeedbackGenerator(style: style).impactOccurred()
    }
}

Usage Examples:

// Light vibration
HapticsEngine.impact(style: .light)

// Medium vibration
HapticsEngine.impact(style: .medium)

// Heavy vibration
HapticsEngine.impact(style: .heavy)

Validation Tools

Provides common input validation functionality.

enum Validate {
    // Email validation
    static func validateEmail(_ email: String) -> Bool {
        let emailPattern = #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"#
        let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailPattern)
        return emailPredicate.evaluate(with: email)
    }
    
    // Password length validation
    static func validatePasswordLength(_ password: String) -> Bool {
        return password.count >= 6 && password.count <= 12 && !password.isEmpty
    }
    
    // Password letter validation
    static func validatePasswordLetter(_ password: String) -> Bool {
        return password.containsLetter && !password.isEmpty
    }
    
    // Password number validation
    static func validatePasswordNumber(_ password: String) -> Bool {
        return password.containsNumber && !password.isEmpty
    }
    
    // Complete password validation
    static func validatePassword(_ password: String) -> Bool {
        return validatePasswordLength(password) && 
               validatePasswordLetter(password) && 
               validatePasswordNumber(password)
    }
}

Usage Examples:

let email = "user@example.com"
let password = "password123"

let isValidEmail = Validate.validateEmail(email)        // true
let isValidPassword = Validate.validatePassword(password) // true

App Navigation Tools

Provides in-app and external URL navigation functionality.

enum OpenApp {
    // Open URL in external browser
    static func openUrlOutsideApp(_ url: String) {
        guard let url = URL(string: url) else { return }
        UIApplication.shared.open(url)
    }
    
    // Open URL within app
    static func openUrlInApp(_ url: String) {
        guard let url = URL(string: url) else { return }
        let safariViewController = SFSafariViewController(url: url)
        if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
           let rootViewController = windowScene.windows.first?.rootViewController {
            rootViewController.present(safariViewController, animated: true)
        }
    }
}

Usage Examples:

// Open in external browser
OpenApp.openUrlOutsideApp("https://www.apple.com")

// Open within app
OpenApp.openUrlInApp("https://developer.apple.com")

Compatibility Features

Cross-Version Compatibility

// iOS 17+ compatible onChange modifier
someView.onChangeCompat(of: value) { oldValue, newValue in
    // Handle value changes, automatically adapts to iOS 17+ and earlier versions
}

// Haptic feedback compatibility
someView.sensoryFeedbackCompat(trigger: triggerValue)

Enum Definitions

// Button style types
enum ButtonStyleType {
    case common  // Common button style
    case text    // Text button style
}

// Subscription types
enum SubscriptionType: String, CaseIterable {
    case revenueCat  // RevenueCat subscription
    case storeKit2   // StoreKit2 subscription
}

// Presentation styles
enum SheetOrFullScreenCover: String, CaseIterable {
    case sheet           // Sheet presentation
    case fullScreenCover // Full screen cover
}

Dependencies

This module requires the following external libraries:

  • JDStatusBarNotification - Status bar notifications
  • WhatsNewKit - "What's New" presentation
  • AlertToast - Toast notifications
  • RevenueCat (optional) - Subscription management
  • SafariServices - In-app browser

Best Practices

1. Modular Usage

// Combine multiple modifiers
ContentView()
    .cardRoundedCorners()
    .cardShadow()
    .requirePremium()
    .showToast($showToast, message: "Success!", isSuccess: true)

2. State Management

@State private var isLoading = false
@State private var showError = false

Button("Submit") {
    isLoading = true
    // Perform operation
}
.loading($isLoading)
.showToast($showError, message: "Operation failed", isSuccess: false)

3. Theme Adaptation

// Automatically adapt to dark/light mode
CardView()
    .colorSchemeShadow(
        light: .gray.opacity(0.3),
        dark: .white.opacity(0.1)
    )
    .viewBackground()

Last updated on