Skip to content

Commit

Permalink
Updates for Swiftly Salesforce v10
Browse files Browse the repository at this point in the history
  • Loading branch information
mike4aday committed Mar 27, 2022
1 parent e729690 commit 5b506d2
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 17 deletions.
4 changes: 4 additions & 0 deletions MySalesforceAccounts.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
EA6351F32666947600D3F4C1 /* Salesforce.json in Resources */ = {isa = PBXBuildFile; fileRef = EA6351F22666947600D3F4C1 /* Salesforce.json */; };
EAEE128427F0DB9100BC3D2E /* SwiftlySalesforce in Frameworks */ = {isa = PBXBuildFile; productRef = EAEE128327F0DB9100BC3D2E /* SwiftlySalesforce */; };
EAEE128627F0F26300BC3D2E /* LoadingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEE128527F0F26300BC3D2E /* LoadingState.swift */; };
EAEE128827F0FDC600BC3D2E /* AsyncButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAEE128727F0FDC600BC3D2E /* AsyncButton.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -52,6 +53,7 @@
EA6351E0266693BC00D3F4C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
EA6351F22666947600D3F4C1 /* Salesforce.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Salesforce.json; sourceTree = "<group>"; };
EAEE128527F0F26300BC3D2E /* LoadingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingState.swift; sourceTree = "<group>"; };
EAEE128727F0FDC600BC3D2E /* AsyncButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncButton.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -104,6 +106,7 @@
isa = PBXGroup;
children = (
EA6351C5266693BC00D3F4C1 /* Assets.xcassets */,
EAEE128727F0FDC600BC3D2E /* AsyncButton.swift */,
EA6351C3266693BB00D3F4C1 /* ContentView.swift */,
EA49FFE52666E0B200917E3D /* ErrorView.swift */,
EA6351CA266693BC00D3F4C1 /* Info.plist */,
Expand Down Expand Up @@ -278,6 +281,7 @@
buildActionMask = 2147483647;
files = (
EAEE128627F0F26300BC3D2E /* LoadingState.swift in Sources */,
EAEE128827F0FDC600BC3D2E /* AsyncButton.swift in Sources */,
EA6351C4266693BB00D3F4C1 /* ContentView.swift in Sources */,
EA6351C2266693BB00D3F4C1 /* MySalesforceAccountsApp.swift in Sources */,
EA49FFE62666E0B200917E3D /* ErrorView.swift in Sources */,
Expand Down
84 changes: 84 additions & 0 deletions MySalesforceAccounts/AsyncButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// AsyncButton.swift
// MySalesforceAccounts
//
// Created by Michael Epstein on 3/27/22.
//

import Foundation
import SwiftUI

// Borrowed from https://www.swiftbysundell.com/articles/building-an-async-swiftui-button/
struct AsyncButton<Label: View>: View {

var action: () async -> Void
var actionOptions = Set(ActionOption.allCases)
@ViewBuilder var label: () -> Label

@State private var isDisabled = false
@State private var showProgressView = false

var body: some View {
Button(
action: {
if actionOptions.contains(.disableButton) {
isDisabled = true
}

Task {
var progressViewTask: Task<Void, Error>?

if actionOptions.contains(.showProgressView) {
progressViewTask = Task {
try await Task.sleep(nanoseconds: 150_000_000)
showProgressView = true
}
}

await action()
progressViewTask?.cancel()

isDisabled = false
showProgressView = false
}
},
label: {
ZStack {
label().opacity(showProgressView ? 0 : 1)

if showProgressView {
ProgressView()
}
}
}
)
.disabled(isDisabled)
}
}

extension AsyncButton {
enum ActionOption: CaseIterable {
case disableButton
case showProgressView
}
}

extension AsyncButton where Label == Text {
init(_ label: String,
actionOptions: Set<ActionOption> = Set(ActionOption.allCases),
action: @escaping () async -> Void) {
self.init(action: action) {
Text(label)
}
}
}

extension AsyncButton where Label == Image {
init(systemImageName: String,
actionOptions: Set<ActionOption> = Set(ActionOption.allCases),
action: @escaping () async -> Void) {
self.init(action: action) {
Image(systemName: systemImageName)
}
}
}
44 changes: 30 additions & 14 deletions MySalesforceAccounts/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,37 @@ import SwiftlySalesforce
struct ContentView: View {

@StateObject var salesforce: Connection = try! Salesforce.connect()
@State var state: LoadingState<QueryResult<SalesforceRecord>> = .idle
@State var state: LoadingState<[SalesforceRecord]> = .idle

var body: some View {
switch state {
case .idle:
Color.clear
.task {
do {
let results = try await salesforce.myRecords(type: "Account", fields: ["Id", "Name", "BillingCity"])
state = .loaded(results)
}
catch {
state = .failed(error)
}
await load()
}
case .loading:
ProgressView()
case .failed(let error):
ErrorView(error: error, retry: { print("TODO") })
case .loaded(let queryResult):
QueryResultView(queryResult: queryResult)
ErrorView(error: error, retry: { await load() })
case .loaded(let records):
AsyncButton(action: load) {
HStack {
AsyncButton(systemImageName: "arrow.clockwise", action: load)
Text("Loaded: \(Date().formatted(date: .abbreviated, time: .standard))")
}
}
RecordsView(records: records)
}
}
}

extension ContentView {

struct QueryResultView: View {
var queryResult: QueryResult<SalesforceRecord>
struct RecordsView: View {
var records: [SalesforceRecord]
var body: some View {
List(queryResult.records, id: \.id) { account in
List(records, id: \.id) { account in
VStack(alignment: .leading) {
Text(account["Name"] ?? "N/A").bold()
Text("ID: \(account.id)")
Expand All @@ -53,6 +53,22 @@ extension ContentView {
}
}

extension ContentView {

func load() async {
state = .loading
Task {
do {
let queryResults = try await salesforce.myRecords(type: "Account", fields: ["Id", "Name", "BillingCity"])
state = .loaded(queryResults.records)
}
catch {
state = .failed(error)
}
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
Expand Down
8 changes: 5 additions & 3 deletions MySalesforceAccounts/ErrorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import SwiftUI
struct ErrorView: View {

var error: Error
var retry: () -> ()
var retry: () async -> ()

init(error: Error, retry: @escaping () -> ()) {
init(error: Error, retry: @escaping () async -> ()) {
self.error = error
self.retry = retry
}
Expand All @@ -27,7 +27,9 @@ struct ErrorView: View {
.bold()
Text(error.localizedDescription)
Button("Try Again") {
retry()
Task {
await retry()
}
}
Spacer()
}
Expand Down

0 comments on commit 5b506d2

Please sign in to comment.