mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-04-25 04:12:15 +00:00
feat: updated
This commit is contained in:
parent
7875271b7e
commit
357024770a
@ -130,7 +130,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
// Dzeio Charts
|
||||
implementation("com.dzeio:charts:edd78e87e1")
|
||||
implementation("com.dzeio:charts:cbd5f57f8d")
|
||||
|
||||
// Dzeio Crash Handler
|
||||
implementation("com.dzeio:crashhandler:1.0.1")
|
||||
@ -139,7 +139,7 @@ dependencies {
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.0-alpha01")
|
||||
implementation("javax.inject:javax.inject:1")
|
||||
implementation("com.google.android.material:material:1.8.0-rc01")
|
||||
implementation("com.google.android.material:material:1.9.0-alpha01")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
|
||||
@ -169,18 +169,15 @@ dependencies {
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
|
||||
// Graph
|
||||
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
|
||||
|
||||
// Hilt
|
||||
implementation("com.google.dagger:hilt-android:2.44.2")
|
||||
kapt("com.google.dagger:hilt-compiler:2.44.2")
|
||||
|
||||
// ROOM
|
||||
implementation("androidx.room:room-runtime:2.4.3")
|
||||
kapt("androidx.room:room-compiler:2.4.3")
|
||||
implementation("androidx.room:room-ktx:2.4.3")
|
||||
testImplementation("androidx.room:room-testing:2.4.3")
|
||||
implementation("androidx.room:room-runtime:2.5.0")
|
||||
kapt("androidx.room:room-compiler:2.5.0")
|
||||
implementation("androidx.room:room-ktx:2.5.0")
|
||||
testImplementation("androidx.room:room-testing:2.5.0")
|
||||
|
||||
// Futures
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
|
@ -1,150 +0,0 @@
|
||||
package com.dzeio.openhealth.graphs
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import com.dzeio.openhealth.data.weight.Weight
|
||||
import com.dzeio.openhealth.units.Units
|
||||
import com.dzeio.openhealth.utils.ChartUtils
|
||||
import com.github.mikephil.charting.charts.LineChart
|
||||
import com.github.mikephil.charting.components.LimitLine
|
||||
import com.github.mikephil.charting.components.YAxis
|
||||
import com.github.mikephil.charting.data.Entry
|
||||
import com.github.mikephil.charting.data.LineData
|
||||
import com.github.mikephil.charting.data.LineDataSet
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* TODO: Migrate to DzeioCharts when it is ready
|
||||
*
|
||||
* Setup the mikephil Chart for the Weight
|
||||
*/
|
||||
object WeightChart {
|
||||
fun setup(
|
||||
chart: LineChart,
|
||||
view: View,
|
||||
data: List<Weight>,
|
||||
modifier: Units.Mass,
|
||||
goal: Float?,
|
||||
limit: Boolean = true
|
||||
) {
|
||||
ChartUtils.lineChartSetup(
|
||||
chart,
|
||||
MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
),
|
||||
MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorOnBackground
|
||||
)
|
||||
)
|
||||
|
||||
if (data.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
// Axis Max/Min
|
||||
var axisMin = max(data.minOf { it.weight } - 10, 0f)
|
||||
var axisMax = data.maxOf { it.weight } + 10
|
||||
|
||||
if (goal != null) {
|
||||
axisMax = max(axisMax, goal)
|
||||
axisMin = min(axisMin, goal)
|
||||
}
|
||||
|
||||
// Average calculation
|
||||
val averageCalculation = min(30, max(3, data.size / 2))
|
||||
val isEven = averageCalculation % 2 == 1
|
||||
val midValue = averageCalculation / 2
|
||||
|
||||
val averageYs = data.mapIndexed { index, entry ->
|
||||
var minItem = index - midValue
|
||||
var maxItem = index + if (!isEven) midValue + 1 else midValue
|
||||
val lastEntry = data.size - 1
|
||||
if (minItem < 0) {
|
||||
maxItem += kotlin.math.abs(minItem)
|
||||
minItem = 0
|
||||
}
|
||||
if (maxItem >= lastEntry) {
|
||||
val diff = maxItem - lastEntry
|
||||
minItem = max(0, minItem - diff)
|
||||
maxItem -= diff
|
||||
}
|
||||
|
||||
var average = 0f
|
||||
for (i in minItem..maxItem) {
|
||||
average += data[i].weight
|
||||
}
|
||||
|
||||
return@mapIndexed Entry(
|
||||
entry.timestamp.toFloat(),
|
||||
(average / (maxItem - minItem + 1)) * modifier.modifier
|
||||
)
|
||||
}
|
||||
|
||||
val rawData = ChartUtils.lineDataSet(
|
||||
LineDataSet(
|
||||
data.mapIndexed { _, weight ->
|
||||
return@mapIndexed Entry(
|
||||
weight.timestamp.toFloat(),
|
||||
weight.weight * modifier.modifier
|
||||
)
|
||||
},
|
||||
"Weight"
|
||||
)
|
||||
).apply {
|
||||
axisDependency = YAxis.AxisDependency.RIGHT
|
||||
}
|
||||
|
||||
val averageData = ChartUtils.lineDataSet(LineDataSet(averageYs, "Average")).apply {
|
||||
axisDependency = YAxis.AxisDependency.RIGHT
|
||||
color = Color.GREEN
|
||||
}
|
||||
|
||||
val entries = ArrayList<Entry>()
|
||||
for (item in data) {
|
||||
entries.add(
|
||||
Entry(
|
||||
item.timestamp.toFloat(),
|
||||
item.weight * modifier.modifier
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
chart.apply {
|
||||
|
||||
this.data = LineData(rawData, averageData)
|
||||
|
||||
val twoWeeks = (data[data.size - 1].timestamp - data[0].timestamp) > 1290000000f
|
||||
|
||||
if (twoWeeks && limit) {
|
||||
// idk what I did but it works lol
|
||||
setVisibleXRange(
|
||||
0f, data[data.size - 1].timestamp / 1000f
|
||||
)
|
||||
|
||||
axisRight.axisMinimum = axisMin * modifier.modifier
|
||||
axisRight.axisMaximum = axisMax * modifier.modifier
|
||||
|
||||
// BIS... :(
|
||||
// Also it invalidate the view so I don't have to call invalidate
|
||||
moveViewToX(data[data.size - 1].timestamp - 1290000000f)
|
||||
}
|
||||
|
||||
if (goal != null) {
|
||||
val limit = LimitLine(goal * modifier.modifier)
|
||||
limit.lineColor = Color.RED
|
||||
val dash = 30f
|
||||
limit.enableDashedLine(dash, dash, 1f)
|
||||
limit.lineWidth = 1f
|
||||
limit.textColor = Color.BLACK
|
||||
|
||||
axisRight.removeAllLimitLines()
|
||||
axisRight.addLimitLine(limit)
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ package com.dzeio.openhealth.ui
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -11,6 +10,7 @@ import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.updatePadding
|
||||
@ -21,7 +21,6 @@ import androidx.navigation.ui.NavigationUI
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.dzeio.openhealth.Application
|
||||
import com.dzeio.openhealth.R
|
||||
import com.dzeio.openhealth.core.BaseActivity
|
||||
import com.dzeio.openhealth.databinding.ActivityMainBinding
|
||||
@ -35,7 +34,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
companion object {
|
||||
const val TAG = "${Application.TAG}/MainActivity"
|
||||
val TAG: String = this::class.java.simpleName
|
||||
}
|
||||
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
@ -48,7 +47,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(R.style.Theme_OpenHealth_NoActionBar)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
}
|
||||
|
||||
override fun onCreated(savedInstanceState: Bundle?) {
|
||||
@ -58,7 +56,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
// Comportement chelou API 28-
|
||||
// Comportement normal 31+
|
||||
|
||||
// do not do the cool status/navigation bars for API 29 & 30
|
||||
if (Build.VERSION.SDK_INT != Build.VERSION_CODES.R && Build.VERSION.SDK_INT != Build.VERSION_CODES.Q) {
|
||||
// allow to put the content behind the status bar & Navigation bar (one of them at least lul)
|
||||
@ -66,25 +63,23 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
|
||||
// Make the color of the navigation bar semi-transparent
|
||||
// window.navigationBarColor = Color.TRANSPARENT
|
||||
// Make the color of the status bar transparent
|
||||
// window.statusBarColor = Color.TRANSPARENT
|
||||
// Apply the previous changes
|
||||
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
|
||||
// Update toolbar height with the statusbar size included
|
||||
// ALSO: make both the status/navigation bars transparent (WHYYYYYYY)
|
||||
val toolbarHeight = binding.toolbar.layoutParams.height
|
||||
window.decorView.setOnApplyWindowInsetsListener { _, insets ->
|
||||
val statusBarSize = insets.systemWindowInsetTop
|
||||
// Use getInsets(int) with WindowInsets.Type.systemBars() instead.
|
||||
val statusBarSize = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
insets.getInsets(WindowInsets.Type.systemBars()).top
|
||||
} else {
|
||||
insets.systemWindowInsetTop
|
||||
}
|
||||
// Add padding to the toolbar (YaY I know how something works)
|
||||
binding.toolbar.updatePadding(top = statusBarSize)
|
||||
binding.toolbar.layoutParams.height = toolbarHeight + statusBarSize
|
||||
return@setOnApplyWindowInsetsListener insets
|
||||
}
|
||||
|
||||
// normally makes sure icons are at the correct color but idk if it works
|
||||
// normally makes sure icons are at the correct color
|
||||
when (this.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK)) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> {
|
||||
WindowCompat.getInsetsController(window, window.decorView).apply {
|
||||
@ -121,25 +116,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
binding.bottomNav.setupWithNavController(navController)
|
||||
|
||||
// registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||
//
|
||||
// }
|
||||
// .launch(Manifest.permission.ACTIVITY_RECOGNITION)
|
||||
|
||||
createNotificationChannel()
|
||||
|
||||
// Services
|
||||
WaterReminderWorker.setup(this)
|
||||
// StepCountService.setup(this)
|
||||
|
||||
ServiceUtils.startService(this, OpenHealthService::class.java)
|
||||
}
|
||||
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
menuInflater.inflate(R.menu.main, menu)
|
||||
return true
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean =
|
||||
@ -149,22 +136,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
NavigationUI.onNavDestinationSelected(item, navController) ||
|
||||
super.onOptionsItemSelected(item)
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
Log.d("MainActivity", "onActivityResult $requestCode $resultCode")
|
||||
for (fragment in supportFragmentManager.primaryNavigationFragment!!.childFragmentManager.fragments) {
|
||||
fragment.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
val notificationManager: NotificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
for (channel in NotificationChannels.values()) {
|
||||
Log.d("MainActivity", channel.channelName)
|
||||
Log.d(TAG, channel.channelName)
|
||||
try {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
@ -174,7 +152,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Error Creating Notification Channel", e)
|
||||
Log.e(TAG, "Error Creating Notification Channel", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,16 @@ import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.dzeio.charts.Entry
|
||||
import com.dzeio.charts.series.LineSerie
|
||||
import com.dzeio.openhealth.core.BaseFragment
|
||||
import com.dzeio.openhealth.data.water.Water
|
||||
import com.dzeio.openhealth.data.weight.Weight
|
||||
import com.dzeio.openhealth.databinding.FragmentHomeBinding
|
||||
import com.dzeio.openhealth.graphs.WeightChart
|
||||
import com.dzeio.openhealth.ui.weight.WeightDialog
|
||||
import com.dzeio.openhealth.units.Units
|
||||
import com.dzeio.openhealth.utils.DrawUtils
|
||||
import com.dzeio.openhealth.utils.ChartUtils
|
||||
import com.dzeio.openhealth.utils.DrawUtils
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlin.math.max
|
||||
@ -89,18 +90,11 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavWaterHome())
|
||||
}
|
||||
|
||||
// Make a line Chart using the graph library
|
||||
ChartUtils.lineChartSetup(
|
||||
binding.weightGraph,
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
),
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorOnBackground
|
||||
)
|
||||
)
|
||||
binding.weightGraph.apply {
|
||||
val serie = LineSerie(this)
|
||||
ChartUtils.materielTheme(this, requireView())
|
||||
series = arrayListOf(serie)
|
||||
}
|
||||
|
||||
// Update the water intake Graph when the water intake changes
|
||||
viewModel.water.observe(viewLifecycleOwner) {
|
||||
@ -147,13 +141,28 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
* Function that update the graph for the weight
|
||||
*/
|
||||
private fun updateGraph(list: List<Weight>) {
|
||||
WeightChart.setup(
|
||||
binding.weightGraph,
|
||||
requireView(),
|
||||
list,
|
||||
viewModel.massUnit.value!!,
|
||||
viewModel.goalWeight.value
|
||||
)
|
||||
val chart = binding.weightGraph
|
||||
val serie = chart.series[0] as LineSerie
|
||||
|
||||
val entries: ArrayList<Entry> = arrayListOf()
|
||||
|
||||
list.forEach {
|
||||
entries.add(
|
||||
Entry(
|
||||
it.timestamp.toDouble(),
|
||||
it.weight
|
||||
)
|
||||
)
|
||||
}
|
||||
serie.entries = entries
|
||||
|
||||
if (list.isEmpty()) {
|
||||
chart.xAxis.x = 0.0
|
||||
} else {
|
||||
chart.xAxis.x = list[0].timestamp.toDouble()
|
||||
}
|
||||
|
||||
chart.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +174,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
* function that update the water count in the home page
|
||||
*/
|
||||
private fun updateWater(newValue: Int) {
|
||||
|
||||
// get the current Unit
|
||||
val waterUnit =
|
||||
Units.Volume.find(settings.getString("water_unit", "milliliter") ?: "Milliliter")
|
||||
@ -193,7 +201,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
height = binding.background.height
|
||||
}
|
||||
|
||||
|
||||
// Prepare the update animation
|
||||
val animator = ValueAnimator.ofInt(
|
||||
this.oldValue.toInt(),
|
||||
@ -201,7 +208,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
)
|
||||
animator.duration = 300 // ms
|
||||
animator.addUpdateListener {
|
||||
|
||||
this.oldValue = (it.animatedValue as Int).toFloat()
|
||||
val value = 100 * it.animatedValue as Int / viewModel.dailyWaterIntake.toFloat()
|
||||
|
||||
|
@ -6,6 +6,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.dzeio.charts.Entry
|
||||
import com.dzeio.charts.axis.Line
|
||||
import com.dzeio.charts.series.BarSerie
|
||||
import com.dzeio.openhealth.Application
|
||||
import com.dzeio.openhealth.adapters.StepsAdapter
|
||||
@ -18,6 +19,7 @@ import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@AndroidEntryPoint
|
||||
class StepsHomeFragment :
|
||||
@ -58,27 +60,33 @@ class StepsHomeFragment :
|
||||
chart.apply {
|
||||
ChartUtils.materielTheme(chart, requireView())
|
||||
yAxis.apply {
|
||||
onValueFormat = { value -> "${value.toInt()}" }
|
||||
setYMin(0f)
|
||||
}
|
||||
|
||||
xAxis.apply {
|
||||
dataWidth = 604800000.0
|
||||
textPaint.textSize = 32f
|
||||
onValueFormat = onValueFormat@{
|
||||
val formatter = DateFormat.getDateTimeInstance(
|
||||
DateFormat.SHORT,
|
||||
val formatter = DateFormat.getDateInstance(
|
||||
DateFormat.SHORT,
|
||||
Locale.getDefault()
|
||||
)
|
||||
return@onValueFormat formatter.format(Date(it.toLong()))
|
||||
}
|
||||
|
||||
}
|
||||
annotator.annotationTitleFormat = { "${it.y.roundToInt()} steps" }
|
||||
annotator.annotationSubTitleFormat = annotationSubTitleFormat@{
|
||||
val formatter = DateFormat.getDateInstance(
|
||||
DateFormat.SHORT,
|
||||
Locale.getDefault()
|
||||
)
|
||||
return@annotationSubTitleFormat formatter.format(Date(it.x.toLong()))
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.goal.observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
chart.yAxis.addLine(it.toFloat())
|
||||
chart.yAxis.addLine(it.toFloat(), Line(true))
|
||||
chart.refresh()
|
||||
}
|
||||
}
|
||||
@ -120,7 +128,6 @@ class StepsHomeFragment :
|
||||
|
||||
chart.xAxis.x = chart.xAxis.getXMin()
|
||||
|
||||
|
||||
chart.refresh()
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class ListWeightFragment :
|
||||
|
||||
xAxis.apply {
|
||||
// 7 day history
|
||||
// increment = (7 * 24 * 60 * 60 * 1000).toDouble()
|
||||
dataWidth = (7 * 24 * 60 * 60 * 1000).toDouble()
|
||||
textPaint.color = MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorOnPrimaryContainer
|
||||
@ -124,7 +124,6 @@ class ListWeightFragment :
|
||||
)
|
||||
return@onValueFormat formatter.format(Date(it.toLong()))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,51 +0,0 @@
|
||||
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 {
|
||||
|
||||
/**
|
||||
* Stolen from StackOverflow but I don't remember where...
|
||||
*
|
||||
* Convert an immutable Bitmap to a mutable one if possible
|
||||
*/
|
||||
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
|
||||
}
|
||||
}
|
@ -2,117 +2,51 @@ package com.dzeio.openhealth.utils
|
||||
|
||||
import android.view.View
|
||||
import com.dzeio.charts.ChartView
|
||||
import com.dzeio.charts.components.Annotation
|
||||
import com.dzeio.charts.series.BarSerie
|
||||
import com.dzeio.charts.series.LineSerie
|
||||
import com.github.mikephil.charting.charts.BarLineChartBase
|
||||
import com.github.mikephil.charting.charts.LineChart
|
||||
import com.github.mikephil.charting.components.AxisBase
|
||||
import com.github.mikephil.charting.components.Description
|
||||
import com.github.mikephil.charting.components.XAxis
|
||||
import com.github.mikephil.charting.data.BarLineScatterCandleBubbleData
|
||||
import com.github.mikephil.charting.data.Entry
|
||||
import com.github.mikephil.charting.data.LineDataSet
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter
|
||||
import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import java.text.SimpleDateFormat
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
/**
|
||||
* Utils object to create graphics using the mikephil charting library
|
||||
*
|
||||
* TODO: migrate to DzeioCharts once it is ready
|
||||
* Utils object to create Charts
|
||||
*/
|
||||
object ChartUtils {
|
||||
|
||||
fun lineChartSetup(chart: LineChart, mainColor: Int, textColor: Int) {
|
||||
barLineChartSetup(chart, mainColor, textColor)
|
||||
// chart.isAutoScaleMinMaxEnabled = true
|
||||
}
|
||||
|
||||
fun lineDataSet(lineDataSet: LineDataSet): LineDataSet {
|
||||
return lineDataSet.apply {
|
||||
setDrawCircles(false)
|
||||
setDrawCircleHole(false)
|
||||
mode = LineDataSet.Mode.HORIZONTAL_BEZIER
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : BarLineScatterCandleBubbleData<out IBarLineScatterCandleBubbleDataSet<out Entry>>?> barLineChartSetup(
|
||||
chart: BarLineChartBase<T>,
|
||||
mainColor: Int,
|
||||
textColor: Int
|
||||
) {
|
||||
chart.apply {
|
||||
// Setup
|
||||
legend.isEnabled = true
|
||||
description = Description().apply { isEnabled = false }
|
||||
|
||||
xAxis.apply {
|
||||
valueFormatter = DateValueFormatter()
|
||||
position = XAxis.XAxisPosition.BOTTOM
|
||||
setDrawGridLines(false)
|
||||
setLabelCount(3, true)
|
||||
this.textColor = textColor
|
||||
// setDrawGridLines(false)
|
||||
// setDrawZeroLine(false)
|
||||
setDrawAxisLine(false)
|
||||
disableGridDashedLine()
|
||||
invalidateOutline()
|
||||
}
|
||||
|
||||
axisLeft.apply {
|
||||
axisMinimum = 0f
|
||||
isEnabled = false
|
||||
axisLineColor = mainColor
|
||||
this.textColor = textColor
|
||||
setDrawZeroLine(false)
|
||||
setLabelCount(0, true)
|
||||
setDrawGridLines(false)
|
||||
setDrawBorders(false)
|
||||
}
|
||||
axisRight.apply {
|
||||
axisMinimum = 0f
|
||||
this.textColor = textColor
|
||||
setLabelCount(4, true)
|
||||
}
|
||||
setNoDataTextColor(textColor)
|
||||
|
||||
legend.isEnabled = false
|
||||
isDragEnabled = true
|
||||
// isScaleYEnabled = false
|
||||
description = Description().apply { isEnabled = false }
|
||||
isScaleXEnabled = true
|
||||
setPinchZoom(false)
|
||||
setDrawGridBackground(false)
|
||||
setDrawBorders(false)
|
||||
}
|
||||
}
|
||||
|
||||
class DateValueFormatter(
|
||||
private val transformer: Int = 1
|
||||
) : ValueFormatter() {
|
||||
override fun getAxisLabel(value: Float, axis: AxisBase?): String {
|
||||
return SimpleDateFormat(
|
||||
"yyyy-MM-dd",
|
||||
Locale.getDefault()
|
||||
).format(Date(value.toLong() * transformer))
|
||||
// return super.getAxisLabel(value, axis)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Material theme to a DzeioChart [ChartView]
|
||||
*/
|
||||
fun materielTheme(chart: ChartView, view: View) {
|
||||
|
||||
val errorColor = MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorError
|
||||
)
|
||||
|
||||
chart.apply {
|
||||
annotator.apply {
|
||||
backgroundPaint.color = MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorBackgroundFloating
|
||||
)
|
||||
titlePaint.color = MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorOnBackground
|
||||
)
|
||||
subTitlePaint.color = MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorOnBackground
|
||||
)
|
||||
|
||||
orientation = Annotation.Orientation.VERTICAL
|
||||
|
||||
annotationTitleFormat = { it.y.roundToLong().toString() }
|
||||
annotationSubTitleFormat = annotationSubTitleFormat@{
|
||||
val formatter = DateFormat.getDateTimeInstance(
|
||||
DateFormat.SHORT,
|
||||
DateFormat.SHORT,
|
||||
Locale.getDefault()
|
||||
)
|
||||
return@annotationSubTitleFormat formatter.format(Date(it.x.roundToLong()))
|
||||
}
|
||||
}
|
||||
yAxis.apply {
|
||||
textLabel.color = MaterialColors.getColor(
|
||||
view,
|
||||
@ -122,7 +56,10 @@ object ChartUtils {
|
||||
view,
|
||||
com.google.android.material.R.attr.colorOnPrimaryContainer
|
||||
)
|
||||
goalLinePaint.color = errorColor
|
||||
goalLinePaint.color = MaterialColors.getColor(
|
||||
view,
|
||||
com.google.android.material.R.attr.colorError
|
||||
)
|
||||
}
|
||||
|
||||
xAxis.apply {
|
||||
|
@ -155,7 +155,14 @@ class Configuration(
|
||||
private val defaultValue: Float = -1f
|
||||
) : Field<Float?>(defaultValue) {
|
||||
override fun exists(): Boolean = prefs.contains(key)
|
||||
override fun internalGet(): Float = prefs.getFloat(key, defaultValue)
|
||||
override fun internalGet(): Float {
|
||||
return try {
|
||||
prefs.getFloat(key, defaultValue)
|
||||
} catch (e: ClassCastException) {
|
||||
val it = prefs.getString(key, "")
|
||||
it?.toFloatOrNull() ?: defaultValue
|
||||
}
|
||||
}
|
||||
override fun internalSet(value: Float?) =
|
||||
prefs.edit { if (value == null) remove(key) else putFloat(key, value) }
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.dzeio.openhealth.ui.MainActivity
|
||||
import com.dzeio.openhealth.Application
|
||||
|
||||
/**
|
||||
* Utils class for services
|
||||
@ -20,11 +20,11 @@ object ServiceUtils {
|
||||
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
for (runninService in activityManager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (service.name.equals(runninService.service.className)) {
|
||||
Log.w(MainActivity.TAG, "Service already existing, not starting again")
|
||||
Log.w(Application.TAG, "Service already existing, not starting again")
|
||||
return
|
||||
}
|
||||
}
|
||||
Log.i(MainActivity.TAG, "Starting service ${service.name}")
|
||||
Log.i(Application.TAG, "Starting service ${service.name}")
|
||||
Intent(context, service).also { intent -> context.startService(intent) }
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@
|
||||
android:id="@+id/bottom_nav"
|
||||
android:layout_width="match_parent"
|
||||
android:fitsSystemWindows="false"
|
||||
app:labelVisibilityMode="labeled"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
|
@ -303,10 +303,11 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.github.mikephil.charting.charts.LineChart
|
||||
<com.dzeio.charts.ChartView
|
||||
android:id="@+id/weight_graph"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:layout_margin="8dp"
|
||||
android:minHeight="200dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_extensions"
|
||||
android:enabled="false"
|
||||
android:title="@string/menu_extensions"
|
||||
android:icon="@drawable/ic_outline_account_circle_24"/>
|
||||
</menu>
|
||||
|
Loading…
x
Reference in New Issue
Block a user