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

Commit

Permalink
Improve calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
AnkitSuda committed Nov 21, 2022
1 parent f8d5e45 commit 8cbb7d0
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ interface WorkoutsDao {
@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 is_hidden = 0 AND in_progress = 0 GROUP BY start_at")
fun getWorkoutsCount(): Flow<List<CountWithDate>>

@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>>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ class WorkoutsRepository @Inject constructor(
workoutsDao.getWorkoutsWithExtraInfoAltPaged()
}
}
.flow.map {
.flow
.map {
it.map { item ->
val logEntries = item.junctions?.flatMap { j -> j.logEntries }
WorkoutWithExtraInfo(
Expand All @@ -316,6 +317,9 @@ class WorkoutsRepository @Inject constructor(
}
}

fun getWorkoutsCount() =
workoutsDao.getWorkoutsCount()

fun getWorkoutsCountOnDateRange(dateStart: LocalDate, dateEnd: LocalDate) =
workoutsDao.getWorkoutsCountOnDateRange(
dateStart = dateStart.toEpochMillis(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.calendar

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.ankitsuda.rebound.ui.calendar.models.CalendarMonth
import com.ankitsuda.rebound.ui.calendar.models.InDateStyle
import com.ankitsuda.rebound.ui.calendar.models.MonthConfig
import com.ankitsuda.rebound.ui.calendar.models.OutDateStyle
import kotlinx.coroutines.Job
import java.time.DayOfWeek
import java.time.Month
import java.time.YearMonth

class CalendarPagingDataSource(
private val startYear: Int,
private val firstDayOfWeek: DayOfWeek,
) :
PagingSource<Int, CalendarMonth>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CalendarMonth> {
val year = params.key ?: startYear
return try {
val monthConfig = MonthConfig(
outDateStyle = OutDateStyle.NONE,
inDateStyle = InDateStyle.ALL_MONTHS,
startMonth = YearMonth.of(year, Month.JANUARY),
endMonth = YearMonth.of(year, Month.DECEMBER),
hasBoundaries = true,
maxRowCount = Int.MAX_VALUE,
firstDayOfWeek = firstDayOfWeek,
job = Job()
)


LoadResult.Page(
data = monthConfig.months,
prevKey = year - 1,
nextKey = year + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}

override fun getRefreshKey(state: PagingState<Int, CalendarMonth>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Today
Expand All @@ -29,19 +28,21 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.items
import com.ankitsuda.base.utils.generateId
import com.ankitsuda.base.utils.toLocalDate
import com.ankitsuda.navigation.*
import com.ankitsuda.rebound.ui.calendar.components.CalendarMonthItem
import com.ankitsuda.rebound.ui.calendar.components.CalendarYearHeader
import com.ankitsuda.rebound.ui.calendar.models.CalendarMonth
import com.ankitsuda.rebound.ui.components.TopBar
import com.ankitsuda.rebound.ui.components.TopBarIconButton
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.onebone.toolbar.CollapsingToolbarScaffold
import me.onebone.toolbar.ScrollStrategy
import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState
import java.time.LocalDate
import java.time.Month
import java.time.Year

@Composable
Expand All @@ -56,79 +57,88 @@ fun CalendarScreen(
val collapsingState = rememberCollapsingToolbarScaffoldState()
val scrollState = rememberLazyListState()

val mCalendar by viewModel.calendar.collectAsState(null)
val countsWithDate by viewModel.workoutsCountOnDates.collectAsState()
val calendar = viewModel.calendar.collectAsLazyPagingItems()
val countsWithDate by viewModel.workoutsCountOnDates.collectAsState(emptyList())
val today = LocalDate.now()

val coroutine = rememberCoroutineScope()
val coroutineScope = rememberCoroutineScope()

LaunchedEffect(mCalendar) {
mCalendar?.let { calendar ->
if (calendar.isNotEmpty() && !didFirstAutoScroll) {
try {
scrollState.scrollToItem(calendar.indexOf((calendar.filter {
it.month == today.month.value && today.year == today.year
}[0])))
} catch (e: Exception) {
e.printStackTrace()
suspend fun scrollToToday(smooth: Boolean = true) {
for (i in 0 until calendar.itemCount) {
val item = calendar.peek(i)
if (item is CalendarMonth && item.yearMonth.year == today.year && item.month == today.monthValue) {
if (smooth) {
scrollState.animateScrollToItem(i)
} else {
scrollState.scrollToItem(i)
}
break
}
}
}

LaunchedEffect(calendar.itemCount) {
calendar.let { calendar ->
if (calendar.itemCount > 0 && !didFirstAutoScroll) {
delay(100)
scrollToToday()
didFirstAutoScroll = true
}
}
}

mCalendar?.let { calendar ->
CollapsingToolbarScaffold(
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
state = collapsingState,
toolbar = {
TopBar(
title = stringResource(id = R.string.calendar),
strictLeftIconAlignToStart = true,
leftIconBtn = {
TopBarIconButton(
icon = Icons.Outlined.ArrowBack,
title = stringResource(id = R.string.back)
) {
navController.popBackStack()
}
},
rightIconBtn = {
TopBarIconButton(
icon = Icons.Outlined.Today,
title = stringResource(id = R.string.jump_to_today),
onClick = {
coroutine.launch {
scrollState.animateScrollToItem(calendar.indexOf((calendar.filter {
it.month == today.month.value && it.year == today.year
}[0])))
}
})
})
},
modifier = Modifier.background(MaterialTheme.colors.background)
CollapsingToolbarScaffold(
scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed,
state = collapsingState,
toolbar = {
TopBar(
title = stringResource(id = R.string.calendar),
strictLeftIconAlignToStart = true,
leftIconBtn = {
TopBarIconButton(
icon = Icons.Outlined.ArrowBack,
title = stringResource(id = R.string.back)
) {
navController.popBackStack()
}
},
rightIconBtn = {
TopBarIconButton(
icon = Icons.Outlined.Today,
title = stringResource(id = R.string.jump_to_today),
onClick = {
coroutineScope.launch {
scrollToToday()
}
})
})
},
modifier = Modifier.background(MaterialTheme.colors.background)
) {
LazyColumn(
state = scrollState, modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
) {
LazyColumn(
state = scrollState, modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
) {
for (item in calendar) {
if (item.month == Month.JANUARY.value) {
item(key = "year_header_${item.year}") {
CalendarYearHeader(
year = Year.of(item.year),
onClick = {
navigator.navigate(
LeafScreen.History.createRoute(
year = item.year,
)
)
}
items(calendar, key = {
when (it) {
is CalendarMonth -> "month_block_${it.month}_${it.year}"
is Int -> "year_header_$it"
else -> generateId()
}
}) { item ->
when (item) {
is Int -> CalendarYearHeader(
year = Year.of(item),
onClick = {
navigator.navigate(
LeafScreen.History.createRoute(
year = item,
)
)
}
}
item(key = "month_block_${item.month}_${item.year}") {
)
is CalendarMonth ->
CalendarMonthItem(
month = item,
selectedDate = today,
Expand All @@ -151,10 +161,10 @@ fun CalendarScreen(
)
}
)
}
}
}

}
}

}
}
Loading

0 comments on commit 8cbb7d0

Please sign in to comment.