-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Firebase Integration and Confidence Filtering #35
Changes from 1 commit
3001b8d
0d9808d
a6efbe8
94b373f
c824af3
0cfbd51
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,4 +133,35 @@ | |
await logger.error("Could not store consent form: \(error)") | ||
} | ||
} | ||
|
||
func add(cough: Cough) async { | ||
if FeatureFlags.disableFirebase { | ||
logger.debug("Received new cough event: \(cough.timestamp)") | ||
return | ||
} | ||
|
||
do { | ||
try await configuration.userDocumentReference | ||
.collection("CoughEvents") // Store all cough events in a /CoughEvents collection | ||
.document(UUID().uuidString) // Generate a unique ID for each cough event | ||
.setData([ | ||
"timestamp": cough.timestamp, | ||
"confidence": cough.confidence | ||
]) | ||
} catch { | ||
logger.error("Could not store cough event: \(error)") | ||
} | ||
} | ||
|
||
// For batch saving multiple coughs at once (optional) | ||
func add(coughs: [Cough]) async { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If not used now, please remove. |
||
if FeatureFlags.disableFirebase { | ||
logger.debug("Received batch of \(coughs.count) cough events") | ||
return | ||
} | ||
|
||
for cough in coughs { | ||
await add(cough: cough) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,51 +13,63 @@ | |
// | ||
|
||
import SwiftUI | ||
import Spezi | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix this error |
||
|
||
struct CoughModelView: View { | ||
@State var viewModel = CoughDetectionViewModel() | ||
@Environment(CoughSyncStandard.self) private var standard | ||
@State private var viewModel: CoughDetectionViewModel? | ||
|
||
var body: some View { | ||
VStack { | ||
Spacer() | ||
detectionStatusView() | ||
Spacer() | ||
microphoneButton() | ||
if let viewModel = viewModel { | ||
Spacer() | ||
detectionStatusView() | ||
Spacer() | ||
microphoneButton() | ||
.padding() | ||
} else { | ||
// Show a loading indicator | ||
ProgressView("Loading...") | ||
} | ||
} | ||
.onAppear { | ||
// Initialize viewModel here when environment is available | ||
viewModel = CoughDetectionViewModel(standard: standard) | ||
} | ||
.padding() | ||
} | ||
|
||
private var microphoneImage: some View { | ||
Image(systemName: viewModel.detectionStarted ? "stop.fill" : "mic.fill") | ||
Image(systemName: viewModel?.detectionStarted == true ? "stop.fill" : "mic.fill") | ||
.font(.system(size: 50)) | ||
.padding(30) | ||
.background(viewModel.detectionStarted ? .gray.opacity(0.7) : .blue) | ||
.background(viewModel?.detectionStarted == true ? .gray.opacity(0.7) : .blue) | ||
.foregroundStyle(.white) | ||
.clipShape(Circle()) | ||
.shadow(color: .gray, radius: 5) | ||
.contentTransition(.symbolEffect(.replace)) | ||
.accessibilityLabel(viewModel.detectionStarted ? "Stop sound detection" : "Start sound detection") | ||
.accessibilityLabel(viewModel?.detectionStarted == true ? "Stop sound detection" : "Start sound detection") | ||
} | ||
|
||
@ViewBuilder | ||
private func detectionStatusView() -> some View { | ||
if !viewModel.detectionStarted { | ||
if viewModel?.detectionStarted == false { | ||
VStack(spacing: 10) { | ||
ContentUnavailableView( | ||
"No Sound Detected", | ||
systemImage: "waveform.badge.magnifyingglass", | ||
description: Text("Tap the microphone to start detecting") | ||
) | ||
Text("Cough Count: \(viewModel.coughCount)") | ||
Text("Cough Count: \(viewModel?.coughCount ?? 0)") | ||
.font(.title2) | ||
.foregroundColor(.secondary) | ||
} | ||
} else if let predictedSound = viewModel.identifiedSound { | ||
} else if let predictedSound = viewModel?.identifiedSound { | ||
VStack(spacing: 10) { | ||
Text(predictedSound.0) | ||
.font(.system(size: 26)) | ||
Text("Cough Count: \(viewModel.coughCount)") | ||
Text("Coughs Today: \(viewModel.coughCollection.coughsToday())") | ||
Text("Cough Difference: \(viewModel.coughCollection.coughDiffDay())") | ||
Text("Cough Count: \(viewModel?.coughCount ?? 0)") | ||
Text("Coughs Today: \(viewModel?.coughCollection.coughsToday() ?? 0)") | ||
Text("Cough Difference: \(viewModel?.coughCollection.coughDiffDay() ?? 0)") | ||
} | ||
.multilineTextAlignment(.center) | ||
.padding() | ||
|
@@ -78,12 +90,12 @@ | |
|
||
private func toggleListening() { | ||
withAnimation { | ||
viewModel.detectionStarted.toggle() | ||
viewModel?.detectionStarted.toggle() | ||
} | ||
if viewModel.detectionStarted { | ||
viewModel.startListening() | ||
if viewModel?.detectionStarted == true { | ||
viewModel?.startListening() | ||
} else { | ||
viewModel.stopListening() | ||
viewModel?.stopListening() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,23 +20,33 @@ | |
import SpeziViews | ||
import SwiftUI | ||
|
||
|
||
struct Dashboard: View { | ||
@Environment(Account.self) private var account: Account? | ||
@Environment(CoughSyncStandard.self) private var standard | ||
@Binding var presentingAccount: Bool | ||
|
||
@State private var viewModel = CoughDetectionViewModel() | ||
// Don't initialize viewModel right away | ||
@State private var viewModel: CoughDetectionViewModel? | ||
@State private var previousCoughCount: Int = 0 | ||
|
||
init(presentingAccount: Binding<Bool>) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix this error. |
||
self._presentingAccount = presentingAccount | ||
} | ||
|
||
var body: some View { | ||
NavigationStack { | ||
ScrollView { | ||
VStack(spacing: 20) { | ||
coughSummaryCard() | ||
coughStats() | ||
Divider() | ||
if let viewModel = viewModel { | ||
VStack(spacing: 20) { | ||
coughSummaryCard() | ||
coughStats() | ||
Divider() | ||
} | ||
.padding() | ||
} else { | ||
// Show a loading indicator or placeholder | ||
ProgressView("Loading...") | ||
} | ||
.padding() | ||
} | ||
.navigationTitle("Summary") | ||
.toolbar { | ||
|
@@ -45,10 +55,14 @@ | |
} | ||
} | ||
.onAppear { | ||
previousCoughCount = viewModel.coughCount | ||
// Initialize viewModel here when environment is available | ||
viewModel = CoughDetectionViewModel(standard: standard) | ||
} | ||
.onAppear { | ||
previousCoughCount = viewModel?.coughCount ?? 0 | ||
} | ||
.onChange(of: viewModel.coughCount) { oldValue, _ in | ||
previousCoughCount = oldValue | ||
.onChange(of: viewModel?.coughCount) { oldValue, _ in | ||
previousCoughCount = oldValue ?? 0 | ||
} | ||
} | ||
} | ||
|
@@ -61,7 +75,7 @@ | |
Text("Today") | ||
.font(.headline) | ||
.foregroundColor(.primary) | ||
Text("\(viewModel.coughCount) ") | ||
Text("\(viewModel?.coughCount ?? 0) ") | ||
.font(.largeTitle) | ||
.bold() | ||
.foregroundColor(.blue) | ||
|
@@ -112,7 +126,7 @@ | |
|
||
@ViewBuilder | ||
private func statusCircle() -> some View { | ||
let change = viewModel.coughCount - previousCoughCount | ||
let change = viewModel?.coughCount ?? 0 - previousCoughCount | ||
let color: Color = change > 0 ? .red : (change < 0 ? .green : .blue) | ||
let trendSymbol = change > 0 ? "↑" : (change < 0 ? "↓" : "–") | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -337,6 +337,9 @@ | |
} | ||
} | ||
} | ||
}, | ||
"Loading..." : { | ||
|
||
}, | ||
"Next" : { | ||
"localizations" : { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this used? If not necessary, please remove.