Skip to content

Commit 3e42a0e

Browse files
committed
Reindent AuthenticateWithPKICertificateView.
1 parent 97fd6a4 commit 3e42a0e

File tree

1 file changed

+160
-159
lines changed

1 file changed

+160
-159
lines changed

Shared/Samples/Authenticate with PKI certificate/AuthenticateWithPKICertificateView.swift

Lines changed: 160 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -18,168 +18,169 @@ import SwiftUI
1818

1919
struct AuthenticateWithPKICertificateView: View {
2020
/// The model that backs this view.
21-
@StateObject private var model = Model()
21+
@StateObject private var model = Model()
2222

23-
var body: some View {
24-
Form {
25-
switch model.portalContent {
26-
case .success(let success):
27-
ForEach(success.results, id: \.id?.rawValue) { item in
28-
Button(item.title) {
29-
model.selectedItem = .init(portalItem: item)
30-
}
31-
.buttonStyle(.plain)
32-
}
33-
case .failure:
34-
urlEntryView
35-
ContentUnavailableView(
36-
"Error",
37-
systemImage: "exclamationmark.triangle",
38-
description: Text("Error searching specified portal.")
39-
)
40-
case nil:
41-
if model.isConnecting {
42-
ProgressView()
43-
.frame(maxWidth: .infinity)
44-
} else {
45-
urlEntryView
46-
}
47-
}
48-
}
49-
.onTeardown {
50-
// Reset the challenge handlers and clear credentials
51-
// when the view disappears so that user is prompted to enter
52-
// credentials every time the sample is run, and to clean
53-
// the environment for other samples.
54-
await model.teardownAuthenticator()
55-
}
56-
.sheet(item: $model.selectedItem) { selectedItem in
57-
NavigationStack {
58-
MapView(map: Map(item: selectedItem.portalItem))
59-
.navigationTitle(selectedItem.portalItem.title)
60-
.navigationBarTitleDisplayMode(.inline)
61-
.toolbar {
62-
ToolbarItem(placement: .topBarTrailing) {
63-
Button("Done") {
64-
model.selectedItem = nil
65-
}
66-
}
67-
}
68-
}
69-
.interactiveDismissDisabled()
70-
.highPriorityGesture(DragGesture())
71-
.pagePresentation()
72-
}
73-
.animation(.default, value: model.isConnecting)
74-
.authenticator(model.authenticator)
75-
}
76-
77-
@ViewBuilder private var urlEntryView: some View {
78-
Section {
79-
HStack {
80-
TextField("PKI Secured Portal URL", text: $model.portalURLString)
81-
.onSubmit { Task { await model.connectToPortal() } }
82-
.autocapitalization(.none)
83-
.keyboardType(.URL)
84-
Button("Connect") {
85-
Task { await model.connectToPortal() }
86-
}
87-
.disabled(model.portalURL == nil)
88-
}
89-
}
90-
}
91-
}
92-
93-
/// A value that represents an item selected by the user.
94-
private struct SelectedItem: Identifiable {
95-
/// The portal item that was selected.
96-
let portalItem: PortalItem
97-
98-
var id: ObjectIdentifier {
99-
ObjectIdentifier(portalItem)
100-
}
101-
}
102-
103-
extension AuthenticateWithPKICertificateView {
104-
@MainActor
105-
class Model: ObservableObject {
106-
/// The authenticator to handle authentication challenges.
107-
let authenticator = Authenticator()
108-
109-
/// The URL string entered by the user.
110-
@Published var portalURLString = ""
111-
112-
/// The fetched portal content.
113-
@Published var portalContent: Result<PortalQueryResultSet<PortalItem>, Error>?
114-
115-
/// A Boolean value indicating if a portal connection is in progress.
116-
@Published var isConnecting = false
117-
118-
/// The selected item.
119-
@Published fileprivate var selectedItem: SelectedItem?
120-
121-
/// The URL of the portal.
122-
var portalURL: URL? { URL(string: portalURLString) }
123-
124-
init() {
125-
setupAuthenticator()
126-
}
127-
128-
/// Connects to the portal and finds a batch of webmaps.
129-
func connectToPortal() async {
130-
precondition(portalURL != nil)
131-
132-
isConnecting = true
133-
defer { isConnecting = false }
134-
135-
do {
136-
let portal = Portal(url: portalURL!)
137-
try await portal.load()
138-
let results = try await portal.findItems(queryParameters: .items(ofKinds: [.webMap]))
139-
portalContent = .success(results)
140-
} catch {
141-
portalContent = .failure(error)
142-
}
143-
}
144-
145-
/// Sets up the authenticator to handle challenges.
146-
private func setupAuthenticator() {
147-
// Setting the challenge handlers here when the model is created so user is prompted to enter
148-
// credentials every time trying the sample. In real world applications, set challenge
149-
// handlers at the start of the application.
150-
151-
// Sets authenticator as ArcGIS and Network challenge handlers to handle authentication
152-
// challenges.
153-
ArcGISEnvironment.authenticationManager.handleChallenges(using: authenticator)
154-
155-
// In your application you may want to uncomment this code to persist
156-
// credentials in the keychain.
157-
// setupPersistentCredentialStorage()
158-
}
159-
160-
/// Stops the authenticator from handling the challenges and clears credentials.
161-
nonisolated func teardownAuthenticator() async {
162-
// Resets challenge handlers.
163-
ArcGISEnvironment.authenticationManager.handleChallenges(using: nil)
23+
var body: some View {
24+
Form {
25+
switch model.portalContent {
26+
case .success(let success):
27+
ForEach(success.results, id: \.id?.rawValue) { item in
28+
Button(item.title) {
29+
model.selectedItem = .init(portalItem: item)
30+
}
31+
.buttonStyle(.plain)
32+
}
33+
case .failure:
34+
urlEntryView
35+
ContentUnavailableView(
36+
"Error",
37+
systemImage: "exclamationmark.triangle",
38+
description: Text("Error searching specified portal.")
39+
)
40+
case nil:
41+
if model.isConnecting {
42+
ProgressView()
43+
.frame(maxWidth: .infinity)
44+
} else {
45+
urlEntryView
46+
}
47+
}
48+
}
49+
.onTeardown {
50+
// Reset the challenge handlers and clear credentials
51+
// when the view disappears so that user is prompted to enter
52+
// credentials every time the sample is run, and to clean
53+
// the environment for other samples.
54+
await model.teardownAuthenticator()
55+
}
56+
.sheet(item: $model.selectedItem) { selectedItem in
57+
NavigationStack {
58+
MapView(map: Map(item: selectedItem.portalItem))
59+
.navigationTitle(selectedItem.portalItem.title)
60+
.navigationBarTitleDisplayMode(.inline)
61+
.toolbar {
62+
ToolbarItem(placement: .topBarTrailing) {
63+
Button("Done") {
64+
model.selectedItem = nil
65+
}
66+
}
67+
}
68+
}
69+
.interactiveDismissDisabled()
70+
.highPriorityGesture(DragGesture())
71+
.pagePresentation()
72+
}
73+
.animation(.default, value: model.isConnecting)
74+
.authenticator(model.authenticator)
75+
}
76+
77+
@ViewBuilder private var urlEntryView: some View {
78+
Section {
79+
HStack {
80+
TextField("PKI Secured Portal URL", text: $model.portalURLString)
81+
.onSubmit { Task { await model.connectToPortal() } }
82+
.autocapitalization(.none)
83+
.keyboardType(.URL)
84+
Button("Connect") {
85+
Task { await model.connectToPortal() }
86+
}
87+
.disabled(model.portalURL == nil)
88+
}
89+
}
90+
}
91+
}
16492

165-
// In your application, code may need to run at a different
166-
// point in time based on the workflow desired. For example, it
167-
// might make sense to remove credentials when the user taps
168-
// a "sign out" button.
169-
await ArcGISEnvironment.authenticationManager.revokeOAuthTokens()
170-
await ArcGISEnvironment.authenticationManager.clearCredentialStores()
171-
}
93+
/// A value that represents an item selected by the user.
94+
private struct SelectedItem: Identifiable {
95+
/// The portal item that was selected.
96+
let portalItem: PortalItem
97+
98+
var id: ObjectIdentifier {
99+
ObjectIdentifier(portalItem)
100+
}
101+
}
172102

173-
/// Sets up new ArcGIS and Network credential stores that will be persisted in the keychain.
174-
private func setupPersistentCredentialStorage() {
175-
Task {
176-
try await ArcGISEnvironment.authenticationManager.setupPersistentCredentialStorage(
177-
access: .whenUnlockedThisDeviceOnly,
178-
synchronizesWithiCloud: false
179-
)
180-
}
181-
}
182-
}}
103+
extension AuthenticateWithPKICertificateView {
104+
@MainActor
105+
class Model: ObservableObject {
106+
/// The authenticator to handle authentication challenges.
107+
let authenticator = Authenticator()
108+
109+
/// The URL string entered by the user.
110+
@Published var portalURLString = ""
111+
112+
/// The fetched portal content.
113+
@Published var portalContent: Result<PortalQueryResultSet<PortalItem>, Error>?
114+
115+
/// A Boolean value indicating if a portal connection is in progress.
116+
@Published var isConnecting = false
117+
118+
/// The selected item.
119+
@Published fileprivate var selectedItem: SelectedItem?
120+
121+
/// The URL of the portal.
122+
var portalURL: URL? { URL(string: portalURLString) }
123+
124+
init() {
125+
setupAuthenticator()
126+
}
127+
128+
/// Connects to the portal and finds a batch of webmaps.
129+
func connectToPortal() async {
130+
precondition(portalURL != nil)
131+
132+
isConnecting = true
133+
defer { isConnecting = false }
134+
135+
do {
136+
let portal = Portal(url: portalURL!)
137+
try await portal.load()
138+
let results = try await portal.findItems(queryParameters: .items(ofKinds: [.webMap]))
139+
portalContent = .success(results)
140+
} catch {
141+
portalContent = .failure(error)
142+
}
143+
}
144+
145+
/// Sets up the authenticator to handle challenges.
146+
private func setupAuthenticator() {
147+
// Setting the challenge handlers here when the model is created so user is prompted to enter
148+
// credentials every time trying the sample. In real world applications, set challenge
149+
// handlers at the start of the application.
150+
151+
// Sets authenticator as ArcGIS and Network challenge handlers to handle authentication
152+
// challenges.
153+
ArcGISEnvironment.authenticationManager.handleChallenges(using: authenticator)
154+
155+
// In your application you may want to uncomment this code to persist
156+
// credentials in the keychain.
157+
// setupPersistentCredentialStorage()
158+
}
159+
160+
/// Stops the authenticator from handling the challenges and clears credentials.
161+
nonisolated func teardownAuthenticator() async {
162+
// Resets challenge handlers.
163+
ArcGISEnvironment.authenticationManager.handleChallenges(using: nil)
164+
165+
// In your application, code may need to run at a different
166+
// point in time based on the workflow desired. For example, it
167+
// might make sense to remove credentials when the user taps
168+
// a "sign out" button.
169+
await ArcGISEnvironment.authenticationManager.revokeOAuthTokens()
170+
await ArcGISEnvironment.authenticationManager.clearCredentialStores()
171+
}
172+
173+
/// Sets up new ArcGIS and Network credential stores that will be persisted in the keychain.
174+
private func setupPersistentCredentialStorage() {
175+
Task {
176+
try await ArcGISEnvironment.authenticationManager.setupPersistentCredentialStorage(
177+
access: .whenUnlockedThisDeviceOnly,
178+
synchronizesWithiCloud: false
179+
)
180+
}
181+
}
182+
}
183+
}
183184

184185
#Preview {
185186
AuthenticateWithPKICertificateView()

0 commit comments

Comments
 (0)