Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

-
- A new toggle to show images was introduced (off by default). [#29](https://github.com/LibreFitOrg/LibreFit/issues/29)

### Deprecated

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ private val SHOW_KEEP_ANDROID_OPEN_KEY = booleanPreferencesKey("showKeepAndroidO
private val USE_SCROLL_WHEEL_FOR_INPUT_KEY = booleanPreferencesKey("use_number_picker")
private val DISMISS_SCROLL_WHELL_INPUT_AUTOMATICALLY =
booleanPreferencesKey("dismiss_input_modal_bottom_sheet_automatically_key")
private val SHOW_EXERCISES_IMAGES_KEY = booleanPreferencesKey("show_exercises_images_key")
private val UNIT_SYSTEM_KEY = stringPreferencesKey("unit_system")
/**
* Central repository managing application-level preferences, including theme, unit systems, and language.
Expand Down Expand Up @@ -169,6 +170,14 @@ class UserPreferencesRepository @Inject constructor(
initialValue = true
)

val showExercisesImages: StateFlow<Boolean?> = dataStore.data
.map { preferences -> preferences[SHOW_EXERCISES_IMAGES_KEY] }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = null
)

val dismissScrollWheelInputAutomatically: StateFlow<Boolean> = dataStore.data
.map { preferences -> preferences[DISMISS_SCROLL_WHELL_INPUT_AUTOMATICALLY] == true }
.stateIn(
Expand Down Expand Up @@ -314,6 +323,12 @@ class UserPreferencesRepository @Inject constructor(
dataStore.edit { preferences -> preferences[USE_SCROLL_WHEEL_FOR_INPUT_KEY] = useScroll }
}

suspend fun saveShowExercisesImages(show: Boolean) {
dataStore.edit { preferences ->
preferences[SHOW_EXERCISES_IMAGES_KEY] = show
}
}

suspend fun saveDismissScrollWheelInputAutomatically(dismissAutomatically: Boolean) {
dataStore.edit { preferences ->
preferences[DISMISS_SCROLL_WHELL_INPUT_AUTOMATICALLY] = dismissAutomatically
Expand Down
39 changes: 22 additions & 17 deletions app/src/main/java/org/librefit/ui/components/ExerciseCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import kotlin.time.Duration.Companion.seconds
* @param isDragging when `true`, it applies a shadow to further emphasize with a shadow that the card is dragged.
* @param useScrollWheelForInput If `true`, [InputModalBottomSheet] appears instead of keyboard
* @param dismissScrollWheelInputAutomatically If both this and [useScrollWheelForInput] are `true`, the [InputModalBottomSheet] will be dismissed automatically after first edit.
* @param showExercisesImages If `true`, it shows image of exercise
* @param updateExerciseNotes A function to update notes based on [UiExercise.id]. For more details, refer to
* [org.librefit.ui.screens.workout.WorkoutScreenViewModel.updateExerciseNotes] and
* [org.librefit.ui.screens.editWorkout.EditWorkoutScreenViewModel.updateExerciseNotes].
Expand Down Expand Up @@ -195,6 +196,7 @@ fun SharedTransitionScope.ExerciseCard(
isDragging: Boolean,
useScrollWheelForInput: Boolean,
dismissScrollWheelInputAutomatically: Boolean,
showExercisesImages: Boolean?,
onReorderRequest: () -> Unit,
deleteSet: (Long) -> Unit,
updateExerciseNotes: (String, Long) -> Unit,
Expand Down Expand Up @@ -244,23 +246,25 @@ fun SharedTransitionScope.ExerciseCard(
) {
val model =
remember(exerciseWithSets.exerciseDC.images) { exerciseWithSets.exerciseDC.images.firstOrNull() }
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = exerciseWithSets.exerciseDC.name,
contentScale = ContentScale.Crop,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.padding(end = 10.dp)
.sharedElement(
sharedContentState = rememberSharedContentState(
key = exerciseWithSets.exercise.id.toString() + exerciseWithSets.exerciseDC.id
),
animatedVisibilityScope = animatedVisibilityScope
)
.size(50.dp)
.clip(MaterialTheme.shapes.medium)
)
if (showExercisesImages == true) {
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = exerciseWithSets.exerciseDC.name,
contentScale = ContentScale.Crop,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.padding(end = 10.dp)
.sharedElement(
sharedContentState = rememberSharedContentState(
key = exerciseWithSets.exercise.id.toString() + exerciseWithSets.exerciseDC.id
),
animatedVisibilityScope = animatedVisibilityScope
)
.size(50.dp)
.clip(MaterialTheme.shapes.medium)
)
}
Text(
text = exerciseWithSets.exerciseDC.name,
style = MaterialTheme.typography.headlineSmall,
Expand Down Expand Up @@ -1027,6 +1031,7 @@ private fun ExerciseCardPreview() {
isDragging = false,
useScrollWheelForInput = false,
dismissScrollWheelInputAutomatically = false,
showExercisesImages = false,
updateExerciseNotes = { notes, _ ->
e.value = e.value.copy(exercise = e.value.exercise.copy(notes = notes))
},
Expand Down
38 changes: 21 additions & 17 deletions app/src/main/java/org/librefit/ui/components/ExerciseCardSmall.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import org.librefit.util.Formatter.formatTime
fun SharedTransitionScope.ExerciseCardSmall(
exerciseWithSets: UiExerciseWithSets,
isRoutine: Boolean = false,
showExercisesImages: Boolean?,
animatedVisibilityScope: AnimatedVisibilityScope,
onDetail: () -> Unit
) {
Expand All @@ -103,23 +104,25 @@ fun SharedTransitionScope.ExerciseCardSmall(
) {
val model =
remember(exerciseWithSets.exerciseDC.images) { exerciseWithSets.exerciseDC.images.firstOrNull() }
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = exerciseWithSets.exerciseDC.name,
contentScale = ContentScale.Crop,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.padding(end = 10.dp)
.sharedElement(
sharedContentState = rememberSharedContentState(
key = exerciseWithSets.exercise.id.toString() + exerciseWithSets.exerciseDC.id
),
animatedVisibilityScope = animatedVisibilityScope
)
.size(50.dp)
.clip(MaterialTheme.shapes.medium)
)
if (showExercisesImages == true) {
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = exerciseWithSets.exerciseDC.name,
contentScale = ContentScale.Crop,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.padding(end = 10.dp)
.sharedElement(
sharedContentState = rememberSharedContentState(
key = exerciseWithSets.exercise.id.toString() + exerciseWithSets.exerciseDC.id
),
animatedVisibilityScope = animatedVisibilityScope
)
.size(50.dp)
.clip(MaterialTheme.shapes.medium)
)
}
Text(
modifier = Modifier.weight(1f),
text = exerciseWithSets.exerciseDC.name,
Expand Down Expand Up @@ -289,6 +292,7 @@ private fun ExerciseCardSmallPreview() {
),
sets = persistentListOf(UiSet(completed = true), UiSet(reps = 10), UiSet())
),
showExercisesImages = null,
animatedVisibilityScope = this
) { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ fun SharedTransitionScope.EditExerciseScreen(

val exerciseDC by viewModel.exerciseDC.collectAsStateWithLifecycle()

val showExercisesImages by viewModel.showExercisesImages.collectAsStateWithLifecycle()

val isCreateMode = exerciseDC.id.isBlank()

EditExerciseScreenContent(
Expand All @@ -103,6 +105,7 @@ fun SharedTransitionScope.EditExerciseScreen(
instructions = exerciseDC.instructions,
category = exerciseDC.category,
images = exerciseDC.images,
showExercisesImages = showExercisesImages,
navigateBack = navController::navigateUp,
animatedVisibilityScope = animatedVisibilityScope,
updateValue = viewModel::updateValue,
Expand Down Expand Up @@ -141,6 +144,7 @@ private fun SharedTransitionScope.EditExerciseScreenContent(
instructions: List<String>,
images: List<String>,
category: Category,
showExercisesImages: Boolean?,
animatedVisibilityScope: AnimatedVisibilityScope,
navigateBack: () -> Unit,
updateValue: (ExerciseProperty) -> Unit,
Expand Down Expand Up @@ -191,26 +195,28 @@ private fun SharedTransitionScope.EditExerciseScreenContent(
item {
// TODO: implement display all images (like in a horizontal pager)
val model = remember(images) { images.firstOrNull() }
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = name,
contentScale = ContentScale.Crop,
filterQuality = FilterQuality.High,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.sharedElement(
sharedContentState = rememberSharedContentState(stringId + exerciseDcId),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxWidth()
.clip(MaterialTheme.shapes.extraLarge)
.border(
0.5.dp,
color = MaterialTheme.colorScheme.outlineVariant,
shape = MaterialTheme.shapes.extraLarge
),
)
if (showExercisesImages == true) {
AsyncImage(
model = model?.let { "file:///android_asset/${it}" },
fallback = painterResource(R.drawable.no_image),
contentDescription = name,
contentScale = ContentScale.Crop,
filterQuality = FilterQuality.High,
colorFilter = if (model == null) ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) else null,
modifier = Modifier
.sharedElement(
sharedContentState = rememberSharedContentState(stringId + exerciseDcId),
animatedVisibilityScope = animatedVisibilityScope
)
.fillMaxWidth()
.clip(MaterialTheme.shapes.extraLarge)
.border(
0.5.dp,
color = MaterialTheme.colorScheme.outlineVariant,
shape = MaterialTheme.shapes.extraLarge
),
)
}
}
item {
}
Expand Down Expand Up @@ -420,6 +426,7 @@ private fun EditExerciseScreenContentPreview() {
instructions = e.instructions,
category = e.category,
images = e.images,
showExercisesImages = null,
animatedVisibilityScope = this,
saveExercise = {},
updatePrimaryMuscles = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.librefit.db.repository.DatasetRepository
import org.librefit.db.repository.UserPreferencesRepository
import org.librefit.enums.exercise.Category
import org.librefit.enums.exercise.Equipment
import org.librefit.enums.exercise.ExerciseProperty
Expand All @@ -38,9 +39,12 @@ import kotlin.uuid.Uuid
@HiltViewModel
class EditExerciseScreenViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val datasetRepository: DatasetRepository
private val datasetRepository: DatasetRepository,
userPreferencesRepository: UserPreferencesRepository
) : ViewModel() {

val showExercisesImages = userPreferencesRepository.showExercisesImages

val exerciseDCid = savedStateHandle.toRoute<Route.EditExerciseScreen>().exerciseDCid

@OptIn(ExperimentalUuidApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ fun SharedTransitionScope.EditWorkoutScreen(

val useScrollWheelForInput by viewModel.useScrollWheelForInput.collectAsStateWithLifecycle()

val showExercisesImages by viewModel.showExercisesImages.collectAsStateWithLifecycle()

val dismissInputAutomatically by viewModel.dismissScrollWheelInputAutomatically.collectAsStateWithLifecycle()

LaunchedEffect(Unit) {
Expand Down Expand Up @@ -117,6 +119,7 @@ fun SharedTransitionScope.EditWorkoutScreen(
isTitleEmpty = viewModel.isTitleEmpty(),
dismissInputAutomatically = dismissInputAutomatically,
useScrollWheelForInput = useScrollWheelForInput,
showExercisesImages = showExercisesImages,
updateTitle = viewModel::updateTitle,
updateNotes = viewModel::updateNotes,
updateSetTime = viewModel::updateSetTime,
Expand Down Expand Up @@ -149,6 +152,7 @@ private fun SharedTransitionScope.EditWorkoutScreenContent(
isTitleEmpty: Boolean,
dismissInputAutomatically: Boolean,
useScrollWheelForInput: Boolean,
showExercisesImages: Boolean?,
updateTitle: (String) -> Unit,
updateNotes: (String) -> Unit,
deleteSet: (Long) -> Unit,
Expand Down Expand Up @@ -339,6 +343,7 @@ private fun SharedTransitionScope.EditWorkoutScreenContent(
addSet = addSetToExercise,
isDragging = isDragging,
useScrollWheelForInput = useScrollWheelForInput,
showExercisesImages = showExercisesImages,
dismissScrollWheelInputAutomatically = dismissInputAutomatically,
onDetail = { id, idExerciseDC ->
navController.navigate(
Expand Down Expand Up @@ -425,6 +430,7 @@ private fun EditWorkoutScreenPreview() {
isTitleEmpty = false,
useScrollWheelForInput = false,
dismissInputAutomatically = false,
showExercisesImages = null,
updateTitle = { _ -> },
updateNotes = { _ -> },
addSetToExercise = { _ -> },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class EditWorkoutScreenViewModel @Inject constructor(
@param:IoDispatcher private val ioDispatcher: CoroutineDispatcher,
userPreferencesRepository: UserPreferencesRepository
) : ViewModel() {

val showExercisesImages = userPreferencesRepository.showExercisesImages
val useScrollWheelForInput = userPreferencesRepository.useScrollWheelForInput

val dismissScrollWheelInputAutomatically =
Expand Down
Loading
Loading