Skip to content

Commit e0f1b92

Browse files
committed
[#639] Integrate
1 parent 2e2f56a commit e0f1b92

4 files changed

Lines changed: 155 additions & 13 deletions

File tree

template/Modules/Data/Sources/AppConfig/AppConfig.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public final class AppConfig<DecodedConfig: Sendable>: AppConfigProtocol {
4949
}
5050

5151
public func setUp() {
52-
remoteConfig = RemoteConfig.remoteConfig()
52+
// Uncomment after we set up firebase remote config
53+
// remoteConfig = RemoteConfig.remoteConfig()
5354
setUpConfigSettings()
5455
setUpDefaults()
5556
setUpListener()

template/Tuist/Interfaces/SwiftUI/Sources/Application/App.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
import Data
2+
import FactoryKit
13
import SwiftUI
24

35
@main
46
struct {PROJECT_NAME}App: App {
57

8+
@Injected(\.exampleAppConfig) private var appConfig: AppConfig<ExampleAppConfiguration>
9+
10+
init() {
11+
appConfig.setUp()
12+
}
13+
614
var body: some Scene {
715
WindowGroup {
816
LandingView()

template/Tuist/Interfaces/SwiftUI/Sources/Presentation/Modules/Home/HomeView.swift

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,132 @@ import SwiftUI
22

33
struct HomeView: View {
44

5+
@StateObject private var viewModel: HomeViewModel
56
var onSignOut: () -> Void = {}
67

8+
init(viewModel: HomeViewModel = HomeViewModel(), onSignOut: @escaping () -> Void = {}) {
9+
_viewModel = StateObject(wrappedValue: viewModel)
10+
self.onSignOut = onSignOut
11+
}
12+
13+
var body: some View {
14+
NavigationView {
15+
VStack(spacing: 20) {
16+
Image(systemName: "person.crop.circle.badge.checkmark")
17+
.font(.system(size: 48))
18+
.foregroundColor(.accentColor)
19+
20+
Text("Signed In")
21+
.font(.title2.bold())
22+
23+
Text(viewModel.configuration.welcomeMessage)
24+
.font(.headline)
25+
.multilineTextAlignment(.center)
26+
.foregroundStyle(.primary)
27+
28+
Text("Configuration loaded from remote config")
29+
.multilineTextAlignment(.center)
30+
.foregroundStyle(.secondary)
31+
.font(.caption)
32+
33+
ConfigurationCard(
34+
configuration: ConfigurationCardUIModel(
35+
isFeatureEnabled: viewModel.configuration.isFeatureEnabled,
36+
maxRetryCount: viewModel.configuration.maxRetryCount,
37+
apiTimeout: viewModel.configuration.apiTimeout
38+
)
39+
)
40+
41+
Spacer()
42+
43+
Button("Sign Out", action: onSignOut)
44+
.buttonStyle(.borderedProminent)
45+
}
46+
.padding()
47+
.navigationTitle("Home")
48+
.navigationBarTitleDisplayMode(.inline)
49+
}
50+
}
51+
}
52+
53+
private struct ConfigurationCard: View {
54+
55+
let configuration: ConfigurationCardUIModel
56+
757
var body: some View {
8-
VStack(spacing: 20) {
9-
Image(systemName: "person.crop.circle.badge.checkmark")
10-
.font(.system(size: 48))
11-
.foregroundColor(.accentColor)
12-
Text("Signed In")
13-
.font(.title2.bold())
14-
Text("This starter flow demonstrates the signed-in state that teams can build on with product-specific screens.")
15-
.multilineTextAlignment(.center)
16-
.foregroundStyle(.secondary)
17-
18-
Button("Sign Out", action: onSignOut)
19-
.buttonStyle(.borderedProminent)
58+
VStack(alignment: .leading, spacing: 12) {
59+
Text("App Configuration")
60+
.font(.headline)
61+
.frame(maxWidth: .infinity, alignment: .leading)
62+
63+
VStack(alignment: .leading, spacing: 8) {
64+
ConfigurationRow(
65+
title: "Feature Enabled",
66+
value: configuration.isFeatureEnabled ? "Yes" : "No",
67+
systemImage: configuration.isFeatureEnabled ? "checkmark.circle.fill" : "xmark.circle.fill",
68+
color: configuration.isFeatureEnabled ? .green : .red
69+
)
70+
71+
ConfigurationRow(
72+
title: "Max Retry Count",
73+
value: "\(configuration.maxRetryCount)",
74+
systemImage: "arrow.clockwise",
75+
color: .blue
76+
)
77+
78+
ConfigurationRow(
79+
title: "API Timeout",
80+
value: "\(configuration.apiTimeout, default: "%.1f")s",
81+
systemImage: "clock",
82+
color: .orange
83+
)
84+
}
2085
}
2186
.padding()
87+
.background(Color(.systemGray6))
88+
.cornerRadius(12)
89+
}
90+
}
91+
92+
private struct ConfigurationCardUIModel {
93+
94+
let isFeatureEnabled: Bool
95+
let maxRetryCount: Int
96+
let apiTimeout: Double
97+
98+
init(
99+
isFeatureEnabled: Bool = false,
100+
maxRetryCount: Int = 3,
101+
apiTimeout: Double = 30.0
102+
) {
103+
self.isFeatureEnabled = isFeatureEnabled
104+
self.maxRetryCount = maxRetryCount
105+
self.apiTimeout = apiTimeout
106+
}
107+
}
108+
109+
private struct ConfigurationRow: View {
110+
111+
let title: String
112+
let value: String
113+
let systemImage: String
114+
let color: Color
115+
116+
var body: some View {
117+
HStack {
118+
Image(systemName: systemImage)
119+
.foregroundColor(color)
120+
.frame(width: 20)
121+
122+
Text(title)
123+
.font(.subheadline)
124+
125+
Spacer()
126+
127+
Text(value)
128+
.font(.subheadline)
129+
.fontWeight(.medium)
130+
.foregroundColor(color)
131+
}
22132
}
23133
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Combine
2+
import Data
3+
import Domain
4+
import FactoryKit
5+
import Foundation
6+
7+
@MainActor
8+
final class HomeViewModel: ObservableObject {
9+
10+
@Published private(set) var configuration = ExampleAppConfiguration()
11+
12+
private var disposeBag = Set<AnyCancellable>()
13+
14+
@Injected(\.exampleAppConfig) private var appConfig: AppConfig<ExampleAppConfiguration>
15+
16+
nonisolated init() {
17+
Task { @MainActor in
18+
appConfig.currentConfigPublisher
19+
.assign(to: \.configuration, on: self)
20+
.store(in: &disposeBag)
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)