diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index b569449..ace114e 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -37,6 +37,7 @@
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index d92a927..a600112 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -74,6 +74,7 @@ dependencies {
api(project(":feature:exercises"))
api(project(":feature:create-exercise"))
api((project(":feature:exercises-category")))
+ api((project(":feature:exercises-muscle")))
api(project(":core:navigation"))
api(project(":core:designsystem"))
diff --git a/app/src/main/java/com/lifting/app/navigation/LiftingNavHost.kt b/app/src/main/java/com/lifting/app/navigation/LiftingNavHost.kt
index f587efb..1f513d7 100644
--- a/app/src/main/java/com/lifting/app/navigation/LiftingNavHost.kt
+++ b/app/src/main/java/com/lifting/app/navigation/LiftingNavHost.kt
@@ -31,9 +31,10 @@ import com.lifting.app.core.navigation.screens.NavBarScreen
import com.lifting.app.feature.create_exercise.navigation.createExerciseBottomSheetScreen
import com.lifting.app.feature.create_exercise.navigation.navigateToCreateExercise
import com.lifting.app.feature.exercises.navigation.exercisesScreen
-import com.lifting.app.feature.exercises_category.navigation.SELECTED_EXERCISE_CATEGORY
import com.lifting.app.feature.exercises_category.navigation.exercisesCategoryBottomSheetScreen
import com.lifting.app.feature.exercises_category.navigation.navigateToExercisesCategory
+import com.lifting.app.feature.exercises_muscle.navigation.exercisesMuscleBottomSheetScreen
+import com.lifting.app.feature.exercises_muscle.navigation.navigateToExercisesMuscle
/**
* Created by bedirhansaricayir on 03.08.2024
@@ -127,6 +128,7 @@ private fun NavGraphBuilder.exercisesRoot(navController: NavController) {
exerciseDetail(navController)
createExercisesBottomSheet(navController)
exercisesCategoryBottomSheet(navController)
+ exercisesMuscleBottomSheet(navController)
}
}
@@ -254,13 +256,9 @@ private fun NavGraphBuilder.createExercisesBottomSheet(navController: NavControl
createExerciseBottomSheetScreen(
navController = navController,
onNavigateBack = navController::popBackStack,
- onNavigateToCategories = { category ->
- navController.currentBackStackEntry?.savedStateHandle?.set(
- SELECTED_EXERCISE_CATEGORY,
- value = category
- )
- navController.navigateToExercisesCategory()
- }
+ onNavigateToCategories = navController::navigateToExercisesCategory,
+ onNavigateToMuscles = navController::navigateToExercisesMuscle
+
)
}
@@ -268,6 +266,9 @@ private fun NavGraphBuilder.exercisesCategoryBottomSheet(navController: NavContr
exercisesCategoryBottomSheetScreen(navController)
}
+private fun NavGraphBuilder.exercisesMuscleBottomSheet(navController: NavController) {
+ exercisesMuscleBottomSheetScreen(navController)
+}
@Composable
private fun SampleScreen(text: String, onClick: () -> Unit) {
diff --git a/core/data/src/main/java/com/lifting/app/core/data/repository/muscles/PrePopulateData.kt b/core/data/src/main/java/com/lifting/app/core/data/repository/muscles/PrePopulateData.kt
index 0f829ff..2996648 100644
--- a/core/data/src/main/java/com/lifting/app/core/data/repository/muscles/PrePopulateData.kt
+++ b/core/data/src/main/java/com/lifting/app/core/data/repository/muscles/PrePopulateData.kt
@@ -1,6 +1,8 @@
package com.lifting.app.core.data.repository.muscles
+import com.lifting.app.core.data.mapper.Mapper.toDomain
import com.lifting.app.core.database.model.MuscleEntity
+import com.lifting.app.core.model.Muscle
/**
* Created by bedirhansaricayir on 21.08.2024
@@ -24,4 +26,7 @@ fun getPrePopulateMuscles(): List = listOf(
MuscleEntity(tag = "shoulders", name = "Shoulders", isDeletable = false, isHidden = false),
MuscleEntity(tag = "traps", name = "Traps", isDeletable = false, isHidden = false),
MuscleEntity(tag = "triceps", name = "Triceps", isDeletable = false, isHidden = false),
-)
\ No newline at end of file
+)
+
+fun String.parseToMuscle(): Muscle? =
+ getPrePopulateMuscles().find { it.tag == this }?.toDomain()
diff --git a/core/navigation/src/main/java/com/lifting/app/core/navigation/screens/Screen.kt b/core/navigation/src/main/java/com/lifting/app/core/navigation/screens/Screen.kt
index 9f3abf8..325b81c 100644
--- a/core/navigation/src/main/java/com/lifting/app/core/navigation/screens/Screen.kt
+++ b/core/navigation/src/main/java/com/lifting/app/core/navigation/screens/Screen.kt
@@ -55,5 +55,6 @@ sealed class LiftingScreen(
//<
@Serializable data class CreateExercisesBottomSheet(val route: String = this.toString()) : LiftingScreen()
@Serializable data class ExercisesCategoryBottomSheet(val route: String = this.toString()) : LiftingScreen()
+ @Serializable data class ExercisesMuscleBottomSheet(val route: String = this.toString()) : LiftingScreen()
//
}
\ No newline at end of file
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseScreen.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseScreen.kt
index 62828a3..a6d836c 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseScreen.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseScreen.kt
@@ -114,8 +114,8 @@ internal fun CreateExerciseScreenSuccess(
SingleSelectableCard(
name = "Primary Muscle",
- value = state.selectedMuscle,
- onClick = { }
+ value = state.selectedMuscle?.name,
+ onClick = { onEvent(CreateExerciseUIEvent.OnMuscleClicked(state.selectedMuscle?.tag)) }
)
}
}
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEffect.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEffect.kt
index df93705..acb963f 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEffect.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEffect.kt
@@ -8,4 +8,5 @@ import com.lifting.app.core.base.viewmodel.Effect
sealed interface CreateExerciseUIEffect : Effect {
data object NavigateBack : CreateExerciseUIEffect
data class NavigateToCategories(val selectedCategory: String) : CreateExerciseUIEffect
+ data class NavigateToMuscles(val selectedMuscle: String?) : CreateExerciseUIEffect
}
\ No newline at end of file
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEvent.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEvent.kt
index d4d5b17..8dee172 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEvent.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIEvent.kt
@@ -1,7 +1,6 @@
package com.lifting.app.feature.create_exercise
import com.lifting.app.core.base.viewmodel.Event
-import com.lifting.app.core.model.ExerciseCategory
/**
* Created by bedirhansaricayir on 21.08.2024
@@ -11,7 +10,8 @@ sealed interface CreateExerciseUIEvent : Event {
data object OnActionClick : CreateExerciseUIEvent
data class OnExerciseNameChanged(val exerciseName: String) : CreateExerciseUIEvent
data class OnExerciseNotesChanged(val exerciseNotes: String) : CreateExerciseUIEvent
- data class OnCategoryChanged(val category: ExerciseCategory) : CreateExerciseUIEvent
+ data class OnCategoryChanged(val category: String) : CreateExerciseUIEvent
data class OnSelectedMuscleChanged(val selectedMuscle: String) : CreateExerciseUIEvent
data class OnCategoryClicked(val selectedCategory: String) : CreateExerciseUIEvent
+ data class OnMuscleClicked(val selectedMuscle: String?) : CreateExerciseUIEvent
}
\ No newline at end of file
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIState.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIState.kt
index 7f93e48..4e968dd 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIState.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseUIState.kt
@@ -15,7 +15,7 @@ sealed interface CreateExerciseUIState : State {
val categories: List,
val selectedCategory: ExerciseCategory,
val muscles: List,
- val selectedMuscle: String? = null
+ val selectedMuscle: Muscle? = null
) : CreateExerciseUIState
data class Error(val message: String?) : CreateExerciseUIState
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseViewModel.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseViewModel.kt
index c06f313..ee9f6cc 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseViewModel.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/CreateExerciseViewModel.kt
@@ -4,8 +4,10 @@ import androidx.lifecycle.viewModelScope
import com.lifting.app.core.base.viewmodel.BaseViewModel
import com.lifting.app.core.data.repository.exercises.ExercisesRepository
import com.lifting.app.core.data.repository.muscles.MusclesRepository
+import com.lifting.app.core.data.repository.muscles.parseToMuscle
import com.lifting.app.core.model.ExerciseCategory
import com.lifting.app.core.model.allExerciseCategories
+import com.lifting.app.core.model.parseToExerciseCategory
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onStart
@@ -33,6 +35,7 @@ class CreateExerciseViewModel @Inject constructor(
is CreateExerciseUIEvent.OnExerciseNotesChanged -> updateExerciseNotes(event.exerciseNotes)
is CreateExerciseUIEvent.OnSelectedMuscleChanged -> updateSelectedMuscle(event.selectedMuscle)
is CreateExerciseUIEvent.OnCategoryClicked -> navigateToCategoriesEffect(event.selectedCategory)
+ is CreateExerciseUIEvent.OnMuscleClicked -> navigateToMusclesEffect(event.selectedMuscle)
}
}
@@ -74,7 +77,7 @@ class CreateExerciseViewModel @Inject constructor(
name = this.exerciseName,
notes = this.exerciseNotes,
category = this.selectedCategory,
- primaryMuscleTag = this.selectedMuscle,
+ primaryMuscleTag = this.selectedMuscle?.tag,
)
}
}
@@ -89,9 +92,9 @@ class CreateExerciseViewModel @Inject constructor(
setEffect(CreateExerciseUIEffect.NavigateToCategories(selectedCategory))
}
- private fun updateSelectedCategory(selectedCategory: ExerciseCategory) {
+ private fun updateSelectedCategory(selectedCategory: String) {
updateState { currentState ->
- (currentState as CreateExerciseUIState.Success).copy(selectedCategory = selectedCategory)
+ (currentState as CreateExerciseUIState.Success).copy(selectedCategory = selectedCategory.parseToExerciseCategory())
}
}
@@ -109,7 +112,11 @@ class CreateExerciseViewModel @Inject constructor(
private fun updateSelectedMuscle(selectedMuscle: String) {
updateState { currentState ->
- (currentState as CreateExerciseUIState.Success).copy(selectedMuscle = selectedMuscle)
+ (currentState as CreateExerciseUIState.Success).copy(selectedMuscle = selectedMuscle.parseToMuscle())
}
}
+
+ private fun navigateToMusclesEffect(selectedMuscle: String?) {
+ setEffect(CreateExerciseUIEffect.NavigateToMuscles(selectedMuscle))
+ }
}
\ No newline at end of file
diff --git a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/navigation/CreateExerciseNavigation.kt b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/navigation/CreateExerciseNavigation.kt
index a5f1836..fe807f2 100644
--- a/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/navigation/CreateExerciseNavigation.kt
+++ b/feature/create-exercise/src/main/kotlin/com/lifting/app/feature/create_exercise/navigation/CreateExerciseNavigation.kt
@@ -8,7 +8,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
-import com.lifting.app.core.model.parseToExerciseCategory
import com.lifting.app.core.navigation.screens.LiftingScreen
import com.lifting.app.feature.create_exercise.CreateExerciseScreen
import com.lifting.app.feature.create_exercise.CreateExerciseUIEffect
@@ -21,13 +20,15 @@ import com.lifting.app.feature.create_exercise.CreateExerciseViewModel
val CREATE_EXERCISE_SCREEN = LiftingScreen.CreateExercisesBottomSheet().route
const val SELECTED_EXERCISE_CATEGORY = "SELECTED_EXERCISE_CATEGORY"
+const val SELECTED_EXERCISE_MUSCLE = "SELECTED_EXERCISE_MUSCLE"
fun NavController.navigateToCreateExercise() = navigate(CREATE_EXERCISE_SCREEN)
fun NavGraphBuilder.createExerciseBottomSheetScreen(
navController: NavController,
onNavigateBack: () -> Unit,
- onNavigateToCategories: (String) -> Unit
+ onNavigateToCategories: () -> Unit,
+ onNavigateToMuscles: () -> Unit,
) {
bottomSheet(CREATE_EXERCISE_SCREEN) {
@@ -39,7 +40,20 @@ fun NavGraphBuilder.createExerciseBottomSheetScreen(
effect.collect {
when(it) {
CreateExerciseUIEffect.NavigateBack -> onNavigateBack()
- is CreateExerciseUIEffect.NavigateToCategories -> onNavigateToCategories(it.selectedCategory)
+ is CreateExerciseUIEffect.NavigateToCategories -> {
+ navController.currentBackStackEntry?.savedStateHandle?.set(
+ SELECTED_EXERCISE_CATEGORY,
+ value = it.selectedCategory
+ )
+ onNavigateToCategories()
+ }
+ is CreateExerciseUIEffect.NavigateToMuscles -> {
+ navController.currentBackStackEntry?.savedStateHandle?.set(
+ SELECTED_EXERCISE_MUSCLE,
+ value = it.selectedMuscle
+ )
+ onNavigateToMuscles()
+ }
}
}
}
@@ -49,9 +63,20 @@ fun NavGraphBuilder.createExerciseBottomSheetScreen(
?.getStateFlow(SELECTED_EXERCISE_CATEGORY, null)
?.collectAsState()
+ val selectedMuscle = navController.currentBackStackEntry
+ ?.savedStateHandle
+ ?.getStateFlow(SELECTED_EXERCISE_MUSCLE,null)
+ ?.collectAsState()
+
LaunchedEffect(selectedCategory) {
selectedCategory?.value?.let {
- viewModel.setEvent(CreateExerciseUIEvent.OnCategoryChanged(it.parseToExerciseCategory()))
+ viewModel.setEvent(CreateExerciseUIEvent.OnCategoryChanged(it))
+ }
+ }
+
+ LaunchedEffect(selectedMuscle) {
+ selectedMuscle?.value?.let {
+ viewModel.setEvent(CreateExerciseUIEvent.OnSelectedMuscleChanged(it))
}
}
diff --git a/feature/exercises-muscle/build.gradle.kts b/feature/exercises-muscle/build.gradle.kts
new file mode 100644
index 0000000..737b1fb
--- /dev/null
+++ b/feature/exercises-muscle/build.gradle.kts
@@ -0,0 +1,52 @@
+plugins {
+ id(BuildPlugins.ANDROID_LIBRARY_PLUGIN)
+ id(BuildPlugins.KOTLIN_ANDROID_PLUGIN)
+ id(BuildPlugins.DAGGER_HILT)
+ id(BuildPlugins.KSP_PLUGIN)
+}
+
+android {
+ namespace = "com.lifting.app.feature.exercises_muscle"
+ compileSdk = AppConfig.COMPILE_SDK
+
+ defaultConfig {
+ minSdk = AppConfig.MIN_SDK
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ buildFeatures {
+ compose = true
+ }
+
+ composeOptions {
+ kotlinCompilerExtensionVersion = Versions.kotlinCompilerExtensionVersion
+ }
+
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+
+dependencies {
+ api(project(":core:base"))
+ api(project(":core:navigation"))
+ api(project(":core:ui"))
+ api(project(":core:data"))
+
+
+ Kotlin.list.forEach(::api)
+
+ with(Di) {
+ implementation(hiltAndroid)
+ implementation(hiltNavigationCompose)
+ ksp(hiltCompiler)
+ ksp(hiltAndroidCompiler)
+ }
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleScreen.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleScreen.kt
new file mode 100644
index 0000000..ed7afd9
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleScreen.kt
@@ -0,0 +1,121 @@
+package com.lifting.app.feature.exercises_muscle
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.lifting.app.core.designsystem.LiftingTheme
+import com.lifting.app.core.model.Muscle
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+
+@Composable
+internal fun ExercisesMuscleScreen(
+ modifier: Modifier = Modifier,
+ state: ExercisesMuscleUIState,
+ onEvent: (ExercisesMuscleUIEvent) -> Unit
+) {
+ ExercisesMuscleScreenContent(
+ modifier = modifier,
+ state = state,
+ onEvent = onEvent
+ )
+}
+
+@Composable
+internal fun ExercisesMuscleScreenContent(
+ modifier: Modifier = Modifier,
+ state: ExercisesMuscleUIState,
+ onEvent: (ExercisesMuscleUIEvent) -> Unit
+) {
+ when (state) {
+ is ExercisesMuscleUIState.Error -> {}
+ ExercisesMuscleUIState.Loading -> {}
+ is ExercisesMuscleUIState.Success ->
+ ExercisesMuscleListScreen(
+ modifier = Modifier,
+ state = state,
+ onEvent = onEvent
+ )
+ }
+}
+
+@Composable
+internal fun ExercisesMuscleListScreen(
+ modifier: Modifier = Modifier,
+ state: ExercisesMuscleUIState.Success,
+ onEvent: (ExercisesMuscleUIEvent) -> Unit
+) {
+ LazyColumn(
+ modifier = modifier
+ .fillMaxWidth()
+ .background(LiftingTheme.colors.background),
+ ) {
+ item {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 24.dp, vertical = 12.dp),
+ text = "Select Muscle",
+ textAlign = TextAlign.Center,
+ style = LiftingTheme.typography.header2,
+ color = LiftingTheme.colors.onBackground
+ )
+ }
+ items(
+ state.muscles,
+ key = { muscle -> muscle.tag }
+ ) { muscle ->
+ ExercisesMuscleListItem(
+ muscle = muscle,
+ isSelected = muscle.tag == state.selectedMuscle,
+ onClick = { onEvent(ExercisesMuscleUIEvent.OnMuscleClick(muscle)) }
+ )
+ }
+ }
+}
+
+@Composable
+internal fun ExercisesMuscleListItem(
+ modifier: Modifier = Modifier,
+ muscle: Muscle,
+ isSelected: Boolean = false,
+ onClick: () -> Unit
+) {
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .clickable { onClick() }
+ .padding(horizontal = 24.dp, vertical = 12.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = muscle.name,
+ color = LiftingTheme.colors.onBackground,
+ style = LiftingTheme.typography.subtitle1
+ )
+
+ if (isSelected) {
+ Icon(
+ imageVector = LiftingTheme.icons.done,
+ contentDescription = "Selected",
+ tint = LiftingTheme.colors.primary
+ )
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEffect.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEffect.kt
new file mode 100644
index 0000000..355c805
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEffect.kt
@@ -0,0 +1,12 @@
+package com.lifting.app.feature.exercises_muscle
+
+import com.lifting.app.core.base.viewmodel.Effect
+import com.lifting.app.core.model.Muscle
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+
+sealed interface ExercisesMuscleUIEffect : Effect {
+ data class SetMuscleToBackStack(val selectedMuscle: Muscle) : ExercisesMuscleUIEffect
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEvent.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEvent.kt
new file mode 100644
index 0000000..454b317
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIEvent.kt
@@ -0,0 +1,13 @@
+package com.lifting.app.feature.exercises_muscle
+
+import com.lifting.app.core.base.viewmodel.Event
+import com.lifting.app.core.model.Muscle
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+
+sealed interface ExercisesMuscleUIEvent : Event {
+ data class OnMuscleClick(val muscle: Muscle) : ExercisesMuscleUIEvent
+ data class OnSelectedMuscleChanged(val muscle: String) : ExercisesMuscleUIEvent
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIState.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIState.kt
new file mode 100644
index 0000000..bc5fffe
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleUIState.kt
@@ -0,0 +1,13 @@
+package com.lifting.app.feature.exercises_muscle
+
+import com.lifting.app.core.base.viewmodel.State
+import com.lifting.app.core.model.Muscle
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+sealed interface ExercisesMuscleUIState : State {
+ data object Loading : ExercisesMuscleUIState
+ data class Success(val muscles: List, val selectedMuscle: String? = "") : ExercisesMuscleUIState
+ data class Error(val message: String) : ExercisesMuscleUIState
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleViewModel.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleViewModel.kt
new file mode 100644
index 0000000..f21919e
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/ExercisesMuscleViewModel.kt
@@ -0,0 +1,69 @@
+package com.lifting.app.feature.exercises_muscle
+
+import androidx.lifecycle.viewModelScope
+import com.lifting.app.core.base.viewmodel.BaseViewModel
+import com.lifting.app.core.data.repository.muscles.MusclesRepository
+import com.lifting.app.core.model.Muscle
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+
+@HiltViewModel
+class ExercisesMuscleViewModel @Inject constructor(
+ private val musclesRepository: MusclesRepository
+) : BaseViewModel() {
+
+ private val selectedMuscle = MutableStateFlow("")
+
+ override fun setInitialState(): ExercisesMuscleUIState = ExercisesMuscleUIState.Loading
+
+ override fun handleEvents(event: ExercisesMuscleUIEvent) {
+ when (event) {
+ is ExercisesMuscleUIEvent.OnMuscleClick -> onMuscleClick(event.muscle)
+ is ExercisesMuscleUIEvent.OnSelectedMuscleChanged -> onSelectedMuscleChanged(event.muscle)
+ }
+ }
+
+ init {
+ setUIState()
+ }
+
+ private fun setUIState() {
+ viewModelScope.launch {
+ musclesRepository.getMuscles()
+ .onStart {
+ setState(ExercisesMuscleUIState.Loading)
+ }
+ .catch { throwable ->
+ setState(
+ ExercisesMuscleUIState.Error(
+ message = throwable.message ?: "Something Went Wrong!"
+ )
+ )
+ }
+ .collect { muscles ->
+ setState(
+ ExercisesMuscleUIState.Success(
+ muscles = muscles,
+ selectedMuscle = selectedMuscle.value
+ )
+ )
+ }
+ }
+ }
+
+ private fun onMuscleClick(muscle: Muscle) {
+ setEffect(ExercisesMuscleUIEffect.SetMuscleToBackStack(muscle))
+ }
+
+ private fun onSelectedMuscleChanged(muscle: String) {
+ selectedMuscle.value = muscle
+ }
+}
\ No newline at end of file
diff --git a/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/navigation/ExercisesMuscleNavigation.kt b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/navigation/ExercisesMuscleNavigation.kt
new file mode 100644
index 0000000..088674f
--- /dev/null
+++ b/feature/exercises-muscle/src/main/kotlin/com/lifting/app/feature/exercises_muscle/navigation/ExercisesMuscleNavigation.kt
@@ -0,0 +1,65 @@
+package com.lifting.app.feature.exercises_muscle.navigation
+
+import androidx.compose.material.navigation.bottomSheet
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import com.lifting.app.core.navigation.screens.LiftingScreen
+import com.lifting.app.feature.exercises_muscle.ExercisesMuscleScreen
+import com.lifting.app.feature.exercises_muscle.ExercisesMuscleUIEffect
+import com.lifting.app.feature.exercises_muscle.ExercisesMuscleUIEvent
+import com.lifting.app.feature.exercises_muscle.ExercisesMuscleViewModel
+
+/**
+ * Created by bedirhansaricayir on 28.08.2024
+ */
+
+const val SELECTED_EXERCISE_MUSCLE = "SELECTED_EXERCISE_MUSCLE"
+
+val EXERCISES_MUSCLE_SCREEN = LiftingScreen.ExercisesMuscleBottomSheet().route
+
+fun NavController.navigateToExercisesMuscle() = navigate(EXERCISES_MUSCLE_SCREEN)
+
+fun NavGraphBuilder.exercisesMuscleBottomSheetScreen(
+ navController: NavController
+) {
+ bottomSheet(EXERCISES_MUSCLE_SCREEN) {
+
+ val viewModel: ExercisesMuscleViewModel = hiltViewModel()
+ val state by viewModel.state.collectAsStateWithLifecycle()
+ val effect = viewModel.effect
+
+ LaunchedEffect(effect) {
+ effect.collect {
+ when(it) {
+ is ExercisesMuscleUIEffect.SetMuscleToBackStack -> {
+
+ navController.previousBackStackEntry?.savedStateHandle?.set(
+ SELECTED_EXERCISE_MUSCLE,
+ it.selectedMuscle.tag
+ )
+ navController.popBackStack()
+
+ }
+ }
+ }
+ }
+
+ val selectedMuscle = navController.previousBackStackEntry?.savedStateHandle?.get(SELECTED_EXERCISE_MUSCLE)
+
+ LaunchedEffect(selectedMuscle) {
+ selectedMuscle?.let {
+ viewModel.setEvent(ExercisesMuscleUIEvent.OnSelectedMuscleChanged(selectedMuscle))
+ }
+ }
+
+ ExercisesMuscleScreen(
+ state = state,
+ onEvent = viewModel::setEvent
+ )
+
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index dbc66c7..2614249 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -29,3 +29,4 @@ include(":core:ui")
include(":feature:exercises")
include(":feature:create-exercise")
include(":feature:exercises-category")
+include(":feature:exercises-muscle")
\ No newline at end of file