feat(CalendarView): merge recurring training slots and enhance event filtering
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 42s

- Implemented a new method to merge recurring training slots with identical weekdays and time windows, improving calendar event management.
- Updated event filtering logic to exclude cancelled training sessions, ensuring only relevant training events are displayed.
- Enhanced the loading process to handle source errors more effectively, improving user experience in the CalendarView.
This commit is contained in:
Torsten Schulz (local)
2026-05-13 00:07:47 +02:00
parent 54d9b9fc86
commit 61b1f27e5e
6 changed files with 293 additions and 26 deletions

View File

@@ -6,6 +6,7 @@ import android.net.Uri
import de.tt_tagebuch.shared.api.AccidentApi
import de.tt_tagebuch.shared.api.ApiLogsApi
import de.tt_tagebuch.shared.api.ClubApprovalsApi
import de.tt_tagebuch.shared.api.ClickTtAccountApi
import de.tt_tagebuch.shared.api.ApiConfig
import de.tt_tagebuch.shared.api.AuthApi
import de.tt_tagebuch.shared.api.PublicAuthApi
@@ -22,6 +23,7 @@ import de.tt_tagebuch.shared.api.MemberActivitiesApi
import de.tt_tagebuch.shared.api.MemberGroupPhotosApi
import de.tt_tagebuch.shared.api.MemberTransferConfigApi
import de.tt_tagebuch.shared.api.MembersApi
import de.tt_tagebuch.shared.api.MyTischtennisApi
import de.tt_tagebuch.shared.api.OfficialTournamentsApi
import de.tt_tagebuch.shared.api.PermissionsApi
import de.tt_tagebuch.shared.api.SessionApi
@@ -101,6 +103,8 @@ class AppDependencies(context: Context) {
val clubInternalTournamentsManager = ClubInternalTournamentsManager(TournamentsApi(client))
val officialTournamentsReadManager = OfficialTournamentsReadManager(OfficialTournamentsApi(client))
val memberTransferConfigApi = MemberTransferConfigApi(client)
val myTischtennisApi = MyTischtennisApi(client)
val clickTtAccountApi = ClickTtAccountApi(client)
val diaryManager = DiaryManager(
DiaryApi(client),

View File

@@ -122,15 +122,18 @@ private fun parseClockToApi(raw: String): String? {
return h.toString().padStart(2, '0') + ":" + m.toString().padStart(2, '0')
}
private fun trainingWeekdayLabel(tr: (String, String) -> String, weekday: Int): String = when (weekday) {
0 -> tr("trainingTimesTab.sunday", "Sonntag")
1 -> tr("trainingTimesTab.monday", "Montag")
2 -> tr("trainingTimesTab.tuesday", "Dienstag")
3 -> tr("trainingTimesTab.wednesday", "Mittwoch")
4 -> tr("trainingTimesTab.thursday", "Donnerstag")
5 -> tr("trainingTimesTab.friday", "Freitag")
6 -> tr("trainingTimesTab.saturday", "Samstag")
else -> ""
private fun trainingWeekdayLabel(languageCode: String, weekday: Int): String {
fun g(key: String, fb: String) = MobileStrings.get(languageCode, key, fb)
return when (weekday) {
0 -> g("trainingTimesTab.sunday", "Sonntag")
1 -> g("trainingTimesTab.monday", "Montag")
2 -> g("trainingTimesTab.tuesday", "Dienstag")
3 -> g("trainingTimesTab.wednesday", "Mittwoch")
4 -> g("trainingTimesTab.thursday", "Donnerstag")
5 -> g("trainingTimesTab.friday", "Freitag")
6 -> g("trainingTimesTab.saturday", "Samstag")
else -> ""
}
}
private fun trainingGroupMemberLabel(m: TrainingGroupMemberBrief): String {
@@ -519,7 +522,6 @@ internal fun MobileClubSettingsScreen(dependencies: AppDependencies, onBack: ()
}
}
@Composable
@Composable
private fun ClubTrainingGroupsTabContent(
dependencies: AppDependencies,
@@ -818,16 +820,16 @@ private fun ClubTrainingTimesTabContent(
loading = false
}
if (loading) {
Text(tr("trainingTimesTab.loading", "Lade Trainingszeiten..."), modifier = Modifier.padding(top = 24.dp))
return
}
if (error != null) {
Text(error!!, color = MaterialTheme.colors.error)
return
}
LazyColumn(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Column(modifier = Modifier.fillMaxSize()) {
error?.let {
Text(it, color = MaterialTheme.colors.error, modifier = Modifier.padding(bottom = 8.dp))
}
when {
loading -> CircularProgressIndicator(modifier = Modifier.padding(top = 24.dp))
else -> LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
items(groups, key = { it.id }) { g ->
Card(modifier = Modifier.fillMaxWidth(), elevation = ClubSettingsCardElev) {
Column(Modifier.padding(12.dp)) {
@@ -852,7 +854,7 @@ private fun ClubTrainingTimesTabContent(
Text(tr("trainingTimesTab.weekday", "Wochentag:"), style = MaterialTheme.typography.caption)
Box {
TextButton(onClick = { weekdayMenuNew = true }) {
Text(trainingWeekdayLabel(tr, newWeekday))
Text(trainingWeekdayLabel(languageCode, newWeekday))
}
DropdownMenu(expanded = weekdayMenuNew, onDismissRequest = { weekdayMenuNew = false }) {
(0..6).forEach { d ->
@@ -861,7 +863,7 @@ private fun ClubTrainingTimesTabContent(
newWeekday = d
weekdayMenuNew = false
},
) { Text(trainingWeekdayLabel(tr, d)) }
) { Text(trainingWeekdayLabel(languageCode, d)) }
}
}
}
@@ -926,7 +928,7 @@ private fun ClubTrainingTimesTabContent(
verticalAlignment = Alignment.CenterVertically,
) {
Column(modifier = Modifier.weight(1f)) {
Text(trainingWeekdayLabel(tr, t.weekday), fontWeight = FontWeight.Medium)
Text(trainingWeekdayLabel(languageCode, t.weekday), fontWeight = FontWeight.Medium)
Text("${formatTimeDisplay(t.startTime)} ${formatTimeDisplay(t.endTime)}")
}
if (canWrite) {
@@ -951,6 +953,8 @@ private fun ClubTrainingTimesTabContent(
}
}
}
}
}
}
if (editing != null) {
@@ -963,7 +967,7 @@ private fun ClubTrainingTimesTabContent(
Text(tr("trainingTimesTab.weekday", "Wochentag:"), style = MaterialTheme.typography.caption)
Box {
TextButton(onClick = { weekdayMenuEdit = true }) {
Text(trainingWeekdayLabel(tr, editWeekday))
Text(trainingWeekdayLabel(languageCode, editWeekday))
}
DropdownMenu(expanded = weekdayMenuEdit, onDismissRequest = { weekdayMenuEdit = false }) {
(0..6).forEach { d ->
@@ -972,7 +976,7 @@ private fun ClubTrainingTimesTabContent(
editWeekday = d
weekdayMenuEdit = false
},
) { Text(trainingWeekdayLabel(tr, d)) }
) { Text(trainingWeekdayLabel(languageCode, d)) }
}
}
}