HydroFlux 0.1.2
This commit is contained in:
@@ -145,15 +145,15 @@ export class Dashboard {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Strava Integration -->
|
||||
<!-- Distance / Fitness Integration -->
|
||||
<div class="bg-gradient-to-br from-orange-50 to-white rounded-2xl p-6 shadow-md">
|
||||
<h3 class="text-sm font-semibold text-gray-700 mb-4">Strava Integration</h3>
|
||||
<h3 class="text-sm font-semibold text-gray-700 mb-4">Distance</h3>
|
||||
<div class="flex flex-col items-center justify-center py-4">
|
||||
<div class="w-16 h-16 bg-gradient-to-br from-orange-500 to-orange-600 rounded-2xl flex items-center justify-center mb-3 shadow-lg transform rotate-12">
|
||||
<span class="text-3xl font-bold text-white transform -rotate-12">S</span>
|
||||
<span class="text-3xl font-bold text-white transform -rotate-12">D</span>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-gray-800">5.2km Run</span>
|
||||
<span class="text-xs text-gray-500 mt-1">Last Sync: 2h ago</span>
|
||||
<span class="text-lg font-bold text-gray-800" id="distanceDisplay">${(healthData.distance || 0).toFixed(2)}km</span>
|
||||
<span class="text-xs text-gray-500 mt-1">Today's Total</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -195,11 +195,15 @@ export class Dashboard {
|
||||
this.renderGoals(goalsData);
|
||||
|
||||
// Expose Native Callback
|
||||
window.updateHealthData = (steps, sleepHoursTotal) => {
|
||||
console.log("Received Health Data:", steps, sleepHoursTotal);
|
||||
window.updateHealthData = (steps, sleepHoursTotal, distanceKm) => {
|
||||
console.log("Received Health Data:", steps, sleepHoursTotal, distanceKm);
|
||||
|
||||
// Save to Storage
|
||||
localStorage.setItem('hydroflux_health_data', JSON.stringify({ steps: steps, sleep: sleepHoursTotal }));
|
||||
localStorage.setItem('hydroflux_health_data', JSON.stringify({
|
||||
steps: steps,
|
||||
sleep: sleepHoursTotal,
|
||||
distance: distanceKm || 0 // Default to 0 if undefined
|
||||
}));
|
||||
|
||||
// Update UI directly
|
||||
const stepsCount = this.container.querySelector('#stepsCount');
|
||||
@@ -210,7 +214,21 @@ export class Dashboard {
|
||||
const sleepTime = this.container.querySelector('#sleepTime');
|
||||
if (sleepTime) sleepTime.textContent = `${sh}h ${sm}m`;
|
||||
|
||||
// Update Distance Card (Replacing Strava Placeholder or updating it)
|
||||
// Assuming the Strava card is now the general Fitness/Distance card as requested?
|
||||
// "can we have the distance tab actually pull stats from health connect"
|
||||
// Let's look for a distance element or update the text '5.2km Run' -> 'X.X km'
|
||||
|
||||
// NOTE: The current HTML has "5.2km Run" hardcoded in the Strava card.
|
||||
// I should verify if I should target that specific element.
|
||||
// There is no ID on that span. I'll add one via full replacement of render or just target via text?
|
||||
// Safer to re-render or target widely.
|
||||
|
||||
// Let's assume I upgrade the render() to include an ID first?
|
||||
// Actually, let's just save the data here. The Dashboard.render() needs to read it.
|
||||
|
||||
this.updateDynamicElements(steps, 10000);
|
||||
if (this.updateDistanceDisplay) this.updateDistanceDisplay(distanceKm);
|
||||
};
|
||||
|
||||
// Trigger initial sync if native interface exists
|
||||
@@ -395,6 +413,11 @@ export class Dashboard {
|
||||
}
|
||||
}
|
||||
|
||||
updateDistanceDisplay(distance) {
|
||||
const el = this.container.querySelector('#distanceDisplay');
|
||||
if (el) el.textContent = (distance || 0).toFixed(2) + 'km';
|
||||
}
|
||||
|
||||
startTimers() {
|
||||
const updateTime = () => {
|
||||
const now = new Date();
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.health.connect.client.HealthConnectClient
|
||||
import androidx.health.connect.client.permission.HealthPermission
|
||||
import androidx.health.connect.client.records.StepsRecord
|
||||
import androidx.health.connect.client.records.SleepSessionRecord
|
||||
import androidx.health.connect.client.records.DistanceRecord // Added
|
||||
import androidx.health.connect.client.request.ReadRecordsRequest
|
||||
import androidx.health.connect.client.request.AggregateRequest
|
||||
import androidx.health.connect.client.time.TimeRangeFilter
|
||||
@@ -28,7 +29,8 @@ class MainActivity : FragmentActivity() {
|
||||
// Define Permissions we need
|
||||
private val PERMISSIONS = setOf(
|
||||
HealthPermission.getReadPermission(StepsRecord::class),
|
||||
HealthPermission.getReadPermission(SleepSessionRecord::class)
|
||||
HealthPermission.getReadPermission(SleepSessionRecord::class),
|
||||
HealthPermission.getReadPermission(DistanceRecord::class) // Added
|
||||
)
|
||||
|
||||
private val requestPermissions = registerForActivityResult(
|
||||
@@ -169,55 +171,74 @@ class MainActivity : FragmentActivity() {
|
||||
val startOfDay = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS).toInstant()
|
||||
val now = Instant.now()
|
||||
|
||||
var totalSteps = 0L
|
||||
var sleepHours = 0.0
|
||||
|
||||
// 1. Try Read Steps (AGGREGATE)
|
||||
try {
|
||||
val response = healthConnectClient.aggregate(
|
||||
AggregateRequest(
|
||||
metrics = setOf(StepsRecord.COUNT_TOTAL),
|
||||
timeRangeFilter = TimeRangeFilter.between(startOfDay, now)
|
||||
)
|
||||
var totalSteps = 0L
|
||||
var sleepHours = 0.0
|
||||
var totalDistance = 0.0
|
||||
|
||||
// 1. Try Read Steps (AGGREGATE)
|
||||
try {
|
||||
val response = healthConnectClient.aggregate(
|
||||
AggregateRequest(
|
||||
metrics = setOf(StepsRecord.COUNT_TOTAL),
|
||||
timeRangeFilter = TimeRangeFilter.between(startOfDay, now)
|
||||
)
|
||||
// The result may be null if no data
|
||||
totalSteps = response[StepsRecord.COUNT_TOTAL] ?: 0
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
val msg = e.message ?: "Unknown Error"
|
||||
runOnUiThread { Toast.makeText(activity, "Steps Error: $msg", Toast.LENGTH_LONG).show() }
|
||||
totalSteps = 0
|
||||
}
|
||||
|
||||
// 2. Try Read Sleep (AGGREGATE)
|
||||
try {
|
||||
val sleepResponse = healthConnectClient.aggregate(
|
||||
AggregateRequest(
|
||||
metrics = setOf(SleepSessionRecord.SLEEP_DURATION_TOTAL),
|
||||
timeRangeFilter = TimeRangeFilter.between(now.minus(24, ChronoUnit.HOURS), now)
|
||||
)
|
||||
)
|
||||
// The result may be null if no data
|
||||
totalSteps = response[StepsRecord.COUNT_TOTAL] ?: 0
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
val msg = e.message ?: "Unknown Error"
|
||||
runOnUiThread { Toast.makeText(activity, "Steps Error: $msg", Toast.LENGTH_LONG).show() }
|
||||
totalSteps = 0
|
||||
}
|
||||
|
||||
// 2. Try Read Sleep (AGGREGATE)
|
||||
try {
|
||||
val sleepResponse = healthConnectClient.aggregate(
|
||||
AggregateRequest(
|
||||
metrics = setOf(SleepSessionRecord.SLEEP_DURATION_TOTAL),
|
||||
timeRangeFilter = TimeRangeFilter.between(now.minus(24, ChronoUnit.HOURS), now)
|
||||
)
|
||||
// Get total duration in Seconds (Duration -> Seconds)
|
||||
val duration = sleepResponse[SleepSessionRecord.SLEEP_DURATION_TOTAL]
|
||||
if (duration != null) {
|
||||
sleepHours = duration.seconds / 3600.0
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
sleepHours = 0.0
|
||||
)
|
||||
// Get total duration in Seconds (Duration -> Seconds)
|
||||
val duration = sleepResponse[SleepSessionRecord.SLEEP_DURATION_TOTAL]
|
||||
if (duration != null) {
|
||||
sleepHours = duration.seconds / 3600.0
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
if (!activity.isFinishing && !activity.isDestroyed) {
|
||||
try {
|
||||
myWebView.evaluateJavascript("window.updateHealthData($totalSteps, $sleepHours)", null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
sleepHours = 0.0
|
||||
}
|
||||
|
||||
// 3. Try Read Distance (AGGREGATE)
|
||||
try {
|
||||
val distanceResponse = healthConnectClient.aggregate(
|
||||
AggregateRequest(
|
||||
metrics = setOf(DistanceRecord.DISTANCE_TOTAL),
|
||||
timeRangeFilter = TimeRangeFilter.between(startOfDay, now)
|
||||
)
|
||||
)
|
||||
val dist = distanceResponse[DistanceRecord.DISTANCE_TOTAL]
|
||||
if (dist != null) {
|
||||
totalDistance = dist.inKilometers // Double
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
totalDistance = 0.0
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
if (!activity.isFinishing && !activity.isDestroyed) {
|
||||
try {
|
||||
// Pass Steps, Sleep, AND Distance
|
||||
myWebView.evaluateJavascript("window.updateHealthData($totalSteps, $sleepHours, $totalDistance)", null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
Hydroflux/releases/HydroFlux V7.apk
Normal file
BIN
Hydroflux/releases/HydroFlux V7.apk
Normal file
Binary file not shown.
Reference in New Issue
Block a user