From d1bc7255bc9b594d7c6d5c2fdbc9d1b3359ef5d6 Mon Sep 17 00:00:00 2001 From: Fabrizio Demaria Date: Fri, 29 Nov 2024 18:34:44 +0100 Subject: [PATCH] feat: More DemoApp tests and cases --- .../ConfidenceDemoApp/ConfidenceDemoApp.swift | 37 +++++++++++----- .../ConfidenceDemoApp/ContentView.swift | 44 +++++++++++++++---- .../ConfidenceDemoApp/LoginView.swift | 10 +---- Sources/Confidence/Confidence.swift | 4 -- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift b/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift index b5426628..ae173065 100644 --- a/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift +++ b/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift @@ -1,31 +1,32 @@ import Confidence import SwiftUI + @main struct ConfidenceDemoApp: App { @AppStorage("loggedUser") private var loggedUser: String? + @AppStorage("appVersion") private var appVersion = 0 private let confidence: Confidence private let flaggingState = ExperimentationFlags() + private let secret = ProcessInfo.processInfo.environment["CLIENT_SECRET"] ?? "" init() { confidence = Confidence - .Builder(clientSecret: ProcessInfo.processInfo.environment["CLIENT_SECRET"] ?? "", loggerLevel: .TRACE) + .Builder(clientSecret: secret, loggerLevel: .TRACE) .build() - - if let loggedUser = loggedUser { - confidence.putContextLocal(context: ["user_id": ConfidenceValue.init(string: loggedUser)], removeKeys: []) - do { - try confidence.activate() - flaggingState.state = .ready - } catch { - print("Error during activation of Confidence") - flaggingState.state = .error(ExperimentationFlags.CustomError(message: error.localizedDescription)) - } + appVersion = appVersion + 1 // Simulate update of the app on every new run + var context = ["app_version": ConfidenceValue.init(integer: appVersion)] + if let user = loggedUser { + context["user_id"] = ConfidenceValue.init(string: user) } + confidence.putContextLocal(context: context, removeKeys: []) + updateConfidence() } var body: some Scene { WindowGroup { + Text("Client secret: \(secret)") + .font(.caption) if loggedUser == nil { LoginView(confidence: confidence) .environmentObject(flaggingState) @@ -35,6 +36,20 @@ struct ConfidenceDemoApp: App { } } } + + private func updateConfidence() { + Task { + do { + flaggingState.state = .loading + try confidence.activate() // Activating the existing cache, in case the new fetch fails i.e. offline mode + try await Task.sleep(nanoseconds: 2 * 1_000_000_000) + try await confidence.fetchAndActivate() + flaggingState.state = .ready + } catch { + flaggingState.state = .error(ExperimentationFlags.CustomError(message: error.localizedDescription)) + } + } + } } class ExperimentationFlags: ObservableObject { diff --git a/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift b/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift index 6aec74cd..778b004c 100644 --- a/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift +++ b/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift @@ -7,6 +7,7 @@ struct ContentView: View { @AppStorage("loggedUser") private var loggedUser: String? @State var isLoggingOut: Bool = false @State var loggedOut: Bool = false + @State var textColor: Color = .red private let confidence: Confidence @@ -19,21 +20,27 @@ struct ContentView: View { if (status.state == .loading && !isLoggingOut) { VStack { Spacer() - Text("Welcome \(loggedUser ?? "?")") + Text("Login successful: \(loggedUser ?? "?")") Text("We are preparing your experience...") ProgressView() - Spacer() } } else { - VStack { - Text("Hello World!") - .font(.largeTitle) - .foregroundStyle(ContentView.getColor(color: confidence.getValue(key: "swift-demoapp.color", defaultValue: "Gray"))) + if (status.state == .ready) { + VStack { + Spacer() + if let user = loggedUser { + let eval = confidence.getEvaluation(key: "swift-demoapp.color", defaultValue: "Gray") + Text("Hello \(eval.reason)") + .font(.largeTitle) + // Any change of flagState triggers a re-read of the value + // The "state = ready" wrapper makes sure only the reconciled value is shown at any time + .foregroundStyle(ContentView.getColor(color: eval.value)) + .padding() + } + } } - .padding() Button("Logout") { isLoggingOut = true - loggedUser = nil status.state = .loading Task { @@ -46,6 +53,27 @@ struct ContentView: View { .navigationDestination(isPresented: $loggedOut) { LoginView(confidence: confidence) } + Spacer() + } + ZStack { + VStack { + Spacer() + Text("This text doesn't wait for flags to be loaded") + .font(.caption) + .foregroundStyle(textColor) // This is set on onAppear and not changing, although it might show different values within the session if the user exit and re-enter ContentView + Text("This text dynamically change on flag re-load") + .font(.caption) + // Any change of flagState triggers a re-read of the value + .foregroundStyle(ContentView.getColor(color: confidence.getValue(key: "swift-demoapp.color", defaultValue: "Gray"))) + } + }.onAppear { + let eval = confidence.getEvaluation(key: "swift-demoapp.color", defaultValue: "Gray") + /* + Due to syntetic delay, the new context hasn't entered the SDK yet se we are operating with + the last seen context before the view loads + */ + print(">> Evaluation reason: \(eval)") + textColor = ContentView.getColor(color: eval.value) } } } diff --git a/ConfidenceDemoApp/ConfidenceDemoApp/LoginView.swift b/ConfidenceDemoApp/ConfidenceDemoApp/LoginView.swift index f0469dd5..12e879da 100644 --- a/ConfidenceDemoApp/ConfidenceDemoApp/LoginView.swift +++ b/ConfidenceDemoApp/ConfidenceDemoApp/LoginView.swift @@ -22,14 +22,14 @@ struct LoginView: View { status.state = .loading // Load flags Task { - try? await Task.sleep(nanoseconds: 5 * 1_000_000_000) // Sleep for 3 seconds + try? await Task.sleep(nanoseconds: 5 * 1_000_000_000) await confidence.putContext(context: ["user_id": .init(string: "user1")]) status.state = .ready } // Load everything else for this user Task { loggingIn = true - try? await Task.sleep(nanoseconds: 1 * 1_000_000_000) // Sleep for 3 seconds + try? await Task.sleep(nanoseconds: 1 * 1_000_000_000) loggedUser = "user1" loggingIn = false loginCompleted = true @@ -45,10 +45,4 @@ struct LoginView: View { } } } - private var combinedBinding: Binding { - Binding( - get: { loginCompleted && flagsLoaded }, - set: { _ in } // No-op; navigation state is derived from other properties - ) - } } diff --git a/Sources/Confidence/Confidence.swift b/Sources/Confidence/Confidence.swift index 4b4f0127..d60b762c 100644 --- a/Sources/Confidence/Confidence.swift +++ b/Sources/Confidence/Confidence.swift @@ -64,10 +64,6 @@ public class Confidence: ConfidenceEventSender { } let savedFlags = try storage.load(defaultValue: FlagResolution.EMPTY) cache = savedFlags - debugLogger?.logMessage( - message: "[Activating stored cache]", - isWarning: false - ) } }