✨ :: Add example application

This commit is contained in:
Felix M.
2026-01-31 10:41:02 +01:00
parent 27392ece2a
commit 81a830c36f
14 changed files with 958 additions and 0 deletions
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,85 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,40 @@
//
// ContentView.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Basic Example", systemImage: SFSymbol.iPhoneGen3.rawValue) {
BasicExampleView()
}
Tab("Notch Example", systemImage: SFSymbol.iPhoneGen2.rawValue) {
NotchExampleView()
}
Tab("UIKit Example", systemImage: SFSymbol.squareStack.rawValue) {
UIKitExampleView()
}
Tab("SwiftUI Example", systemImage: SFSymbol.swift.rawValue) {
SwiftUIExampleView()
}
}
.overlay(alignment: .top) {
Text("– Gradient Loading Bar Example –")
.font(.caption)
.offset(x: 0, y: .space3)
.accessibilityHidden(true)
}
}
}
// MARK: - Preview
#Preview {
ContentView()
}
@@ -0,0 +1,83 @@
//
// BasicExampleView.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import GradientLoadingBar
import SwiftUI
/// A basic example view demonstrating the usage of the `GradientLoadingBar`.
struct BasicExampleView: View {
private let relativeToSafeAreaLoadingBar = GradientLoadingBar()
private let ignoringSafeAreaLoadingBar = GradientLoadingBar(isRelativeToSafeArea: false)
var body: some View {
NavigationStack {
VStack(spacing: .space6) {
VStack(spacing: .space2) {
Text("Relative to Safe Area")
.font(.headline)
HStack(spacing: .space2) {
Button {
relativeToSafeAreaLoadingBar.fadeOut()
} label: {
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
Button {
relativeToSafeAreaLoadingBar.fadeIn()
} label: {
Label("Show", systemImage: SFSymbol.eye.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
}
}
VStack(spacing: .space2) {
Text("Ignores Safe Area")
.font(.headline)
HStack(spacing: .space2) {
Button {
ignoringSafeAreaLoadingBar.fadeOut()
} label: {
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
Button {
ignoringSafeAreaLoadingBar.fadeIn()
} label: {
Label("Show", systemImage: SFSymbol.eye.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
}
}
}
.padding(.space6)
.navigationTitle("Basic Example")
}
.onDisappear {
relativeToSafeAreaLoadingBar.fadeOut()
ignoringSafeAreaLoadingBar.fadeOut()
}
}
}
// MARK: - Preview
#Preview {
// Previews do not provide a key window, therefore button interactions do not display the loading bar.
// To view the loading bar in action, run the example application in the simulator.
BasicExampleView()
}
@@ -0,0 +1,58 @@
//
// NotchExampleView.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import GradientLoadingBar
import SwiftUI
/// An example view demonstrating the usage of the `NotchGradientLoadingBar`
struct NotchExampleView: View {
private let notchGradientLoadingBar = NotchGradientLoadingBar()
var body: some View {
NavigationStack {
VStack(spacing: .space4) {
HStack(spacing: .space2) {
Button {
notchGradientLoadingBar.fadeOut()
} label: {
Label("Hide", systemImage: SFSymbol.eyeSlash.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
Button {
notchGradientLoadingBar.fadeIn()
} label: {
Label("Show", systemImage: SFSymbol.eye.rawValue)
.padding(.space1)
}
.buttonStyle(.borderedProminent)
}
Text("**Note:** In case the device doesn't have a notch, the loading bar will be displayed with a regular layout.")
.font(.footnote)
.multilineTextAlignment(.center)
.padding(.horizontal, .space2)
}
.padding(.space6)
.navigationTitle("Notch Example")
}
.onDisappear {
notchGradientLoadingBar.fadeOut()
}
}
}
// MARK: - Preview
#Preview {
// Previews do not provide a key window, therefore button interactions do not display the loading bar.
// To view the loading bar in action, run the example application in the simulator.
NotchExampleView()
}
@@ -0,0 +1,57 @@
//
// SwiftUIExampleView.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import GradientLoadingBar
import SwiftUI
private enum Config {
/// The custom gradient colors we use.
///
/// Source: <https://color.adobe.com/Pink-Flamingo-color-theme-10343714/>
static let gradientColors = [
#colorLiteral(red: 0.9490196078, green: 0.3215686275, blue: 0.431372549, alpha: 1), #colorLiteral(red: 0.9450980392, green: 0.4784313725, blue: 0.5921568627, alpha: 1), #colorLiteral(red: 0.9529411765, green: 0.737254902, blue: 0.7843137255, alpha: 1), #colorLiteral(red: 0.4274509804, green: 0.8666666667, blue: 0.9490196078, alpha: 1), #colorLiteral(red: 0.7568627451, green: 0.9411764706, blue: 0.9568627451, alpha: 1),
].map(Color.init)
}
/// A SwiftUI view demonstrating the usage of the `GradientLoadingBarView`,
/// showcasing both default and custom gradient colors.
struct SwiftUIExampleView: View {
var body: some View {
NavigationStack {
VStack(spacing: .space6) {
VStack(spacing: .space2) {
Text("Default Gradient Colors")
.font(.callout)
GradientLoadingBarView()
.frame(height: 3)
.clipShape(RoundedRectangle(cornerRadius: 1.5))
}
VStack(spacing: .space2) {
Text("Custom Gradient Colors")
.font(.callout)
GradientLoadingBarView(
gradientColors: Config.gradientColors,
)
.frame(height: 3)
.clipShape(RoundedRectangle(cornerRadius: 1.5))
}
}
.padding(.space6)
.navigationTitle("SwiftUI Example")
}
}
}
// MARK: - Preview
#Preview {
SwiftUIExampleView()
}
@@ -0,0 +1,109 @@
//
// UIKitExampleView.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import GradientLoadingBar
import SwiftUI
import UIKit
private enum Config {
/// The custom gradient colors we use.
///
/// Source: <https://color.adobe.com/Pink-Flamingo-color-theme-10343714/>
static let gradientColors = [
#colorLiteral(red: 0.9490196078, green: 0.3215686275, blue: 0.431372549, alpha: 1), #colorLiteral(red: 0.9450980392, green: 0.4784313725, blue: 0.5921568627, alpha: 1), #colorLiteral(red: 0.9529411765, green: 0.737254902, blue: 0.7843137255, alpha: 1), #colorLiteral(red: 0.4274509804, green: 0.8666666667, blue: 0.9490196078, alpha: 1), #colorLiteral(red: 0.7568627451, green: 0.9411764706, blue: 0.9568627451, alpha: 1),
]
}
/// A SwiftUI view that demonstrates the usage of `GradientActivityIndicatorView` from UIKit.
struct UIKitExampleView: View {
var body: some View {
NavigationStack {
UIKitExampleViewControllerRepresentable()
.navigationTitle("UIKit Example")
}
}
}
// MARK: - Supporting Types
/// A UIViewControllerRepresentable that wraps the `UIKitExampleViewController`.
private struct UIKitExampleViewControllerRepresentable: UIViewControllerRepresentable {
func makeUIViewController(context _: Context) -> UIViewController {
UIKitExampleViewController()
}
func updateUIViewController(_: UIViewController, context _: Context) {}
}
/// A UIViewController that showcases the `GradientActivityIndicatorView`
/// with default and custom gradient colors.
private final class UIKitExampleViewController: UIViewController {
// MARK: - Private Properties
private let contentStackView = UIStackView()
private let defaultGradientColorsLabel = UILabel()
private let defaultGradientActivityIndicatorView = GradientActivityIndicatorView()
private let customGradientColorsLabel = UILabel()
private let customGradientActivityIndicatorView = GradientActivityIndicatorView()
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpSubviews()
setUpConstraints()
}
// MARK: - Private Methods
private func setUpSubviews() {
contentStackView.axis = .vertical
contentStackView.alignment = .fill
contentStackView.spacing = .space2
contentStackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(contentStackView)
defaultGradientColorsLabel.text = "Default Gradient Colors"
defaultGradientColorsLabel.textAlignment = .center
defaultGradientColorsLabel.font = .preferredFont(forTextStyle: .callout)
contentStackView.addArrangedSubview(defaultGradientColorsLabel)
contentStackView.addArrangedSubview(defaultGradientActivityIndicatorView)
contentStackView.setCustomSpacing(.space6, after: defaultGradientActivityIndicatorView)
customGradientColorsLabel.text = "Custom Gradient Colors"
customGradientColorsLabel.textAlignment = .center
customGradientColorsLabel.font = .preferredFont(forTextStyle: .callout)
contentStackView.addArrangedSubview(customGradientColorsLabel)
customGradientActivityIndicatorView.gradientColors = Config.gradientColors
contentStackView.addArrangedSubview(customGradientActivityIndicatorView)
}
private func setUpConstraints() {
NSLayoutConstraint.activate([
contentStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: .space6),
contentStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -.space6),
contentStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
defaultGradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: 3),
customGradientActivityIndicatorView.heightAnchor.constraint(equalToConstant: 3),
])
}
}
// MARK: - Preview
#Preview {
UIKitExampleView()
}
@@ -0,0 +1,18 @@
//
// GradientLoadingBarExampleApp.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import SwiftUI
@main
struct GradientLoadingBarExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
@@ -0,0 +1,36 @@
//
// CGFloat+Spacing.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import CoreGraphics
/// Standard spacing values based on a 4-point grid.
///
/// These constants provide a shared spacing scale to ensure visual consistency across layouts.
/// Values are expressed in points and increase in 4-point increments.
///
/// Naming follows the pattern `spaceN`, where `N` represents the number of 4-point units (e.g. `space3` = 12 points).
///
/// ### Usage
///
/// ```swift
/// VStack(spacing: .space4) {
/// Text("Title")
/// Text("Subtitle")
/// }
/// ```
extension CGFloat {
static let space0: CGFloat = 0
static let space1: CGFloat = 4
static let space2: CGFloat = 8
static let space3: CGFloat = 12
static let space4: CGFloat = 16
static let space5: CGFloat = 20
static let space6: CGFloat = 24
static let space8: CGFloat = 32
static let space10: CGFloat = 40
}
@@ -0,0 +1,58 @@
//
// SFSymbol.swift
// GradientLoadingBarExample
//
// Created by Felix Mau on 10.01.26.
// Copyright © 2026 Felix Mau. All rights reserved.
//
import SwiftUI
import UIKit
/// SF Symbols used by the example application.
///
/// Using an enum avoids hard-coded string literals and improves discoverability, autocompletion and compile-time safety.
/// The raw value of each case corresponds to the SF Symbol’s system name.
enum SFSymbol: String {
case eye
case eyeSlash = "eye.slash"
case iPhoneGen2 = "iphone.gen2"
case iPhoneGen3 = "iphone.gen3"
case squareStack = "square.stack"
case swift
}
// MARK: - Helper
extension Image {
/// Creates a SwiftUI `Image` from an `SFSymbol`.
///
/// ### Usage
///
/// ```swift
/// Image(sfSymbol: .house)
/// ```
///
/// - Parameter sfSymbol: The SF Symbol to display.
init(sfSymbol: SFSymbol) {
self.init(systemName: sfSymbol.rawValue)
}
}
extension UIImage {
/// Creates a `UIImage` from an `SFSymbol`.
///
/// ### Usage
///
/// ```swift
/// let image = UIImage(sfSymbol: .plus)
/// ```
///
/// - Parameter sfSymbol: The SF Symbol to display.
///
/// - Returns: A system image, or `nil` if the symbol name is invalid or
/// unavailable on the current OS version.
convenience init?(sfSymbol: SFSymbol) {
self.init(systemName: sfSymbol.rawValue)
}
}