1
0
mirror of https://github.com/dzeiocom/OpenHealth.git synced 2025-06-07 15:29:55 +00:00

Stated Adding Water Intake

This commit is contained in:
Florian Bouillon 2021-12-22 01:44:34 +01:00
parent e1f11e1ae2
commit 077397749c
Signed by: Florian Bouillon
GPG Key ID: 50BD648F12C86AB6
33 changed files with 1109 additions and 694 deletions

7
.gitignore vendored
View File

@ -1,12 +1,7 @@
*.iml *.iml
.gradle .gradle
/local.properties /local.properties
/.idea/caches /.idea
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store .DS_Store
/build /build
/captures /captures

17
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?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>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Reformat" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
</profile>
</component>

5
.idea/misc.xml generated
View File

@ -7,6 +7,8 @@
<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" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/drawable/half_circle.xml" value="0.421" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/drawable/ic_ellipse_2.xml" value="0.4165" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/drawable/ic_logo_app.xml" value="0.163" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/drawable/ic_logo_app.xml" value="0.163" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/activity_main.xml" value="0.5" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/activity_main.xml" value="0.5" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/app_bar_main.xml" value="0.5192107995846313" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/app_bar_main.xml" value="0.5192107995846313" />
@ -15,9 +17,10 @@
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/dialog_edit_weight.xml" value="0.33" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/dialog_edit_weight.xml" value="0.33" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/dialog_register_weight.xml" value="0.5" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/dialog_register_weight.xml" value="0.5" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_gallery.xml" value="0.3109375" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_gallery.xml" value="0.3109375" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_home.xml" value="0.25" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_home.xml" value="0.6845493562231759" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_import.xml" value="0.55" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_import.xml" value="0.55" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_list_weight.xml" value="0.33" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_list_weight.xml" value="0.33" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/fragment_water_home.xml" value="0.55" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/layout_item_weight.xml" value="0.5" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/layout_item_weight.xml" value="0.5" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/nav_header_main.xml" value="0.3109375" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/layout/nav_header_main.xml" value="0.3109375" />
<entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/menu/activity_main_drawer.xml" value="0.39947916666666666" /> <entry key="..\:/git/Dzeio/OpenHealth/app/src/main/res/menu/activity_main_drawer.xml" value="0.39947916666666666" />

View File

@ -5,10 +5,7 @@ import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
@ -16,9 +13,6 @@ 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.ui.main.home.HomeFragmentDirections
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint

View File

@ -4,18 +4,27 @@ import android.content.Context
import androidx.room.Database import androidx.room.Database
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import com.dzeio.openhealth.data.weight.Water
import com.dzeio.openhealth.data.weight.WaterDao
import com.dzeio.openhealth.data.weight.WeightDao import com.dzeio.openhealth.data.weight.WeightDao
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
@Database(entities = [Weight::class], version = 1, exportSchema = false) @Database(
entities = [
Weight::class,
Water::class
], version = 1, exportSchema = false
)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun weightDao() : WeightDao abstract fun weightDao(): WeightDao
abstract fun waterDao(): WaterDao
companion object { companion object {
private const val DATABASE_NAME = "open_health" private const val DATABASE_NAME = "open_health"
// For Singleton instantiation // For Singleton instantiation
@Volatile private var instance: AppDatabase? = null @Volatile
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase { fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) { return instance ?: synchronized(this) {

View File

@ -0,0 +1,29 @@
package com.dzeio.openhealth.data.weight
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.sql.Date
import java.text.DateFormat.getDateInstance
import java.util.*
@Entity()
data class Water(
@PrimaryKey(autoGenerate = true) var id: Long = 0,
var value: Int = 0,
@ColumnInfo(index = true)
var timestamp: Long = System.currentTimeMillis(),
var source: String = "OpenHealth"
) {
init {
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)
timestamp = cal.timeInMillis
}
fun formatTimestamp(): String = getDateInstance().format(Date(timestamp))
}

View File

@ -0,0 +1,26 @@
package com.dzeio.openhealth.data.weight
import androidx.room.*
import com.dzeio.openhealth.core.BaseDao
import dagger.Provides
import kotlinx.coroutines.flow.Flow
@Dao
interface WaterDao : BaseDao<Water> {
@Query("SELECT * FROM Water")
fun getAll(): Flow<List<Water>>
@Query("SELECT * FROM Water where id = :weightId")
fun getOne(weightId: Long): Flow<Water?>
@Query("Select count(*) from Water")
fun getCount(): Flow<Int>
@Query("Select * FROM Water WHERE id=(SELECT max(id) FROM Water)")
fun last(): Flow<Water?>
@Query("DELETE FROM Water where source = :source")
suspend fun deleteFromSource(source: String)
}

View File

@ -0,0 +1,32 @@
package com.dzeio.openhealth.data.weight
import android.util.Log
import kotlinx.coroutines.flow.*
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class WaterRepository @Inject constructor(
private val waterDao: WaterDao
) {
fun getWaters() = waterDao.getAll()
fun lastWater() = waterDao.last()
fun getWater(id: Long) = waterDao.getOne(id)
suspend fun addWater(value: Water) = waterDao.insert(value)
suspend fun deleteWater(value: Water) = waterDao.delete(value)
suspend fun deleteFromSource(value: String) = waterDao.deleteFromSource(value)
fun todayWater() = lastWater().filter {
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)
Log.d("WaterRepository", "${it?.timestamp} ${cal.timeInMillis}")
return@filter it?.timestamp == cal.timeInMillis
}
}

View File

@ -2,6 +2,7 @@ package com.dzeio.openhealth.di
import android.content.Context import android.content.Context
import com.dzeio.openhealth.data.AppDatabase import com.dzeio.openhealth.data.AppDatabase
import com.dzeio.openhealth.data.weight.WaterDao
import com.dzeio.openhealth.data.weight.WeightDao import com.dzeio.openhealth.data.weight.WeightDao
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -24,4 +25,9 @@ class DatabaseModule {
fun provideWeightDao(appDatabase: AppDatabase): WeightDao { fun provideWeightDao(appDatabase: AppDatabase): WeightDao {
return appDatabase.weightDao() return appDatabase.weightDao()
} }
@Provides
fun provideWaterDao(appDatabase: AppDatabase): WaterDao {
return appDatabase.waterDao()
}
} }

View File

@ -1,4 +1,4 @@
package com.dzeio.openhealth.connectors package com.dzeio.openhealth.extensions
enum class DataType { enum class DataType {
WEIGHT WEIGHT

View File

@ -1,10 +1,10 @@
package com.dzeio.openhealth.connectors package com.dzeio.openhealth.extensions
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
abstract class Connector { abstract class Extension {
enum class Data { enum class Data {
WEIGHT, WEIGHT,
@ -13,7 +13,7 @@ abstract class Connector {
abstract val sourceID: String abstract val sourceID: String
open fun init(activity: Activity) {} open fun init(activity: Activity): Array<Data> = arrayOf()
/** /**
* Same as Activity/Fragment onRequestPermissionResult * Same as Activity/Fragment onRequestPermissionResult
@ -27,5 +27,7 @@ abstract class Connector {
*/ */
open fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {} open fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {}
open fun <T> import(data: Data, cb: (item: T, end: Boolean) -> Unit) {}
open fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) {} open fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) {}
} }

View File

@ -1,173 +1,186 @@
package com.dzeio.openhealth.connectors package com.dzeio.openhealth.extensions
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.fitness.Fitness import com.google.android.gms.fitness.Fitness
import com.google.android.gms.fitness.FitnessOptions import com.google.android.gms.fitness.FitnessOptions
import com.google.android.gms.fitness.data.DataPoint import com.google.android.gms.fitness.data.DataPoint
import com.google.android.gms.fitness.data.DataSet import com.google.android.gms.fitness.data.DataType
import com.google.android.gms.fitness.data.DataType import com.google.android.gms.fitness.request.DataReadRequest
import com.google.android.gms.fitness.request.DataReadRequest import java.text.DateFormat
import java.text.DateFormat import java.util.*
import java.util.* import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit
class GoogleFit(
class GoogleFit( private val activity: Activity,
private val activity: Activity, ) : Extension() {
) : Connector() { companion object {
companion object { const val TAG = "GoogleFitConnector"
const val TAG = "GoogleFitConnector" }
}
override val sourceID: String = "GoogleFit"
override val sourceID: String = "GoogleFit"
private val fitnessOptions = FitnessOptions.builder()
private val fitnessOptions = FitnessOptions.builder() .addDataType(DataType.TYPE_WEIGHT)
.addDataType(DataType.TYPE_WEIGHT) .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
.addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE) .build()
.build()
private fun checkPermissionsAndRun(data: Data) {
private fun checkPermissionsAndRun(data: Data) { if (permissionApproved()) {
if (permissionApproved()) { signIn(data)
signIn(data) } else {
} else { Log.d(TAG, "Asking for permission")
Log.d(TAG, "Asking for permission") // Ask for permission
// Ask for permission ActivityCompat.requestPermissions(
ActivityCompat.requestPermissions( activity,
activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), data.ordinal
data.ordinal )
) }
} }
}
private fun permissionApproved(): Boolean {
private fun permissionApproved(): Boolean { val approved = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val approved = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission( activity,
activity, Manifest.permission.ACCESS_FINE_LOCATION)
Manifest.permission.ACCESS_FINE_LOCATION) } else {
} else { true
true }
} return approved
return approved }
}
private fun signIn(data: Data) {
private fun signIn(data: Data) { if (oAuthPermissionsApproved()) {
if (oAuthPermissionsApproved()) { startImport(data)
startImport(data) } else {
} else { Log.d("GoogleFitImporter", "Signing In")
Log.d("GoogleFitImporter", "Signing In") GoogleSignIn.requestPermissions(
GoogleSignIn.requestPermissions( activity,
activity, data.ordinal,
data.ordinal, getGoogleAccount(), fitnessOptions)
getGoogleAccount(), fitnessOptions) }
} }
}
private fun oAuthPermissionsApproved() = GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions)
private fun oAuthPermissionsApproved() = GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions)
private fun getGoogleAccount() = GoogleSignIn.getAccountForExtension(activity, fitnessOptions)
private fun getGoogleAccount() = GoogleSignIn.getAccountForExtension(activity, fitnessOptions)
private val timeRange by lazy {
private val timeRange by lazy { val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")) calendar.time = Date()
calendar.time = Date() val endTime = calendar.timeInMillis
val endTime = calendar.timeInMillis
// Set year to 2013 to be sure to get data from when Google Fit Started to today
// Set year to 2013 to be sure to get data from when Google Fit Started to today calendar.set(Calendar.YEAR, 2013)
calendar.set(Calendar.YEAR, 2013) val startTime = calendar.timeInMillis
val startTime = calendar.timeInMillis arrayOf(startTime, endTime)
arrayOf(startTime, endTime) }
}
private fun startImport(data: Data) {
private fun startImport(data: Data) { Log.d("GoogleFitImporter", "Importing for ${data.name}")
Log.d("GoogleFitImporter", "Importing for ${data.name}")
val dateFormat = DateFormat.getDateInstance()
val dateFormat = DateFormat.getDateInstance() Log.i(TAG, "Range Start: ${dateFormat.format(timeRange[0])}")
Log.i(TAG, "Range Start: ${dateFormat.format(timeRange[0])}") Log.i(TAG, "Range End: ${dateFormat.format(timeRange[1])}")
Log.i(TAG, "Range End: ${dateFormat.format(timeRange[1])}")
var type = DataType.TYPE_WEIGHT
var type = DataType.TYPE_WEIGHT var timeUnit = TimeUnit.MILLISECONDS
var timeUnit = TimeUnit.MILLISECONDS
when (data) {
when (data) { Data.STEPS -> {
Data.STEPS -> { type = DataType.TYPE_STEP_COUNT_CUMULATIVE
type = DataType.TYPE_STEP_COUNT_CUMULATIVE }
} else -> {}
else -> {} }
}
runRequest(DataReadRequest.Builder()
runRequest(DataReadRequest.Builder() .read(type)
.read(type) .setTimeRange(timeRange[0], timeRange[1], timeUnit)
.setTimeRange(timeRange[0], timeRange[1], timeUnit) .build(), data)
.build(), data)
}
}
private fun runRequest(request: DataReadRequest, data: Data) {
private fun runRequest(request: DataReadRequest, data: Data) { Fitness.getHistoryClient(activity, GoogleSignIn.getAccountForExtension(activity, fitnessOptions))
Fitness.getHistoryClient(activity, GoogleSignIn.getAccountForExtension(activity, fitnessOptions)) .readData(request)
.readData(request) .addOnSuccessListener { response ->
.addOnSuccessListener { response -> Log.d(TAG, "Received response! ${response.dataSets.size} ${response.buckets.size} ${response.status}")
Log.d(TAG, "Received response! ${response.dataSets.size} ${response.buckets.size} ${response.status}") for (dataSet in response.dataSets) {
for (dataSet in response.dataSets) { Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name} ${dataSet.dataPoints.size}")
Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name} ${dataSet.dataPoints.size}") dataSet.dataPoints.forEachIndexed { index, dp ->
dataSet.dataPoints.forEachIndexed { index, dp -> val isLast = (index + 1) == dataSet.dataPoints.size
val isLast = (index + 1) == dataSet.dataPoints.size
// Global
// Global Log.i(TAG,"Importing Data point:")
Log.i(TAG,"Importing Data point:") Log.i(TAG,"\tType: ${dp.dataType.name}")
Log.i(TAG,"\tType: ${dp.dataType.name}") Log.i(TAG,"\tStart: ${dp.getStartTimeString()}")
Log.i(TAG,"\tStart: ${dp.getStartTimeString()}") Log.i(TAG,"\tEnd: ${dp.getEndTimeString()}")
Log.i(TAG,"\tEnd: ${dp.getEndTimeString()}")
// Field Specifics
// Field Specifics for (field in dp.dataType.fields) {
for (field in dp.dataType.fields) { Log.i(TAG,"\tField: ${field.name} Value: ${dp.getValue(field)}")
Log.i(TAG,"\tField: ${field.name} Value: ${dp.getValue(field)}") when (data) {
when (data) { Data.WEIGHT -> {
Data.WEIGHT -> { val weight = Weight()
val weight = Weight() weight.timestamp = dp.getStartTime(TimeUnit.MILLISECONDS)
weight.timestamp = dp.getStartTime(TimeUnit.MILLISECONDS) weight.weight = dp.getValue(field).asFloat()
weight.weight = dp.getValue(field).asFloat() weightCallback(weight, isLast)
weightCallback(weight, isLast) }
} else -> {}
else -> {} }
} }
} }
} }
} }
} .addOnFailureListener { e ->
.addOnFailureListener { e -> Log.e(TAG,"There was an error reading data from Google Fit", e)
Log.e(TAG,"There was an error reading data from Google Fit", e) }
} }
}
private fun DataPoint.getStartTimeString(): String = Date(this.getStartTime(TimeUnit.SECONDS) * 1000L).toLocaleString()
private fun DataPoint.getStartTimeString(): String = Date(this.getStartTime(TimeUnit.SECONDS) * 1000L).toLocaleString()
private fun DataPoint.getEndTimeString(): String = Date(this.getEndTime(TimeUnit.SECONDS) * 1000L).toLocaleString()
private fun DataPoint.getEndTimeString(): String = Date(this.getEndTime(TimeUnit.SECONDS) * 1000L).toLocaleString()
override fun onRequestPermissionResult(
override fun onRequestPermissionResult( requestCode: Int,
requestCode: Int, permission: Array<String>,
permission: Array<String>, grantResult: IntArray
grantResult: IntArray ) {
) { signIn(Data.values()[requestCode])
signIn(Data.values()[requestCode]) }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { signIn(Data.values()[requestCode])
signIn(Data.values()[requestCode]) }
}
private lateinit var weightCallback: (weight: Weight, end: Boolean) -> Unit
private lateinit var weightCallback: (weight: Weight, end: Boolean) -> Unit
override fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) {
override fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) { this.weightCallback = callback
this.weightCallback = callback checkPermissionsAndRun(Data.WEIGHT)
checkPermissionsAndRun(Data.WEIGHT) }
}
private lateinit var callback : (item: Any, end: Boolean) -> Unit
override fun <T> import(data: Data, cb: (item: T, end: Boolean) -> Unit) {
callback = cb as (item: Any, end: Boolean) -> Unit
when (data) {
Data.WEIGHT -> {
checkPermissionsAndRun(data)
}
else -> {
Log.d(TAG, "PRRRRRRRRRRRRR")
}
}
}
} }

View File

@ -1,4 +1,4 @@
package com.dzeio.openhealth.connectors package com.dzeio.openhealth.extensions
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
@ -7,7 +7,6 @@ import android.os.Build
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import com.dzeio.openhealth.data.AppDatabase
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.fitness.Fitness import com.google.android.gms.fitness.Fitness
@ -22,7 +21,6 @@ import com.google.android.gms.fitness.request.OnDataPointListener
import com.google.android.gms.fitness.request.SensorRequest import com.google.android.gms.fitness.request.SensorRequest
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.*
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit

View File

@ -1,108 +1,108 @@
package com.dzeio.openhealth.connectors.samsunghealth package com.dzeio.openhealth.extensions.samsunghealth
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import com.dzeio.openhealth.connectors.Connector import com.dzeio.openhealth.extensions.Extension
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.samsung.android.sdk.healthdata.* import com.samsung.android.sdk.healthdata.*
import com.samsung.android.sdk.healthdata.HealthConstants.StepCount import com.samsung.android.sdk.healthdata.HealthConstants.StepCount
import com.samsung.android.sdk.healthdata.HealthDataStore.ConnectionListener import com.samsung.android.sdk.healthdata.HealthDataStore.ConnectionListener
import com.samsung.android.sdk.healthdata.HealthPermissionManager.* import com.samsung.android.sdk.healthdata.HealthPermissionManager.*
/** /**
* Does not FUCKING work * Does not FUCKING work
*/ */
class SamsungHealth( class SamsungHealth(
private val context: Activity private val context: Activity
) : Connector() { ) : Extension() {
companion object { companion object {
const val TAG = "SamsungHealthConnector" const val TAG = "SamsungHealthConnector"
} }
private val listener = object : ConnectionListener { private val listener = object : ConnectionListener {
override fun onConnected() { override fun onConnected() {
Log.d(TAG, "Connected!") Log.d(TAG, "Connected!")
if (isPermissionAcquired()) { if (isPermissionAcquired()) {
reporter.start() reporter.start()
} else { } else {
requestPermission() requestPermission()
} }
} }
override fun onConnectionFailed(p0: HealthConnectionErrorResult?) { override fun onConnectionFailed(p0: HealthConnectionErrorResult?) {
Log.d(TAG, "Health data service is not available.") Log.d(TAG, "Health data service is not available.")
} }
override fun onDisconnected() { override fun onDisconnected() {
Log.d(TAG, "Health data service is disconnected.") Log.d(TAG, "Health data service is disconnected.")
} }
} }
private val store : HealthDataStore = HealthDataStore(context, listener) private val store : HealthDataStore = HealthDataStore(context, listener)
private fun isPermissionAcquired(): Boolean { private fun isPermissionAcquired(): Boolean {
val permKey = PermissionKey(StepCount.HEALTH_DATA_TYPE, PermissionType.READ) val permKey = PermissionKey(StepCount.HEALTH_DATA_TYPE, PermissionType.READ)
val pmsManager = HealthPermissionManager(store) val pmsManager = HealthPermissionManager(store)
try { try {
// Check whether the permissions that this application needs are acquired // Check whether the permissions that this application needs are acquired
val resultMap = pmsManager.isPermissionAcquired(setOf(permKey)) val resultMap = pmsManager.isPermissionAcquired(setOf(permKey))
return !resultMap.containsValue(java.lang.Boolean.FALSE) return !resultMap.containsValue(java.lang.Boolean.FALSE)
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
Log.e(TAG, "Permission request fails.", e) Log.e(TAG, "Permission request fails.", e)
} }
return false return false
} }
private fun requestPermission() { private fun requestPermission() {
val permKey = PermissionKey(StepCount.HEALTH_DATA_TYPE, PermissionType.READ) val permKey = PermissionKey(StepCount.HEALTH_DATA_TYPE, PermissionType.READ)
val pmsManager = HealthPermissionManager(store) val pmsManager = HealthPermissionManager(store)
try { try {
// Show user permission UI for allowing user to change options // Show user permission UI for allowing user to change options
pmsManager.requestPermissions(setOf(permKey), context) pmsManager.requestPermissions(setOf(permKey), context)
.setResultListener { result: PermissionResult -> .setResultListener { result: PermissionResult ->
Log.d(TAG, "Permission callback is received.") Log.d(TAG, "Permission callback is received.")
val resultMap = val resultMap =
result.resultMap result.resultMap
if (resultMap.containsValue(java.lang.Boolean.FALSE)) { if (resultMap.containsValue(java.lang.Boolean.FALSE)) {
Log.d(TAG, "No Data???") Log.d(TAG, "No Data???")
} else { } else {
// Get the current step count and display it // Get the current step count and display it
reporter.start() reporter.start()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Permission setting fails.", e) Log.e(TAG, "Permission setting fails.", e)
} }
} }
private val stepCountObserver = object : StepCountReporter.StepCountObserver { private val stepCountObserver = object : StepCountReporter.StepCountObserver {
override fun onChanged(count: Int) { override fun onChanged(count: Int) {
Log.d(TAG, "Step reported : $count") Log.d(TAG, "Step reported : $count")
} }
} }
private val reporter = StepCountReporter(store, stepCountObserver, Handler(Looper.getMainLooper())) private val reporter = StepCountReporter(store, stepCountObserver, Handler(Looper.getMainLooper()))
/** /**
* Connector * Connector
*/ */
override val sourceID: String = "SamsungHealth" override val sourceID: String = "SamsungHealth"
override fun onRequestPermissionResult( override fun onRequestPermissionResult(
requestCode: Int, requestCode: Int,
permission: Array<String>, permission: Array<String>,
grantResult: IntArray grantResult: IntArray
) {} ) {}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {} override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {}
override fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) { override fun importWeight(callback: (weight: Weight, end: Boolean) -> Unit) {
store.connectService() store.connectService()
} }
} }

View File

@ -1,4 +1,4 @@
package com.dzeio.openhealth.connectors.samsunghealth package com.dzeio.openhealth.extensions.samsunghealth
import android.os.Handler import android.os.Handler
import android.util.Log import android.util.Log

View File

@ -1,32 +1,42 @@
package com.dzeio.openhealth.ui.main.home package com.dzeio.openhealth.ui.home
import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
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 androidx.fragment.app.commit 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
import com.dzeio.openhealth.core.BaseFragment import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.data.weight.Water
import com.dzeio.openhealth.databinding.FragmentHomeBinding import com.dzeio.openhealth.databinding.FragmentHomeBinding
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.ui.dialogs.AddWeightDialog import com.dzeio.openhealth.ui.weight.AddWeightDialog
import com.dzeio.openhealth.ui.main.list_weight.ListWeightFragment import com.dzeio.openhealth.utils.BitmapUtils
import com.dzeio.openhealth.utils.DrawUtils
import com.github.mikephil.charting.components.AxisBase import com.github.mikephil.charting.components.AxisBase
import com.github.mikephil.charting.components.Description import com.github.mikephil.charting.components.Description
import com.github.mikephil.charting.components.XAxis import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.formatter.ValueFormatter import com.github.mikephil.charting.formatter.ValueFormatter
import com.google.android.material.color.MaterialColors
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -50,6 +60,54 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
AddWeightDialog().show(requireActivity().supportFragmentManager, null) AddWeightDialog().show(requireActivity().supportFragmentManager, null)
} }
binding.fragmentHomeWaterAdd.setOnClickListener {
lifecycleScope.launchWhenStarted {
Log.d(TAG, "Collecting latest $this")
if (viewModel.fetchTodayWater().count() == 0) {
Log.d(TAG, "No value, Adding...")
val w = Water()
w.value = 200
viewModel.updateWater(w)
return@launchWhenStarted
}
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)
}
}
}
binding.fragmentHomeWaterRemove.setOnClickListener {
lifecycleScope.launch {
val item = viewModel.fetchTodayWater().first()
Log.d(TAG, "Collected latest $it")
if (item != null) {
item.value -= 200
if (item.value == 0) {
viewModel.deleteWater(item)
} else {
viewModel.updateWater(item)
}
}
}
}
binding.listWeight.setOnClickListener { binding.listWeight.setOnClickListener {
Log.d("T", "Trying to move") Log.d("T", "Trying to move")
@ -106,7 +164,10 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
binding.weightGraph.axisRight.setDrawGridLines(false) binding.weightGraph.axisRight.setDrawGridLines(false)
binding.weightGraph.xAxis.valueFormatter = object : ValueFormatter() { binding.weightGraph.xAxis.valueFormatter = object : ValueFormatter() {
override fun getAxisLabel(value: Float, axis: AxisBase?): String { override fun getAxisLabel(value: Float, axis: AxisBase?): String {
return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(value.toLong())) return SimpleDateFormat(
"yyyy-MM-dd",
Locale.getDefault()
).format(Date(value.toLong()))
//return super.getAxisLabel(value, axis) //return super.getAxisLabel(value, axis)
} }
} }
@ -121,6 +182,7 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
// ) // )
} }
@SuppressLint("PrivateResource")
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
@ -132,68 +194,48 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
updateGraph(it) updateGraph(it)
} }
} }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { lifecycleScope.launchWhenStarted {
super.onActivityResult(requestCode, resultCode, data) viewModel.fetchTodayWater().collect {
Log.d(TAG, "Activity Result!") Log.d(TAG, "Pouet? $it")
when (resultCode) { if (it != null) {
RESULT_OK -> { updateWater(it.value)
// fit.performActionForRequestCode(ActionRequestCode.FIND_DATA_SOURCES) } else {
} updateWater(0)
else -> { }
Log.e(TAG, "Error: $requestCode, $resultCode")
} }
} }
updateWater(0)
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, private fun updateWater(water: Int) {
grantResults: IntArray) { binding.fragmentHomeWaterCurrent.text = water.toString()
when {
grantResults.isEmpty() -> {
// If user interaction was interrupted, the permission request
// is cancelled and you receive empty arrays.
Log.i(TAG, "User interaction was cancelled.")
}
grantResults[0] == PackageManager.PERMISSION_GRANTED -> { val graph = BitmapUtils.convertToMutable(
Log.d(TAG, "Granted") requireContext(),
// Permission was granted. BitmapFactory.decodeResource(resources, R.drawable.ellipse)
// val fitActionRequestCode = ActionRequestCode.values()[requestCode] )
// fitActionRequestCode.let {
// // fit.signIn(ActionRequestCode.FIND_DATA_SOURCES)
// }
}
else -> {
// Permission denied.
// In this Activity we've chosen to notify the user that they graph?.let { btmp ->
// have rejected a core permission for the app since it makes the Activity useless. val canvas = Canvas(btmp)
// We're communicating this message in a Snackbar since this is a sample app, but DrawUtils.drawArc(
// core permissions would typically be best requested during a welcome-screen flow. canvas,
100 * water / 1200,
MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorPrimary
)
)
canvas.save()
// Additionally, it is important to remember that a permission might have been // val params = binding.background.layoutParams
// rejected without asking the user for permission (device policy or "Never ask // params.height = binding.background.measuredWidth
// again" prompts). Therefore, a user interface affordance is typically implemented // binding.background.layoutParams = params
// when permissions are denied. Otherwise, your app could appear unresponsive to
// touches or interactions which have required permissions. binding.background.setImageBitmap(graph)
Log.e(TAG, "Error")
// Snackbar.make(
// findViewById(R.id.main_activity_view),
// R.string.permission_denied_explanation,
// Snackbar.LENGTH_INDEFINITE)
// .setAction(R.string.settings) {
// // Build intent that displays the App settings screen.
// val intent = Intent()
// intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
// val uri = Uri.fromParts("package",
// BuildConfig.APPLICATION_ID, null)
// intent.data = uri
// intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// startActivity(intent)
// }
// .show()
}
} }
} }
} }

View File

@ -1,14 +1,20 @@
package com.dzeio.openhealth.ui.main.home package com.dzeio.openhealth.ui.home
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.WaterRepository
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.data.weight.WeightRepository import com.dzeio.openhealth.data.weight.WeightRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class HomeViewModel @Inject internal constructor( class HomeViewModel @Inject internal constructor(
private val weightRepository: WeightRepository private val weightRepository: WeightRepository,
private val waterRepository: WaterRepository
) : BaseViewModel() { ) : BaseViewModel() {
fun fetchWeights() = weightRepository.getWeights() fun fetchWeights() = weightRepository.getWeights()
@ -20,4 +26,11 @@ class HomeViewModel @Inject internal constructor(
suspend fun deleteWeight(weight: Weight) = weightRepository.deleteWeight(weight) suspend fun deleteWeight(weight: Weight) = weightRepository.deleteWeight(weight)
suspend fun addWeight(weight: Weight) = weightRepository.addWeight(weight) suspend fun addWeight(weight: Weight) = weightRepository.addWeight(weight)
fun fetchTodayWater() = waterRepository.todayWater()
suspend fun updateWater(water: Water) = waterRepository.addWater(water)
suspend fun deleteWater(water: Water) = waterRepository.deleteWater(water)
} }

View File

@ -1,4 +1,4 @@
package com.dzeio.openhealth.ui.main.imports package com.dzeio.openhealth.ui.imports
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Intent import android.content.Intent
@ -11,10 +11,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.dzeio.openhealth.connectors.Connector import com.dzeio.openhealth.extensions.Extension
import com.dzeio.openhealth.connectors.GoogleFit import com.dzeio.openhealth.extensions.GoogleFit
//import com.dzeio.openhealth.connectors.GoogleFit //import com.dzeio.openhealth.connectors.GoogleFit
import com.dzeio.openhealth.connectors.samsunghealth.SamsungHealth import com.dzeio.openhealth.extensions.samsunghealth.SamsungHealth
import com.dzeio.openhealth.core.BaseFragment import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.databinding.FragmentImportBinding import com.dzeio.openhealth.databinding.FragmentImportBinding
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -30,7 +30,7 @@ class ImportFragment : BaseFragment<ImportViewModel, FragmentImportBinding>(Impo
private lateinit var progressDialog: ProgressDialog private lateinit var progressDialog: ProgressDialog
private lateinit var fit: Connector private lateinit var fit: Extension
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -43,9 +43,7 @@ class ImportFragment : BaseFragment<ImportViewModel, FragmentImportBinding>(Impo
} }
binding.importGoogleFit.setOnClickListener { binding.importGoogleFit.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { importFromGoogleFit()
importFromGoogleFit()
}
} }
binding.importSamsungHealth.setOnClickListener { binding.importSamsungHealth.setOnClickListener {
importFromSamsungHealth() importFromSamsungHealth()

View File

@ -1,11 +1,10 @@
package com.dzeio.openhealth.ui.main.imports package com.dzeio.openhealth.ui.imports
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.dzeio.openhealth.core.BaseViewModel import com.dzeio.openhealth.core.BaseViewModel
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.data.weight.WeightRepository import com.dzeio.openhealth.data.weight.WeightRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import java.security.CodeSource
import javax.inject.Inject import javax.inject.Inject

View File

@ -0,0 +1,2 @@
package com.dzeio.openhealth.ui.water

View File

@ -1,68 +1,67 @@
package com.dzeio.openhealth.ui.dialogs package com.dzeio.openhealth.ui.weight
import android.app.AlertDialog import android.view.LayoutInflater
import android.view.LayoutInflater import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.lifecycleScope import com.dzeio.openhealth.R
import com.dzeio.openhealth.R import com.dzeio.openhealth.core.BaseDialog
import com.dzeio.openhealth.core.BaseDialog import com.dzeio.openhealth.data.weight.Weight
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.databinding.DialogAddWeightBinding
import com.dzeio.openhealth.databinding.DialogAddWeightBinding import com.dzeio.openhealth.ui.home.HomeViewModel
import com.dzeio.openhealth.ui.main.home.HomeViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collect
@AndroidEntryPoint
@AndroidEntryPoint class AddWeightDialog : BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeViewModel::class.java) {
class AddWeightDialog : BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeViewModel::class.java) {
override val bindingInflater: (LayoutInflater) -> DialogAddWeightBinding = DialogAddWeightBinding::inflate
override val bindingInflater: (LayoutInflater) -> DialogAddWeightBinding = DialogAddWeightBinding::inflate
override fun onBuilderInit(builder: MaterialAlertDialogBuilder) {
override fun onBuilderInit(builder: MaterialAlertDialogBuilder) { super.onBuilderInit(builder)
super.onBuilderInit(builder)
builder.apply {
builder.apply { setTitle("Add your weight (kg)")
setTitle("Add your weight (kg)") setIcon(activity?.let { ContextCompat.getDrawable(it, R.drawable.ic_outline_timeline_24) })
setIcon(activity?.let { ContextCompat.getDrawable(it, R.drawable.ic_outline_timeline_24) }) setPositiveButton("Validate") { dialog, _ ->
setPositiveButton("Validate") { dialog, _ -> save()
save() }
} setNegativeButton("Cancel") { dialog, _ ->
setNegativeButton("Cancel") { dialog, _ -> dialog.cancel()
dialog.cancel() }
}
}
} }
}
override fun onCreated() {
override fun onCreated() { super.onCreated()
super.onCreated()
lifecycleScope.launchWhenStarted {
lifecycleScope.launchWhenStarted { viewModel.lastWeight().collect {
viewModel.lastWeight().collect { if (it != null) {
if (it != null) { binding.kg.value = it.weight.toInt()
binding.kg.value = it.weight.toInt() binding.gram.value = ((it.weight - it.weight.toInt()) * 10 ).toInt()
binding.gram.value = ((it.weight - it.weight.toInt()) * 10 ).toInt() }
} }
} }
}
binding.kg.maxValue = 636
binding.kg.maxValue = 636 binding.kg.minValue = 0
binding.kg.minValue = 0
binding.gram.maxValue = 9
binding.gram.maxValue = 9 binding.gram.minValue = 0
binding.gram.minValue = 0 }
}
private fun save() {
private fun save() { val weight = Weight().apply {
val weight = Weight().apply { weight = binding.kg.value + (binding.gram.value.toFloat() / 10)
weight = binding.kg.value + (binding.gram.value.toFloat() / 10) source = "OpenHealth"
source = "OpenHealth"
}
} lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { viewModel.addWeight(weight)
viewModel.addWeight(weight) }
} //callback?.invoke()
//callback?.invoke() dialog?.dismiss()
dialog?.dismiss() }
}
} }

View File

@ -1,162 +1,165 @@
package com.dzeio.openhealth.ui.dialogs package com.dzeio.openhealth.ui.weight
import android.app.AlertDialog import android.app.Dialog
import android.app.DatePickerDialog import android.os.Build
import android.app.Dialog import android.os.Bundle
import android.content.res.Resources import android.util.Log
import android.os.Build import android.view.LayoutInflater
import android.os.Bundle import android.view.MenuItem
import android.util.Log import android.view.Window
import android.view.LayoutInflater import androidx.core.content.ContextCompat
import android.view.MenuItem import androidx.lifecycle.lifecycleScope
import android.view.ViewGroup import androidx.navigation.fragment.findNavController
import android.view.Window import androidx.navigation.fragment.navArgs
import androidx.annotation.RequiresApi import com.dzeio.openhealth.R
import androidx.core.content.ContextCompat import com.dzeio.openhealth.core.BaseFullscreenDialog
import androidx.lifecycle.lifecycleScope import com.dzeio.openhealth.data.weight.Weight
import androidx.navigation.fragment.findNavController import com.dzeio.openhealth.databinding.DialogEditWeightBinding
import androidx.navigation.fragment.navArgs import com.dzeio.openhealth.ui.home.HomeViewModel
import com.dzeio.openhealth.R import com.google.android.material.datepicker.MaterialDatePicker
import com.dzeio.openhealth.core.BaseFullscreenDialog import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.dzeio.openhealth.data.weight.Weight import com.google.android.material.timepicker.MaterialTimePicker
import com.dzeio.openhealth.databinding.DialogAddWeightBinding import dagger.hilt.android.AndroidEntryPoint
import com.dzeio.openhealth.databinding.DialogEditWeightBinding import kotlinx.coroutines.flow.collect
import com.dzeio.openhealth.ui.main.home.HomeViewModel import java.util.*
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder @AndroidEntryPoint
import com.google.android.material.timepicker.MaterialTimePicker class EditWeightDialog :
import dagger.hilt.android.AndroidEntryPoint BaseFullscreenDialog<HomeViewModel, DialogEditWeightBinding>(HomeViewModel::class.java) {
import kotlinx.coroutines.flow.collect
import java.util.* override val bindingInflater: (LayoutInflater) -> DialogEditWeightBinding =
DialogEditWeightBinding::inflate
@AndroidEntryPoint
class EditWeightDialog : BaseFullscreenDialog<HomeViewModel, DialogEditWeightBinding>(HomeViewModel::class.java) { override val isFullscreenLayout = true
override val bindingInflater: (LayoutInflater) -> DialogEditWeightBinding = DialogEditWeightBinding::inflate val args: EditWeightDialogArgs by navArgs()
override val isFullscreenLayout = true lateinit var weight: Weight
val args: EditWeightDialogArgs by navArgs() // override fun onBuilderInit(builder: AlertDialog.Builder) {
// super.onBuilderInit(builder)
lateinit var weight: Weight //
// builder.apply {
// override fun onBuilderInit(builder: AlertDialog.Builder) { // setTitle("Add your weight (kg)")
// super.onBuilderInit(builder) // setIcon(activity?.let { ContextCompat.getDrawable(it, R.drawable.ic_outline_timeline_24) })
// // setPositiveButton("Validate") { dialog, _ ->
// builder.apply { // save()
// setTitle("Add your weight (kg)") // }
// setIcon(activity?.let { ContextCompat.getDrawable(it, R.drawable.ic_outline_timeline_24) }) // setNegativeButton("Cancel") { dialog, _ ->
// setPositiveButton("Validate") { dialog, _ -> // dialog.cancel()
// save() // }
// } //
// setNegativeButton("Cancel") { dialog, _ -> // }
// dialog.cancel() // }
// }
// override fun onDialogInit(dialog: Dialog) {
// } super.onDialogInit(dialog)
// }
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
override fun onDialogInit(dialog: Dialog) { }
super.onDialogInit(dialog)
override fun onCreated(savedInstanceState: Bundle?) {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) super.onCreated(savedInstanceState)
}
lifecycleScope.launchWhenStarted {
override fun onCreated(savedInstanceState: Bundle?) { viewModel.fetchWeight(args.id).collect {
super.onCreated(savedInstanceState) weight = it!!
binding.layoutDialogEditWeightKg.value = it.weight.toInt()
lifecycleScope.launchWhenStarted { binding.layoutDialogEditWeightGram.value =
viewModel.fetchWeight(args.id).collect { ((it.weight - it.weight.toInt()) * 10).toInt()
weight = it!!
binding.layoutDialogEditWeightKg.value = it.weight.toInt() binding.layoutDialogEditWeightTimestamp.setText(it.formatTimestamp())
binding.layoutDialogEditWeightGram.value = ((it.weight - it.weight.toInt()) * 10 ).toInt() }
}
binding.layoutDialogEditWeightTimestamp.setText(it.formatTimestamp())
} binding.layoutDialogEditWeightKg.maxValue = 636
} binding.layoutDialogEditWeightKg.minValue = 0
binding.layoutDialogEditWeightKg.maxValue = 636 binding.layoutDialogEditWeightGram.maxValue = 9
binding.layoutDialogEditWeightKg.minValue = 0 binding.layoutDialogEditWeightGram.minValue = 0
binding.layoutDialogEditWeightGram.maxValue = 9 binding.layoutDialogEditWeightTimestamp.setOnClickListener {
binding.layoutDialogEditWeightGram.minValue = 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val date = Date(weight.timestamp)
binding.layoutDialogEditWeightTimestamp.setOnClickListener { val datePicker = MaterialDatePicker.Builder.datePicker()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { .setTitleText("Select Date")
val date = Date(weight.timestamp) .setSelection(weight.timestamp)
val datePicker = MaterialDatePicker.Builder.datePicker() .build()
.setTitleText("Select Date")
.setSelection(weight.timestamp) val fragManager = requireActivity().supportFragmentManager
.build()
datePicker.addOnPositiveButtonClickListener { tsp ->
val fragManager = requireActivity().supportFragmentManager val timePicker = MaterialTimePicker.Builder()
.setHour(date.hours)
datePicker.addOnPositiveButtonClickListener { tsp -> .setMinute(date.minutes)
val timePicker = MaterialTimePicker.Builder() .setTitleText("Pouet")
.setHour(date.hours) .build()
.setMinute(date.minutes)
.setTitleText("Pouet") timePicker.addOnPositiveButtonClickListener {
.build() Log.d("T", "${timePicker.hour} ${timePicker.minute}")
val newDate = Date(tsp)
timePicker.addOnPositiveButtonClickListener { newDate.hours = timePicker.hour
Log.d("T", "${timePicker.hour} ${timePicker.minute}") newDate.minutes = timePicker.minute
val newDate = Date(tsp) weight.timestamp = newDate.time
newDate.hours = timePicker.hour binding.layoutDialogEditWeightTimestamp.setText(weight.formatTimestamp())
newDate.minutes = timePicker.minute Log.d("Res", newDate.time.toString())
weight.timestamp = newDate.time }
binding.layoutDialogEditWeightTimestamp.setText(weight.formatTimestamp()) timePicker.show(fragManager, "dialog")
Log.d("Res", newDate.time.toString()) }
} datePicker.show(fragManager, "dialog")
timePicker.show(fragManager, "dialog") Log.d("Tag", "${date.year + 1900}, ${date.month}, ${date.day}")
} // val dg = DatePickerDialog(requireActivity())
datePicker.show(fragManager, "dialog") // dg.setOnDateSetListener { _, year, month, day ->
Log.d("Tag", "${date.year + 1900}, ${date.month}, ${date.day}") //
// val dg = DatePickerDialog(requireActivity()) // }
// dg.setOnDateSetListener { _, year, month, day -> // dg.updateDate(date.year + 1900, date.month, date.day)
// // dg.show()
// } } else {
// dg.updateDate(date.year + 1900, date.month, date.day) TODO("VERSION.SDK_INT < N")
// dg.show() }
} else {
TODO("VERSION.SDK_INT < N")
} }
}
}
private fun save() {
} lifecycleScope.launchWhenCreated {
weight.weight =
private fun save() { binding.layoutDialogEditWeightKg.value + (binding.layoutDialogEditWeightGram.value.toFloat() / 10)
lifecycleScope.launchWhenCreated { viewModel.addWeight(weight)
weight.weight = binding.layoutDialogEditWeightKg.value + (binding.layoutDialogEditWeightGram.value.toFloat() / 10) findNavController().popBackStack()
viewModel.addWeight(weight) }
findNavController().popBackStack() }
}
} override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean { R.id.menu_fullscreen_dialog_save -> {
return when (item.itemId) { save()
R.id.menu_fullscreen_dialog_save -> { true
save() }
true R.id.menu_fullscreen_dialog_delete -> {
} MaterialAlertDialogBuilder(requireContext())
R.id.menu_fullscreen_dialog_delete -> { .setTitle("Delete Weight?")
MaterialAlertDialogBuilder(requireContext()) .setMessage("Are you sure you want to delete this weight?")
.setTitle("Delete Weight?") .setPositiveButton("Yes") { _, _ ->
.setMessage("Are you sure you want to delete this weight?") lifecycleScope.launchWhenStarted {
.setPositiveButton("Yes") {_, _ -> viewModel.deleteWeight(weight)
lifecycleScope.launchWhenStarted { findNavController().popBackStack()
viewModel.deleteWeight(weight) }
findNavController().popBackStack() }
} .setIcon(
} ContextCompat.getDrawable(
.setIcon(ContextCompat.getDrawable(requireContext(), R.drawable.ic_outline_delete_24)) requireContext(),
.setNegativeButton("No") { _, _ ->} R.drawable.ic_outline_delete_24
.show() )
true )
} .setNegativeButton("No") { _, _ -> }
else -> super.onOptionsItemSelected(item) .show()
} true
}
} else -> super.onOptionsItemSelected(item)
}
}
} }

View File

@ -1,54 +1,53 @@
package com.dzeio.openhealth.ui.main.list_weight package com.dzeio.openhealth.ui.weight
import android.os.Bundle import android.os.Bundle
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 androidx.core.os.bundleOf import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import com.dzeio.openhealth.adapters.WeightAdapter
import com.dzeio.openhealth.adapters.WeightAdapter import com.dzeio.openhealth.core.BaseFragment
import com.dzeio.openhealth.core.BaseFragment import com.dzeio.openhealth.databinding.FragmentListWeightBinding
import com.dzeio.openhealth.data.weight.Weight import com.dzeio.openhealth.ui.home.HomeViewModel
import com.dzeio.openhealth.databinding.FragmentListWeightBinding import dagger.hilt.android.AndroidEntryPoint
import com.dzeio.openhealth.ui.dialogs.EditWeightDialog import kotlinx.coroutines.flow.collectLatest
import com.dzeio.openhealth.ui.main.home.HomeViewModel
import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint
import kotlinx.coroutines.flow.collect class ListWeightFragment :
import kotlinx.coroutines.flow.collectLatest BaseFragment<HomeViewModel, FragmentListWeightBinding>(HomeViewModel::class.java) {
import java.util.*
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentListWeightBinding =
@AndroidEntryPoint FragmentListWeightBinding::inflate
class ListWeightFragment : BaseFragment<HomeViewModel, FragmentListWeightBinding>(HomeViewModel::class.java) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentListWeightBinding = FragmentListWeightBinding::inflate super.onViewCreated(view, savedInstanceState)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val recycler = binding.list
super.onViewCreated(view, savedInstanceState)
val manager = LinearLayoutManager(requireContext())
val recycler = binding.list recycler.layoutManager = manager
val manager = LinearLayoutManager(requireContext()) val adapter = WeightAdapter()
recycler.layoutManager = manager adapter.onItemClick = {
findNavController().navigate(
val adapter = WeightAdapter() ListWeightFragmentDirections.actionNavListWeightToNavEditWeight(
adapter.onItemClick = { it.id
findNavController().navigate(ListWeightFragmentDirections.actionNavListWeightToNavEditWeight(it.id)) )
//EditWeightDialog().show(requireActivity().supportFragmentManager, "dialog") )
} //EditWeightDialog().show(requireActivity().supportFragmentManager, "dialog")
recycler.adapter = adapter }
recycler.adapter = adapter
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
viewModel.fetchWeights().collectLatest { viewLifecycleOwner.lifecycleScope.launchWhenCreated {
val itt = it.toMutableList() viewModel.fetchWeights().collectLatest {
itt.sortWith { o1, o2 -> if (o1.timestamp > o2.timestamp) -1 else 1 } val itt = it.toMutableList()
adapter.set(itt) itt.sortWith { o1, o2 -> if (o1.timestamp > o2.timestamp) -1 else 1 }
} adapter.set(itt)
} }
}
}
}
} }

View File

@ -0,0 +1,49 @@
package com.dzeio.openhealth.utils
import android.content.Context
import android.graphics.Bitmap
import java.io.File
import java.io.RandomAccessFile
import java.nio.channels.FileChannel
object BitmapUtils {
/**
* Find source of function lol
*/
fun convertToMutable(context: Context, imgIn: Bitmap): Bitmap? {
val width = imgIn.width
val height = imgIn.height
val type = imgIn.config
var outputFile: File? = null
val outputDir = context.cacheDir
try {
outputFile = File.createTempFile(
System.currentTimeMillis().toString(),
null,
outputDir
)
outputFile.deleteOnExit()
val randomAccessFile = RandomAccessFile(outputFile, "rw")
val channel = randomAccessFile.channel
val map = channel.map(
FileChannel.MapMode.READ_WRITE,
0,
(imgIn.rowBytes * height).toLong()
)
imgIn.copyPixelsToBuffer(map)
imgIn.recycle()
val result = Bitmap.createBitmap(width, height, type)
map.position(0)
result.copyPixelsFromBuffer(map)
channel.close()
randomAccessFile.close()
outputFile.delete()
return result
} catch (e: Exception) {
} finally {
outputFile?.delete()
}
return null
}
}

View File

@ -0,0 +1,30 @@
package com.dzeio.openhealth.utils
import android.graphics.*
object DrawUtils {
/**
* Fuck Graphics
*/
fun drawArc(canvas: Canvas, percent: Int, pColor: Int) {
canvas.width
val spacing = 120f
val r1 = RectF(
spacing,
spacing,
canvas.width - spacing,
canvas.height * 2 - spacing * 3
)
val paint = Paint()
paint.apply {
strokeWidth = 200f
style = Paint.Style.STROKE
color = pColor
isAntiAlias = true
strokeCap = Paint.Cap.ROUND
}
canvas.drawArc(r1, 180f, 180 * percent / 100f, false, paint)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="156dp"
android:height="81dp"
android:viewportWidth="156"
android:viewportHeight="81">
<path
android:pathData="M153,78C153,36.579 119.421,3 78,3C36.579,3 3,36.579 3,78"
android:strokeWidth="5"
android:fillColor="#00000000"
android:strokeColor="#C9C5CA"
android:strokeLineCap="round"/>
</vector>

View File

@ -1,10 +1,157 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.main.home.HomeFragment"> android:orientation="vertical"
tools:context=".ui.home.HomeFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewFilledStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="54dp"
android:layout_marginHorizontal="16dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:weightSum="2">
<TextView
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Weight"
android:layout_weight="1" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_baseline_add_24" />
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_outline_hexagon_24" />
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
android:gravity="bottom"
android:weightSum="3">
<ImageView
android:id="@+id/fragment_home_water_remove"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:src="@drawable/ic_outline_hexagon_24"
app:layout_constraintBottom_toBottomOf="@+id/linearLayout"
app:layout_constraintEnd_toStartOf="@+id/linearLayout"
app:layout_constraintTop_toTopOf="@+id/linearLayout" />
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/background">
<TextView
android:id="@+id/fragment_home_water_current"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="900ml"
android:textAlignment="center" />
<TextView
android:id="@+id/fragment_home_water_total"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="1200ml"
android:textAlignment="center" />
</LinearLayout>
<ImageView
android:id="@+id/fragment_home_water_add"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:src="@drawable/ic_baseline_add_24"
app:layout_constraintBottom_toBottomOf="@+id/linearLayout"
app:layout_constraintStart_toEndOf="@+id/linearLayout"
app:layout_constraintTop_toTopOf="@+id/linearLayout" />
<ImageView
android:id="@+id/background"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="2:1"
android:src="@drawable/ic_outline_hexagon_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Unused Currently -->
<!-- <com.google.android.material.card.MaterialCardView-->
<!-- style="?attr/materialCardViewFilledStyle"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginStart="16dp"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:layout_weight="1"-->
<!-- android:layout_marginEnd="16dp">-->
<!-- </com.google.android.material.card.MaterialCardView>-->
</LinearLayout>
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewFilledStyle" style="?attr/materialCardViewFilledStyle"
@ -12,41 +159,34 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp">
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal"> android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:id="@+id/constraintLayout2"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="54dp" android:layout_height="54dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:gravity="fill_horizontal|center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent" android:weightSum="2">
tools:layout_editor_absoluteX="16dp">
<TextView <TextView
style="@style/TextAppearance.Material3.TitleMedium" style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Weight" android:text="Weight"
app:layout_constraintBottom_toBottomOf="parent" android:layout_weight="1" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" android:layout_weight="1"
app:layout_constraintEnd_toEndOf="parent" android:gravity="end">
app:layout_constraintTop_toTopOf="parent">
<ImageView <ImageView
android:id="@+id/add_weight" android:id="@+id/add_weight"
android:layout_width="24dp" android:layout_width="24dp"
@ -58,24 +198,17 @@
android:id="@+id/list_weight" android:id="@+id/list_weight"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:src="@drawable/ic_outline_hexagon_24" android:src="@drawable/ic_outline_hexagon_24" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>
<com.github.mikephil.charting.charts.LineChart <com.github.mikephil.charting.charts.LineChart
android:id="@+id/weight_graph" android:id="@+id/weight_graph"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="200dp"
android:minHeight="200dp" android:minHeight="200dp" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/constraintLayout2" />
<!-- <com.jjoe64.graphview.GraphView--> <!-- <com.jjoe64.graphview.GraphView-->
<!-- android:id="@+id/weight_graph"--> <!-- android:id="@+id/weight_graph"-->
@ -87,8 +220,8 @@
<!-- app:layout_constraintStart_toStartOf="parent"--> <!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@+id/constraintLayout2" />--> <!-- app:layout_constraintTop_toBottomOf="@+id/constraintLayout2" />-->
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.main.imports.ImportFragment"> tools:context=".ui.imports.ImportFragment">
<TextView <TextView
android:id="@+id/text_slideshow" android:id="@+id/text_slideshow"

View File

@ -11,4 +11,4 @@
android:padding="16dp" android:padding="16dp"
tools:listitem="@layout/layout_item_weight" tools:listitem="@layout/layout_item_weight"
tools:context=".ui.main.list_weight.ListWeightFragment" /> tools:context=".ui.weight.ListWeightFragment" />

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -7,7 +7,7 @@
<fragment <fragment
android:id="@+id/nav_home" android:id="@+id/nav_home"
android:name="com.dzeio.openhealth.ui.main.home.HomeFragment" android:name="com.dzeio.openhealth.ui.home.HomeFragment"
android:label="@string/menu_home" android:label="@string/menu_home"
tools:layout="@layout/fragment_home" > tools:layout="@layout/fragment_home" >
<action <action
@ -28,13 +28,13 @@
<fragment <fragment
android:id="@+id/nav_import" android:id="@+id/nav_import"
android:name="com.dzeio.openhealth.ui.main.imports.ImportFragment" android:name="com.dzeio.openhealth.ui.imports.ImportFragment"
android:label="@string/menu_import" android:label="@string/menu_import"
tools:layout="@layout/fragment_import" /> tools:layout="@layout/fragment_import" />
<fragment <fragment
android:id="@+id/nav_list_weight" android:id="@+id/nav_list_weight"
android:name="com.dzeio.openhealth.ui.main.list_weight.ListWeightFragment" android:name="com.dzeio.openhealth.ui.weight.ListWeightFragment"
android:label="@string/menu_list_weight" android:label="@string/menu_list_weight"
tools:layout="@layout/fragment_list_weight" > tools:layout="@layout/fragment_list_weight" >
<action <action
@ -48,7 +48,7 @@
<fragment <fragment
android:id="@+id/nav_edit_weight" android:id="@+id/nav_edit_weight"
android:name="com.dzeio.openhealth.ui.dialogs.EditWeightDialog" android:name="com.dzeio.openhealth.ui.weight.EditWeightDialog"
android:label="@string/menu_edit_weight" android:label="@string/menu_edit_weight"
tools:layout="@layout/dialog_edit_weight"> tools:layout="@layout/dialog_edit_weight">