mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-06-14 17:59:18 +00:00
Clean up
This commit is contained in:
17
.idea/deploymentTargetDropDown.xml
generated
17
.idea/deploymentTargetDropDown.xml
generated
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="deploymentTargetDropDown">
|
|
||||||
<runningDeviceTargetSelectedWithDropDown>
|
|
||||||
<Target>
|
|
||||||
<type value="RUNNING_DEVICE_TARGET" />
|
|
||||||
<deviceKey>
|
|
||||||
<Key>
|
|
||||||
<type value="SERIAL_NUMBER" />
|
|
||||||
<value value="14e181ff" />
|
|
||||||
</Key>
|
|
||||||
</deviceKey>
|
|
||||||
</Target>
|
|
||||||
</runningDeviceTargetSelectedWithDropDown>
|
|
||||||
<timeTargetWasSelectedWithDropDown value="2021-12-21T23:29:01.995426900Z" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -3,7 +3,7 @@
|
|||||||
<component name="DesignSurface">
|
<component name="DesignSurface">
|
||||||
<option name="filePathToZoomLevelMap">
|
<option name="filePathToZoomLevelMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_home.xml" value="0.13489583333333333" />
|
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_home.xml" value="0.33" />
|
||||||
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_import.xml" value="0.1" />
|
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_import.xml" value="0.1" />
|
||||||
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/menu/activity_main_drawer.xml" value="0.10989583333333333" />
|
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/menu/activity_main_drawer.xml" value="0.10989583333333333" />
|
||||||
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/menu/main.xml" value="0.1875" />
|
<entry key="..\:/Git/Dzeio/OpenHealth/app/src/main/res/menu/main.xml" value="0.1875" />
|
||||||
|
@ -42,7 +42,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.7.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.0'
|
implementation 'androidx.appcompat:appcompat:1.4.0'
|
||||||
implementation 'javax.inject:javax.inject:1'
|
implementation 'javax.inject:javax.inject:1'
|
||||||
@ -50,8 +49,18 @@ dependencies {
|
|||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
|
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
|
||||||
|
|
||||||
|
// DataStore
|
||||||
|
implementation "androidx.datastore:datastore:1.0.0"
|
||||||
|
|
||||||
|
// Navigation
|
||||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
||||||
|
|
||||||
|
// Services
|
||||||
|
implementation 'androidx.work:work-runtime-ktx:2.7.1'
|
||||||
|
|
||||||
|
// Tests
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
@ -71,7 +80,7 @@ dependencies {
|
|||||||
implementation files('libs/samsung-health-data-1.5.0.aar')
|
implementation files('libs/samsung-health-data-1.5.0.aar')
|
||||||
|
|
||||||
// ROOM
|
// ROOM
|
||||||
def room_version = "2.3.0"
|
def room_version = "2.4.0"
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:$room_version"
|
implementation "androidx.room:room-runtime:$room_version"
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
@ -23,6 +23,19 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.OpenHealth">
|
android:theme="@style/Theme.OpenHealth">
|
||||||
|
|
||||||
|
<receiver android:name=".services.BroadcastReceiver"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<!-- Water Intake -->
|
||||||
|
<service android:name=".services.WaterReminderService"
|
||||||
|
android:label="Water Intake service"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
<!-- Samsung Health-->
|
<!-- Samsung Health-->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.samsung.android.health.permission.read"
|
android:name="com.samsung.android.health.permission.read"
|
||||||
|
@ -4,4 +4,8 @@ import android.app.Application
|
|||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class Application : Application() {}
|
class Application : Application() {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "OpenHealth"
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,10 @@
|
|||||||
package com.dzeio.openhealth
|
package com.dzeio.openhealth
|
||||||
|
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -13,6 +17,7 @@ import androidx.navigation.ui.setupActionBarWithNavController
|
|||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.dzeio.openhealth.core.BaseActivity
|
import com.dzeio.openhealth.core.BaseActivity
|
||||||
import com.dzeio.openhealth.databinding.ActivityMainBinding
|
import com.dzeio.openhealth.databinding.ActivityMainBinding
|
||||||
|
import com.dzeio.openhealth.services.WaterReminderService
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@ -41,6 +46,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
|
|
||||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
|
|
||||||
|
WaterReminderService.setup(this)
|
||||||
|
createNotificationChannel()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@ -66,8 +74,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
Log.d("MainActivity", "onActivityResult $requestCode $resultCode")
|
||||||
for (fragment in supportFragmentManager.primaryNavigationFragment!!.childFragmentManager.fragments) {
|
for (fragment in supportFragmentManager.primaryNavigationFragment!!.childFragmentManager.fragments) {
|
||||||
fragment.onActivityResult(requestCode, resultCode, data)
|
fragment.onActivityResult(requestCode, resultCode, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createNotificationChannel() {
|
||||||
|
// Create the NotificationChannel, but only on API 26+ because
|
||||||
|
// the NotificationChannel class is new and not in the support library
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
val channel = NotificationChannel("openhealth", "Default Channel", importance)
|
||||||
|
// Register the channel with the system
|
||||||
|
val notificationManager: NotificationManager =
|
||||||
|
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
notificationManager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
25
app/src/main/java/com/dzeio/openhealth/core/BaseService.kt
Normal file
25
app/src/main/java/com/dzeio/openhealth/core/BaseService.kt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.dzeio.openhealth.core
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkRequest
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
|
||||||
|
abstract class BaseService(context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun schedule(tag: String, request: WorkRequest, context: Context) {
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.cancelAllWorkByTag(tag)
|
||||||
|
|
||||||
|
Log.d("OpenHealth/BaseService", "Scheduled Job $tag")
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.enqueue(request)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,4 +26,13 @@ data class Water(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun formatTimestamp(): String = getDateInstance().format(Date(timestamp))
|
fun formatTimestamp(): String = getDateInstance().format(Date(timestamp))
|
||||||
|
|
||||||
|
fun isToday(): Boolean {
|
||||||
|
val cal = Calendar.getInstance()
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
cal.set(Calendar.MINUTE, 0)
|
||||||
|
cal.set(Calendar.SECOND, 0)
|
||||||
|
cal.set(Calendar.MILLISECOND, 0)
|
||||||
|
return timestamp == cal.timeInMillis
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,12 +21,6 @@ class WaterRepository @Inject constructor(
|
|||||||
suspend fun deleteFromSource(value: String) = waterDao.deleteFromSource(value)
|
suspend fun deleteFromSource(value: String) = waterDao.deleteFromSource(value)
|
||||||
|
|
||||||
fun todayWater() = lastWater().filter {
|
fun todayWater() = lastWater().filter {
|
||||||
val cal = Calendar.getInstance()
|
return@filter it != null && it.isToday()
|
||||||
cal.set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
cal.set(Calendar.MINUTE, 0)
|
|
||||||
cal.set(Calendar.SECOND, 0)
|
|
||||||
cal.set(Calendar.MILLISECOND, 0)
|
|
||||||
Log.d("WaterRepository", "${it?.timestamp} ${cal.timeInMillis}")
|
|
||||||
return@filter it?.timestamp == cal.timeInMillis
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
@Dao
|
@Dao
|
||||||
interface WeightDao : BaseDao<Weight> {
|
interface WeightDao : BaseDao<Weight> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Weight")
|
@Query("SELECT * FROM Weight ORDER BY timestamp")
|
||||||
fun getAll(): Flow<List<Weight>>
|
fun getAll(): Flow<List<Weight>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Weight where id = :weightId")
|
@Query("SELECT * FROM Weight where id = :weightId")
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.dzeio.openhealth.services
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
class BroadcastReceiver : BroadcastReceiver() {
|
||||||
|
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
context?.let {
|
||||||
|
WaterReminderService.setup(it)
|
||||||
|
Log.d("OpenHealth/BR", "Scheduled Jobs!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package com.dzeio.openhealth.services
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.dzeio.openhealth.Application
|
||||||
|
import com.dzeio.openhealth.MainActivity
|
||||||
|
import com.dzeio.openhealth.R
|
||||||
|
import com.dzeio.openhealth.core.BaseService
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class WaterReminderService(
|
||||||
|
private val context: Context,
|
||||||
|
params: WorkerParameters
|
||||||
|
) : BaseService(context, params) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "${Application.TAG}/WaterService"
|
||||||
|
fun setup(context: Context) {
|
||||||
|
schedule(
|
||||||
|
TAG,
|
||||||
|
PeriodicWorkRequestBuilder<WaterReminderService>(15, TimeUnit.MINUTES)
|
||||||
|
.addTag(TAG)
|
||||||
|
.build(),
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnspecifiedImmutableFlag")
|
||||||
|
override fun doWork(): Result {
|
||||||
|
Log.d(TAG, "Ran! ${Date().toLocaleString()}")
|
||||||
|
with(NotificationManagerCompat.from(context)) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
notify(
|
||||||
|
(Math.random() * 100).toInt(), NotificationCompat.Builder(context, "openhealth")
|
||||||
|
.setContentTitle("Did you drink?")
|
||||||
|
.setContentText("Drink now!")
|
||||||
|
.setSmallIcon(R.drawable.ic_logo_small)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setContentIntent(
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
Intent(context, MainActivity::class.java).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
},
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
notify(
|
||||||
|
(Math.random() * 100).toInt(), NotificationCompat.Builder(context, "openhealth")
|
||||||
|
.setContentTitle("Did you drink?")
|
||||||
|
.setContentText("Drink now!")
|
||||||
|
.setSmallIcon(R.drawable.ic_logo_small)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setContentIntent(
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
Intent(context, MainActivity::class.java).apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
},
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,20 +1,14 @@
|
|||||||
package com.dzeio.openhealth.ui.home
|
package com.dzeio.openhealth.ui.home
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.animation.ValueAnimator
|
||||||
import android.app.Activity.RESULT_OK
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.dzeio.openhealth.R
|
import com.dzeio.openhealth.R
|
||||||
@ -36,10 +30,10 @@ import com.google.android.material.color.MaterialColors
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.IOException
|
import java.text.DateFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.math.min
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewModel::class.java) {
|
class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewModel::class.java) {
|
||||||
@ -56,38 +50,39 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
viewModel.init()
|
||||||
|
|
||||||
binding.addWeight.setOnClickListener {
|
binding.addWeight.setOnClickListener {
|
||||||
AddWeightDialog().show(requireActivity().supportFragmentManager, null)
|
AddWeightDialog().show(requireActivity().supportFragmentManager, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.fragmentHomeWaterAdd.setOnClickListener {
|
binding.fragmentHomeWaterAdd.setOnClickListener { _ ->
|
||||||
lifecycleScope.launchWhenStarted {
|
|
||||||
|
|
||||||
Log.d(TAG, "Collecting latest $this")
|
val water = viewModel.water.value
|
||||||
if (viewModel.fetchTodayWater().count() == 0) {
|
|
||||||
Log.d(TAG, "No value, Adding...")
|
if (water == null) {
|
||||||
val w = Water()
|
|
||||||
w.value = 200
|
val w = Water()
|
||||||
viewModel.updateWater(w)
|
w.value = 200
|
||||||
return@launchWhenStarted
|
viewModel.updateWater(w)
|
||||||
|
} else {
|
||||||
|
water.value += 200
|
||||||
|
viewModel.updateWater(water)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.fragmentHomeWaterRemove.setOnClickListener { _ ->
|
||||||
|
|
||||||
|
val water = viewModel.water.value
|
||||||
|
|
||||||
|
if (water != null) {
|
||||||
|
|
||||||
|
water.value -= 200
|
||||||
|
if (water.value == 0) {
|
||||||
|
viewModel.deleteWater(water)
|
||||||
|
} else {
|
||||||
|
viewModel.updateWater(water)
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
viewModel.fetchTodayWater().count()
|
|
||||||
val item = viewModel.fetchTodayWater().lastOrNull()
|
|
||||||
Log.d(TAG, "Collected latest $item")
|
|
||||||
if (item == null) {
|
|
||||||
|
|
||||||
val w = Water()
|
|
||||||
w.value = 200
|
|
||||||
viewModel.updateWater(w)
|
|
||||||
} else {
|
|
||||||
item.value += 200
|
|
||||||
viewModel.updateWater(item)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(TAG, "EXCEPTION", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,13 +115,26 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup Graph
|
// Setup Graph
|
||||||
// binding.weightGraph.gridLabelRenderer.labelFormatter = DateAsXAxisLabelFormatter(requireContext())
|
// binding.weightGraph.apply {
|
||||||
// binding.weightGraph.gridLabelRenderer.numHorizontalLabels = 3 // only 4 because of the space
|
// gridLabelRenderer.labelFormatter = DateAsXAxisLabelFormatter(
|
||||||
// binding.weightGraph.viewport.isXAxisBoundsManual = true
|
// requireContext(),
|
||||||
//// binding.weightGraph.gridLabelRenderer.setHumanRounding(false);
|
// DateFormat.getDateInstance(DateFormat.MEDIUM)
|
||||||
// binding.weightGraph.addSeries(serie)
|
// )
|
||||||
|
// gridLabelRenderer.numHorizontalLabels = 3 // only 4 because of the space
|
||||||
|
// gridLabelRenderer.numVerticalLabels = 3
|
||||||
|
// gridLabelRenderer.gridStyle = GridLabelRenderer.GridStyle.HORIZONTAL
|
||||||
|
// viewport.isXAxisBoundsManual = true
|
||||||
|
// viewport.isScalable = true
|
||||||
|
// viewport.setScalableY(true)
|
||||||
|
// viewport.isScrollable = true
|
||||||
|
// viewport.setScrollableY(true)
|
||||||
|
// gridLabelRenderer.setHumanRounding(false);
|
||||||
|
// addSeries(serie)
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private val serie: LineGraphSeries<DataPoint> = LineGraphSeries()
|
||||||
// private val entries = LineGraphSeries<DataPoint>()
|
// private val entries = LineGraphSeries<DataPoint>()
|
||||||
|
|
||||||
private fun updateGraph(list: List<Weight>) {
|
private fun updateGraph(list: List<Weight>) {
|
||||||
@ -173,37 +181,41 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
}
|
}
|
||||||
binding.weightGraph.data = LineData(dataSet)
|
binding.weightGraph.data = LineData(dataSet)
|
||||||
binding.weightGraph.invalidate()
|
binding.weightGraph.invalidate()
|
||||||
|
binding.weightGraph.setVisibleXRange(
|
||||||
|
(list[list.size - 1].timestamp - 604800000).toFloat(),
|
||||||
|
list[list.size - 1].timestamp.toFloat()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// binding.weightGraph.gridLabelRenderer.numHorizontalLabels = 3 // only 4 because of the space
|
||||||
|
// binding.weightGraph.gridLabelRenderer.numVerticalLabels = 3
|
||||||
|
//
|
||||||
|
// binding.weightGraph.viewport.maxXAxisSize = 604800000.0 * 2
|
||||||
|
//// binding.weightGraph.viewport.setMinimalViewport(0.0, 604800000.0, minValue.toDouble(), maxValue.toDouble())
|
||||||
|
//
|
||||||
// serie.resetData(list
|
// serie.resetData(list
|
||||||
// .map { DataPoint(Date(it.timestamp), it.weight.toDouble()) }
|
// .map { DataPoint(Date(it.timestamp), it.weight.toDouble()) }
|
||||||
// .toTypedArray()
|
// .toTypedArray())
|
||||||
// )
|
//
|
||||||
|
// binding.weightGraph.viewport.scrollToEnd()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("PrivateResource")
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
|
||||||
lifecycleScope.launchWhenStarted {
|
lifecycleScope.launchWhenStarted {
|
||||||
viewModel.fetchWeights().collectLatest {
|
viewModel.fetchWeights().collectLatest {
|
||||||
if (it.isEmpty()) {
|
|
||||||
return@collectLatest
|
|
||||||
}
|
|
||||||
updateGraph(it)
|
updateGraph(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launchWhenStarted {
|
viewModel.water.observe(viewLifecycleOwner) {
|
||||||
viewModel.fetchTodayWater().collect {
|
if (it != null) {
|
||||||
Log.d(TAG, "Pouet? $it")
|
updateWater(it.value)
|
||||||
if (it != null) {
|
} else {
|
||||||
updateWater(it.value)
|
updateWater(0)
|
||||||
} else {
|
|
||||||
updateWater(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +224,8 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWater(water: Int) {
|
private fun updateWater(water: Int) {
|
||||||
binding.fragmentHomeWaterCurrent.text = water.toString()
|
val oldValue = binding.fragmentHomeWaterCurrent.text.toString().replace("ml", "").toInt()
|
||||||
|
binding.fragmentHomeWaterCurrent.text = "${water}ml"
|
||||||
|
|
||||||
val graph = BitmapUtils.convertToMutable(
|
val graph = BitmapUtils.convertToMutable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
@ -220,22 +233,24 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
|||||||
)
|
)
|
||||||
|
|
||||||
graph?.let { btmp ->
|
graph?.let { btmp ->
|
||||||
val canvas = Canvas(btmp)
|
ValueAnimator.ofFloat(min(oldValue.toFloat(), 1200f), min(water.toFloat(), 1200f))
|
||||||
DrawUtils.drawArc(
|
.apply {
|
||||||
canvas,
|
duration = 300
|
||||||
100 * water / 1200,
|
addUpdateListener {
|
||||||
MaterialColors.getColor(
|
val canvas = Canvas(btmp)
|
||||||
requireView(),
|
DrawUtils.drawArc(
|
||||||
com.google.android.material.R.attr.colorPrimary
|
canvas,
|
||||||
)
|
100 * it.animatedValue as Float / 1200f,
|
||||||
)
|
MaterialColors.getColor(
|
||||||
canvas.save()
|
requireView(),
|
||||||
|
com.google.android.material.R.attr.colorPrimary
|
||||||
// val params = binding.background.layoutParams
|
)
|
||||||
// params.height = binding.background.measuredWidth
|
)
|
||||||
// binding.background.layoutParams = params
|
canvas.save()
|
||||||
|
binding.background.setImageBitmap(graph)
|
||||||
binding.background.setImageBitmap(graph)
|
}
|
||||||
|
start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package com.dzeio.openhealth.ui.home
|
package com.dzeio.openhealth.ui.home
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.dzeio.openhealth.core.BaseViewModel
|
import com.dzeio.openhealth.core.BaseViewModel
|
||||||
import com.dzeio.openhealth.data.weight.Water
|
import com.dzeio.openhealth.data.weight.Water
|
||||||
import com.dzeio.openhealth.data.weight.WaterRepository
|
import com.dzeio.openhealth.data.weight.WaterRepository
|
||||||
@ -9,6 +12,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@ -29,8 +33,25 @@ class HomeViewModel @Inject internal constructor(
|
|||||||
|
|
||||||
fun fetchTodayWater() = waterRepository.todayWater()
|
fun fetchTodayWater() = waterRepository.todayWater()
|
||||||
|
|
||||||
suspend fun updateWater(water: Water) = waterRepository.addWater(water)
|
val water: MutableLiveData<Water?> = MutableLiveData(null)
|
||||||
suspend fun deleteWater(water: Water) = waterRepository.deleteWater(water)
|
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
waterRepository.todayWater().collectLatest {
|
||||||
|
water.postValue(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateWater(water: Water) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
waterRepository.addWater(water)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun deleteWater(item: Water) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
waterRepository.deleteWater(item)
|
||||||
|
water.postValue(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ object DrawUtils {
|
|||||||
/**
|
/**
|
||||||
* Fuck Graphics
|
* Fuck Graphics
|
||||||
*/
|
*/
|
||||||
fun drawArc(canvas: Canvas, percent: Int, pColor: Int) {
|
fun drawArc(canvas: Canvas, percent: Float, pColor: Int) {
|
||||||
canvas.width
|
canvas.width
|
||||||
val spacing = 120f
|
val spacing = 120f
|
||||||
val r1 = RectF(
|
val r1 = RectF(
|
||||||
|
13
app/src/main/res/drawable/ic_logo_small.xml
Normal file
13
app/src/main/res/drawable/ic_logo_small.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="324dp"
|
||||||
|
android:height="324dp"
|
||||||
|
android:viewportWidth="324"
|
||||||
|
android:viewportHeight="324">
|
||||||
|
<path
|
||||||
|
android:pathData="M290,199.975C302.15,199.975 312,190.125 312,177.975V146.025C312,133.875 302.15,124.025 290,124.025H212.975C205.795,124.025 199.975,118.205 199.975,111.025V34C199.975,21.85 190.125,12 177.975,12H146.025C133.875,12 124.025,21.85 124.025,34V111.025C124.025,118.205 118.205,124.025 111.025,124.025H34C21.85,124.025 12,133.875 12,146.025V177.975C12,190.125 21.85,199.975 34,199.975H111.025C118.205,199.975 124.025,205.795 124.025,212.975V290C124.025,302.15 133.875,312 146.025,312H177.975C190.125,312 199.975,302.15 199.975,290V212.975C199.975,205.795 205.795,199.975 212.975,199.975H290Z"
|
||||||
|
android:strokeWidth="23"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:fillAlpha="0.5"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
Reference in New Issue
Block a user