121 lines
3.0 KiB
Swift
121 lines
3.0 KiB
Swift
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
public struct DevLauncherRootView: View {
|
|
@ObservedObject var viewModel: DevLauncherViewModel
|
|
@State private var showingUserProfile = false
|
|
|
|
init(viewModel: DevLauncherViewModel) {
|
|
self.viewModel = viewModel
|
|
}
|
|
|
|
public var body: some View {
|
|
NavigationView {
|
|
TabView {
|
|
HomeTabView()
|
|
.tabItem {
|
|
Image(systemName: "house.fill")
|
|
Text("Home")
|
|
}
|
|
|
|
UpdatesTabView()
|
|
.tabItem {
|
|
Image(systemName: "arrow.2.circlepath")
|
|
Text("Updates")
|
|
}
|
|
|
|
SettingsTabView()
|
|
.tabItem {
|
|
Image(systemName: "gearshape")
|
|
Text("Settings")
|
|
}
|
|
}
|
|
.onAppear {
|
|
DevLauncherTabBarManager.shared.setCustomAppearance()
|
|
}
|
|
.onDisappear {
|
|
DevLauncherTabBarManager.shared.restoreOriginalAppearance()
|
|
}
|
|
.navigationBarHidden(true)
|
|
.environmentObject(viewModel)
|
|
.environmentObject(DevLauncherNavigation(showingUserProfile: $showingUserProfile))
|
|
}
|
|
.navigationViewStyle(.stack)
|
|
.sheet(isPresented: $showingUserProfile) {
|
|
AccountSheet()
|
|
.environmentObject(viewModel)
|
|
}
|
|
.fullScreenCover(isPresented: $viewModel.showingCrashReport) {
|
|
if let error = viewModel.currentError {
|
|
CrashReportView(
|
|
error: error,
|
|
errorInstance: viewModel.storedCrashInstance,
|
|
onDismiss: {
|
|
viewModel.dismissCrashReport()
|
|
}
|
|
)
|
|
}
|
|
}
|
|
.alert("Error loading app", isPresented: $viewModel.showingErrorAlert) {
|
|
Button("OK") {
|
|
viewModel.dismissErrorAlert()
|
|
}
|
|
} message: {
|
|
Text(viewModel.errorAlertMessage)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct RecentlyOpenedAppRow: View {
|
|
let app: RecentlyOpenedApp
|
|
let onTap: () -> Void
|
|
@EnvironmentObject var viewModel: DevLauncherViewModel
|
|
|
|
private var isServerActive: Bool {
|
|
guard let url = URL(string: app.url),
|
|
let port = url.port else {
|
|
return false
|
|
}
|
|
|
|
return viewModel.devServers.contains { server in
|
|
guard let serverURL = URL(string: server.url),
|
|
let serverPort = serverURL.port else {
|
|
return false
|
|
}
|
|
return serverPort == port
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
Button {
|
|
onTap()
|
|
} label: {
|
|
HStack(alignment: .center) {
|
|
Circle()
|
|
.fill(isServerActive ? Color.green : Color.gray)
|
|
.frame(width: 12, height: 12)
|
|
VStack(alignment: .leading) {
|
|
Text(app.name)
|
|
.font(.headline)
|
|
.foregroundColor(.primary)
|
|
Text(app.url)
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
.lineLimit(1)
|
|
}
|
|
|
|
Spacer()
|
|
Image(systemName: "chevron.right")
|
|
.font(.caption)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
.padding()
|
|
.background(Color.expoSecondarySystemBackground)
|
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
|
}
|
|
.buttonStyle(PlainButtonStyle())
|
|
}
|
|
}
|