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

Commit

Permalink
Improve exercises screen
Browse files Browse the repository at this point in the history
  • Loading branch information
AnkitSuda committed Nov 22, 2022
1 parent eac1dab commit f6fe396
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@

package com.ankitsuda.rebound.data.db.daos

import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import com.ankitsuda.rebound.domain.entities.Exercise
import com.ankitsuda.rebound.domain.entities.ExerciseWithExtraInfo
import com.ankitsuda.rebound.domain.entities.ExerciseWithMuscle
import com.ankitsuda.rebound.domain.entities.LogEntriesWithWorkout
import kotlinx.coroutines.flow.Flow
Expand All @@ -32,6 +34,12 @@ interface ExercisesDao {
@Query("SELECT * FROM exercises ORDER BY name")
fun getAllExercises(): Flow<List<Exercise>>

@Query(
"""
"""
)
fun getAllExercisesWithExtraInfoPaged(searchQuery: String?): PagingSource<Int, ExerciseWithExtraInfo>

@Query("SELECT * FROM exercises ORDER BY name")
fun getAllExercisesWithMuscles(): Flow<List<ExerciseWithMuscle>>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package com.ankitsuda.rebound.data.repositories

import androidx.paging.Pager
import androidx.paging.PagingConfig
import com.ankitsuda.base.utils.generateId
import com.ankitsuda.rebound.data.db.daos.ExercisesDao
import com.ankitsuda.rebound.data.db.daos.MusclesDao
Expand Down Expand Up @@ -62,6 +64,11 @@ class ExercisesRepository @Inject constructor(
list
}

fun getExercisesWithExtraInfoPaged(searchQuery: String? = null) = Pager(PagingConfig(pageSize = 15)) {
exercisesDao.getAllExercisesWithExtraInfoPaged(searchQuery = searchQuery)
}.flow


suspend fun createExercise(
name: String? = null,
notes: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ import java.time.LocalDateTime
import java.util.*

data class ExerciseWithExtraInfo(
@Embedded
var exercise: Exercise,
@Relation(
parentColumn = "primary_muscle_tag",
entityColumn = "tag"
)
var primaryMuscle: Muscle?,
@ColumnInfo(name = "logs_count")
var logsCount: Long,
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.items
import com.ankitsuda.base.utils.generateId
import com.ankitsuda.navigation.LeafScreen
import com.ankitsuda.navigation.LocalNavigator
import com.ankitsuda.navigation.Navigator
import com.ankitsuda.navigation.RESULT_EXERCISES_SCREEN_EXERCISE_ID
import com.ankitsuda.rebound.domain.entities.ExerciseWithExtraInfo
import com.ankitsuda.rebound.ui.components.*
import com.ankitsuda.rebound.ui.theme.LocalThemeState
Expand All @@ -43,11 +48,6 @@ import com.google.accompanist.pager.ExperimentalPagerApi
import me.onebone.toolbar.ScrollStrategy
import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState

@OptIn(
ExperimentalPagerApi::class,
ExperimentalFoundationApi::class,
ExperimentalAnimationApi::class
)
@Composable
fun ExercisesScreen(
navController: NavController,
Expand All @@ -58,7 +58,7 @@ fun ExercisesScreen(
val isSearchMode by viewModel.isSearchMode.observeAsState(false)
val searchTerm by viewModel.searchTerm.observeAsState("")

val groupedExercises by viewModel.groupedExercises.collectAsState(initial = emptyMap())
val exercisesPaged = viewModel.exercisesPaged.collectAsLazyPagingItems()

val layout: @Composable () -> Unit = {
ExercisesScreenContent(
Expand All @@ -67,13 +67,14 @@ fun ExercisesScreen(
isBottomSheet = isBottomSheet,
isSearchMode = isSearchMode,
searchTerm = searchTerm,
groupedExercises = groupedExercises,
exercisesPaged = exercisesPaged,
onToggleSearchMode = {
viewModel.toggleSearchMode()
},
onChangeSearchTerm = {
viewModel.setSearchTerm(it)
}
) {
viewModel.setSearchTerm(it)
}
)
}

if (isBottomSheet) {
Expand All @@ -85,15 +86,14 @@ fun ExercisesScreen(
}
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun ExercisesScreenContent(
navController: NavController,
navigator: Navigator,
isBottomSheet: Boolean,
isSearchMode: Boolean,
searchTerm: String,
groupedExercises: Map<String, List<ExerciseWithExtraInfo>>,
exercisesPaged: LazyPagingItems<Any>,
onToggleSearchMode: () -> Unit,
onChangeSearchTerm: (String) -> Unit
) {
Expand Down Expand Up @@ -149,28 +149,32 @@ private fun ExercisesScreenContent(
modifier = Modifier
.fillMaxSize(),
) {
for (group in groupedExercises) {
stickyHeader(key = group.key) {
Text(
modifier = Modifier
.fillMaxWidth()
.background(LocalThemeState.current.backgroundColor)
.padding(horizontal = 24.dp, vertical = 8.dp),
text = group.key,
style = ReboundTheme.typography.caption,
color = LocalThemeState.current.onBackgroundColor.copy(alpha = 0.75f)
)
items(exercisesPaged, key = {
when (it) {
is ExerciseWithExtraInfo -> it.exercise.exerciseId
is String -> "header_$it"
else -> generateId()
}

items(items = group.value, key = { it.exercise.exerciseId }) { item ->
ExerciseItem(
}) { item ->
when (item) {
is String ->
Text(
modifier = Modifier
.fillMaxWidth()
.background(LocalThemeState.current.backgroundColor)
.padding(horizontal = 24.dp, vertical = 8.dp),
text = item,
style = ReboundTheme.typography.caption,
color = LocalThemeState.current.onBackgroundColor.copy(alpha = 0.75f)
)
is ExerciseWithExtraInfo -> ExerciseItem(
name = item.exercise.name.toString(),
muscle = item.primaryMuscle?.name.toString(),
totalLogs = item.logsCount,
onClick = {
if (isBottomSheet) {
navController.previousBackStackEntry?.savedStateHandle?.set(
"result_exercises_screen_exercise_id",
RESULT_EXERCISES_SCREEN_EXERCISE_ID,
item.exercise.exerciseId
)
navController.popBackStack()
Expand All @@ -181,12 +185,11 @@ private fun ExercisesScreenContent(
)
)
}
})
}
)
}
}
}


}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.insertSeparators
import com.ankitsuda.base.utils.extensions.shareWhileObserved
import com.ankitsuda.rebound.data.repositories.ExercisesRepository
import com.ankitsuda.rebound.data.repositories.MusclesRepository
Expand All @@ -33,66 +36,64 @@ import javax.inject.Inject
class ExercisesScreenViewModel @Inject constructor(
private val exercisesRepository: ExercisesRepository
) : ViewModel() {
private var _isSearchMode = MutableLiveData(false)
private var _isSearchMode = MutableStateFlow(false)
val isSearchMode = _isSearchMode

private var _searchTerm = MutableLiveData("")
private var _searchTerm = MutableStateFlow("")
val searchTerm = _searchTerm

private val allExercises = arrayListOf<ExerciseWithExtraInfo>()

private var _filteredExercises: SnapshotStateList<ExerciseWithExtraInfo> =
SnapshotStateList()
val exercisesPaged = _searchTerm.flatMapLatest {
exercisesRepository.getExercisesWithExtraInfoPaged(
searchQuery = it.trim().takeIf { q -> q.isNotBlank() }
)
.map { pagingData ->
mapPage(pagingData)
}
.cachedIn(viewModelScope)
.shareWhileObserved(viewModelScope)
}

private var _groupedExercises: MutableStateFlow<Map<String, List<ExerciseWithExtraInfo>>> =
MutableStateFlow(emptyMap())
val groupedExercises = _groupedExercises
.shareWhileObserved(viewModelScope)

init {
viewModelScope.launch {
exercisesRepository.getExercisesWithExtraInfo().collect {
allExercises.clear()
allExercises.addAll(it)
filterExercises()
private fun mapPage(pagingData: PagingData<ExerciseWithExtraInfo>): PagingData<Any> =
pagingData.insertSeparators { before, after ->
val afterFirstChar = after?.exercise?.name?.firstOrNull()?.uppercase()
if (before?.exercise?.name?.firstOrNull()
?.uppercase() != afterFirstChar
) {
afterFirstChar
} else {
null
}
}
}

fun toggleSearchMode() {
_isSearchMode.value = !(_isSearchMode.value)!!
filterExercises()
_isSearchMode.value = !_isSearchMode.value
_searchTerm.value = ""
}

fun setSearchTerm(term: String) {
_searchTerm.value = term
filterExercises()
}

private fun filterExercises() {
viewModelScope.launch {
// if (_searchTerm.value?.isNotBlank() == true) {
// _filteredExercises.value = allExercises.last()
// .filter { it.exercise.name?.contains(_searchTerm.value!!, true) == true }
// private fun filterExercises() {
// viewModelScope.launch {
// _filteredExercises.clear()
// if (_isSearchMode.value == true) {
// _filteredExercises.addAll(allExercises.filter {
// it.exercise.name?.contains(
// _searchTerm.value!!,
// true
// ) == true
// })
// } else {
Timber.d("Filtering list $allExercises")
_filteredExercises.clear()
if (_isSearchMode.value == true) {
_filteredExercises.addAll(allExercises.filter {
it.exercise.name?.contains(
_searchTerm.value!!,
true
) == true
})
} else {
_filteredExercises.addAll(allExercises)
}

_groupedExercises.emit(_filteredExercises.groupBy {
(it.exercise.name?.firstOrNull() ?: "#").toString().uppercase(Locale.getDefault())
})
// _filteredExercises.addAll(allExercises)
// }
}
}
//
// _groupedExercises.emit(_filteredExercises.groupBy {
// (it.exercise.name?.firstOrNull() ?: "#").toString().uppercase(Locale.getDefault())
// })
//// }
// }
// }

}

0 comments on commit f6fe396

Please sign in to comment.