mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-04-22 02:42:15 +00:00
u
Signed-off-by: Avior <github@avior.me>
This commit is contained in:
parent
6f33e2a1c3
commit
939dcd24d3
@ -1,6 +1,6 @@
|
||||
<!-- omit in toc -->
|
||||
|
||||
# Contributing to TCGdex
|
||||
# Contributing to OpenHealth
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
@ -31,19 +31,22 @@ All types of contributions are encouraged and valued. See the [Table of Contents
|
||||
|
||||
This project and everyone participating in it is governed by the
|
||||
[DZEIO Code of Conduct](https://github.com/dzeiocom/OpenHealth/blob/master/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to <contact@tcgdex.net>.
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to <contact.openhealth@dze.io>.
|
||||
|
||||
## I Have a Question
|
||||
|
||||
<!--
|
||||
> If you want to ask a question, we assume that you have read the available Documentation at <https://www.tcgdex.dev>.
|
||||
The best way to ask questions is to join our Discord server at <https://discord.gg/NehYTAhsZE>.
|
||||
You can also ask them on the Github Repository, it is best to search for existing [Issues](https://github.com/dzeiocom/OpenHealth/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in a new issue. It is also advisable to search the internet for answers first.
|
||||
-->
|
||||
You <!--can also--> ask them on the Github Repository, it is best to search for existing [Issues](https://github.com/dzeiocom/OpenHealth/issues) that might help you.
|
||||
In case you have found a suitable issue and still need clarification, you can write your question in a new issue. It is also advisable to search the internet for answers first.
|
||||
|
||||
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
||||
|
||||
- Open an [Issue](https://github.com/dzeiocom/OpenHealth/issues/new).
|
||||
- Provide as much context as you can about what you're running into.
|
||||
- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
|
||||
- Provide project and platform versions (Android Version, Application Version), depending on what seems relevant.
|
||||
|
||||
We will then take care of the issue as soon as possible.
|
||||
|
||||
@ -73,13 +76,12 @@ Depending on how large the project is, you may want to outsource the questioning
|
||||
|
||||
A good issue report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Determine if your issue is not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://www.tcgdex.dev). If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already an issue report existing for your bug or error in the [bug tracker](https://github.com/tcgdex/javascript-sdk/issues).
|
||||
- Determine if your issue is not an error on your side e.g. using incompatible environment components/versions. If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already an issue report existing for your bug or error in the [bug tracker](https://github.com/dzeiocom/OpenHealth/issues).
|
||||
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
|
||||
- Collect information about the bug:
|
||||
- Stack trace (Traceback)
|
||||
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
|
||||
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
|
||||
- OS, Platform and Version (Phone, OS Version, App Version, etc...)
|
||||
- Possibly your input and the output
|
||||
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
|
||||
|
||||
@ -87,16 +89,16 @@ A good issue report shouldn't leave others needing to chase you up for more info
|
||||
|
||||
#### How Do I Submit a Good Bug Report?
|
||||
|
||||
> You must never report security related issues, vulnerabilities or bugs to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <security@tcgdex.net>.
|
||||
> You must never report security related issues, vulnerabilities or bugs to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <security@dze.io>.
|
||||
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
|
||||
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
|
||||
|
||||
- Open an [Issue](https://github.com/tcgdex/javascript-sdk/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
||||
- Open an [Issue](https://github.com/dzeiocom/OpenHealth/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
||||
- Explain the behavior you would expect and the actual behavior.
|
||||
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
|
||||
- Provide the information you collected in the previous section.
|
||||
|
||||
Once it's filed:
|
||||
Once it's filled:
|
||||
|
||||
- The project team will label the issue accordingly.
|
||||
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
|
||||
@ -106,28 +108,27 @@ Once it's filed:
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for TCGdex, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
||||
This section guides you through submitting an enhancement suggestion for OpenHealth, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
||||
|
||||
<!-- omit in toc -->
|
||||
|
||||
#### Before Submitting an Enhancement
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Read the [documentation](https://www.tcgdex.dev) carefully and find out if the functionality is already covered, maybe by an individual configuration.
|
||||
- Perform a [search](https://github.com/tcgdex/javascript-sdk/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- Perform a [search](https://github.com/dzeiocom/OpenHealth/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
|
||||
|
||||
<!-- omit in toc -->
|
||||
|
||||
#### How Do I Submit a Good Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as [GitHub issues](https://github.com/tcgdex/javascript-sdk/issues).
|
||||
Enhancement suggestions are tracked as [GitHub issues](https://github.com/dzeiocom/OpenHealth/issues).
|
||||
|
||||
- Use a **clear and descriptive title** for the issue to identify the suggestion.
|
||||
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
|
||||
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
|
||||
- **Explain why this enhancement would be useful** to most TCGdex users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
||||
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to.
|
||||
- **Explain why this enhancement would be useful** to most OpenHealth users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
||||
|
||||
<!-- You might want to create an issue template for enhancement suggestions that can be used as a guide and that defines the structure of the information to be included. If you do so, reference it here in the description. -->
|
||||
|
||||
@ -137,14 +138,10 @@ _note: Follow the different styleguides listed below when contributing_
|
||||
|
||||
- Fork 🍴 the project. _see the `fork` button at the top right of the screen_
|
||||
- make the changes you want in your repository.
|
||||
- Create a Pull request here https://github.com/tcgdex/javascript-sdk/compare by selecting your repository patch with our `master` branch _If it's not finished put WIP: before_
|
||||
- Create a Pull request here https://github.com/dzeiocom/OpenHealth/compare by selecting your repository patch with our `master` branch _If it's not finished put WIP: before_
|
||||
- we don't like ❌, so if your pull request has its automated checks ending with the red cross, please double check your changes until it show the awesome 🟢, or ask for help !
|
||||
- If your pull request is ready for review remove WIP: put it s ready for review and we will handle the rest !
|
||||
|
||||
### Improving The Documentation
|
||||
|
||||
The documentation is updated in the Documentation repository at <https://github.com/tcgdex/documentation>
|
||||
|
||||
## Styleguides
|
||||
|
||||
### Coding Guidelines
|
||||
@ -184,4 +181,4 @@ In short, please name your Pull Requests/Commits following this format
|
||||
|
||||
## Attribution
|
||||
|
||||
This guide is based on [Contribution Gen]((https://github.com/bttger/contributing-gen)) and was adapted by the TCGdex community !
|
||||
This guide is based on [Contribution Gen]((https://github.com/bttger/contributing-gen)) and was adapted by the OpenHealth community !
|
||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Florian Bouillon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
63
README.md
63
README.md
@ -1,28 +1,43 @@
|
||||
<p align="center">
|
||||
<a href="http://npmjs.com/@tcgdex/sdk">
|
||||
<img src="https://img.shields.io/npm/v/@tcgdex/sdk?style=flat-square" alt="NOM Version">
|
||||
</a>
|
||||
<a href="http://npmjs.com/@tcgdex/sdk">
|
||||
<img src="https://img.shields.io/npm/dm/@tcgdex/sdk?style=flat-square" alt="NPM Downloads">
|
||||
</a>
|
||||
<a href="https://app.codecov.io/gh/tcgdex/javascript-sdk/">
|
||||
<img src="https://img.shields.io/codecov/c/github/tcgdex/javascript-sdk?style=flat-square&token=FR4BI94N4Q" alt="npm version">
|
||||
</a>
|
||||
<a href="https://github.com/tcgdex/javascript-sdk/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/tcgdex/javascript-sdk?style=flat-square" alt="Github stars">
|
||||
</a>
|
||||
<a href="https://github.com/tcgdex/javascript-sdk/actions/workflows/build.yml">
|
||||
<img src="https://img.shields.io/github/workflow/status/tcgdex/javascript-sdk/Build%20&%20Test?style=flat-square" alt="the TCGdex JAvascript SDK is released under the MIT license." />
|
||||
</a>
|
||||
<a href="https://discord.gg/NehYTAhsZE">
|
||||
<img src="https://img.shields.io/discord/857231041261076491?color=%235865F2&label=Discord&style=flat-square" alt="Discord Link">
|
||||
</a>
|
||||
</p>
|
||||
#  Open Health
|
||||
|
||||
# Open Health
|
||||
Your privacy-friendly FOSS Health Application
|
||||
|
||||
TODO: Make a good text here
|
||||
TODO: Change CONTRIBUTING.md to be correct
|
||||
<a href="https://f-droid.org/repository/browse/?fdid=com.dzeio.openhealth" target="_blank">
|
||||
<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="80"/>
|
||||
</a>
|
||||
<a href="https://play.google.com/store/apps/details?id=com.dzeio.openhealth" target="_blank">
|
||||
<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" alt="Get it on Google Play" height="80"/>
|
||||
</a>
|
||||
|
||||
## Features
|
||||
|
||||
- Material 3 Design !
|
||||
- Log Multiple Health information like your Weight, Water Intake, Food Consumption and Steps
|
||||
- An enormous Food Database through OpenFoodFact !
|
||||
- no account creation !
|
||||
- External Services supported (not available on F-Droid) : Google Fit, Samsung Health and Withings Mate
|
||||
- Your data are entirely in your control ! (when not syncing to an external service)
|
||||
|
||||
## Privacy and Permissions
|
||||
|
||||
No Ads are served through this app.
|
||||
|
||||
Permissions requests are for specifics usage and are only requests the first time they are needed:
|
||||
|
||||
| Permission | Why is it requested |
|
||||
| :--------------------: | :--------------------------------------------------------------- |
|
||||
| ACCESS_FINE_LOCATION | Google Fit Extension Requirement (maybe not, still have to test) |
|
||||
| ACCESS_COARSE_LOCATION | Same as above |
|
||||
| ACTIVITY_RECOGNITION | Device Steps Usage |
|
||||
|
||||
No other permissions are used (even the internet permission ;)).
|
||||
|
||||
## Build
|
||||
|
||||
- Install Android Studio
|
||||
- Select your variant from the Build Variant pane (bottom left, default to debug)
|
||||
- click on the debug icon for debug
|
||||
- it will be running on your emulator/device
|
||||
|
||||
## Contributing
|
||||
|
||||
@ -31,9 +46,7 @@ See [CONTRIBUTING.md](https://github.com/dzeiocom/OpenHealth/blob/master/CONTRIB
|
||||
TL::DR
|
||||
|
||||
- Fork
|
||||
|
||||
- Commit your changes
|
||||
|
||||
- Pull Request on this Repository
|
||||
|
||||
## License
|
||||
|
@ -51,6 +51,12 @@ android {
|
||||
versionName "1.0.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// Languages
|
||||
def locales = ["en", "fr"]
|
||||
|
||||
buildConfigField "String[]", "LOCALES", "new String[]{\""+locales.join("\",\"")+"\"}"
|
||||
resConfigs locales
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@ -143,4 +149,4 @@ dependencies {
|
||||
testImplementation "androidx.room:room-testing:$room_version"
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">OpenHealth - Debug</string>
|
||||
</resources>
|
||||
<string name="app_name" translatable="false">OpenHealth - Debug</string>
|
||||
</resources>
|
||||
|
@ -1,8 +1,13 @@
|
||||
package com.dzeio.openhealth
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import java.util.Locale
|
||||
|
||||
@HiltAndroidApp
|
||||
class Application : Application() {
|
||||
@ -15,5 +20,16 @@ class Application : Application() {
|
||||
|
||||
// Android Dynamics Colors
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
|
||||
// Change application Language based on setting
|
||||
val preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val lang = preferences.getString("global_language", Locale.getDefault().language)
|
||||
val locale = Locale(lang)
|
||||
Locale.setDefault(locale)
|
||||
|
||||
val overrideConfiguration = baseContext.resources.configuration
|
||||
overrideConfiguration.locale = locale
|
||||
val context: Context = createConfigurationContext(overrideConfiguration)
|
||||
val resources: Resources = context.getResources()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
WorkManager.getInstance(this)
|
||||
.cancelAllWork()
|
||||
WaterReminderService.setup(this)
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
@ -107,7 +106,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
Log.e("MainActivity", "Error Creating Notification Channel", e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,9 +123,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
)
|
||||
true
|
||||
}
|
||||
R.id.action_about -> {
|
||||
navController.navigate(
|
||||
HomeFragmentDirections.actionNavHomeToAboutFragment()
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class WaterAdapter() : BaseAdapter<Water, LayoutItemListBinding>() {
|
||||
position: Int
|
||||
) {
|
||||
holder.binding.value.text = "${item.value}ml"
|
||||
holder.binding.datetime.text = "${item.formatTimestamp()} ${item.timestamp}"
|
||||
holder.binding.datetime.text = "${item.formatTimestamp()}"
|
||||
holder.binding.edit.setOnClickListener {
|
||||
onItemClick?.invoke(item)
|
||||
}
|
||||
|
@ -6,8 +6,11 @@ import com.dzeio.openhealth.core.BaseAdapter
|
||||
import com.dzeio.openhealth.core.BaseViewHolder
|
||||
import com.dzeio.openhealth.data.weight.Weight
|
||||
import com.dzeio.openhealth.databinding.LayoutItemListBinding
|
||||
import com.dzeio.openhealth.units.WeightUnit
|
||||
|
||||
class WeightAdapter() : BaseAdapter<Weight, LayoutItemListBinding>() {
|
||||
class WeightAdapter : BaseAdapter<Weight, LayoutItemListBinding>() {
|
||||
|
||||
var unit: WeightUnit = WeightUnit.KG
|
||||
|
||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> LayoutItemListBinding
|
||||
get() = LayoutItemListBinding::inflate
|
||||
@ -19,10 +22,11 @@ class WeightAdapter() : BaseAdapter<Weight, LayoutItemListBinding>() {
|
||||
item: Weight,
|
||||
position: Int
|
||||
) {
|
||||
holder.binding.value.text = "${item.weight}kg"
|
||||
val weightTxt = String.format("%.1f", item.weight * unit.fromKG)
|
||||
holder.binding.value.text = "$weightTxt${unit.unit}"
|
||||
holder.binding.datetime.text = item.formatTimestamp()
|
||||
holder.binding.edit.setOnClickListener {
|
||||
onItemClick?.invoke(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +1,14 @@
|
||||
package com.dzeio.openhealth.core
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
abstract class BaseFragment<VM : BaseViewModel, VB : ViewBinding>(private val viewModelClass: Class<VM>) : Fragment() {
|
||||
abstract class BaseFragment<VM : BaseViewModel, VB : ViewBinding>(
|
||||
private val viewModelClass: Class<VM>
|
||||
) :
|
||||
BaseStaticFragment<VB>() {
|
||||
|
||||
val viewModel by lazy {
|
||||
ViewModelProvider(this)[viewModelClass]
|
||||
}
|
||||
|
||||
private var _binding: VB? = null
|
||||
val binding get() = _binding!!
|
||||
|
||||
/**
|
||||
* Setup everything!
|
||||
*/
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
_binding = bindingInflater(inflater, container, false)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to inflate the Fragment Bindings
|
||||
*
|
||||
* use like this: `ViewBinding::inflater`
|
||||
*/
|
||||
abstract val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> VB
|
||||
|
||||
/**
|
||||
* Destroy binding
|
||||
*/
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
package com.dzeio.openhealth.core
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
abstract class BaseStaticFragment<VB : ViewBinding> : Fragment() {
|
||||
|
||||
private var _binding: VB? = null
|
||||
val binding get() = _binding!!
|
||||
|
||||
/**
|
||||
* Setup everything!
|
||||
*/
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
_binding = bindingInflater(inflater, container, false)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to inflate the Fragment Bindings
|
||||
*
|
||||
* use like this: `ViewBinding::inflater`
|
||||
*/
|
||||
abstract val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> VB
|
||||
|
||||
/**
|
||||
* Destroy binding
|
||||
*/
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
22
app/src/main/java/com/dzeio/openhealth/di/SystemModule.kt
Normal file
22
app/src/main/java/com/dzeio/openhealth/di/SystemModule.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package com.dzeio.openhealth.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.PreferenceManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
class SystemModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSettings(@ApplicationContext context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
}
|
143
app/src/main/java/com/dzeio/openhealth/graphs/WeightChart.kt
Normal file
143
app/src/main/java/com/dzeio/openhealth/graphs/WeightChart.kt
Normal file
@ -0,0 +1,143 @@
|
||||
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.GraphUtils
|
||||
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
|
||||
|
||||
object WeightChart {
|
||||
fun setup(
|
||||
chart: LineChart,
|
||||
view: View,
|
||||
data: List<Weight>,
|
||||
modifier: Units.Mass,
|
||||
goal: Float?,
|
||||
limit: Boolean = true
|
||||
) {
|
||||
GraphUtils.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 = GraphUtils.lineDataSet(
|
||||
LineDataSet(
|
||||
data.mapIndexed { _, weight ->
|
||||
return@mapIndexed Entry(
|
||||
weight.timestamp.toFloat(),
|
||||
weight.weight * modifier.modifier
|
||||
)
|
||||
},
|
||||
"Weight"
|
||||
)
|
||||
).apply {
|
||||
axisDependency = YAxis.AxisDependency.RIGHT
|
||||
}
|
||||
|
||||
val averageData = GraphUtils.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.addLimitLine(limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,5 +6,5 @@ enum class NotificationChannels(
|
||||
val importance: Int
|
||||
) {
|
||||
// 3 is IMPORTANCE_DEFAULT
|
||||
DEFAULT("openhealth_default", "Default Channel", 3)
|
||||
}
|
||||
WATER("water", "Water Notifications", 3)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkerParameters
|
||||
import com.dzeio.openhealth.Application
|
||||
@ -42,23 +43,24 @@ class WaterReminderService(
|
||||
Log.d(TAG, "Ran! ${Date().toLocaleString()}")
|
||||
with(NotificationManagerCompat.from(context)) {
|
||||
val flag =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_IMMUTABLE else 0
|
||||
val intent = NavDeepLinkBuilder(context)
|
||||
.setGraph(R.navigation.mobile_navigation)
|
||||
.setDestination(R.id.nav_home)
|
||||
// Will nav to water home when there will be a way to add it there
|
||||
// .setDestination(R.id.nav_water_home)
|
||||
.createTaskStackBuilder()
|
||||
.getPendingIntent(0, flag)
|
||||
val builder =
|
||||
NotificationCompat.Builder(context, NotificationChannels.DEFAULT.channelName)
|
||||
NotificationCompat.Builder(context, NotificationChannels.WATER.id)
|
||||
.setContentTitle("Did you drink?")
|
||||
.setContentText("Drink now! ${Date().toLocaleString()}")
|
||||
.setSmallIcon(R.drawable.ic_logo_small)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
Intent(context, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
},
|
||||
flag
|
||||
)
|
||||
).build()
|
||||
intent
|
||||
)
|
||||
.build()
|
||||
notify(
|
||||
NotificationIds.WaterIntake.ordinal,
|
||||
builder
|
||||
@ -66,4 +68,4 @@ class WaterReminderService(
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package com.dzeio.openhealth.ui.about
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import com.dzeio.openhealth.BuildConfig
|
||||
import com.dzeio.openhealth.R
|
||||
import com.dzeio.openhealth.core.BaseStaticFragment
|
||||
import com.dzeio.openhealth.databinding.FragmentAboutBinding
|
||||
|
||||
class AboutFragment : BaseStaticFragment<FragmentAboutBinding>() {
|
||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentAboutBinding
|
||||
get() = FragmentAboutBinding::inflate
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.version.text =
|
||||
resources.getString(R.string.version_number, BuildConfig.VERSION_NAME)
|
||||
|
||||
binding.contactUs.setOnClickListener {
|
||||
openLink("mailto:context.openhealth@dze.io")
|
||||
}
|
||||
|
||||
binding.github.setOnClickListener {
|
||||
openLink("https://github.com/dzeiocom/OpenHealth")
|
||||
}
|
||||
}
|
||||
|
||||
private fun openLink(url: String) {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(requireContext(), "Could not handle link $url", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.dzeio.openhealth.ui.home
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.RectF
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
@ -13,74 +13,61 @@ import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.dzeio.openhealth.Application
|
||||
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.AddWeightDialog
|
||||
import com.dzeio.openhealth.units.UnitFactory
|
||||
import com.dzeio.openhealth.utils.DrawUtils
|
||||
import com.dzeio.openhealth.utils.GraphUtils
|
||||
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 dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.min
|
||||
import kotlin.properties.Delegates
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewModel::class.java) {
|
||||
|
||||
companion object {
|
||||
const val TAG = "${Application.TAG}/HomeFragment"
|
||||
}
|
||||
|
||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentHomeBinding
|
||||
get() = FragmentHomeBinding::inflate
|
||||
|
||||
private var intake by Delegates.notNull<Float>()
|
||||
private val settings: SharedPreferences by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Bindings
|
||||
binding.addWeight.setOnClickListener {
|
||||
AddWeightDialog().show(requireActivity().supportFragmentManager, null)
|
||||
}
|
||||
|
||||
binding.fragmentHomeWaterAdd.setOnClickListener {
|
||||
|
||||
val water = viewModel.water.value
|
||||
|
||||
if (water == null) {
|
||||
|
||||
if (water == null || !water.isToday()) {
|
||||
val w = Water()
|
||||
w.value = 200
|
||||
w.value = viewModel.waterCupSize
|
||||
viewModel.updateWater(w)
|
||||
} else {
|
||||
water.value += 200
|
||||
water.value += viewModel.waterCupSize
|
||||
viewModel.updateWater(water)
|
||||
}
|
||||
}
|
||||
|
||||
intake = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.getString("water_intake", "1200")?.toFloat() ?: 1200f
|
||||
|
||||
binding.fragmentHomeWaterTotal.text = "${intake.toInt()}ml"
|
||||
|
||||
binding.fragmentHomeWaterRemove.setOnClickListener { _ ->
|
||||
binding.fragmentHomeWaterTotal.text =
|
||||
String.format(
|
||||
resources.getString(viewModel.waterUnit.unit),
|
||||
viewModel.dailyWaterIntake
|
||||
)
|
||||
|
||||
binding.fragmentHomeWaterRemove.setOnClickListener {
|
||||
val water = viewModel.water.value
|
||||
|
||||
if (water != null) {
|
||||
|
||||
water.value -= 200
|
||||
if (water.value == 0) {
|
||||
water.value -= viewModel.waterCupSize
|
||||
if (water.value <= 0) {
|
||||
viewModel.deleteWater(water)
|
||||
} else {
|
||||
viewModel.updateWater(water)
|
||||
@ -88,22 +75,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavListWeight())
|
||||
}
|
||||
@ -126,32 +97,13 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
}
|
||||
|
||||
private fun updateGraph(list: List<Weight>) {
|
||||
if (list.isNotEmpty()) {
|
||||
val entries = ArrayList<Entry>()
|
||||
for (item in list) {
|
||||
entries.add(Entry(item.timestamp.toFloat(), item.weight))
|
||||
}
|
||||
|
||||
val dataSet = LineDataSet(entries, "Label").apply {
|
||||
axisDependency = YAxis.AxisDependency.RIGHT
|
||||
setDrawCircles(false)
|
||||
setDrawCircleHole(false)
|
||||
mode = LineDataSet.Mode.HORIZONTAL_BEZIER
|
||||
}
|
||||
|
||||
binding.weightGraph.apply {
|
||||
|
||||
// Apply new dataset
|
||||
|
||||
data = LineData(dataSet)
|
||||
|
||||
// idk what I did but it works lol
|
||||
setVisibleXRange(
|
||||
0f, entries[entries.size - 1].x / 1000f
|
||||
)
|
||||
|
||||
val goal = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.getString("weight_goal", null)?.toFloatOrNull()
|
||||
WeightChart.setup(
|
||||
binding.weightGraph,
|
||||
requireView(),
|
||||
list,
|
||||
viewModel.weightUnit,
|
||||
viewModel.goalWeight?.toFloat()
|
||||
)
|
||||
|
||||
// legend.apply {
|
||||
// isEnabled = true
|
||||
@ -165,29 +117,6 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
// setCustom(arrayOf(legendEntry))
|
||||
// }
|
||||
// }
|
||||
|
||||
setDrawBorders(false)
|
||||
|
||||
// BIS... :(
|
||||
// Also it invalidate the view so I don't have to call invalidate
|
||||
moveViewToX(entries[entries.size - 1].x - 1600000000f)
|
||||
|
||||
if (goal != null) {
|
||||
axisRight.axisMinimum = goal
|
||||
val limit = LimitLine(goal)
|
||||
limit.lineColor = Color.RED
|
||||
val dash = 30f
|
||||
limit.enableDashedLine(dash, dash, 0f)
|
||||
limit.lineWidth = 1f
|
||||
limit.textColor = Color.BLACK
|
||||
limit.textSize = 12f
|
||||
|
||||
axisRight.addLimitLine(limit)
|
||||
} else {
|
||||
isAutoScaleMinMaxEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@ -197,23 +126,28 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
viewModel.fetchWeights().collectLatest {
|
||||
updateGraph(it)
|
||||
}
|
||||
updateWater(0)
|
||||
updateWater(1234)
|
||||
updateWater(0, 1)
|
||||
}
|
||||
|
||||
viewModel.water.observe(viewLifecycleOwner) {
|
||||
Log.d(TAG, "${it?.formatTimestamp()} $it")
|
||||
if (it != null) {
|
||||
updateWater(it.value)
|
||||
updateWater(0, it.value)
|
||||
} else {
|
||||
updateWater(0)
|
||||
updateWater(0, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWater(water: Int) {
|
||||
val oldValue = binding.fragmentHomeWaterCurrent.text.toString().replace("ml", "").toInt()
|
||||
binding.fragmentHomeWaterCurrent.text = "${water}ml"
|
||||
private fun updateWater(oldValue: Int, newValue: Int) {
|
||||
|
||||
val waterUnit =
|
||||
UnitFactory.volume(settings.getString("water_unit", "milliliter") ?: "Milliliter")
|
||||
|
||||
binding.fragmentHomeWaterCurrent.text =
|
||||
String.format(
|
||||
resources.getString(waterUnit.unit),
|
||||
(newValue * waterUnit.modifier).toInt()
|
||||
)
|
||||
|
||||
var width = 1500
|
||||
var height = 750
|
||||
@ -260,25 +194,27 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding>(HomeViewMo
|
||||
3f
|
||||
)
|
||||
|
||||
Log.d("Test", "${min(oldValue.toFloat(), intake)} ${min(water.toFloat(), intake)}")
|
||||
ValueAnimator.ofFloat(min(oldValue.toFloat(), intake), min(water.toFloat(), intake))
|
||||
.apply {
|
||||
duration = 300
|
||||
addUpdateListener {
|
||||
DrawUtils.drawArc(
|
||||
canvas,
|
||||
100 * it.animatedValue as Float / intake,
|
||||
rect,
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
),
|
||||
6f
|
||||
)
|
||||
canvas.save()
|
||||
binding.background.setImageBitmap(graph)
|
||||
}
|
||||
start()
|
||||
ValueAnimator.ofInt(
|
||||
min(oldValue, viewModel.dailyWaterIntake),
|
||||
min(newValue, viewModel.dailyWaterIntake)
|
||||
).apply {
|
||||
duration = 300
|
||||
addUpdateListener {
|
||||
|
||||
DrawUtils.drawArc(
|
||||
canvas,
|
||||
100 * it.animatedValue as Int / viewModel.dailyWaterIntake.toFloat(),
|
||||
rect,
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
),
|
||||
6f
|
||||
)
|
||||
canvas.save()
|
||||
binding.background.setImageBitmap(graph)
|
||||
}
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,62 @@
|
||||
package com.dzeio.openhealth.ui.home
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.dzeio.openhealth.Application.Companion.TAG
|
||||
import com.dzeio.openhealth.core.BaseViewModel
|
||||
import com.dzeio.openhealth.data.water.Water
|
||||
import com.dzeio.openhealth.data.water.WaterRepository
|
||||
import com.dzeio.openhealth.data.weight.Weight
|
||||
import com.dzeio.openhealth.data.weight.WeightRepository
|
||||
import com.dzeio.openhealth.units.UnitFactory
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class HomeViewModel @Inject internal constructor(
|
||||
private val weightRepository: WeightRepository,
|
||||
private val waterRepository: WaterRepository
|
||||
private val waterRepository: WaterRepository,
|
||||
settings: SharedPreferences
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _water = MutableLiveData<Water?>(null)
|
||||
val water: LiveData<Water?> = _water
|
||||
|
||||
var waterCupSize = settings.getInt("water_cup_size", 200)
|
||||
|
||||
var waterUnit =
|
||||
UnitFactory.volume(settings.getString("water_unit", "milliliter") ?: "Milliliter")
|
||||
|
||||
var weightUnit =
|
||||
UnitFactory.mass(settings.getString("weight_unit", "kilogram") ?: "kilogram")
|
||||
|
||||
val goalWeight: Int? =
|
||||
(settings.getString("weight_goal", null)?.toIntOrNull())
|
||||
|
||||
val dailyWaterIntake: Int =
|
||||
((settings.getString("water_intake", "1200")?.toFloatOrNull() ?: 1200f) * waterUnit.modifier)
|
||||
.toInt()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
waterRepository.todayWater().collectLatest {
|
||||
_water.value = it
|
||||
}
|
||||
}
|
||||
// don't listen for prefs changes
|
||||
settings.registerOnSharedPreferenceChangeListener { _, key ->
|
||||
Log.d(TAG, "Pref changed: $key")
|
||||
when (key) {
|
||||
"water_cup_size" -> {
|
||||
waterCupSize = settings.getInt("water_cup_size", 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,7 +64,6 @@ class HomeViewModel @Inject internal constructor(
|
||||
*/
|
||||
fun fetchWeights() = weightRepository.getWeights()
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@ -44,11 +75,7 @@ class HomeViewModel @Inject internal constructor(
|
||||
|
||||
suspend fun addWeight(weight: Weight) = weightRepository.addWeight(weight)
|
||||
|
||||
suspend fun fetchTodayWater() = waterRepository.todayWater()
|
||||
|
||||
private val _water = MutableLiveData<Water?>(null)
|
||||
val water: LiveData<Water?> = _water
|
||||
|
||||
fun fetchTodayWater() = waterRepository.todayWater()
|
||||
|
||||
fun updateWater(water: Water) {
|
||||
viewModelScope.launch {
|
||||
@ -62,4 +89,4 @@ class HomeViewModel @Inject internal constructor(
|
||||
_water.postValue(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,99 @@
|
||||
package com.dzeio.openhealth.ui.settings
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.dzeio.openhealth.BuildConfig
|
||||
import com.dzeio.openhealth.R
|
||||
import com.dzeio.openhealth.units.UnitFactory
|
||||
import java.util.Locale
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
val settings: SharedPreferences by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||
|
||||
// Force only numbers on Goal
|
||||
val weightGoal = findPreference<EditTextPreference>("weight_goal")
|
||||
weightGoal?.setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_NUMBER
|
||||
weightGoal?.apply {
|
||||
setOnBindEditTextListener {
|
||||
it.inputType = InputType.TYPE_CLASS_NUMBER
|
||||
}
|
||||
val value = settings.getString("weight_goal", null)
|
||||
val modifier = UnitFactory.mass(settings.getString("weight_unit", null) ?: "kilogram")
|
||||
if (value != null && value.isNotEmpty()) {
|
||||
text = (value.toFloat() * modifier.modifier).toString()
|
||||
}
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val alue = ((newValue as String).toInt() / modifier.modifier).toInt().toString()
|
||||
settings.edit()
|
||||
.putString(
|
||||
"weight_goal",
|
||||
alue
|
||||
)
|
||||
.apply()
|
||||
text = alue
|
||||
return@setOnPreferenceChangeListener false
|
||||
}
|
||||
}
|
||||
|
||||
// 251 kg
|
||||
// 553 lb
|
||||
|
||||
findPreference<ListPreference>("weight_unit")?.apply {
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val unit = settings.getString("weight_unit", "kilogram")
|
||||
?: return@setOnPreferenceChangeListener true
|
||||
val goal = settings.getString("weight_goal", null)
|
||||
?: return@setOnPreferenceChangeListener true
|
||||
val modifier = UnitFactory.mass(newValue as String)
|
||||
val oldModifier = UnitFactory.mass(unit)
|
||||
val value =
|
||||
(goal.toFloat() / oldModifier.modifier * modifier.modifier).toInt().toString()
|
||||
settings.edit()
|
||||
.putString(
|
||||
"weight_goal",
|
||||
value
|
||||
)
|
||||
.apply()
|
||||
weightGoal?.text = value
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
|
||||
val languagesPreference = findPreference<ListPreference>("global_language")
|
||||
Log.d("TAG", Locale.getDefault().language)
|
||||
languagesPreference?.apply {
|
||||
entries = BuildConfig.LOCALES
|
||||
entryValues = BuildConfig.LOCALES
|
||||
setDefaultValue(Locale.getDefault().language)
|
||||
}
|
||||
|
||||
// Update App Locale
|
||||
languagesPreference?.setOnPreferenceChangeListener { _, newValue ->
|
||||
val locale = Locale(newValue as String)
|
||||
Locale.setDefault(locale)
|
||||
val config = Configuration()
|
||||
config.locale = locale
|
||||
|
||||
requireActivity().baseContext.resources.updateConfiguration(
|
||||
config,
|
||||
requireActivity().baseContext.resources.displayMetrics
|
||||
)
|
||||
|
||||
requireActivity().recreate()
|
||||
|
||||
return@setOnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ class EditWaterDialog :
|
||||
|
||||
water.timestamp = tsp
|
||||
binding.date.setText(water.formatTimestamp())
|
||||
|
||||
}
|
||||
datePicker.show(fragManager, "dialog")
|
||||
Log.d("Tag", "${date.year + 1900}, ${date.month}, ${date.day}")
|
||||
@ -88,8 +87,6 @@ class EditWaterDialog :
|
||||
} else {
|
||||
TODO("VERSION.SDK_INT < N")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
viewModel.init(args.id)
|
||||
@ -133,6 +130,5 @@ class EditWaterDialog :
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
package com.dzeio.openhealth.ui.water
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.dzeio.openhealth.Application.Companion.TAG
|
||||
import com.dzeio.openhealth.adapters.WaterAdapter
|
||||
import com.dzeio.openhealth.core.BaseFragment
|
||||
import com.dzeio.openhealth.databinding.FragmentMainWaterHomeBinding
|
||||
@ -17,9 +15,6 @@ import com.github.mikephil.charting.data.BarDataSet
|
||||
import com.github.mikephil.charting.data.BarEntry
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.TimeZone
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WaterHomeFragment :
|
||||
@ -62,6 +57,10 @@ class WaterHomeFragment :
|
||||
)
|
||||
)
|
||||
|
||||
binding.buttonEditDefaultIntake.setOnClickListener {
|
||||
findNavController().navigate(WaterHomeFragmentDirections.actionNavWaterHomeToNavWaterSizeDialog())
|
||||
}
|
||||
|
||||
chart.xAxis.valueFormatter = GraphUtils.DateValueFormatter(1000 * 60 * 60 * 24)
|
||||
|
||||
viewModel.items.observe(viewLifecycleOwner) { list ->
|
||||
|
@ -1,13 +1,102 @@
|
||||
package com.dzeio.openhealth.ui.water
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import com.dzeio.openhealth.R
|
||||
import com.dzeio.openhealth.core.BaseDialog
|
||||
import com.dzeio.openhealth.databinding.DialogWaterSizeSelectorBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class WaterSizeSelectorDialog :
|
||||
BaseDialog<WaterSizeSelectorViewModel, DialogWaterSizeSelectorBinding>(
|
||||
WaterSizeSelectorViewModel::class.java
|
||||
) {
|
||||
|
||||
override val bindingInflater: (LayoutInflater) -> DialogWaterSizeSelectorBinding
|
||||
get() = DialogWaterSizeSelectorBinding::inflate
|
||||
|
||||
override fun onCreated() {
|
||||
super.onCreated()
|
||||
|
||||
binding.cancel.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.validate.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
viewModel.cupSize.observe(this) {
|
||||
binding.customSizeText.text = String.format(
|
||||
getString(R.string.custom_amount),
|
||||
"${it}ml"
|
||||
)
|
||||
binding.size100ml.setBackgroundColor(Color.TRANSPARENT)
|
||||
binding.size250ml.setBackgroundColor(Color.TRANSPARENT)
|
||||
binding.size500ml.setBackgroundColor(Color.TRANSPARENT)
|
||||
binding.size1000ml.setBackgroundColor(Color.TRANSPARENT)
|
||||
binding.customSize.setBackgroundColor(Color.TRANSPARENT)
|
||||
val back = resources.getColor(
|
||||
com.google.android.material.R.color.material_dynamic_primary95,
|
||||
)
|
||||
when (it) {
|
||||
100 -> {
|
||||
binding.size100ml.setBackgroundColor(back)
|
||||
}
|
||||
250 -> {
|
||||
binding.size250ml.setBackgroundColor(back)
|
||||
}
|
||||
500 -> {
|
||||
binding.size500ml.setBackgroundColor(back)
|
||||
}
|
||||
1000 -> {
|
||||
binding.size1000ml.setBackgroundColor(back)
|
||||
}
|
||||
else -> {
|
||||
binding.customSize.setBackgroundColor(back)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.size100ml.setOnClickListener {
|
||||
viewModel.setCupSize(100)
|
||||
}
|
||||
binding.size250ml.setOnClickListener {
|
||||
viewModel.setCupSize(250)
|
||||
}
|
||||
binding.size500ml.setOnClickListener {
|
||||
viewModel.setCupSize(500)
|
||||
}
|
||||
binding.size1000ml.setOnClickListener {
|
||||
viewModel.setCupSize(1000)
|
||||
}
|
||||
|
||||
binding.customSize.setOnClickListener {
|
||||
val editTextLayout = TextInputLayout(requireContext())
|
||||
|
||||
val editText = TextInputEditText(requireContext())
|
||||
editText.setText(viewModel.cupSize.value.toString())
|
||||
|
||||
editTextLayout.addView(editText)
|
||||
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setView(editTextLayout)
|
||||
.setTitle("Custom Cup Size")
|
||||
.setOnCancelListener {
|
||||
it.dismiss()
|
||||
}
|
||||
.setPositiveButton(
|
||||
R.string.validate
|
||||
) { dialog, _ ->
|
||||
viewModel.setCupSize(editText.text.toString().toInt())
|
||||
dismiss()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,32 @@
|
||||
package com.dzeio.openhealth.ui.water
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.dzeio.openhealth.core.BaseViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class WaterSizeSelectorViewModel : BaseViewModel() {
|
||||
@HiltViewModel
|
||||
class WaterSizeSelectorViewModel @Inject constructor(
|
||||
private val settings: SharedPreferences
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _cupSize = MutableLiveData(0)
|
||||
|
||||
val cupSize = _cupSize
|
||||
|
||||
init {
|
||||
val cup = settings.getInt("water_cup_size", -1)
|
||||
if (cup != -1) {
|
||||
_cupSize.value = cup
|
||||
}
|
||||
}
|
||||
|
||||
fun setCupSize(value: Int) {
|
||||
settings.edit()
|
||||
.putInt("water_cup_size", value)
|
||||
.apply()
|
||||
|
||||
_cupSize.value = value
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ class AddWeightDialog : BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeVi
|
||||
setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.cancel()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +39,7 @@ class AddWeightDialog : BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeVi
|
||||
viewModel.lastWeight().collect {
|
||||
if (it != null) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,12 +55,11 @@ class AddWeightDialog : BaseDialog<HomeViewModel, DialogAddWeightBinding>(HomeVi
|
||||
val weight = Weight().apply {
|
||||
weight = binding.kg.value + (binding.gram.value.toFloat() / 10)
|
||||
source = "OpenHealth"
|
||||
|
||||
}
|
||||
lifecycleScope.launchWhenCreated {
|
||||
viewModel.addWeight(weight)
|
||||
}
|
||||
//callback?.invoke()
|
||||
// callback?.invoke()
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,24 @@ package com.dzeio.openhealth.ui.weight
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.dzeio.openhealth.R
|
||||
import com.dzeio.openhealth.adapters.WeightAdapter
|
||||
import com.dzeio.openhealth.core.BaseFragment
|
||||
import com.dzeio.openhealth.data.weight.Weight
|
||||
import com.dzeio.openhealth.databinding.FragmentListWeightBinding
|
||||
import com.dzeio.openhealth.graphs.WeightChart
|
||||
import com.dzeio.openhealth.ui.home.HomeViewModel
|
||||
import com.dzeio.openhealth.units.WeightUnit
|
||||
import com.dzeio.openhealth.utils.GraphUtils
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
@ -21,33 +30,82 @@ class ListWeightFragment :
|
||||
override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentListWeightBinding =
|
||||
FragmentListWeightBinding::inflate
|
||||
|
||||
val settings by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
val recycler = binding.list
|
||||
|
||||
val manager = LinearLayoutManager(requireContext())
|
||||
recycler.layoutManager = manager
|
||||
|
||||
val adapter = WeightAdapter()
|
||||
|
||||
val unit = settings.getString("weight_unit", "Kilogram") ?: "Kilogram"
|
||||
|
||||
adapter.unit = WeightUnit.fromSettings(unit)
|
||||
|
||||
adapter.onItemClick = {
|
||||
findNavController().navigate(
|
||||
ListWeightFragmentDirections.actionNavListWeightToNavEditWeight(
|
||||
it.id
|
||||
)
|
||||
)
|
||||
//EditWeightDialog().show(requireActivity().supportFragmentManager, "dialog")
|
||||
// EditWeightDialog().show(requireActivity().supportFragmentManager, "dialog")
|
||||
}
|
||||
recycler.adapter = adapter
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
|
||||
viewModel.fetchWeights().collectLatest {
|
||||
updateGraph(it)
|
||||
val itt = it.toMutableList()
|
||||
itt.sortWith { o1, o2 -> if (o1.timestamp > o2.timestamp) -1 else 1 }
|
||||
adapter.set(itt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GraphUtils.lineChartSetup(
|
||||
binding.chart,
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
),
|
||||
MaterialColors.getColor(
|
||||
requireView(),
|
||||
com.google.android.material.R.attr.colorOnBackground
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGraph(list: List<Weight>) {
|
||||
WeightChart.setup(
|
||||
binding.chart,
|
||||
requireView(),
|
||||
list,
|
||||
viewModel.weightUnit,
|
||||
viewModel.goalWeight?.toFloat(),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.action_add).isVisible = true
|
||||
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_add -> {
|
||||
findNavController().navigate(ListWeightFragmentDirections.actionNavListWeightToNavAddWeightDialog())
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
app/src/main/java/com/dzeio/openhealth/units/UnitFactory.kt
Normal file
20
app/src/main/java/com/dzeio/openhealth/units/UnitFactory.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package com.dzeio.openhealth.units
|
||||
|
||||
object UnitFactory {
|
||||
fun mass(unit: String): Units.Mass {
|
||||
return when (unit.lowercase()) {
|
||||
"kilogram", "kilograms", "kg" -> Units.Mass.KILOGRAM
|
||||
"pound", "pounds", "lb" -> Units.Mass.POUND
|
||||
else -> Units.Mass.KILOGRAM
|
||||
}
|
||||
}
|
||||
|
||||
fun volume(unit: String): Units.Volume {
|
||||
return when (unit.lowercase()) {
|
||||
"milliliter", "milliliters", "ml" -> Units.Volume.MILLILITER
|
||||
"imperial ounce", "imperial ounces", "oz" -> Units.Volume.IMPERIAL_OUNCE
|
||||
"us ounce", "us ounces" -> Units.Volume.US_OUNCE
|
||||
else -> Units.Volume.MILLILITER
|
||||
}
|
||||
}
|
||||
}
|
57
app/src/main/java/com/dzeio/openhealth/units/Units.kt
Normal file
57
app/src/main/java/com/dzeio/openhealth/units/Units.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package com.dzeio.openhealth.units
|
||||
|
||||
import com.dzeio.openhealth.R
|
||||
|
||||
object Units {
|
||||
enum class Mass(
|
||||
/**
|
||||
* Value based on the Kilogram
|
||||
*/
|
||||
val modifier: Float,
|
||||
val singular: Int,
|
||||
val plural: Int,
|
||||
val unit: Int
|
||||
) {
|
||||
KILOGRAM(
|
||||
1f,
|
||||
R.string.unit_mass_kilogram_name_singular,
|
||||
R.string.unit_mass_kilogram_name_plural,
|
||||
R.string.unit_mass_kilogram_unit
|
||||
),
|
||||
POUND(
|
||||
0.45359237f,
|
||||
R.string.unit_mass_pound_name_singular,
|
||||
R.string.unit_mass_pound_name_plural,
|
||||
R.string.unit_mass_pound_unit
|
||||
)
|
||||
}
|
||||
|
||||
enum class Volume(
|
||||
/**
|
||||
* Value based on the Kilogram
|
||||
*/
|
||||
val modifier: Float,
|
||||
val singular: Int,
|
||||
val plural: Int,
|
||||
val unit: Int
|
||||
) {
|
||||
MILLILITER(
|
||||
1f,
|
||||
R.string.unit_volume_milliliter_name_singular,
|
||||
R.string.unit_volume_milliliter_name_plural,
|
||||
R.string.unit_volume_milliliter_unit
|
||||
),
|
||||
IMPERIAL_OUNCE(
|
||||
0.03519503f,
|
||||
R.string.unit_volume_imperial_ounce_name_singular,
|
||||
R.string.unit_volume_imperial_ounce_name_plural,
|
||||
R.string.unit_volume_ounce_unit
|
||||
),
|
||||
US_OUNCE(
|
||||
0.03381413f,
|
||||
R.string.unit_volume_us_ounce_name_singular,
|
||||
R.string.unit_volume_us_ounce_name_plural,
|
||||
R.string.unit_volume_ounce_unit
|
||||
)
|
||||
}
|
||||
}
|
21
app/src/main/java/com/dzeio/openhealth/units/WaterUnit.kt
Normal file
21
app/src/main/java/com/dzeio/openhealth/units/WaterUnit.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package com.dzeio.openhealth.units
|
||||
|
||||
enum class WaterUnit(
|
||||
val unit: String,
|
||||
val fromML: Float
|
||||
) {
|
||||
ML("ml", 1f),
|
||||
US_OZ("oz", 0.03381413f),
|
||||
IMP_OZ("oz", 0.03519503f);
|
||||
|
||||
companion object {
|
||||
fun fromSettings(value: String): WaterUnit {
|
||||
return when (value.lowercase()) {
|
||||
"milliliter" -> ML
|
||||
"us ounce" -> US_OZ
|
||||
"imperial ounce" -> IMP_OZ
|
||||
else -> ML
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
app/src/main/java/com/dzeio/openhealth/units/WeightUnit.kt
Normal file
19
app/src/main/java/com/dzeio/openhealth/units/WeightUnit.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.dzeio.openhealth.units
|
||||
|
||||
enum class WeightUnit(
|
||||
val unit: String,
|
||||
val fromKG: Float
|
||||
) {
|
||||
KG("kg", 1f),
|
||||
LBS("lbs", 2.2046226218488f);
|
||||
|
||||
companion object {
|
||||
fun fromSettings(value: String): WeightUnit {
|
||||
return when (value.lowercase()) {
|
||||
"kilogram" -> KG
|
||||
"pounds" -> LBS
|
||||
else -> KG
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ 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 java.text.SimpleDateFormat
|
||||
@ -21,6 +22,14 @@ object GraphUtils {
|
||||
// chart.isAutoScaleMinMaxEnabled = true
|
||||
}
|
||||
|
||||
fun lineDataSet(lineDataSet: LineDataSet): LineDataSet {
|
||||
return lineDataSet.apply {
|
||||
setDrawCircles(false)
|
||||
setDrawCircleHole(false)
|
||||
mode = LineDataSet.Mode.HORIZONTAL_BEZIER
|
||||
}
|
||||
}
|
||||
|
||||
fun barChartSetup(chart: BarChart, mainColor: Int, textColor: Int) {
|
||||
barLineChartSetup(chart, mainColor, textColor)
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 9.0 KiB |
10
app/src/main/res/drawable/ic_baseline_line_style_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_line_style_24.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,16h5v-2H3V16zM9.5,16h5v-2h-5V16zM16,16h5v-2h-5V16zM3,20h2v-2H3V20zM7,20h2v-2H7V20zM11,20h2v-2h-2V20zM15,20h2v-2h-2V20zM19,20h2v-2h-2V20zM3,12h8v-2H3V12zM13,12h8v-2h-8V12zM3,4v4h18V4H3z"/>
|
||||
</vector>
|
49
app/src/main/res/drawable/ic_logo_full.xml
Normal file
49
app/src/main/res/drawable/ic_logo_full.xml
Normal file
File diff suppressed because one or more lines are too long
10
app/src/main/res/drawable/ic_logo_github.xml
Normal file
10
app/src/main/res/drawable/ic_logo_github.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:pathData="M10.9,2.1c-4.6,0.5 -8.3,4.2 -8.8,8.7c-0.5,4.7 2.2,8.9 6.3,10.5C8.7,21.4 9,21.2 9,20.8v-1.6c0,0 -0.4,0.1 -0.9,0.1c-1.4,0 -2,-1.2 -2.1,-1.9c-0.1,-0.4 -0.3,-0.7 -0.6,-1C5.1,16.3 5,16.3 5,16.2C5,16 5.3,16 5.4,16c0.6,0 1.1,0.7 1.3,1c0.5,0.8 1.1,1 1.4,1c0.4,0 0.7,-0.1 0.9,-0.2c0.1,-0.7 0.4,-1.4 1,-1.8c-2.3,-0.5 -4,-1.8 -4,-4c0,-1.1 0.5,-2.2 1.2,-3C7.1,8.8 7,8.3 7,7.6C7,7.2 7,6.6 7.3,6c0,0 1.4,0 2.8,1.3C10.6,7.1 11.3,7 12,7s1.4,0.1 2,0.3C15.3,6 16.8,6 16.8,6C17,6.6 17,7.2 17,7.6c0,0.8 -0.1,1.2 -0.2,1.4c0.7,0.8 1.2,1.8 1.2,3c0,2.2 -1.7,3.5 -4,4c0.6,0.5 1,1.4 1,2.3v2.6c0,0.3 0.3,0.6 0.7,0.5c3.7,-1.5 6.3,-5.1 6.3,-9.3C22,6.1 16.9,1.4 10.9,2.1z"
|
||||
android:fillColor="@android:color/white"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_outline_edit_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_edit_24.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_outline_free_breakfast_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_free_breakfast_24.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,19h16v2L4,21zM20,3L4,3v10c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.11,0 2,-0.9 2,-2L22,5c0,-1.11 -0.89,-2 -2,-2zM16,13c0,1.1 -0.9,2 -2,2L8,15c-1.1,0 -2,-0.9 -2,-2L6,5h10v8zM20,8h-2L18,5h2v3z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_outline_local_drink_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_local_drink_24.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,2l2.01,18.23C5.13,21.23 5.97,22 7,22h10c1.03,0 1.87,-0.77 1.99,-1.77L21,2L3,2zM17,20l-10,0.01L5.89,10L18.1,10L17,20zM18.33,8L5.67,8l-0.44,-4h13.53l-0.43,4zM12,19c1.66,0 3,-1.34 3,-3 0,-2 -3,-5.4 -3,-5.4S9,14 9,16c0,1.66 1.34,3 3,3zM12,13.91c0.59,0.91 1,1.73 1,2.09 0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1c0,-0.37 0.41,-1.19 1,-2.09z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_outline_mail_24.xml
Normal file
10
app/src/main/res/drawable/ic_outline_mail_24.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6zM20,6l-8,4.99L4,6h16zM20,18L4,18L4,8l8,5 8,-5v10z"/>
|
||||
</vector>
|
@ -1,7 +1,182 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_local_drink_24" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/switch_cup_size" />
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/size_100ml"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_local_drink_24" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="100ml" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/size_250ml"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_local_drink_24" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="250ml" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/size_500ml"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_local_drink_24" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="500ml" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/size_1000ml"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_local_drink_24" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="1000ml" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/custom_size"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/material_dynamic_primary90"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_outline_edit_24" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/custom_size_text"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/custom_amount"
|
||||
tools:text="Custom amount: 100ml" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/validate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/validate" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
65
app/src/main/res/layout/fragment_about.xml
Normal file
65
app/src/main/res/layout/fragment_about.xml
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="32dp"
|
||||
app:srcCompat="@drawable/ic_logo_full" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/tagline"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/version_number"
|
||||
app:drawableStartCompat="@drawable/ic_baseline_extension_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/github"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/about_star_on_github"
|
||||
app:drawableStartCompat="@drawable/ic_logo_github" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contact_us"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/contact_us"
|
||||
app:drawableStartCompat="@drawable/ic_outline_mail_24" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/licenses"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/licenses"
|
||||
app:drawableStartCompat="@drawable/ic_baseline_line_style_24" />
|
||||
|
||||
</LinearLayout>
|
@ -15,7 +15,7 @@
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
@ -40,7 +40,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Weight" />
|
||||
android:text="@string/water_intake" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
@ -48,12 +48,6 @@
|
||||
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:id="@+id/goto_water_home"
|
||||
android:layout_width="24dp"
|
||||
@ -75,7 +69,7 @@
|
||||
android:id="@+id/fragment_home_water_remove"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/ic_outline_hexagon_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/linearLayout"
|
||||
@ -98,7 +92,7 @@
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="900ml"
|
||||
android:text="@string/unit_volume_milliliter_unit"
|
||||
android:textAlignment="center" />
|
||||
|
||||
|
||||
@ -107,7 +101,7 @@
|
||||
style="@style/TextAppearance.Material3.LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="1200ml"
|
||||
android:text="@string/unit_volume_milliliter_unit"
|
||||
android:textAlignment="center" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -117,7 +111,7 @@
|
||||
android:id="@+id/fragment_home_water_add"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/ic_baseline_add_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/linearLayout"
|
||||
@ -180,7 +174,7 @@
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Weight"
|
||||
android:text="@string/weight"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<LinearLayout
|
||||
@ -193,7 +187,7 @@
|
||||
android:id="@+id/add_weight"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_baseline_add_24" />
|
||||
|
||||
<ImageView
|
||||
@ -203,7 +197,6 @@
|
||||
android:src="@drawable/ic_outline_hexagon_24" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.github.mikephil.charting.charts.LineChart
|
||||
@ -212,18 +205,8 @@
|
||||
android:layout_height="200dp"
|
||||
android:minHeight="200dp" />
|
||||
|
||||
<!-- <com.jjoe64.graphview.GraphView-->
|
||||
<!-- android:id="@+id/weight_graph"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="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" />-->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -1,14 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView 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:tools="http://schemas.android.com/tools"
|
||||
|
||||
|
||||
android:clipToPadding="false"
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<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">
|
||||
|
||||
<com.github.mikephil.charting.charts.LineChart
|
||||
android:id="@+id/chart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:minHeight="200dp" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:clipToPadding="false"
|
||||
android:id="@+id/list"
|
||||
android:padding="16dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
tools:listitem="@layout/layout_item_list"
|
||||
tools:context=".ui.weight.ListWeightFragment" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
tools:listitem="@layout/layout_item_list"
|
||||
tools:context=".ui.weight.ListWeightFragment" />
|
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/nav_header_height"
|
||||
android:background="@drawable/side_nav_bar"
|
||||
android:gravity="bottom"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/nav_header_desc"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
app:srcCompat="@mipmap/ic_launcher_round" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
android:text="@string/nav_header_title"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/nav_header_subtitle" />
|
||||
</LinearLayout>
|
@ -1,16 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_add"
|
||||
android:visible="false"
|
||||
android:icon="@drawable/ic_baseline_add_24"
|
||||
android:title="@string/add"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="ifRoom"
|
||||
android:title="@string/page_settings"
|
||||
android:icon="@drawable/ic_baseline_settings_24"/>
|
||||
<item
|
||||
android:id="@+id/action_extensions"
|
||||
android:title="@string/menu_extensions"
|
||||
app:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_baseline_extension_24"
|
||||
/>
|
||||
</menu>
|
||||
android:icon="@drawable/ic_baseline_extension_24" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:title="@string/about" />
|
||||
</menu>
|
||||
|
@ -38,6 +38,12 @@
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right" />
|
||||
<action
|
||||
android:id="@+id/action_nav_home_to_nav_add_weight_dialog"
|
||||
app:destination="@id/nav_add_weight_dialog" />
|
||||
<action
|
||||
android:id="@+id/action_nav_home_to_aboutFragment"
|
||||
app:destination="@id/aboutFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
@ -53,7 +59,7 @@
|
||||
<fragment
|
||||
android:id="@+id/nav_list_weight"
|
||||
android:name="com.dzeio.openhealth.ui.weight.ListWeightFragment"
|
||||
android:label="@string/menu_list_weight"
|
||||
android:label="@string/weight"
|
||||
tools:layout="@layout/fragment_list_weight" >
|
||||
<action
|
||||
android:id="@+id/action_nav_list_weight_to_nav_edit_weight"
|
||||
@ -62,6 +68,9 @@
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right" />
|
||||
<action
|
||||
android:id="@+id/action_nav_list_weight_to_nav_add_weight_dialog"
|
||||
app:destination="@id/nav_add_weight_dialog" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
@ -88,11 +97,45 @@
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right" />
|
||||
<action
|
||||
android:id="@+id/action_nav_water_home_to_nav_water_size_dialog"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right"
|
||||
app:destination="@id/nav_water_size_dialog" />
|
||||
</fragment>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/nav_water_size_dialog"
|
||||
android:name="com.dzeio.openhealth.ui.water.WaterSizeSelectorDialog"
|
||||
tools:layout="@layout/dialog_water_size_selector"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right">
|
||||
|
||||
</dialog>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/nav_add_weight_dialog"
|
||||
android:name="com.dzeio.openhealth.ui.weight.AddWeightDialog"
|
||||
tools:layout="@layout/dialog_water_size_selector"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right">
|
||||
|
||||
</dialog>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_settings"
|
||||
android:name="com.dzeio.openhealth.ui.settings.SettingsFragment">
|
||||
android:label="@string/page_settings"
|
||||
android:name="com.dzeio.openhealth.ui.settings.SettingsFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popEnterAnim="@android:anim/slide_in_left"
|
||||
app:popExitAnim="@android:anim/slide_out_right">
|
||||
|
||||
</fragment>
|
||||
|
||||
@ -125,4 +168,9 @@
|
||||
app:argType="string" />
|
||||
|
||||
</fragment>
|
||||
</navigation>
|
||||
<fragment
|
||||
android:id="@+id/aboutFragment"
|
||||
android:name="com.dzeio.openhealth.ui.about.AboutFragment"
|
||||
android:label="AboutFragment"
|
||||
tools:layout="@layout/fragment_about"/>
|
||||
</navigation>
|
||||
|
34
app/src/main/res/values-fr/strings.xml
Normal file
34
app/src/main/res/values-fr/strings.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="unit_mass_kilogram_name_singular">Kilograme</string>
|
||||
<string name="unit_mass_kilogram_name_plural">Kilogrames</string>
|
||||
<string name="unit_mass_pound_name_singular">Livre</string>
|
||||
<string name="unit_mass_pound_name_plural">Livres</string>
|
||||
<string name="unit_volume_milliliter_name_singular">Millilitre</string>
|
||||
<string name="unit_volume_milliliter_name_plural">Millilitres</string>
|
||||
<string name="unit_volume_imperial_ounce_name_singular">Once Impérial</string>
|
||||
<string name="unit_volume_imperial_ounce_name_plural">OncesImpérial</string>
|
||||
<string name="unit_volume_us_ounce_name_singular">Once États Unis</string>
|
||||
<string name="unit_volume_us_ounce_name_plural">Onces États Unis</string>
|
||||
<string name="extension_informations">Les importations sont faites au démarrage de l\'application\nLes exports sont faits lorsque qu\'il y a des nouvelles valeurs dans l\'application</string>
|
||||
<string name="menu_home">Accueil</string>
|
||||
<string name="page_settings">Paramètres</string>
|
||||
<string name="nav_water_home">Truc D\'eau</string>
|
||||
<string name="languages">Langages</string>
|
||||
<string name="settings_global">Paramètres Globaux</string>
|
||||
<string name="weight">Poids</string>
|
||||
<string name="water_intake">Consomation d\'eau</string>
|
||||
<string name="switch_cup_size">Changer la taille du verre</string>
|
||||
<string name="validate">Valider</string>
|
||||
<string name="custom_amount">Montant personnalisée: %1$s</string>
|
||||
<string name="menu_import">Importer</string>
|
||||
<string name="menu_edit_weight">Changer le poid</string>
|
||||
<string name="menu_extensions">Extensions</string>
|
||||
<string name="tagline">Ton Application de santé libre, open source et respectueuse de la vie privée</string>
|
||||
<string name="add">Ajouter</string>
|
||||
<string name="about">A Propos</string>
|
||||
<string name="version_number" formatted="false">Version %1$</string>
|
||||
<string name="about_star_on_github">Mettez une étoile sur Github</string>
|
||||
<string name="contact_us">Contactez-nous</string>
|
||||
<string name="licenses">Licenses</string>
|
||||
</resources>
|
@ -4,8 +4,13 @@
|
||||
<item>Male</item>
|
||||
<item>Female</item>
|
||||
</string-array>
|
||||
<string-array name="water_units">
|
||||
<item>Millimeters</item>
|
||||
<item>Ounces</item>
|
||||
<string-array name="weight_units">
|
||||
<item name="kg">@string/unit_mass_kilogram_name_plural</item>
|
||||
<item name="lb">@string/unit_mass_pound_name_singular</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
<string-array name="water_units">
|
||||
<item name="ml">@string/unit_volume_milliliter_name_singular</item>
|
||||
<item name="us_oz">@string/unit_volume_imperial_ounce_name_singular</item>
|
||||
<item name="im_oz">@string/unit_volume_us_ounce_name_singular</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
@ -1,20 +1,44 @@
|
||||
<resources>
|
||||
<string name="app_name">OpenHealth</string>
|
||||
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||
<string name="nav_header_title">Android Studio</string>
|
||||
<string name="nav_header_subtitle">android.studio@android.com</string>
|
||||
<string name="nav_header_desc">Navigation header</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="app_name" translatable="false">OpenHealth</string>
|
||||
<string name="tagline">Your privacy-friendly FOSS Health Application </string>
|
||||
<string name="page_settings">Settings</string>
|
||||
|
||||
<string name="menu_home">Home</string>
|
||||
<string name="menu_gallery">Gallery</string>
|
||||
<string name="menu_slideshow">Slideshow</string>
|
||||
<string name="menu_import">Import</string>
|
||||
<string name="menu_list_weight">Weight List</string>
|
||||
<string name="menu_edit_weight">Edit Weight</string>
|
||||
<string name="nav_list_water">Water Intake</string>
|
||||
<string name="nav_water_home">Water Intake</string>
|
||||
<string name="menu_extensions">Extensions</string>
|
||||
<string name="extension_informations">Imports are done at app startup\nExports are done when new inputs are give to the app</string>
|
||||
</resources>
|
||||
|
||||
<!-- Units -->
|
||||
<string name="unit_mass_kilogram_name_singular">Kilogram</string>
|
||||
<string name="unit_mass_kilogram_name_plural">Kilograms</string>
|
||||
<string name="unit_mass_kilogram_unit" translatable="false">%1$skg</string>
|
||||
|
||||
<string name="unit_mass_pound_name_singular">Pound</string>
|
||||
<string name="unit_mass_pound_name_plural">Pounds</string>
|
||||
<string name="unit_mass_pound_unit" translatable="false">%1$slb</string>
|
||||
|
||||
<string name="unit_volume_milliliter_name_singular">Milliliter</string>
|
||||
<string name="unit_volume_milliliter_name_plural">Milliliters</string>
|
||||
<string name="unit_volume_milliliter_unit" translatable="false">%1$sml</string>
|
||||
|
||||
<string name="unit_volume_imperial_ounce_name_singular">Imperial Ounce</string>
|
||||
<string name="unit_volume_imperial_ounce_name_plural">Imperial Ounces</string>
|
||||
<string name="unit_volume_us_ounce_name_singular">US Ounce</string>
|
||||
<string name="unit_volume_us_ounce_name_plural">US Ounces</string>
|
||||
<string name="unit_volume_ounce_unit" translatable="false">%1$soz</string>
|
||||
<string name="languages">Languages</string>
|
||||
<string name="settings_global">Global Settings</string>
|
||||
<string name="weight">Weight</string>
|
||||
<string name="water_intake">Water Intake</string>
|
||||
<string name="switch_cup_size">Switch cup size</string>
|
||||
<string name="validate">Validate</string>
|
||||
<string name="custom_amount">Custom amount: %1$s</string>
|
||||
<string name="add">Add</string>
|
||||
<string name="about">About</string>
|
||||
<string name="version_number" formatted="false">Version %1$s</string>
|
||||
<string name="about_star_on_github">Star on Github</string>
|
||||
<string name="contact_us">Contact us</string>
|
||||
<string name="licenses">Licenses</string>
|
||||
</resources>
|
||||
|
@ -1,13 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceCategory android:title="Global Settings">
|
||||
<PreferenceCategory android:title="@string/settings_global">
|
||||
<ListPreference
|
||||
android:defaultValue="Male"
|
||||
android:entries="@array/genders"
|
||||
android:entryValues="@array/genders"
|
||||
android:key="global_gender"
|
||||
android:title="Gender" />
|
||||
|
||||
<ListPreference
|
||||
android:key="global_language"
|
||||
android:title="@string/languages" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Weight Settings">
|
||||
|
||||
@ -24,6 +28,14 @@
|
||||
android:digits="0123456789"
|
||||
android:inputType="numberDecimal"
|
||||
android:title="Goal Weight" />
|
||||
<ListPreference
|
||||
android:defaultValue="1"
|
||||
android:entries="@array/weight_units"
|
||||
android:entryValues="@array/weight_units"
|
||||
android:key="weight_unit"
|
||||
android:title="Weight Unit" />
|
||||
|
||||
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Water Settings">
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user