mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-15 20:10:30 +00:00
* Change default UPLOAD_IPA value to 'false' * Part 1 of the great debloat * Remove Mini Tools, adopt native alerts in StikJITApp, and update HomeView UI * Refactor views to use native SwiftUI alerts instead of CustomErrorView * Update ProfileView to use minimal List UI style with native alerts * Fix up homeview * Squash: Redesign HomeView, remove Feature Flags, enable all tabs, refactor alerts, and updates - Redesign HomeView to a simpler style with 'Enable JIT' action. - Remove 'Help & Info' and 'Quick Launch' from Home. - Fix DDI false positive by starting heartbeat on HomeView appear. - Restore robust DDI checks and update app name to 'StikDebug'. - Remove FeatureFlags and Beta tags; enable 'profiles', 'processes', 'location' tabs by default. - Remove 'Devices' tab; add 'Target Device IP' field in Settings. - Hardcode 'Settings' tab to 4th position. - Refactor 'SettingsView' tab customization to be reorder-only. - Remove 'Appearance' theme section from Settings. - Refactor custom error cards to use native SwiftUI/UIKit alerts across the app (HomeView, ConsoleLogsView, ProfileView, etc). - Restore JS callback support and script execution logic in HomeView. - Add necessary Color extensions. - Update project version to 3.0.0. * Clean up: Remove In-App Purchases, update checker, and unused IPA installer code * delete more bloat * fix build issue * Remove widget to save on App IDs * Attempt heartbeat restart when Enable JIT button is pressed * Get rid of PIP * Update Tab Naming * remove more bloat * final changes for today * Remove unused packages * UX Improvements * revert bundle id * Update README.md * remove old idevice * add updated idevice * Fix ddi false positive errors and add templates for GitHub stuff * Remove more unused stuff. * Fix links and update README content * Update compatibility table in README.md * Improve performance of console logs * Remove old code * Change default UPLOAD_IPA value to 'true' * remove the welcome sheet * import support for .mobiledevicepair * Add back LC JIT stuff * Fix heartbeat issues with LC JIT * update the build yml for nightly stuff * Update README.md * Update README.md * Update GitHub Actions workflow for IPA build * Update GitHub Actions workflow for nightly builds * Add URL scheme to kill tasks stikjit://kill-process?pid=1234 * fix build issues * Added App Intents * Unify the error handling style across the app
135 lines
5.1 KiB
Swift
135 lines
5.1 KiB
Swift
//
|
|
// MainTabView.swift
|
|
// StikJIT
|
|
//
|
|
// Created by Stephen on 3/27/25.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
private struct TabDescriptor: Identifiable {
|
|
let id: String
|
|
let title: String
|
|
let systemImage: String
|
|
let builder: () -> AnyView
|
|
}
|
|
|
|
extension Notification.Name {
|
|
static let switchToTab = Notification.Name("MainTabSwitchNotification")
|
|
}
|
|
|
|
struct MainTabView: View {
|
|
@AppStorage(TabConfiguration.storageKey) private var enabledTabIdentifiers: String = TabConfiguration.defaultRawValue
|
|
@AppStorage("primaryTabSelection") private var selection: String = TabConfiguration.defaultIDs.first ?? "home"
|
|
@State private var switchObserver: Any?
|
|
@State private var detachedTab: TabDescriptor?
|
|
@State private var didSetInitialHome = false
|
|
|
|
private var configurableTabs: [TabDescriptor] {
|
|
var tabs: [TabDescriptor] = [
|
|
TabDescriptor(id: "home", title: "Home", systemImage: "house") { AnyView(HomeView()) },
|
|
TabDescriptor(id: "scripts", title: "Scripts", systemImage: "scroll") { AnyView(ScriptListView()) },
|
|
TabDescriptor(id: "tools", title: "Tools", systemImage: "wrench.and.screwdriver") { AnyView(ToolsView()) },
|
|
TabDescriptor(id: "deviceinfo", title: "Device Info", systemImage: "iphone.and.arrow.forward") { AnyView(DeviceInfoView()) },
|
|
TabDescriptor(id: "profiles", title: "App Expiry", systemImage: "calendar.badge.clock") { AnyView(ProfileView()) },
|
|
TabDescriptor(id: "processes", title: "Processes", systemImage: "rectangle.stack.person.crop") { AnyView(ProcessInspectorView()) },
|
|
TabDescriptor(id: "location", title: "Location", systemImage: "location") { AnyView(LocationSimulationView()) }
|
|
]
|
|
return tabs
|
|
}
|
|
|
|
private var availableTabs: [TabDescriptor] {
|
|
configurableTabs
|
|
}
|
|
|
|
private let settingsTab = TabDescriptor(id: "settings", title: "Settings", systemImage: "gearshape.fill") {
|
|
AnyView(SettingsView())
|
|
}
|
|
|
|
private var selectedTabDescriptors: [TabDescriptor] {
|
|
let ids = TabConfiguration.sanitize(raw: enabledTabIdentifiers)
|
|
return ids.compactMap { id in
|
|
availableTabs.first(where: { $0.id == id })
|
|
}
|
|
}
|
|
|
|
private func ensureSelectionIsValid() {
|
|
let ids = displayTabs.map { $0.id }
|
|
if ids.contains(selection) {
|
|
return
|
|
}
|
|
selection = ids.first ?? settingsTab.id
|
|
}
|
|
|
|
private var displayTabs: [TabDescriptor] {
|
|
var tabs = ["home", "scripts", "tools"].compactMap { id in
|
|
configurableTabs.first(where: { $0.id == id })
|
|
}
|
|
tabs.insert(settingsTab, at: min(3, tabs.count))
|
|
return tabs
|
|
}
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
// Allow global themed background to show
|
|
Color.clear.ignoresSafeArea()
|
|
|
|
// Main tabs
|
|
TabView(selection: $selection) {
|
|
ForEach(displayTabs) { descriptor in
|
|
descriptor.builder()
|
|
.tabItem { Label(descriptor.title, systemImage: descriptor.systemImage) }
|
|
.tag(descriptor.id)
|
|
}
|
|
}
|
|
.onAppear {
|
|
enabledTabIdentifiers = TabConfiguration.serialize(TabConfiguration.sanitize(raw: enabledTabIdentifiers))
|
|
ensureSelectionIsValid()
|
|
if !didSetInitialHome {
|
|
if selectedTabDescriptors.contains(where: { $0.id == "home" }) {
|
|
selection = "home"
|
|
} else if let descriptor = availableTabs.first(where: { $0.id == "home" }) {
|
|
detachedTab = descriptor
|
|
}
|
|
didSetInitialHome = true
|
|
}
|
|
switchObserver = NotificationCenter.default.addObserver(forName: .switchToTab, object: nil, queue: .main) { note in
|
|
guard let id = note.object as? String else { return }
|
|
if selectedTabDescriptors.contains(where: { $0.id == id }) {
|
|
selection = id
|
|
} else if let descriptor = availableTabs.first(where: { $0.id == id }) {
|
|
detachedTab = descriptor
|
|
}
|
|
}
|
|
}
|
|
.onDisappear {
|
|
if let observer = switchObserver {
|
|
NotificationCenter.default.removeObserver(observer)
|
|
switchObserver = nil
|
|
}
|
|
}
|
|
.onChange(of: enabledTabIdentifiers) { _ in
|
|
ensureSelectionIsValid()
|
|
}
|
|
.sheet(item: $detachedTab) { descriptor in
|
|
NavigationStack {
|
|
descriptor.builder()
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Close") {
|
|
detachedTab = nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
struct MainTabView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
MainTabView()
|
|
}
|
|
}
|