Commit some more WIP UI work

This commit is contained in:
Brandon Evans 2020-11-24 22:15:11 -07:00
parent 93f15eac99
commit a081a1392e
No known key found for this signature in database
GPG key ID: D58A4B8DB64F8E93
4 changed files with 139 additions and 90 deletions

View file

@ -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()
}

View file

@ -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)
}
}

View file

@ -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()

View file

@ -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)
}
}
}
}