StikDebug/StikJIT/Views/MainTabView.swift
2025-08-03 02:43:52 -04:00

157 lines
5.1 KiB
Swift

//
// MainTabView.swift
// StikJIT
//
// Created by Stephen on 3/27/25.
//
import SwiftUI
import UIKit
fileprivate struct TabItem: Identifiable, Hashable {
let id: Int
let title: String
let systemImage: String
}
fileprivate struct BlurView: UIViewRepresentable {
let style: UIBlurEffect.Style
func makeUIView(context: Context) -> UIVisualEffectView {
UIVisualEffectView(effect: UIBlurEffect(style: style))
}
func updateUIView(_ uiView: UIVisualEffectView, context: Context) {}
}
fileprivate struct RoundedCorner: Shape {
var radius: CGFloat = .infinity
var corners: UIRectCorner = .allCorners
func path(in rect: CGRect) -> Path {
Path(
UIBezierPath(
roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
).cgPath
)
}
}
fileprivate extension View {
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
clipShape(RoundedCorner(radius: radius, corners: corners))
}
}
fileprivate struct CustomTabBar: View {
let items: [TabItem]
@Binding var selection: Int
let accentColor: Color
var body: some View {
HStack {
ForEach(items) { item in
Spacer()
Button(action: { withAnimation { selection = item.id } }) {
VStack(spacing: 4) {
Image(systemName: item.systemImage)
.font(.system(size: 20, weight: .semibold))
Text(item.title)
.font(.caption)
}
.foregroundColor(selection == item.id ? accentColor : .secondary)
}
Spacer()
}
}
.padding(.vertical, 10)
.padding(.horizontal, 12)
.background(
BlurView(style: .systemMaterial)
.ignoresSafeArea(edges: .bottom)
)
.cornerRadius(16, corners: .allCorners)
.shadow(color: Color.black.opacity(0.1), radius: 4, x: 0, y: -2)
}
}
struct MainTabView: View {
@AppStorage("customAccentColor") private var customAccentColorHex: String = ""
@AppStorage("enableAdvancedOptions") private var enableAdvancedOptions = false
@AppStorage("enableTesting") private var enableTesting = false
@State private var selection: Int = 0
@State private var isTabBarHidden: Bool = false
private var accentColor: Color {
customAccentColorHex.isEmpty
? .blue
: Color(hex: customAccentColorHex) ?? .blue
}
private var tabs: [TabItem] {
var items: [TabItem] = [
TabItem(id: 0, title: "Home", systemImage: "house"),
TabItem(id: 1, title: "Scripts", systemImage: "scroll"),
TabItem(id: 2, title: "Testing", systemImage: "square.grid.2x2"),
]
#if DEBUG
items += [
TabItem(id: 3, title: "Location", systemImage: "globe.americas"),
TabItem(id: 4, title: "Info", systemImage: "info.circle.fill"),
TabItem(id: 5, title: "Settings", systemImage: "gearshape.fill")
]
#else
items += [
TabItem(id: 3, title: "Info", systemImage: "info.circle.fill"),
TabItem(id: 4, title: "Settings", systemImage: "gearshape.fill")
]
#endif
return items
}
var body: some View {
ZStack(alignment: .bottom) {
Group {
switch selection {
case 0: HomeView()
case 1: ScriptListView()
case 2: IPAAppManagerView()
#if DEBUG
case 3: LocationSimulatorView(deviceIp: "10.7.0.2")
case 4: DeviceInfoView()
case 5: SettingsView()
#else
case 3: DeviceInfoView()
case 4: SettingsView()
#endif
default: HomeView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.accentColor(accentColor)
.environment(\.accentColor, accentColor)
CustomTabBar(
items: tabs,
selection: $selection,
accentColor: accentColor
)
.offset(x: isTabBarHidden ? -UIScreen.main.bounds.width : 0,
y: -40)
.animation(.spring(response: 0.3, dampingFraction: 0.7),
value: isTabBarHidden)
}
.gesture(
DragGesture(minimumDistance: 30, coordinateSpace: .local)
.onEnded { value in
withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
if value.translation.width < -30 {
isTabBarHidden = true
} else if value.translation.width > 30 {
isTabBarHidden = false
}
}
}
)
.edgesIgnoringSafeArea(.bottom)
}
}