diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 233d020..4ec27b2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,8 +46,7 @@
+ android:permission="android.permission.ACTIVITY_RECOGNITION" />
-
\ No newline at end of file
+
diff --git a/app/src/main/java/com/dzeio/openhealth/adapters/StepsAdapter.kt b/app/src/main/java/com/dzeio/openhealth/adapters/StepsAdapter.kt
index c6f7fb6..1560fd3 100644
--- a/app/src/main/java/com/dzeio/openhealth/adapters/StepsAdapter.kt
+++ b/app/src/main/java/com/dzeio/openhealth/adapters/StepsAdapter.kt
@@ -19,7 +19,7 @@ class StepsAdapter() : BaseAdapter() {
item: Step,
position: Int
) {
- holder.binding.value.text = "${item.value}ml"
+ holder.binding.value.text = "${item.value}steps"
holder.binding.datetime.text = item.formatTimestamp()
holder.binding.edit.setOnClickListener {
onItemClick?.invoke(item)
diff --git a/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt b/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt
index 6a6b361..1c4f78c 100644
--- a/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt
+++ b/app/src/main/java/com/dzeio/openhealth/data/step/Step.kt
@@ -3,21 +3,22 @@ package com.dzeio.openhealth.data.step
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
-import java.sql.Date
import java.text.DateFormat
import java.util.Calendar
+import java.util.Date
+import java.util.Locale
import java.util.TimeZone
@Entity()
data class Step(
@PrimaryKey(autoGenerate = true) var id: Long = 0,
- var value: Float = 0f,
- @ColumnInfo(index = true)
+ var value: Int = 0,
/**
* Timestamp down to an hour
*
* ex: 2022-09-22 10:00:00
*/
+ @ColumnInfo(index = true)
var timestamp: Long = 0,
var source: String = "OpenHealth"
) {
@@ -33,9 +34,30 @@ data class Step(
}
}
- fun formatTimestamp(): String = DateFormat.getDateInstance().format(Date(timestamp))
+ fun formatTimestamp(): String {
+ val formatter = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT,
+ DateFormat.SHORT,
+ Locale.getDefault()
+ )
+ return formatter.format(Date(this.timestamp))
+ }
fun isToday(): Boolean {
+ val it = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
+ it.timeInMillis = timestamp
+ it.set(Calendar.HOUR, 0)
+
+ val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
+
+ cal.set(Calendar.HOUR, 0)
+ cal.set(Calendar.MINUTE, 0)
+ cal.set(Calendar.SECOND, 0)
+ cal.set(Calendar.MILLISECOND, 0)
+ return it.timeInMillis == cal.timeInMillis
+ }
+
+ fun isCurrent(): Boolean {
val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
cal.set(Calendar.MINUTE, 0)
cal.set(Calendar.SECOND, 0)
diff --git a/app/src/main/java/com/dzeio/openhealth/data/step/StepDao.kt b/app/src/main/java/com/dzeio/openhealth/data/step/StepDao.kt
index 5d97152..ecdab8d 100644
--- a/app/src/main/java/com/dzeio/openhealth/data/step/StepDao.kt
+++ b/app/src/main/java/com/dzeio/openhealth/data/step/StepDao.kt
@@ -1,9 +1,7 @@
package com.dzeio.openhealth.data.step
import androidx.room.Dao
-import androidx.room.Insert
import androidx.room.Query
-import androidx.room.Update
import com.dzeio.openhealth.core.BaseDao
import kotlinx.coroutines.flow.Flow
@@ -24,12 +22,4 @@ interface StepDao : BaseDao {
@Query("DELETE FROM Step where source = :source")
suspend fun deleteFromSource(source: String)
-
- @Update
- fun updateNF(vararg obj: Step)
- @Insert
- fun insertNF(vararg obj: Step)
-
- @Query("Select * FROM Step ORDER BY timestamp DESC LIMIT 1")
- fun lastNF(): Step?
}
diff --git a/app/src/main/java/com/dzeio/openhealth/data/step/StepRepository.kt b/app/src/main/java/com/dzeio/openhealth/data/step/StepRepository.kt
index ad6774a..aca13bd 100644
--- a/app/src/main/java/com/dzeio/openhealth/data/step/StepRepository.kt
+++ b/app/src/main/java/com/dzeio/openhealth/data/step/StepRepository.kt
@@ -1,6 +1,8 @@
package com.dzeio.openhealth.data.step
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.withTimeoutOrNull
import javax.inject.Inject
import javax.inject.Singleton
@@ -20,7 +22,22 @@ class StepRepository @Inject constructor(
suspend fun deleteStep(value: Step) = stepDao.delete(value)
suspend fun deleteFromSource(value: String) = stepDao.deleteFromSource(value)
- fun todayStep() = lastStep().filter {
- return@filter it != null && it.isToday()
+ suspend fun todaySteps(): Int {
+ val steps = getSteps().firstOrNull()
+ if (steps == null) {
+ return 0
+ }
+
+ var total = 0
+ for (item in steps) {
+ total += item.value
+ }
+
+ return total
}
-}
\ No newline at end of file
+
+ fun currentStep() = lastStep().filter {
+ return@filter it != null && it.isCurrent()
+ }
+
+}
diff --git a/app/src/main/java/com/dzeio/openhealth/services/OpenHealthService.kt b/app/src/main/java/com/dzeio/openhealth/services/OpenHealthService.kt
index 8ec23d3..4bc0579 100644
--- a/app/src/main/java/com/dzeio/openhealth/services/OpenHealthService.kt
+++ b/app/src/main/java/com/dzeio/openhealth/services/OpenHealthService.kt
@@ -32,18 +32,30 @@ import kotlinx.coroutines.withTimeoutOrNull
class OpenHealthService : Service() {
companion object {
- private const val TAG = "${Application.TAG}/OpenHealthService"
+ private const val TAG = "${Application.TAG}/Service"
}
- val stepRepository: StepRepository
- get() = StepRepository_Factory.newInstance(AppDatabase.getInstance(applicationContext).stepDao())
+ private val stepRepository: StepRepository
+ get() = StepRepository_Factory.newInstance(
+ AppDatabase.getInstance(applicationContext).stepDao()
+ )
private var mNM: NotificationManager? = null
+ private lateinit var notification: Notification
- // Unique Identification Number for the Notification.
- // We use it on Notification start, and to cancel it.
- private val NOTIFICATION: Int = 8942
+ /**
+ * Displayed steps in the notification panel
+ */
+ private var stepsTaken = 0u
+ /**
+ * Need a buffer because sometime it does not complete the function
+ */
+ private var stepsBuffer = 0
+
+ /**
+ * Coroutine shit
+ */
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
@@ -54,8 +66,8 @@ class OpenHealthService : Service() {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.i("LocalService", "Received start id $startId: $intent")
- scope.launch {
- val source = StepSource(this@OpenHealthService)
+ scope.launch {
+ val source = StepSource(this@OpenHealthService)
source.events.receiveAsFlow().collectLatest {
Log.d(TAG, "Received value: $it")
@@ -64,21 +76,24 @@ class OpenHealthService : Service() {
return@collectLatest
}
Log.d(TAG, "New steps registered: $it")
- val step = withTimeoutOrNull(100) {
- return@withTimeoutOrNull stepRepository.todayStep().firstOrNull()
+ stepsTaken += it.toUInt()
+ stepsBuffer += it.toInt()
+ showNotification()
+ val step = withTimeoutOrNull(1000) {
+ return@withTimeoutOrNull stepRepository.currentStep().firstOrNull()
}
Log.d(TAG, "stepRepository: $step")
if (step != null) {
- step.value += it
+ step.value += stepsBuffer
stepRepository.updateStep(step)
} else {
- stepRepository.addStep(Step(value = it))
+ stepRepository.addStep(Step(value = stepsBuffer))
}
+ stepsBuffer = 0
Log.d(TAG, "Added step!")
}
}
-
// Display a notification about us starting. We put an icon in the status bar.
startForeground(NotificationIds.Service.ordinal, showNotification())
@@ -89,10 +104,10 @@ class OpenHealthService : Service() {
override fun onDestroy() {
stopForeground(true)
-
-
// Tell the user we stopped.
Toast.makeText(this, "Service stopped", Toast.LENGTH_SHORT).show()
+
+ super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? {
@@ -115,12 +130,15 @@ class OpenHealthService : Service() {
.getPendingIntent(0, flag)
// Set the info for the views that show in the notification panel.
- val notification: Notification = NotificationCompat.Builder(this, NotificationChannels.SERVICE.id)
+ this.notification = NotificationCompat.Builder(
+ this,
+ NotificationChannels.SERVICE.id
+ )
.setSmallIcon(R.drawable.ic_logo_small)
// .setTicker("Pouet") // the status text
.setWhen(System.currentTimeMillis()) // the time stamp
.setContentTitle("Open Health Service") // the label of the entry
- .setContentText("Watching for your steps") // the contents of the entry
+ .setContentText("Watching for your steps ($stepsTaken)") // the contents of the entry
.setContentIntent(intent) // The intent to send when the entry is clicked
.build()
@@ -129,4 +147,4 @@ class OpenHealthService : Service() {
return notification
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseFragment.kt
index 932f42b..05d35fd 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseFragment.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseFragment.kt
@@ -1,14 +1,21 @@
package com.dzeio.openhealth.ui.browse
+import android.Manifest
import android.content.SharedPreferences
+import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
+import com.dzeio.openhealth.R
import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.databinding.FragmentBrowseBinding
+import com.dzeio.openhealth.utils.PermissionsManager
+import com.google.android.material.card.MaterialCardView
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@@ -22,6 +29,19 @@ class BrowseFragment :
PreferenceManager.getDefaultSharedPreferences(requireContext())
}
+ private lateinit var button: MaterialCardView
+ private val activityResult = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) {
+ if (!it) {
+ // TODO: Show a popup with choice to change it
+ Toast.makeText(requireContext(), R.string.permission_declined, Toast.LENGTH_LONG).show()
+ return@registerForActivityResult
+ }
+
+ button.callOnClick()
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -34,7 +54,25 @@ class BrowseFragment :
}
binding.steps.setOnClickListener {
- findNavController().navigate(BrowseFragmentDirections.actionNavBrowseToStepsHomeFragment())
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ val hasPermission = PermissionsManager.hasPermission(
+ requireContext(),
+ Manifest.permission.ACTIVITY_RECOGNITION
+ )
+
+ if (!hasPermission) {
+ activityResult.launch(Manifest.permission.ACTIVITY_RECOGNITION)
+ return@setOnClickListener
+ }
+ }
+ findNavController().navigate(
+ BrowseFragmentDirections.actionNavBrowseToStepsHomeFragment()
+ )
}
+
+ viewModel.steps.observe(viewLifecycleOwner) {
+ binding.stepsText.setText("$it of xxx steps")
+ }
+
}
}
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseViewModel.kt b/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseViewModel.kt
index 6570d91..7fd10d0 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseViewModel.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/browse/BrowseViewModel.kt
@@ -1,8 +1,25 @@
package com.dzeio.openhealth.ui.browse
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
import com.dzeio.openhealth.core.BaseViewModel
+import com.dzeio.openhealth.data.step.StepRepository
import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
-class BrowseViewModel @Inject internal constructor() : BaseViewModel()
+class BrowseViewModel @Inject internal constructor(
+ stepRepository: StepRepository
+) : BaseViewModel() {
+
+ private val _steps = MutableLiveData(0)
+ val steps: LiveData = _steps
+
+ init {
+ viewModelScope.launch {
+ _steps.postValue(stepRepository.todaySteps())
+ }
+ }
+}
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/extensions/ExtensionsFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/extensions/ExtensionsFragment.kt
index 72386ca..d2a0eb6 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/extensions/ExtensionsFragment.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/extensions/ExtensionsFragment.kt
@@ -32,7 +32,9 @@ class ExtensionsFragment :
private lateinit var activeExtension: Extension
- private val activityResult = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { map ->
+ private val activityResult = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) { map ->
if (map.containsValue(false)) {
// TODO: Show a popup with choice to change it
Toast.makeText(requireContext(), R.string.permission_declined, Toast.LENGTH_LONG).show()
@@ -77,7 +79,11 @@ class ExtensionsFragment :
private fun extensionPermissionsVerified(it: Extension) {
// Check for the extension permissions
- if (it.permissions != null && !PermissionsManager.hasPermission(requireContext(), it.permissions!!)) {
+ if (it.permissions != null && !PermissionsManager.hasPermission(
+ requireContext(),
+ it.permissions!!
+ )
+ ) {
// TODO: show popup explaining the permissions requested
// show permissions
@@ -109,4 +115,4 @@ class ExtensionsFragment :
ExtensionsFragmentDirections.actionNavExtensionsToNavExtension(it.id)
)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
index b4a0734..c07468d 100644
--- a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
+++ b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt
@@ -57,7 +57,7 @@ class StepsHomeFragment :
)
)
- chart.xAxis.valueFormatter = GraphUtils.DateValueFormatter(1000 * 60 * 60)
+ chart.xAxis.valueFormatter = GraphUtils.DateTimeValueFormatter()
viewModel.items.observe(viewLifecycleOwner) { list ->
adapter.set(list)
@@ -65,8 +65,8 @@ class StepsHomeFragment :
val dataset = BarDataSet(
list.map {
return@map BarEntry(
- (it.timestamp / 60 / 60 / 24).toFloat(),
- it.value
+ (it.timestamp).toFloat(),
+ it.value.toFloat()
)
},
""
diff --git a/app/src/main/java/com/dzeio/openhealth/utils/GraphUtils.kt b/app/src/main/java/com/dzeio/openhealth/utils/GraphUtils.kt
index d7fd056..9af6325 100644
--- a/app/src/main/java/com/dzeio/openhealth/utils/GraphUtils.kt
+++ b/app/src/main/java/com/dzeio/openhealth/utils/GraphUtils.kt
@@ -39,9 +39,7 @@ object GraphUtils {
mainColor: Int,
textColor: Int
) {
-
chart.apply {
-
// Setup
legend.isEnabled = true
description = Description().apply { isEnabled = false }
@@ -60,6 +58,7 @@ object GraphUtils {
}
axisLeft.apply {
+ axisMinimum = 0f
isEnabled = false
axisLineColor = mainColor
this.textColor = textColor
@@ -69,6 +68,7 @@ object GraphUtils {
setDrawBorders(false)
}
axisRight.apply {
+ axisMinimum = 0f
this.textColor = textColor
setLabelCount(4, true)
}
@@ -96,4 +96,16 @@ object GraphUtils {
// return super.getAxisLabel(value, axis)
}
}
+
+ class DateTimeValueFormatter(
+ private val transformer: Int = 1
+ ) : ValueFormatter() {
+ override fun getAxisLabel(value: Float, axis: AxisBase?): String {
+ return SimpleDateFormat(
+ "yyyy-MM-dd hh",
+ Locale.getDefault()
+ ).format(Date(value.toLong() * transformer))
+ // return super.getAxisLabel(value, axis)
+ }
+ }
}
diff --git a/app/src/main/java/com/dzeio/openhealth/workers/StepCountService.kt b/app/src/main/java/com/dzeio/openhealth/workers/StepCountService.kt
deleted file mode 100644
index b529d28..0000000
--- a/app/src/main/java/com/dzeio/openhealth/workers/StepCountService.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.dzeio.openhealth.workers
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.util.Log
-import androidx.work.CoroutineWorker
-import androidx.work.PeriodicWorkRequest
-import androidx.work.PeriodicWorkRequestBuilder
-import androidx.work.WorkerParameters
-import com.dzeio.openhealth.Application
-import com.dzeio.openhealth.core.BaseService
-import com.dzeio.openhealth.data.AppDatabase
-import com.dzeio.openhealth.data.step.Step
-import com.dzeio.openhealth.data.step.StepRepository
-import com.dzeio.openhealth.data.step.StepSource
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.withTimeoutOrNull
-import java.util.concurrent.TimeUnit
-
-@SuppressLint("SpecifyJobSchedulerIdRange")
-class StepCountService(
- private val context: Context,
- params: WorkerParameters
-) : CoroutineWorker(context, params) {
-
-
- companion object {
- const val TAG = "${Application.TAG}/StepCountService"
-
- fun setup(context: Context) {
- BaseService.schedule(
- TAG,
- PeriodicWorkRequestBuilder(PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
- .addTag(TAG)
- .build(),
- context
- )
- }
- }
-
- override suspend fun doWork(): Result {
- Log.d(TAG, "Service Started")
- val appDatabase = AppDatabase.getInstance(this.context)
- val repo = StepRepository(appDatabase.stepDao())
-
- val source = StepSource(this.context)
-
- val value = withTimeoutOrNull(10000) {
- source.events.receive()
- }
- if (value == null || value == 0f) {
- Log.d(TAG, "No new steps registered ($value)")
- return Result.success()
- }
- Log.d(TAG, "New steps registered: $value")
- coroutineContext
- val step = repo.todayStep().first()
- if (step != null) {
- step.value += value
- repo.updateStep(step)
- } else {
- repo.addStep(Step(value = value))
- }
-
- return Result.success()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_browse.xml b/app/src/main/res/layout/fragment_browse.xml
index 0610bf2..bfec972 100644
--- a/app/src/main/res/layout/fragment_browse.xml
+++ b/app/src/main/res/layout/fragment_browse.xml
@@ -73,6 +73,7 @@