Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Folium-iOS/Structures/MeshGradientView.swift
2 views
//
//  MeshGradientView.swift
//  Folium-iOS
//
//  Created by Jarrod Norwell on 2/7/2025.
//

import SwiftUI

@available(iOS, introduced: 18)
struct MeshGradientView: View {
    var colours: [Color]
    
    private let points: [SIMD2<Float>] = [
        .init(0.0, 0.0), .init(0.5, 0.0), .init(1.0, 0.0),
        .init(0.0, 0.5), .init(0.5, 0.5), .init(1.0, 0.5),
        .init(0.0, 1.0), .init(0.5, 1.0), .init(1.0, 1.0)
    ]
    
    init(colours: [Color] = Color.coldWarm) {
        self.colours = colours
    }
    
    var body: some View {
        TimelineView(.animation) { timeline in
            MeshGradient(width: 3, height: 3, locations: .points(points), colors: .colors(animated(for: timeline.date)), background: .black, smoothsColors: true)
        }
        .ignoresSafeArea()
    }
    
    private func animated(for date: Date) -> [Color] {
        let phase = CGFloat(date.timeIntervalSince1970)
        return colours.enumerated().map { index, colour in
            let amount = cos(phase + Double(index) * 0.3) * 0.1
            return shift(colour: colour, by: amount)
        }
    }
    
    private func shift(colour: Color, by amount: Double) -> Color {
        var hue: CGFloat = 0
        var saturation: CGFloat = 0
        var brightness: CGFloat = 0
        var alpha: CGFloat = 0
        
        colour.uiColour.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
        
        hue += .init(amount)
        hue = hue.truncatingRemainder(dividingBy: 1.0)
        if hue < 0 {
            hue += 1
        }
        
        return .init(hue: .init(hue), saturation: .init(saturation), brightness: .init(brightness), opacity: .init(alpha))
    }
}