ssap_app/node_modules/expo-dev-launcher/ios/SwiftUI/SettingsTabView.swift

231 lines
6.1 KiB
Swift

// Copyright 2015-present 650 Industries. All rights reserved.
import SwiftUI
// swiftlint:disable:next line_length
private let selectedGesturesInfoMessage = "Selected gestures will toggle the developer menu while inside a preview. The menu allows you to reload or return to home and exposes developer tools."
struct SettingsTabView: View {
@EnvironmentObject var viewModel: DevLauncherViewModel
@State private var showCopiedMessage = false
@State private var defaultPageSize: Int = 10
@State private var showCacheClearedMessage = false
private func createBuildInfoJSON() -> String {
let buildInfoDict: [String: Any] = [
"runtimeVersion": viewModel.buildInfo["runtimeVersion"] as? String ?? "",
"sdkVersion": "53.0.0",
"appName": viewModel.buildInfo["appName"] as? String ?? "",
"appVersion": viewModel.buildInfo["appVersion"] as? String ?? ""
]
do {
let jsonData = try JSONSerialization.data(withJSONObject: buildInfoDict, options: .prettyPrinted)
return String(data: jsonData, encoding: .utf8) ?? "{}"
} catch {
return "{}"
}
}
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 24) {
titleSection
showMenuAtLaunch
gestures
Text(selectedGesturesInfoMessage)
.font(.system(size: 13))
.foregroundStyle(.secondary)
VStack(alignment: .leading, spacing: 8) {
Text("system".uppercased())
.font(.caption)
.foregroundColor(.primary.opacity(0.6))
Divider()
version
Divider()
copyToClipboardButton
}
if isAdminUser {
debugSettings
easUpdateConfig
}
}
.padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
#if os(tvOS)
.background()
#endif
.navigationBarHidden(true)
}
private var showMenuAtLaunch: some View {
HStack {
Image("show-menu-at-launch", bundle: getDevLauncherBundle())
.resizable()
.frame(width: 24, height: 24)
.opacity(0.6)
Toggle("Show menu at launch", isOn: $viewModel.showOnLaunch)
}
.padding()
.background(Color.expoSecondarySystemBackground)
.cornerRadius(12)
}
private var titleSection: some View {
HStack {
Spacer()
VStack {
Image(systemName: "gearshape")
.resizable()
.frame(width: 56, height: 56)
.opacity(0.3)
Text("Settings")
.font(.title2)
.padding(.horizontal, 20)
}
Spacer()
}
}
private var gestures: some View {
VStack(alignment: .leading) {
Text("Menu Gestures".uppercased())
.font(.caption)
.foregroundColor(.primary.opacity(0.6))
VStack {
HStack {
Image("shake-device", bundle: getDevLauncherBundle())
.resizable()
.frame(width: 24, height: 24)
.opacity(0.6)
Toggle("Shake Device", isOn: $viewModel.shakeDevice)
}
.padding()
Divider()
HStack {
Image("three-finger-long-press", bundle: getDevLauncherBundle())
.resizable()
.frame(width: 24, height: 24)
.opacity(0.6)
Toggle("Three-finger long-press", isOn: $viewModel.threeFingerLongPress)
}
.padding()
}
.background(Color.expoSecondarySystemBackground)
.cornerRadius(12)
}
}
private var version: some View {
HStack {
Text("Version")
Spacer()
Text(viewModel.buildInfo["runtimeVersion"] as? String ?? "")
.foregroundColor(.secondary)
}
}
private var copyToClipboardButton: some View {
HStack {
#if os(tvOS)
Button("Clipboard not available on tvOS") {}
#else
Button(showCopiedMessage ? "Copied to clipboard!" : "Copy system info") {
let buildInfoJSON = createBuildInfoJSON()
let clipboard = UIPasteboard.general
clipboard.string = buildInfoJSON
showCopiedMessage = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
showCopiedMessage = false
}
}
Spacer()
Image(systemName: "clipboard")
.resizable()
.scaledToFit()
.frame(width: 16, height: 16)
.foregroundColor(.blue)
#endif
}
}
private var isAdminUser: Bool {
return viewModel.user?.isExpoAdmin == true
}
private var debugSettings: some View {
Section("Debug Settings") {
Button(showCacheClearedMessage ? "Network cache cleared!" : "Clear network cache") {
clearNetworkCache()
}
.foregroundColor(showCacheClearedMessage ? .green : nil)
VStack(alignment: .leading) {
Text("Default Page Size")
Text("Sets the number of items fetched for branches and updates")
.foregroundStyle(.secondary)
.font(.footnote)
Picker("", selection: $defaultPageSize) {
Text("1").tag(1)
Text("5").tag(5)
Text("10").tag(10)
}
.pickerStyle(.segmented)
}
}
}
private var easUpdateConfig: some View {
Section("EAS Update Configuration") {
VStack(alignment: .leading, spacing: 8) {
Text(createEASConfigJSON())
.font(.system(.caption, design: .monospaced))
#if !os(tvOS)
.textSelection(.enabled)
#endif
.padding(.vertical, 4)
}
}
}
private func clearNetworkCache() {
URLCache.shared.removeAllCachedResponses()
showCacheClearedMessage = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
showCacheClearedMessage = false
}
}
private func createEASConfigJSON() -> String {
let appId = viewModel.structuredBuildInfo.appId
let runtimeVersion = viewModel.structuredBuildInfo.runtimeVersion
let usesEASUpdates = viewModel.structuredBuildInfo.usesEASUpdates
let projectUrl = viewModel.structuredBuildInfo.projectUrl ?? ""
return """
{
"appId": "\(appId)",
"runtimeVersion": "\(runtimeVersion)",
"usesEASUpdates": \(usesEASUpdates),
"projectUrl": "\(projectUrl)"
}
"""
}
}
#Preview {
SettingsTabView()
.environmentObject(DevLauncherViewModel())
}