mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Commit some more WIP UI work
This commit is contained in:
parent
93f15eac99
commit
a081a1392e
4 changed files with 139 additions and 90 deletions
|
|
@ -4,59 +4,70 @@ struct AppStoreButtonStyle: ButtonStyle {
|
|||
var installed: Bool
|
||||
var highlighted: Bool
|
||||
|
||||
var textColor: Color {
|
||||
if installed {
|
||||
if highlighted {
|
||||
return Color.white
|
||||
}
|
||||
else {
|
||||
return Color.secondary
|
||||
}
|
||||
}
|
||||
else {
|
||||
if highlighted {
|
||||
return Color.accentColor
|
||||
}
|
||||
else {
|
||||
return Color.white
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func background(isPressed: Bool) -> some View {
|
||||
Group {
|
||||
private struct AppStoreButton: View {
|
||||
var configuration: ButtonStyle.Configuration
|
||||
var installed: Bool
|
||||
var highlighted: Bool
|
||||
// This seems to magically help the highlight colors update on time
|
||||
@SwiftUI.Environment(\.isFocused) var isFocused
|
||||
|
||||
var textColor: Color {
|
||||
if installed {
|
||||
EmptyView()
|
||||
} else {
|
||||
Capsule()
|
||||
.fill(
|
||||
highlighted ?
|
||||
Color.white :
|
||||
Color.accentColor
|
||||
)
|
||||
.brightness(isPressed ? -0.25 : 0)
|
||||
if highlighted {
|
||||
return Color.white
|
||||
}
|
||||
else {
|
||||
return Color.secondary
|
||||
}
|
||||
}
|
||||
else {
|
||||
if highlighted {
|
||||
return Color.accentColor
|
||||
}
|
||||
else {
|
||||
return Color.white
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func background(isPressed: Bool) -> some View {
|
||||
Group {
|
||||
if installed {
|
||||
EmptyView()
|
||||
} else {
|
||||
Capsule()
|
||||
.fill(
|
||||
highlighted ?
|
||||
Color.white :
|
||||
Color.accentColor
|
||||
)
|
||||
.brightness(isPressed ? -0.25 : 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
var body: some View {
|
||||
configuration.label
|
||||
.font(Font.caption.weight(.medium))
|
||||
.foregroundColor(textColor)
|
||||
.padding(EdgeInsets(top: 2, leading: 8, bottom: 2, trailing: 8))
|
||||
.frame(minWidth: 80)
|
||||
.background(background(isPressed: configuration.isPressed))
|
||||
.padding(1)
|
||||
}
|
||||
}
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
configuration.label
|
||||
.font(Font.caption.weight(.medium))
|
||||
.foregroundColor(textColor)
|
||||
.padding(EdgeInsets(top: 2, leading: 8, bottom: 2, trailing: 8))
|
||||
.frame(minWidth: 80)
|
||||
.background(background(isPressed: configuration.isPressed))
|
||||
.padding(1)
|
||||
func makeBody(configuration: ButtonStyle.Configuration) -> some View {
|
||||
AppStoreButton(configuration: configuration, installed: installed, highlighted: highlighted)
|
||||
}
|
||||
}
|
||||
|
||||
struct AppStoreButtonStyle_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
Button("INSTALL", action: {})
|
||||
Button("INSTALLED", action: {})
|
||||
.buttonStyle(AppStoreButtonStyle(installed: true, highlighted: false))
|
||||
.padding()
|
||||
Button("UNINSTALLED", action: {})
|
||||
Button("INSTALL", action: {})
|
||||
.buttonStyle(AppStoreButtonStyle(installed: false, highlighted: false))
|
||||
.padding()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,34 @@ import Version
|
|||
import PromiseKit
|
||||
|
||||
struct ContentView: View {
|
||||
@ObservedObject var appState = AppState()
|
||||
@EnvironmentObject var appState: AppState
|
||||
@State private var selection = Set<String>()
|
||||
@State private var rowBeingConfirmedForUninstallation: AppState.XcodeVersion?
|
||||
|
||||
@State private var category: Category = .all
|
||||
@State private var searchText: String = ""
|
||||
|
||||
var visibleVersions: [AppState.XcodeVersion] {
|
||||
var versions: [AppState.XcodeVersion]
|
||||
switch category {
|
||||
case .all:
|
||||
versions = appState.allVersions
|
||||
case .installed:
|
||||
versions = appState.allVersions.filter { $0.installed }
|
||||
}
|
||||
|
||||
if !searchText.isEmpty {
|
||||
versions = versions.filter { $0.title.contains(searchText) }
|
||||
}
|
||||
|
||||
return versions
|
||||
}
|
||||
|
||||
enum Category {
|
||||
case all, installed
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
List(appState.allVersions, selection: $selection) { row in
|
||||
List(visibleVersions, selection: $selection) { row in
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(row.title)
|
||||
|
|
@ -22,32 +44,13 @@ struct ContentView: View {
|
|||
Button(row.installed ? "INSTALLED" : "INSTALL") {
|
||||
print("Installing...")
|
||||
}
|
||||
.buttonStyle(AppStoreButtonStyle(installed: row.installed,
|
||||
.buttonStyle(AppStoreButtonStyle(installed: row.installed,
|
||||
highlighted: self.selection.contains(row.id)))
|
||||
.disabled(row.installed)
|
||||
}
|
||||
Text(verbatim: row.path ?? "")
|
||||
.font(.caption)
|
||||
.foregroundColor(self.selection.contains(row.id) ? Color(NSColor.selectedMenuItemTextColor) : Color(NSColor.secondaryLabelColor))
|
||||
// if row.installed {
|
||||
// HStack {
|
||||
// Button(action: { row.installed ? self.rowBeingConfirmedForUninstallation = row : self.appState.install(id: row.id) }) {
|
||||
// Text("Uninstall")
|
||||
// }
|
||||
// Button(action: { self.appState.reveal(id: row.id) }) {
|
||||
// Text("Reveal in Finder")
|
||||
// }
|
||||
// Button(action: { self.appState.select(id: row.id) }) {
|
||||
// Text("Select")
|
||||
// }
|
||||
// }
|
||||
// .buttonStyle(PlainButtonStyle())
|
||||
// .foregroundColor(
|
||||
// self.selection.contains(row.id) ?
|
||||
// Color(NSColor.selectedMenuItemTextColor) :
|
||||
// .accentColor
|
||||
// )
|
||||
// }
|
||||
}
|
||||
.contextMenu {
|
||||
Button(action: { row.installed ? self.rowBeingConfirmedForUninstallation = row : self.appState.install(id: row.id) }) {
|
||||
|
|
@ -63,16 +66,31 @@ struct ContentView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 200, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
|
||||
.onAppear(perform: appState.load)
|
||||
.toolbar {
|
||||
ToolbarItem {
|
||||
Button(action: { appState.update().cauterize() }) {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: { self.appState.update() }) {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
}
|
||||
.keyboardShortcut("r")
|
||||
.keyboardShortcut(KeyEquivalent("r"))
|
||||
}
|
||||
ToolbarItem(placement: .principal) {
|
||||
Picker("", selection: $category) {
|
||||
Text("All")
|
||||
.tag(Category.all)
|
||||
Text("Installed")
|
||||
.tag(Category.installed)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
}
|
||||
ToolbarItem {
|
||||
TextField("Search...", text: $searchText)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.frame(width: 200)
|
||||
}
|
||||
}
|
||||
.navigationSubtitle(Text("Updated \(Date().addingTimeInterval(-600), style: .relative) ago"))
|
||||
.frame(minWidth: 200, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
|
||||
.onAppear(perform: appState.load)
|
||||
.alert(item: $appState.error) { error in
|
||||
Alert(title: Text(error.title),
|
||||
message: Text(verbatim: error.message),
|
||||
|
|
@ -84,15 +102,28 @@ struct ContentView: View {
|
|||
primaryButton: .destructive(Text("Uninstall"), action: { self.appState.uninstall(id: row.id) }),
|
||||
secondaryButton: .cancel(Text("Cancel")))
|
||||
}
|
||||
.sheet(isPresented: $appState.presentingSignInAlert, content: {
|
||||
.sheet(isPresented: $appState.presentingSignInAlert) {
|
||||
SignInCredentialsView(isPresented: $appState.presentingSignInAlert)
|
||||
.environmentObject(appState)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
Group {
|
||||
ContentView()
|
||||
.environmentObject({ () -> AppState in
|
||||
let a = AppState()
|
||||
a.allVersions = [
|
||||
AppState.XcodeVersion(title: "12.3", installState: .installed, selected: true, path: nil),
|
||||
AppState.XcodeVersion(title: "12.2", installState: .notInstalled, selected: false, path: nil),
|
||||
AppState.XcodeVersion(title: "12.1", installState: .notInstalled, selected: false, path: nil),
|
||||
AppState.XcodeVersion(title: "12.0", installState: .installed, selected: false, path: nil),
|
||||
]
|
||||
return a
|
||||
}())
|
||||
}
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,27 +7,30 @@ struct SignInCredentialsView: View {
|
|||
@State private var password: String = ""
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Sign in with your Apple ID.")
|
||||
.bold()
|
||||
.padding(.vertical)
|
||||
HStack {
|
||||
Text("Apple ID")
|
||||
TextField("Apple ID", text: $username)
|
||||
Text("Apple ID:")
|
||||
.frame(minWidth: 100, alignment: .trailing)
|
||||
TextField("example@icloud.com", text: $username)
|
||||
.frame(width: 250)
|
||||
}
|
||||
HStack {
|
||||
Text("Password:")
|
||||
.frame(minWidth: 100, alignment: .trailing)
|
||||
SecureField("Required", text: $password)
|
||||
.frame(width: 250)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Password")
|
||||
SecureField("Password", text: $password)
|
||||
}
|
||||
|
||||
HStack {
|
||||
Button("Cancel") {
|
||||
isPresented = false
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
Spacer()
|
||||
Button("Sign In") {
|
||||
appState.continueLogin(username: username, password: password)
|
||||
}
|
||||
.keyboardShortcut(.defaultAction)
|
||||
Button("Cancel") { isPresented = false }
|
||||
.keyboardShortcut(.cancelAction)
|
||||
Button("Next") { appState.continueLogin(username: username, password: password) }
|
||||
.disabled(username.isEmpty)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import Cocoa
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct XcodesApp: App {
|
||||
@StateObject private var appState = AppState()
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
Group {
|
||||
WindowGroup("Xcodes") {
|
||||
ContentView()
|
||||
.environmentObject(appState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue