Skip to content

Commit

Permalink
Merge pull request #7 from ItamiOMW/reports-feature
Browse files Browse the repository at this point in the history
Reports feature
  • Loading branch information
ItamiOMW authored May 20, 2024
2 parents 5f80913 + 1b25246 commit 8d6694b
Show file tree
Hide file tree
Showing 33 changed files with 1,865 additions and 150 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Calorie tracker helps you to keep track of your diet according to your personal goal.\
[Figma design](https://www.figma.com/file/DJ5C3WdVFr8uNEJFUOAhUU/Calorie-Tracker?type=design&node-id=0%3A1&mode=design&t=rMj47XB9ZHeac5w0-1)\
[Ktor backend](https://github.com/ItamiOWM/CalorieTrackerBackend)
[Ktor backend](https://github.com/ItamiOMW/CalorieTrackerBackend)

![Calorie Tracker Thumbnail](https://github.com/ItamiOWM/android-calorie-tracker/blob/master/art/thumbnail.png)

Expand Down
42 changes: 32 additions & 10 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,19 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
buildConfigField("String", "GOOGLE_CLIENT_ID", "\"${localProperties.getProperty("GOOGLE_CLIENT_ID")}\"")
buildConfigField(
"String",
"GOOGLE_CLIENT_ID",
"\"${localProperties.getProperty("GOOGLE_CLIENT_ID")}\""
)
buildConfigField("String", "BASE_URL", "\"${localProperties.getProperty("BASE_URL")}\"")
}
debug {
buildConfigField("String", "GOOGLE_CLIENT_ID", "\"${localProperties.getProperty("GOOGLE_CLIENT_ID")}\"")
buildConfigField(
"String",
"GOOGLE_CLIENT_ID",
"\"${localProperties.getProperty("GOOGLE_CLIENT_ID")}\""
)
buildConfigField("String", "BASE_URL", "\"${localProperties.getProperty("BASE_URL")}\"")
}
}
Expand All @@ -70,27 +78,41 @@ android {

dependencies {

implementation("androidx.core:core-ktx:1.13.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0")
implementation("androidx.activity:activity-compose:1.9.0")
implementation(platform("androidx.compose:compose-bom:2024.04.01"))
implementation(platform("androidx.compose:compose-bom:2024.05.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.04.01"))
androidTestImplementation(platform("androidx.compose:compose-bom:2024.05.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")



// Chart Library
// For Jetpack Compose.
implementation("com.patrykandpatrick.vico:compose:2.0.0-alpha.19")

// For `compose`. Creates a `ChartStyle` based on an M3 Material Theme.
implementation("com.patrykandpatrick.vico:compose-m3:2.0.0-alpha.19")

// Houses the core logic for charts and other elements. Included in all other modules.
implementation("com.patrykandpatrick.vico:core:2.0.0-alpha.19")



//Google Auth
implementation("com.google.android.gms:play-services-auth:21.1.0")
implementation("com.google.android.gms:play-services-auth:21.1.1")

//Kotlinx Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")

//Compose Navigation, keep it 2.7.5 since updating to newer version breaks navigation for some reason
implementation("androidx.navigation:navigation-compose:2.7.5")
Expand Down Expand Up @@ -120,8 +142,8 @@ dependencies {
implementation("androidx.room:room-ktx:2.6.1")

//Data Store Preferences
implementation("androidx.datastore:datastore-preferences:1.1.0")
implementation("androidx.datastore:datastore:1.1.0")
implementation("androidx.datastore:datastore-preferences:1.1.1")
implementation("androidx.datastore:datastore:1.1.1")

//Encrypted Shared Preferences
implementation("androidx.security:security-crypto:1.1.0-alpha06")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class AuthRepositoryImpl @Inject constructor(
private val jwtToken get() = authManager.token

override suspend fun registerGoogle(createUser: CreateUserGoogle): AppResponse<Unit> {
return when (val response = authApiService.registerGoogle(createUser.toRegisterGoogleRequest())) {
return when (val response =
authApiService.registerGoogle(createUser.toRegisterGoogleRequest())) {
is ApiResponse.Success -> {
val user = response.body.user.toUser()
val token = response.body.token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,23 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.itami.calorie_tracker.R
import com.itami.calorie_tracker.core.domain.model.WeightUnit
import com.itami.calorie_tracker.core.presentation.components.WeightPicker
import com.itami.calorie_tracker.core.presentation.theme.CalorieTrackerTheme
import kotlinx.coroutines.flow.Flow

Expand Down Expand Up @@ -89,12 +75,12 @@ fun WeightScreen(
end = CalorieTrackerTheme.padding.large
)
)
WeightSection(
WeightPicker(
weight = state.weight,
onValueChange = { weight ->
onEvent(WeightEvent.WeightValueChange(weight))
},
weightUnit = { state.selectedWeightUnit },
weightUnit = state.selectedWeightUnit,
onChangeWeightUnit = { weightUnit ->
onEvent(WeightEvent.ChangeWeightUnit(weightUnit))
},
Expand Down Expand Up @@ -145,114 +131,6 @@ private fun TopSection(
}
}

@Composable
private fun WeightSection(
weight: String,
onValueChange: (weight: String) -> Unit,
weightUnit: () -> WeightUnit,
onChangeWeightUnit: (WeightUnit) -> Unit,
modifier: Modifier,
) {
var dropdownMenuExpanded by rememberSaveable { mutableStateOf(false) }

Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(CalorieTrackerTheme.spacing.small)
) {
TextField(
modifier = Modifier
.fillMaxWidth(0.5f)
.align(Alignment.Top),
value = weight,
onValueChange = { newValue ->
val newText = newValue.takeIf { input ->
input.isEmpty() || input.toFloatOrNull() != null
}
newText?.let { onValueChange(it) }
},
textStyle = CalorieTrackerTheme.typography.bodyLarge,
colors = TextFieldDefaults.colors(
focusedTextColor = CalorieTrackerTheme.colors.onBackground,
unfocusedTextColor = CalorieTrackerTheme.colors.onBackground,
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
cursorColor = CalorieTrackerTheme.colors.primary,
focusedIndicatorColor = CalorieTrackerTheme.colors.primary,
unfocusedIndicatorColor = CalorieTrackerTheme.colors.primary,
),
label = { },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
singleLine = true,
)
Row(
modifier = Modifier.align(Alignment.Bottom),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(CalorieTrackerTheme.spacing.none)
) {
Text(
text = when (weightUnit()) {
WeightUnit.POUND -> stringResource(id = R.string.weight_unit_short_pounds)
WeightUnit.KILOGRAM -> stringResource(id = R.string.weight_unit_short_kilograms)
},
color = CalorieTrackerTheme.colors.primary,
style = CalorieTrackerTheme.typography.bodyLarge,
)
IconButton(
onClick = {
dropdownMenuExpanded = true
}
) {
Icon(
painter = painterResource(id = R.drawable.icon_arrow_drop_down),
contentDescription = stringResource(R.string.icon_desc_arrow_drop_down),
tint = CalorieTrackerTheme.colors.onBackground,
modifier = Modifier.size(24.dp)
)
DropdownMenu(
expanded = dropdownMenuExpanded,
onDismissRequest = {
dropdownMenuExpanded = false
},
) {
DropdownMenuItem(
text = {
Text(
text = stringResource(R.string.weight_unit_kilograms),
style = CalorieTrackerTheme.typography.bodyLarge,
)
},
onClick = {
onChangeWeightUnit(WeightUnit.KILOGRAM)
dropdownMenuExpanded = false
},
colors = MenuDefaults.itemColors(
textColor = CalorieTrackerTheme.colors.onSurfacePrimary,
),
)
DropdownMenuItem(
text = {
Text(
text = stringResource(R.string.weight_unit_pounds),
style = CalorieTrackerTheme.typography.bodyLarge,
)
},
onClick = {
onChangeWeightUnit(WeightUnit.POUND)
dropdownMenuExpanded = false
},
colors = MenuDefaults.itemColors(
textColor = CalorieTrackerTheme.colors.onSurfacePrimary,
),
)
}
}
}
}
}

@Composable
private fun BottomSection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ import kotlin.math.roundToInt
enum class WeightUnit {
POUND, KILOGRAM;

fun toGrams(weight: Float): Int {
return when(this) {
POUND -> {
poundsToGrams(weight)
}
KILOGRAM -> {
kilogramsToGrams(weight)
}
}
}

fun gramsToPounds(grams: Int): Float {
return grams / 453.592f
}
Expand All @@ -29,7 +40,6 @@ enum class WeightUnit {
return kilograms * 2.20462f
}


fun convert(fromUnit: WeightUnit, toUnit: WeightUnit, weight: Float): Float {
if (fromUnit == toUnit) return weight
return when(fromUnit) {
Expand All @@ -42,4 +52,40 @@ enum class WeightUnit {
}
}
}

fun convert(weightGrams: Int): Float {
return when(this) {
POUND -> {
gramsToPounds(weightGrams)
}

KILOGRAM -> {
gramsToKilograms(weightGrams)
}
}
}

fun format(weight: Float): String {
return when(this) {
POUND -> {
"$weight lbs"
}
KILOGRAM -> {
"$weight kg"
}
}
}

fun format(weightGrams: Int): String {
val weight = convert(weightGrams)
val formattedWeight = String.format("%.1f", weight)
return when(this) {
POUND -> {
"$formattedWeight lbs"
}
KILOGRAM -> {
"$formattedWeight kg"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ class MainActivity : ComponentActivity() {
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.itami.calorie_tracker.core.presentation.components

import androidx.compose.runtime.*
import kotlinx.coroutines.CoroutineScope

/**
* The same as [LaunchedEffect], but skips first invocation.
*/
@Composable
fun UpdateEffect(key: Any, block: suspend CoroutineScope.() -> Unit) {
var isTriggered by remember { mutableStateOf(false) }

LaunchedEffect(key) {
if (isTriggered) {
block()
} else {
isTriggered = true
}
}
}
Loading

0 comments on commit 8d6694b

Please sign in to comment.