diff --git a/StikJIT/Views/MainTabView.swift b/StikJIT/Views/MainTabView.swift index 1903c54..bb9242a 100644 --- a/StikJIT/Views/MainTabView.swift +++ b/StikJIT/Views/MainTabView.swift @@ -6,50 +6,152 @@ // 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 { - if customAccentColorHex.isEmpty { - return .blue - } else { - return Color(hex: customAccentColorHex) ?? .blue - } + customAccentColorHex.isEmpty + ? .blue + : Color(hex: customAccentColorHex) ?? .blue } - - var body: some View { - TabView { - HomeView() - .tabItem { - Label("Home", systemImage: "house") - } - ScriptListView() - .tabItem { - Label("Scripts", systemImage: "scroll") - } - IPAAppManagerView() - .tabItem { - Label("Testing", systemImage: "square.grid.2x2") - } - DeviceInfoView() - .tabItem { - Label("Info", systemImage: "info.circle.fill") - } + + 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 - LocationSimulatorView(deviceIp: "10.7.0.2") - .tabItem { - Label("Location", systemImage: "globe.americas") - } + 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 - SettingsView() - .tabItem { - Label("Settings", systemImage: "gearshape.fill") + 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) } - .accentColor(accentColor) - .environment(\.accentColor, accentColor) + .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) } }