Skip to content
This repository has been archived by the owner on Mar 18, 2024. It is now read-only.

Commit

Permalink
Add muscle selector
Browse files Browse the repository at this point in the history
  • Loading branch information
AnkitSuda committed Nov 29, 2022
1 parent 34c8780 commit cecc320
Show file tree
Hide file tree
Showing 14 changed files with 484 additions and 67 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ dependencies {
implementation project(":modules:common-ui-components-workout-editor")
implementation project(":modules:stopwatch")
implementation project(":modules:ui-customize-barbells")
implementation project(":modules:ui-muscle-selector")

implementation Deps.Kotlin.coroutinesAndroid
kapt Deps.Android.Lifecycle.compiler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.ankitsuda.rebound.ui.measure.MeasureScreen
import com.ankitsuda.rebound.ui.measure.part.add_sheet.AddPartMeasurementBottomSheet
import com.ankitsuda.rebound.ui.measure.part.overview.PartMeasurementsScreen
import com.ankitsuda.rebound.ui.more.MoreScreen
import com.ankitsuda.rebound.ui.muscleselector.MuscleSelectorBottomSheet
import com.ankitsuda.rebound.ui.resttimer.RestTimerScreen
import com.ankitsuda.rebound.ui.settings.SettingsScreen
import com.ankitsuda.rebound.ui.settings.personalization.ColorPickerDemoScreen
Expand Down Expand Up @@ -129,6 +130,7 @@ internal fun AppNavigation(
addRestTimer(navController)
addSupersetSelector(navController)
addBarbellSelector(navController)
addMuscleSelector(navController)
}
}

Expand Down Expand Up @@ -371,7 +373,7 @@ private fun NavGraphBuilder.addReboundSetKeyboardDemo(navController: NavControll

private fun NavGraphBuilder.addCreateExerciseBottomSheet(navController: NavController) {
bottomSheetScreen(LeafScreen.CreateExercise()) {
CreateExerciseScreen()
CreateExerciseScreen(navController)
}
}

Expand Down Expand Up @@ -423,6 +425,12 @@ private fun NavGraphBuilder.addBarbellSelector(navController: NavController) {
}
}

private fun NavGraphBuilder.addMuscleSelector(navController: NavController) {
bottomSheetScreen(LeafScreen.MuscleSelector()) {
MuscleSelectorBottomSheet(navController)
}
}

/**
* Adds an [NavController.OnDestinationChangedListener] to this [NavController] and updates the
* returned [State] which is updated as the destination changes.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2022 Ankit Suda.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/

package com.ankitsuda.rebound.ui.components.listitems

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Check
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.ankitsuda.common.compose.R
import com.ankitsuda.rebound.ui.theme.ReboundTheme

@Composable
fun GenericListItemStyle1(
modifier: Modifier = Modifier,
title: String?,
description: String? = null,
isSelected: Boolean = false,
onClick: (() -> Unit)? = null
) {

Box(
modifier = modifier
) {
Row(
modifier = Modifier
.run {
if (onClick != null) {
clickable(onClick = onClick)
} else {
this
}
}
.padding(start = 24.dp, end = 24.dp, bottom = 12.dp, top = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
title?.let {
Text(
text = title,
style = ReboundTheme.typography.body1,
color = ReboundTheme.colors.onBackground
)
}
description?.let {
Text(
text = it,
style = ReboundTheme.typography.body2,
color = ReboundTheme.colors.onBackground.copy(alpha = 0.75f)
)
}
}

if (isSelected) {
Icon(
imageVector = Icons.Outlined.Check,
contentDescription = stringResource(R.string.selected),
tint = ReboundTheme.colors.primary
)
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,5 @@
<string name="barbell">Barbell</string>
<string name="add_barbell">Add barbell</string>
<string name="select_barbell">Select barbell</string>
<string name="select_muscle">Select muscle</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ const val SUPERSET_ID_KEY = "superset_id"
const val JUNCTION_ID_KEY = "junction_id"
const val ENTRY_ID_KEY = "entry_id"
const val BARBELL_ID_KEY = "barbell_id"
const val MUSCLE_ID_KEY = "muscle_id"

const val RESULT_EXERCISES_SCREEN_EXERCISE_ID = "result_exercises_screen_exercise_id"
const val RESULT_SUPERSET_SELECTOR_SUPERSET_ID_KEY = "result_superset_selector_superset_id"
const val RESULT_BARBELL_SELECTOR_KEY = "result_barbell_selector"
const val RESULT_MUSCLE_SELECTOR_KEY = "result_muscle_selector"

interface Screen {
val route: String
Expand Down Expand Up @@ -521,6 +523,22 @@ sealed class LeafScreen(
"barbell_selector?$JUNCTION_ID_KEY=$junctionId&$BARBELL_ID_KEY=$selectedBarbellId"
}
}

data class MuscleSelector(override val route: String = "muscle_selector?$MUSCLE_ID_KEY={$MUSCLE_ID_KEY}") :
LeafScreen(
route = route,
arguments = listOf(
navArgument(MUSCLE_ID_KEY) {
type = NavType.StringType
nullable = true
},
)
) {
companion object {
fun createRoute(selectedMuscleId: String? = null) =
"muscle_selector?$MUSCLE_ID_KEY=$selectedMuscleId"
}
}
}

@OptIn(ExperimentalAnimationApi::class)
Expand Down
1 change: 1 addition & 0 deletions modules/ui-create-exercise/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies {
implementation project(":modules:common-ui-components")
implementation project(":modules:core-data")
implementation project(":modules:navigation")
implementation project(":modules:ui-muscle-selector")

implementation Deps.Dagger.hilt
kapt Deps.Dagger.hiltCompiler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,39 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Done
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.ankitsuda.navigation.LocalNavigator
import com.ankitsuda.navigation.Navigator
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import com.ankitsuda.base.utils.extensions.getStateFlow
import com.ankitsuda.navigation.*
import com.ankitsuda.rebound.ui.components.AppTextField
import com.ankitsuda.rebound.ui.components.BottomSheetSurface
import com.ankitsuda.rebound.ui.components.TopBar
import com.ankitsuda.rebound.ui.components.TopBarIconButton
import com.ankitsuda.rebound.ui.muscleselector.models.MuscleSelectorResult
import com.google.accompanist.flowlayout.FlowRow
import kotlinx.coroutines.flow.collectLatest
import timber.log.Timber
import kotlin.random.Random

@Composable
fun CreateExerciseScreen(
navController: NavController,
navigator: Navigator = LocalNavigator.current,
viewModel: CreateExerciseScreenViewModel = hiltViewModel()
) {
Expand All @@ -58,15 +61,30 @@ fun CreateExerciseScreen(
val categoriesList = viewModel.allCategories
val musclesList by viewModel.allPrimaryMuscles.collectAsState(initial = emptyList())

val nameValue by viewModel.name.observeAsState("")
val noteValue by viewModel.note.observeAsState("")
val nameValue by viewModel.name.collectAsState("")
val noteValue by viewModel.note.collectAsState("")

val selectedCategory by viewModel.selectedCategory.observeAsState()
val selectedMuscle by viewModel.selectedMuscle.observeAsState("abductors")
val selectedCategory by viewModel.selectedCategory.collectAsState()
val selectedMuscle by viewModel.selectedMuscle.collectAsState("abductors")

val isCreateBtnEnabled = nameValue.trim().isNotEmpty()

Timber.d("TESTING RECOMPOSITION ${Random.nextInt()}")
// Observes results when Superset Selector changes value of arg
val muscleSelectorResult = navController.currentBackStackEntry
?.savedStateHandle
?.getStateFlow<MuscleSelectorResult?>(RESULT_MUSCLE_SELECTOR_KEY, null)
?.collectAsState()

LaunchedEffect(key1 = muscleSelectorResult) {
muscleSelectorResult?.value?.muscleId?.let {
viewModel.setPrimaryMuscle(it)
}

navController.currentBackStackEntry?.savedStateHandle?.set(
RESULT_MUSCLE_SELECTOR_KEY,
null
)
}

BottomSheetSurface {
Column {
Expand All @@ -76,9 +94,12 @@ fun CreateExerciseScreen(
title = stringResource(id = R.string.new_exercise),
strictLeftIconAlignToStart = true,
leftIconBtn = {
TopBarIconButton(icon = Icons.Outlined.Close, title = stringResource(id = R.string.back), onClick = {
navigator.goBack()
})
TopBarIconButton(
icon = Icons.Outlined.Close,
title = stringResource(id = R.string.back),
onClick = {
navigator.goBack()
})
},
rightIconBtn = {
TopBarIconButton(
Expand Down Expand Up @@ -149,28 +170,33 @@ fun CreateExerciseScreen(
)
Spacer(modifier = Modifier.height(8.dp))

FlowRow(crossAxisSpacing = 8.dp) {
for (category in categoriesList) {
Row(
modifier = Modifier
.width((LocalConfiguration.current.screenWidthDp / 2.5).dp)
.clickable(onClick = {
viewModel.setCategory(category)
}, indication = null,
interactionSource = remember { MutableInteractionSource() }),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(selected = selectedCategory == category, onClick = {
viewModel.setCategory(category)
})
Spacer(modifier = Modifier.width(8.dp))

Text(
text = category.tag
)
}
}
Button(onClick = {
navigator.navigate(LeafScreen.MuscleSelector.createRoute(selectedMuscleId = selectedMuscle))
}) {
Text(text = "Select category")
}
// FlowRow(crossAxisSpacing = 8.dp) {
// for (category in categoriesList) {
// Row(
// modifier = Modifier
// .width((LocalConfiguration.current.screenWidthDp / 2.5).dp)
// .clickable(onClick = {
// viewModel.setCategory(category)
// }, indication = null,
// interactionSource = remember { MutableInteractionSource() }),
// verticalAlignment = Alignment.CenterVertically,
// ) {
// RadioButton(selected = selectedCategory == category, onClick = {
// viewModel.setCategory(category)
// })
// Spacer(modifier = Modifier.width(8.dp))
//
// Text(
// text = category.tag
// )
// }
// }
// }
}
Column(
Modifier
Expand All @@ -185,28 +211,33 @@ fun CreateExerciseScreen(
)
Spacer(modifier = Modifier.height(8.dp))

FlowRow(crossAxisSpacing = 8.dp) {
for (muscle in musclesList) {
Row(
modifier = Modifier
.width((LocalConfiguration.current.screenWidthDp / 2.5).dp)
.clickable(onClick =
{
viewModel.setPrimaryMuscle(muscle.tag)
}, indication = null,
interactionSource = remember { MutableInteractionSource() }),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(selected = selectedMuscle == muscle.tag, onClick = {
viewModel.setPrimaryMuscle(muscle.tag)
})
Spacer(modifier = Modifier.width(8.dp))
Text(
text = muscle.name,
)
}
}
Button(onClick = {
navigator.navigate(LeafScreen.MuscleSelector.createRoute(selectedMuscleId = selectedMuscle))
}) {
Text(text = "Select muscle")
}
// FlowRow(crossAxisSpacing = 8.dp) {
// for (muscle in musclesList) {
// Row(
// modifier = Modifier
// .width((LocalConfiguration.current.screenWidthDp / 2.5).dp)
// .clickable(onClick =
// {
// viewModel.setPrimaryMuscle(muscle.tag)
// }, indication = null,
// interactionSource = remember { MutableInteractionSource() }),
// verticalAlignment = Alignment.CenterVertically,
// ) {
// RadioButton(selected = selectedMuscle == muscle.tag, onClick = {
// viewModel.setPrimaryMuscle(muscle.tag)
// })
// Spacer(modifier = Modifier.width(8.dp))
// Text(
// text = muscle.name,
// )
// }
// }
// }
}
}
}
Expand Down
Loading

0 comments on commit cecc320

Please sign in to comment.