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

Commit

Permalink
Paginate and improve history list
Browse files Browse the repository at this point in the history
  • Loading branch information
AnkitSuda committed Nov 20, 2022
1 parent 21080b6 commit 41bc1ac
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 87 deletions.
4 changes: 2 additions & 2 deletions buildSrc/src/main/java/com/ankitsuda/rebound/buildSrc/Deps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ object Deps {
const val liveData = "androidx.compose.runtime:runtime-livedata:$version"
const val activity = "androidx.activity:activity-compose:$activityVersion"
const val viewModels = "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0"
const val paging = "androidx.paging:paging-compose:1.0.0-alpha14"
const val paging = "androidx.paging:paging-compose:1.0.0-alpha17"

// private const val lottieVersion = "4.2.0"
// const val lottie = "com.airbnb.android:lottie-compose:$lottieVersion"
Expand Down Expand Up @@ -127,7 +127,7 @@ object Deps {
}

object Paging {
private const val version = "3.1.0-beta01"
private const val version = "3.1.1"

const val common = "androidx.paging:paging-common-ktx:$version"
const val runtime = "androidx.paging:paging-runtime-ktx:$version"
Expand Down
1 change: 1 addition & 0 deletions modules/core-data/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dependencies {
api project(":modules:common-data")
api project(":modules:common-ui-compose")

api Deps.Android.Room.paging
api Deps.Kotlin.stdlib

kapt Deps.Dagger.hiltCompiler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

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

import androidx.paging.PagingSource
import androidx.room.*
import androidx.sqlite.db.SupportSQLiteQuery
import com.ankitsuda.base.utils.generateId
Expand Down Expand Up @@ -143,9 +144,20 @@ interface WorkoutsDao {
@RawQuery(observedEntities = [Workout::class, ExerciseLogEntry::class, ExerciseWorkoutJunction::class])
fun getAllWorkoutsRawQuery(query: SupportSQLiteQuery): Flow<List<Workout>>

@RawQuery(observedEntities = [Workout::class, ExerciseLogEntry::class, ExerciseWorkoutJunction::class])
fun getAllWorkoutsRawQueryPaged(query: SupportSQLiteQuery): PagingSource<Int, Workout>

@Query("SELECT COUNT(*) as count, start_at as date FROM workouts WHERE date(start_at / 1000,'unixepoch') >= date(:dateStart / 1000,'unixepoch') AND date(start_at / 1000,'unixepoch') <= date(:dateEnd / 1000,'unixepoch') AND is_hidden = 0 AND in_progress = 0 GROUP BY start_at")
fun getWorkoutsCountOnDateRange(dateStart: Long, dateEnd: Long): Flow<List<CountWithDate>>

@Query("""
SELECT SUM(count) FROM (SELECT COUNT(*) as count FROM workouts WHERE
date(start_at / 10000,'unixepoch') >= date(:date / 10000,'unixepoch') AND
date(start_at / 10000,'unixepoch') <= date(:date / 10000,'unixepoch')
AND is_hidden = 0 AND in_progress = 0 GROUP BY start_at)
""")
fun getWorkoutsCountOnMonth(date: Long): Flow<Long>

@Query("SELECT * FROM exercise_logs WHERE id = :logId")
fun getExerciseLogByLogId(logId: String): Flow<ExerciseLog>

Expand Down Expand Up @@ -186,6 +198,22 @@ interface WorkoutsDao {
@Query("UPDATE exercise_workout_junctions SET superset_id = :supersetId WHERE id = :junctionId")
suspend fun updateExerciseWorkoutJunctionSupersetId(junctionId: String, supersetId: Int?)

@Query(
// """
// SELECT w.*, le.* FROM workouts w
// JOIN exercise_workout_junctions j ON j.workout_id = w.id
// JOIN exercise_log_entries le ON j.id = le.junction_id
// WHERE w.is_hidden = 0 AND w.in_progress = 0
// ORDER BY w.completed_at DESC
// """
"""
SELECT * FROM workouts w
WHERE w.is_hidden = 0 AND w.in_progress = 0
ORDER BY w.completed_at DESC
"""
)
fun getWorkoutsWithExtraInfoAltPaged(): PagingSource<Int, WorkoutWithExtraInfoAlt>

@Transaction
suspend fun updateWarmUpSets(
junction: LogEntriesWithExerciseJunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

package com.ankitsuda.rebound.data.repositories

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.map
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery
import com.ankitsuda.base.util.NONE_WORKOUT_ID
Expand Down Expand Up @@ -226,6 +229,40 @@ class WorkoutsRepository @Inject constructor(
it.calculateTotalVolume()
}

private suspend fun getWorkoutExtraInfo(workout: Workout): WorkoutWithExtraInfo {
val totalVolume =
getTotalVolumeLiftedByWorkoutId(workoutId = workout.id).firstOrNull()

val totalExercises =
getExercisesCountByWorkoutId(workoutId = workout.id).firstOrNull()

var totalPRs = 0

val totalPRsOfEntries =
getPRsCountOfEntriesByWorkoutId(workoutId = workout.id).firstOrNull()

totalPRs += workout.personalRecords?.size ?: 0
totalPRs += totalPRsOfEntries ?: 0


return WorkoutWithExtraInfo(
workout = workout,
totalVolume = totalVolume,
totalExercises = totalExercises,
totalPRs = totalPRs
)
}

private suspend fun getWorkoutsExtraInfo(workouts: List<Workout>): List<WorkoutWithExtraInfo> {
val mWorkouts = arrayListOf<WorkoutWithExtraInfo>()
for (workout in workouts) {
mWorkouts.add(
getWorkoutExtraInfo(workout)
)
}

return mWorkouts.toList()
}

fun getWorkoutsWithExtraInfo(date: LocalDate? = null) =
workoutsDao.getAllWorkoutsRawQuery(
Expand All @@ -234,41 +271,38 @@ class WorkoutsRepository @Inject constructor(
if (date != null) arrayOf<Any>(date.toEpochMillis()) else arrayOf()
)
).map {
val mWorkouts = arrayListOf<WorkoutWithExtraInfo>()
for (workout in it) {
val totalVolume =
getTotalVolumeLiftedByWorkoutId(workoutId = workout.id).firstOrNull()

val totalExercises =
getExercisesCountByWorkoutId(workoutId = workout.id).firstOrNull()

var totalPRs = 0

val totalPRsOfEntries =
getPRsCountOfEntriesByWorkoutId(workoutId = workout.id).firstOrNull()
getWorkoutsExtraInfo(it)
}

totalPRs += workout.personalRecords?.size ?: 0
totalPRs += totalPRsOfEntries ?: 0
// fun getWorkoutsWithExtraInfoAlt() = workoutsDao.getWorkoutsWithExtraInfoAlt()

mWorkouts.add(
fun getWorkoutsWithExtraInfoPaged() =
Pager(PagingConfig(pageSize = 15)) {
workoutsDao.getWorkoutsWithExtraInfoAltPaged()
}
.flow.map {
it.map { item ->
val logEntries = item.junctions?.flatMap { j -> j.logEntries }
WorkoutWithExtraInfo(
workout = workout,
totalVolume = totalVolume,
totalExercises = totalExercises,
totalPRs = totalPRs
workout = item.workout,
totalVolume = logEntries?.calculateTotalVolume(),
totalExercises = item.junctions?.size,
totalPRs = logEntries?.getTotalPRs(item.workout?.personalRecords?.size)
)
)
}
}

mWorkouts.toList()
}

fun getWorkoutsCountOnDateRange(dateStart: LocalDate, dateEnd: LocalDate) =
workoutsDao.getWorkoutsCountOnDateRange(
dateStart = dateStart.toEpochMillis(),
dateEnd = dateEnd.toEpochMillis()
)

fun getWorkoutsCountOnMonth(date: Long) =
workoutsDao.getWorkoutsCountOnMonth(
date = date
)

fun getExerciseLogByLogId(logId: String) = workoutsDao.getExerciseLogByLogId(logId)

private suspend fun checkIfWorkoutIsActive(discardActive: Boolean): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,8 @@ fun List<ExerciseLogEntry>.calculateTotalVolume(): Double {
volume += ((entry.weight ?: 0.0) * (entry.reps ?: 0).toDouble())
}
return volume
}

fun List<ExerciseLogEntry>.getTotalPRs(workoutPrs: Int? = null): Int {
return sumOf { it.personalRecords?.size ?: 0 } + (workoutPrs ?: 0)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.domain.entities

import androidx.room.*
import com.ankitsuda.base.utils.toEpochMillis
import java.time.LocalDateTime
import java.util.*

data class WorkoutWithExtraInfoAlt(
@Embedded
var workout: Workout? = null,
@Relation(
entity = ExerciseWorkoutJunction::class,
parentColumn = "id",
entityColumn = "workout_id"
)
var junctions: List<LogEntriesWithExerciseJunction>? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,19 @@ 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.collectAsLazyPagingItems
import androidx.paging.compose.items
import com.ankitsuda.base.util.toReadableString
import com.ankitsuda.base.utils.generateId
import com.ankitsuda.base.utils.toLocalDate
import com.ankitsuda.navigation.*
import com.ankitsuda.rebound.domain.entities.CountWithDate
import com.ankitsuda.rebound.domain.entities.WorkoutWithExtraInfo
import com.ankitsuda.rebound.ui.components.TopBar2
import com.ankitsuda.rebound.ui.components.TopBarIconButton
import com.ankitsuda.rebound.ui.history.components.HistoryHeader
import com.ankitsuda.rebound.ui.history.components.HistorySessionItemCard
import com.ankitsuda.rebound.ui.history.models.CountWithLocalDate
import com.ankitsuda.rebound.ui.theme.ReboundTheme
import kotlinx.coroutines.delay
import me.onebone.toolbar.CollapsingToolbarScaffold
Expand All @@ -69,38 +75,39 @@ fun HistoryScreen(

val collapsingState = rememberCollapsingToolbarScaffoldState()

val workoutsMap by viewModel.workouts.collectAsState(initial = emptyMap())
// val workoutsMap by viewModel.workouts.collectAsState(initial = emptyMap())
val workoutsPage = viewModel.workouts.collectAsLazyPagingItems()

LaunchedEffect(key1 = argumentsDate?.value) {
if (argumentsDate?.value == null) return@LaunchedEffect;

try {
val mDate = argumentsDate.value?.toLocalDate();
var index = -1;

var loopIndex = 0;
for (map in workoutsMap) {
if (map.key?.month == mDate?.month && map.key?.year == mDate?.year) {
index = loopIndex;
break;
} else {
loopIndex += 1 + map.value.size
}
}

if (index > -1) {
delay(100)
scrollState.animateScrollToItem(
index
)
}

navController.currentBackStackEntry
?.savedStateHandle?.remove(DATE_KEY)
} catch (e: Exception) {
e.printStackTrace()
}
}
// LaunchedEffect(key1 = argumentsDate?.value) {
// if (argumentsDate?.value == null) return@LaunchedEffect;
//
// try {
// val mDate = argumentsDate.value?.toLocalDate();
// var index = -1;
//
// var loopIndex = 0;
// for (map in workoutsMap) {
// if (map.key?.month == mDate?.month && map.key?.year == mDate?.year) {
// index = loopIndex;
// break;
// } else {
// loopIndex += 1 + map.value.size
// }
// }
//
// if (index > -1) {
// delay(100)
// scrollState.animateScrollToItem(
// index
// )
// }
//
// navController.currentBackStackEntry
// ?.savedStateHandle?.remove(DATE_KEY)
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }

CollapsingToolbarScaffold(
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
Expand Down Expand Up @@ -141,34 +148,44 @@ fun HistoryScreen(
verticalArrangement = Arrangement.spacedBy(20.dp),
contentPadding = PaddingValues(24.dp)
) {
for (map in workoutsMap) {
if (map.key != null) {
item(key = "${map.key}") {
HistoryHeader(
date = map.key!!,
totalWorkouts = map.value.size
)
items(workoutsPage, key = {
when (it) {
is WorkoutWithExtraInfo -> {
it.workout!!.id
}
is CountWithDate -> {
it.date
}
else -> {
it
}
}
items(map.value, key = { it.workout!!.id }) {
HistorySessionItemCard(
modifier = Modifier
.fillMaxWidth(),
onClick = {
navigator.navigate(
LeafScreen.Session.createRoute(
workoutId = it.workout?.id!!
}) {
when (it) {
is WorkoutWithExtraInfo ->
HistorySessionItemCard(
modifier = Modifier
.fillMaxWidth(),
onClick = {
navigator.navigate(
LeafScreen.Session.createRoute(
workoutId = it.workout?.id!!
)
)
)
},
title = it.workout?.name.toString(),
totalExercises = it.totalExercises ?: 0,
duration = it.workout?.getDuration(),
volume = it.totalVolume,
prs = it.totalPRs ?: 0,
date = it.workout?.startAt ?: it.workout?.completedAt
?: it.workout?.createdAt,
)
},
title = it?.workout?.name.toString(),
totalExercises = it?.totalExercises ?: 0,
duration = it?.workout?.getDuration(),
volume = it?.totalVolume,
prs = it?.totalPRs ?: 0,
date = it?.workout?.startAt ?: it?.workout?.completedAt
?: it?.workout?.createdAt,
)
is CountWithDate ->
HistoryHeader(
date = it.date.toLocalDate() ?: LocalDate.now(),
totalWorkouts = it.count.toInt()
)
}
}
}
Expand Down
Loading

0 comments on commit 41bc1ac

Please sign in to comment.