mirror of
https://github.com/phranck/TUIkit.git
synced 2026-05-21 09:50:35 +00:00
dec8c7c29f
Auto-animating loading indicator with three visual styles: - Dots (braille rotation), Line (ASCII rotation), Bouncing (Larson scanner with fade trail). Time-based frame calculation ensures each spinner runs at its own speed independent of render triggers. Configurable: SpinnerSpeed (.slow/.regular/.fast), BouncingTrackWidth (.minimum/.default/.maximum/.fixed(Int)), BouncingTrailLength (.short/.regular/.long), custom color. Run loop upgraded from 100ms to 40ms polling (~25 FPS) to support smooth animations.
102 lines
3.3 KiB
Swift
102 lines
3.3 KiB
Swift
//
|
|
// ContentView.swift
|
|
// TUIkitExample
|
|
//
|
|
// The main content view that routes between demo pages.
|
|
//
|
|
|
|
import TUIkit
|
|
|
|
// MARK: - Demo Page Enum
|
|
|
|
/// The available demo pages in the example app.
|
|
enum DemoPage: Int, CaseIterable {
|
|
case menu
|
|
case textStyles
|
|
case colors
|
|
case containers
|
|
case overlays
|
|
case layout
|
|
case buttons
|
|
case spinners
|
|
}
|
|
|
|
// MARK: - Content View (Page Router)
|
|
|
|
/// The main content view that switches between pages.
|
|
///
|
|
/// This view acts as a router, displaying the appropriate demo page
|
|
/// based on the current state. It uses `@State` for all reactive
|
|
/// properties — exactly like SwiftUI.
|
|
struct ContentView: View {
|
|
@State var currentPage: DemoPage = .menu
|
|
@State var menuSelection: Int = 0
|
|
|
|
var body: some View {
|
|
// Capture bindings for use in closures
|
|
let pageSetter = $currentPage
|
|
|
|
// Show current page based on state
|
|
// Note: Background color is set by AppRunner using theme.background
|
|
pageContent(for: currentPage, pageSetter: pageSetter)
|
|
.onKeyPress { event in
|
|
switch event.key {
|
|
case .escape:
|
|
// ESC goes back to menu (or exits if already on menu)
|
|
if currentPage != .menu {
|
|
pageSetter.wrappedValue = .menu
|
|
return true // Consumed
|
|
}
|
|
return false // Let default handler exit the app
|
|
|
|
default:
|
|
return false // Let other handlers process
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func pageContent(for page: DemoPage, pageSetter: Binding<DemoPage>) -> some View {
|
|
switch page {
|
|
case .menu:
|
|
MainMenuPage(currentPage: $currentPage, menuSelection: $menuSelection)
|
|
.statusBarItems {
|
|
StatusBarItem(shortcut: Shortcut.arrowsUpDown, label: "nav")
|
|
StatusBarItem(shortcut: Shortcut.enter, label: "select", key: .enter)
|
|
StatusBarItem(shortcut: Shortcut.range("1", "7"), label: "jump")
|
|
}
|
|
case .textStyles:
|
|
TextStylesPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .colors:
|
|
ColorsPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .containers:
|
|
ContainersPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .overlays:
|
|
OverlaysPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .layout:
|
|
LayoutPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .buttons:
|
|
ButtonsPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
case .spinners:
|
|
SpinnersPage()
|
|
.statusBarItems(subPageItems(pageSetter: pageSetter))
|
|
}
|
|
}
|
|
|
|
/// Common status bar items for sub-pages.
|
|
private func subPageItems(pageSetter: Binding<DemoPage>) -> [any StatusBarItemProtocol] {
|
|
[
|
|
StatusBarItem(shortcut: Shortcut.escape, label: "back") { [pageSetter] in
|
|
pageSetter.wrappedValue = .menu
|
|
},
|
|
StatusBarItem(shortcut: Shortcut.arrowsUpDown, label: "scroll"),
|
|
]
|
|
}
|
|
}
|