Diary: erweitere Plan/Assignments, QuickAdd, Accident und Stats

This commit is contained in:
Torsten Schulz (local)
2026-03-05 23:50:10 +01:00
parent dd93755e6b
commit e4e7f521e2
9 changed files with 6841 additions and 0 deletions

View File

@@ -0,0 +1,557 @@
package de.trainingstagebuch.app.network
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import okhttp3.MultipartBody
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.HTTP
import retrofit2.http.Multipart
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.Part
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
import retrofit2.http.QueryMap
@Suppress("LongMethod", "TooManyFunctions")
interface ApiService {
// Auth & Session
@POST("auth/register")
suspend fun register(@Body request: RegisterRequest): BaseResponse<JsonElement>
@POST("auth/login")
suspend fun login(@Body request: LoginRequest): JsonObject
@GET("auth/activate/{activationCode}")
suspend fun activate(@Path("activationCode") activationCode: String): BaseResponse<JsonElement>
@POST("auth/forgot-password")
suspend fun forgotPassword(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("auth/reset-password")
suspend fun resetPassword(@Body body: JsonObject): BaseResponse<JsonElement>
@GET("session/status")
suspend fun getSessionStatus(): BaseResponse<JsonElement>
// Clubs
@GET("clubs")
suspend fun getClubs(): JsonElement
@POST("clubs")
suspend fun createClub(@Body request: CreateClubRequest): JsonElement
@GET("clubs/{clubId}")
suspend fun getClub(@Path("clubId") clubId: String): JsonElement
@PUT("clubs/{clubId}/settings")
suspend fun updateClubSettings(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@GET("clubs/request/{clubId}")
suspend fun requestClubAccess(@Path("clubId") clubId: String): BaseResponse<JsonElement>
@GET("clubs/pending/{clubId}")
suspend fun getPendingApprovals(@Path("clubId") clubId: String): JsonElement
@POST("clubs/approve")
suspend fun approveClubAccess(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("clubs/reject")
suspend fun rejectClubAccess(@Body body: JsonObject): BaseResponse<JsonElement>
// Permissions
@GET("permissions/{clubId}")
suspend fun getPermissions(@Path("clubId") clubId: String): JsonElement
@GET("permissions/roles/available")
suspend fun getAvailableRoles(): JsonElement
@GET("permissions/structure/all")
suspend fun getPermissionStructure(): JsonElement
@GET("permissions/{clubId}/members")
suspend fun getPermissionMembers(@Path("clubId") clubId: String, @Query("t") cacheBust: Long? = null): JsonElement
@PUT("permissions/{clubId}/user/{userId}/role")
suspend fun updateUserRole(@Path("clubId") clubId: String, @Path("userId") userId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("permissions/{clubId}/user/{userId}/status")
suspend fun updateUserStatus(@Path("clubId") clubId: String, @Path("userId") userId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("permissions/{clubId}/user/{userId}/permissions")
suspend fun updateUserPermissions(@Path("clubId") clubId: String, @Path("userId") userId: String, @Body body: JsonObject): BaseResponse<JsonElement>
// Members
@GET("clubmembers/get/{clubId}/{showAll}")
suspend fun getClubMembers(@Path("clubId") clubId: String, @Path("showAll") showAll: Boolean): JsonElement
@GET("clubmembers/notapproved/{clubId}")
suspend fun getNotApprovedMembers(@Path("clubId") clubId: String): JsonElement
@POST("clubmembers/set/{clubId}")
suspend fun setClubMembers(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@POST("clubmembers/update-ratings/{clubId}")
suspend fun updateRatings(@Path("clubId") clubId: String): BaseResponse<JsonElement>
@POST("clubmembers/quick-update-test-membership/{clubId}/{memberId}")
suspend fun quickUpdateTestMembership(@Path("clubId") clubId: String, @Path("memberId") memberId: String): JsonElement
@POST("clubmembers/quick-deactivate/{clubId}/{memberId}")
suspend fun quickDeactivateMember(@Path("clubId") clubId: String, @Path("memberId") memberId: String): JsonElement
@Multipart
@POST("clubmembers/image/{clubId}/{memberId}")
suspend fun uploadClubMemberImage(
@Path("clubId") clubId: String,
@Path("memberId") memberId: String,
@Part image: MultipartBody.Part
): JsonElement
@POST("clubmembers/image/{clubId}/{memberId}/{imageId}/primary")
suspend fun setClubMemberPrimaryImage(
@Path("clubId") clubId: String,
@Path("memberId") memberId: String,
@Path("imageId") imageId: String
): JsonElement
@DELETE("clubmembers/image/{clubId}/{memberId}/{imageId}")
suspend fun deleteClubMemberImage(
@Path("clubId") clubId: String,
@Path("memberId") memberId: String,
@Path("imageId") imageId: String
): JsonElement
@GET("clubmembers/gallery/{clubId}")
suspend fun getClubMemberGallery(@Path("clubId") clubId: String, @Query("format") format: String = "json", @Query("size") size: Int? = null): JsonElement
@GET("member-transfer-config/{clubId}")
suspend fun getMemberTransferConfig(@Path("clubId") clubId: String): JsonElement
@POST("member-transfer-config/{clubId}")
suspend fun saveMemberTransferConfig(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@DELETE("member-transfer-config/{clubId}")
suspend fun deleteMemberTransferConfig(@Path("clubId") clubId: String): JsonElement
@POST("clubmembers/transfer/{clubId}")
suspend fun transferClubMembers(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@GET("membernotes/{memberId}")
suspend fun getMemberNotes(@Path("memberId") memberId: String, @Query("clubId") clubId: String): JsonElement
@POST("membernotes")
suspend fun addMemberNote(@Body body: JsonObject): JsonElement
@HTTP(method = "DELETE", path = "membernotes/{noteId}", hasBody = true)
suspend fun deleteMemberNote(@Path("noteId") noteId: String, @Body body: JsonObject): JsonElement
// Diary
@GET("diary/{clubId}")
suspend fun getDiaryDates(@Path("clubId") clubId: String): JsonElement
@POST("diary/{clubId}")
suspend fun createDiaryDate(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@PUT("diary/{clubId}")
suspend fun updateDiaryTrainingTime(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("diary/{clubId}/{dateId}")
suspend fun deleteDiaryDate(@Path("clubId") clubId: String, @Path("dateId") dateId: String): BaseResponse<JsonElement>
@GET("participants/{dateId}")
suspend fun getParticipants(@Path("dateId") dateId: String): JsonElement
@POST("participants/add")
suspend fun addParticipant(@Body body: JsonObject): JsonElement
@POST("participants/remove")
suspend fun removeParticipant(@Body body: JsonObject): BaseResponse<JsonElement>
@PUT("participants/{dateId}/{memberId}/group")
suspend fun updateParticipantGroup(@Path("dateId") dateId: String, @Path("memberId") memberId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@GET("activities/{dateId}")
suspend fun getActivities(@Path("dateId") dateId: String): JsonElement
@POST("activities/add")
suspend fun addActivity(@Body body: JsonObject): JsonElement
@GET("group/{clubId}/{dateId}")
suspend fun getGroups(@Path("clubId") clubId: String, @Path("dateId") dateId: String): JsonElement
@POST("group")
suspend fun createGroup(@Body body: JsonObject): BaseResponse<JsonElement>
@PUT("group/{groupId}")
suspend fun updateGroup(@Path("groupId") groupId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("group/{groupId}")
suspend fun deleteGroup(@Path("groupId") groupId: String): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "group/{groupId}", hasBody = true)
suspend fun deleteGroupWithBody(@Path("groupId") groupId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@GET("tags")
suspend fun getTags(): JsonElement
@POST("tags")
suspend fun createTag(@Body body: JsonObject): JsonElement
@POST("diary/tag/{clubId}/add-tag")
suspend fun addTagToDiaryDate(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "diary/{clubId}/tag", hasBody = true)
suspend fun deleteTagFromDiaryDate(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@GET("notes")
suspend fun getNotes(@QueryMap query: Map<String, String>): JsonElement
@GET("diarymember/{clubId}/note")
suspend fun getDiaryMemberNotes(@Path("clubId") clubId: String, @QueryMap query: Map<String, String>): JsonElement
@POST("diarymember/{clubId}/note")
suspend fun addDiaryMemberNote(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@DELETE("diarymember/{clubId}/note/{noteId}")
suspend fun deleteDiaryMemberNote(@Path("clubId") clubId: String, @Path("noteId") noteId: String): JsonElement
// Diary activities
@GET("diary-date-activities/{clubId}/{dateId}")
suspend fun getDiaryDateActivities(@Path("clubId") clubId: String, @Path("dateId") dateId: String): JsonElement
@POST("diary-date-activities/{clubId}")
suspend fun createDiaryDateActivity(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("diary-date-activities/{clubId}/{activityId}")
suspend fun updateDiaryDateActivity(@Path("clubId") clubId: String, @Path("activityId") activityId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("diary-date-activities/{clubId}/{activityId}/order")
suspend fun updateDiaryDateActivityOrder(@Path("clubId") clubId: String, @Path("activityId") activityId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("diary-date-activities/{clubId}/{activityId}")
suspend fun deleteDiaryDateActivity(@Path("clubId") clubId: String, @Path("activityId") activityId: String): BaseResponse<JsonElement>
@POST("diary-date-activities/group")
suspend fun createGroupActivity(@Body body: JsonObject): BaseResponse<JsonElement>
@PUT("diary-date-activities/group/{clubId}/{groupActivityId}")
suspend fun updateGroupActivity(@Path("clubId") clubId: String, @Path("groupActivityId") groupActivityId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("diary-date-activities/group/{clubId}/{groupActivityId}")
suspend fun deleteGroupActivity(@Path("clubId") clubId: String, @Path("groupActivityId") groupActivityId: String): BaseResponse<JsonElement>
@GET("diary-member-activities/{clubId}/{diaryDateActivityId}")
suspend fun getDiaryMemberActivities(
@Path("clubId") clubId: String,
@Path("diaryDateActivityId") diaryDateActivityId: String
): JsonElement
@POST("diary-member-activities/{clubId}/{diaryDateActivityId}")
suspend fun setDiaryMemberActivities(
@Path("clubId") clubId: String,
@Path("diaryDateActivityId") diaryDateActivityId: String,
@Body body: JsonObject
): BaseResponse<JsonElement>
@DELETE("diary-member-activities/{clubId}/{diaryDateActivityId}/{participantId}")
suspend fun deleteDiaryMemberActivity(
@Path("clubId") clubId: String,
@Path("diaryDateActivityId") diaryDateActivityId: String,
@Path("participantId") participantId: String
): BaseResponse<JsonElement>
@POST("accident")
suspend fun createAccident(@Body body: JsonObject): BaseResponse<JsonElement>
@GET("accident/{clubId}/{dateId}")
suspend fun getAccidents(
@Path("clubId") clubId: String,
@Path("dateId") dateId: String
): JsonElement
@GET("member-activities/{clubId}/{memberId}")
suspend fun getMemberActivities(
@Path("clubId") clubId: String,
@Path("memberId") memberId: String,
@Query("period") period: String? = null
): JsonElement
@GET("member-activities/{clubId}/{memberId}/last-participations")
suspend fun getMemberLastParticipations(
@Path("clubId") clubId: String,
@Path("memberId") memberId: String,
@Query("limit") limit: Int = 3
): JsonElement
@GET("predefined-activities")
suspend fun getPredefinedActivities(): JsonElement
@GET("predefined-activities/search/query")
suspend fun searchPredefinedActivities(
@Query("q") query: String,
@Query("limit") limit: Int = 10
): JsonElement
// Training
@GET("training-groups/{clubId}")
suspend fun getTrainingGroups(@Path("clubId") clubId: String): JsonElement
@GET("training-groups/{clubId}/member/{memberId}")
suspend fun getMemberTrainingGroups(@Path("clubId") clubId: String, @Path("memberId") memberId: String): JsonElement
@POST("training-groups/{clubId}")
suspend fun createTrainingGroup(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("training-groups/{clubId}/{groupId}")
suspend fun updateTrainingGroup(@Path("clubId") clubId: String, @Path("groupId") groupId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("training-groups/{clubId}/{groupId}")
suspend fun deleteTrainingGroup(@Path("clubId") clubId: String, @Path("groupId") groupId: String): BaseResponse<JsonElement>
@POST("training-groups/{clubId}/{groupId}/member/{memberId}")
suspend fun addMemberToTrainingGroup(@Path("clubId") clubId: String, @Path("groupId") groupId: String, @Path("memberId") memberId: String): BaseResponse<JsonElement>
@DELETE("training-groups/{clubId}/{groupId}/member/{memberId}")
suspend fun removeMemberFromTrainingGroup(@Path("clubId") clubId: String, @Path("groupId") groupId: String, @Path("memberId") memberId: String): BaseResponse<JsonElement>
@GET("training-times/{clubId}")
suspend fun getTrainingTimes(@Path("clubId") clubId: String): JsonElement
@POST("training-times/{clubId}")
suspend fun createTrainingTime(@Path("clubId") clubId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("training-times/{clubId}/{timeId}")
suspend fun updateTrainingTime(@Path("clubId") clubId: String, @Path("timeId") timeId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("training-times/{clubId}/{timeId}")
suspend fun deleteTrainingTime(@Path("clubId") clubId: String, @Path("timeId") timeId: String): BaseResponse<JsonElement>
@GET("training-stats/{clubId}")
suspend fun getTrainingStats(@Path("clubId") clubId: String): JsonElement
// Match / Schedule
@GET("matches/leagues/{clubId}/matches")
suspend fun getLeagueMatches(@Path("clubId") clubId: String, @Query("seasonid") seasonId: String? = null): JsonElement
@GET("matches/leagues/{clubId}/matches/{leagueId}")
suspend fun getMatchesForLeague(@Path("clubId") clubId: String, @Path("leagueId") leagueId: String): JsonElement
@GET("matches/leagues/{clubId}/table/{leagueId}")
suspend fun getLeagueTable(@Path("clubId") clubId: String, @Path("leagueId") leagueId: String): JsonElement
@POST("matches/leagues/{clubId}/table/{leagueId}/fetch")
suspend fun fetchLeagueTable(@Path("clubId") clubId: String, @Path("leagueId") leagueId: String): BaseResponse<JsonElement>
@PATCH("matches/{matchId}/players")
suspend fun updateMatchPlayers(@Path("matchId") matchId: String, @Body body: JsonObject): BaseResponse<JsonElement>
// Teams & documents
@GET("club-teams/club/{clubId}")
suspend fun getClubTeams(@Path("clubId") clubId: String, @Query("seasonid") seasonId: String? = null): JsonElement
@GET("club-teams/leagues/{clubId}")
suspend fun getClubTeamLeagues(@Path("clubId") clubId: String, @Query("seasonid") seasonId: String? = null): JsonElement
@POST("club-teams/club/{clubId}")
suspend fun createClubTeam(@Path("clubId") clubId: String, @Body body: JsonObject): JsonElement
@PUT("club-teams/{clubTeamId}")
suspend fun updateClubTeam(@Path("clubTeamId") clubTeamId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("club-teams/{clubTeamId}")
suspend fun deleteClubTeam(@Path("clubTeamId") clubTeamId: String): BaseResponse<JsonElement>
@GET("team-documents/club-team/{clubTeamId}")
suspend fun getTeamDocuments(@Path("clubTeamId") clubTeamId: String): JsonElement
@Multipart
@POST("team-documents/club-team/{clubTeamId}/upload")
suspend fun uploadTeamDocument(@Path("clubTeamId") clubTeamId: String, @retrofit2.http.Part file: MultipartBody.Part): JsonElement
@POST("team-documents/{documentId}/parse")
suspend fun parseTeamDocument(@Path("documentId") documentId: String, @Query("leagueid") leagueId: String): JsonElement
@GET("team-documents/{documentId}/download")
suspend fun downloadTeamDocument(@Path("documentId") documentId: String): JsonElement
// Tournament
@GET("tournament/{clubId}")
suspend fun getTournaments(@Path("clubId") clubId: String, @Query("type") type: String? = null): JsonElement
@GET("tournament/{clubId}/{tournamentId}")
suspend fun getTournament(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String): JsonElement
@POST("tournament")
suspend fun createTournament(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/mini")
suspend fun createMiniTournament(@Body body: JsonObject): BaseResponse<JsonElement>
@PUT("tournament/{clubId}/{tournamentId}")
suspend fun updateTournament(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/participant")
suspend fun addTournamentParticipant(@Body body: JsonObject): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "tournament/participant", hasBody = true)
suspend fun removeTournamentParticipant(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/participants")
suspend fun getTournamentParticipants(@Body body: JsonObject): JsonElement
@POST("tournament/external-participant")
suspend fun addExternalTournamentParticipant(@Body body: JsonObject): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "tournament/external-participant", hasBody = true)
suspend fun removeExternalTournamentParticipant(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/external-participants")
suspend fun getExternalParticipants(@Body body: JsonObject): JsonElement
@GET("tournament/groups")
suspend fun getTournamentGroups(@Query("clubId") clubId: String, @Query("tournamentId") tournamentId: String): JsonElement
@PUT("tournament/groups")
suspend fun createTournamentGroups(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/groups/create")
suspend fun createTournamentGroupsPerClass(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/groups")
suspend fun fillTournamentGroups(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/matches/create")
suspend fun createTournamentMatches(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/match/result")
suspend fun addTournamentMatchResult(@Body body: JsonObject): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "tournament/match/result", hasBody = true)
suspend fun deleteTournamentMatchResult(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/match/finish")
suspend fun finishTournamentMatch(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/match/reopen")
suspend fun reopenTournamentMatch(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/knockout")
suspend fun startKnockout(@Body body: JsonObject): BaseResponse<JsonElement>
@HTTP(method = "DELETE", path = "tournament/matches/knockout", hasBody = true)
suspend fun deleteKnockoutMatches(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/modus")
suspend fun setTournamentModus(@Body body: JsonObject): BaseResponse<JsonElement>
@GET("tournament/matches/{clubId}/{tournamentId}")
suspend fun getTournamentMatches(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String): JsonElement
@GET("tournament/classes/{clubId}/{tournamentId}")
suspend fun getTournamentClasses(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String): JsonElement
@POST("tournament/class/{clubId}/{tournamentId}")
suspend fun createTournamentClass(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@PUT("tournament/class/{clubId}/{tournamentId}/{classId}")
suspend fun updateTournamentClass(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String, @Path("classId") classId: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("tournament/class/{clubId}/{tournamentId}/{classId}")
suspend fun deleteTournamentClass(@Path("clubId") clubId: String, @Path("tournamentId") tournamentId: String, @Path("classId") classId: String): BaseResponse<JsonElement>
@GET("tournament/stages")
suspend fun getTournamentStages(@Query("clubId") clubId: String, @Query("tournamentId") tournamentId: String): JsonElement
@PUT("tournament/stages")
suspend fun updateTournamentStages(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("tournament/stages/advance")
suspend fun advanceTournamentStage(@Body body: JsonObject): BaseResponse<JsonElement>
// Official tournaments
@GET("official-tournaments/{clubId}")
suspend fun getOfficialTournaments(@Path("clubId") clubId: String): JsonElement
@GET("official-tournaments/{clubId}/participations/summary")
suspend fun getOfficialTournamentSummary(@Path("clubId") clubId: String): JsonElement
@GET("official-tournaments/{clubId}/{id}")
suspend fun getOfficialTournament(@Path("clubId") clubId: String, @Path("id") id: String): JsonElement
@POST("official-tournaments/{clubId}/{id}/participation")
suspend fun upsertOfficialParticipation(@Path("clubId") clubId: String, @Path("id") id: String, @Body body: JsonObject): BaseResponse<JsonElement>
@POST("official-tournaments/{clubId}/{id}/status")
suspend fun updateOfficialStatus(@Path("clubId") clubId: String, @Path("id") id: String, @Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("official-tournaments/{clubId}/{id}")
suspend fun deleteOfficialTournament(@Path("clubId") clubId: String, @Path("id") id: String): BaseResponse<JsonElement>
// MyTischtennis
@GET("mytischtennis/account")
suspend fun getMyTischtennisAccount(): JsonElement
@GET("mytischtennis/status")
suspend fun getMyTischtennisStatus(): JsonElement
@POST("mytischtennis/verify")
suspend fun verifyMyTischtennis(@Body body: JsonObject): JsonElement
@POST("mytischtennis/account")
suspend fun upsertMyTischtennisAccount(@Body body: JsonObject): BaseResponse<JsonElement>
@DELETE("mytischtennis/account")
suspend fun deleteMyTischtennisAccount(): BaseResponse<JsonElement>
@GET("mytischtennis/update-history")
suspend fun getMyTischtennisUpdateHistory(): JsonElement
@POST("mytischtennis/parse-url")
suspend fun parseMyTischtennisUrl(@Body body: JsonObject): JsonElement
@POST("mytischtennis/configure-team")
suspend fun configureMyTischtennisTeam(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("mytischtennis/configure-league")
suspend fun configureMyTischtennisLeague(@Body body: JsonObject): BaseResponse<JsonElement>
@POST("mytischtennis/fetch-team-data/async")
suspend fun startMyTischtennisFetchJob(@Body body: JsonObject): JsonElement
@GET("mytischtennis/fetch-team-data/jobs/{jobId}")
suspend fun getMyTischtennisFetchJob(@Path("jobId") jobId: String): JsonElement
// Logs
@GET("logs")
suspend fun getLogs(@QueryMap params: Map<String, String>): JsonElement
@GET("logs/{id}")
suspend fun getLogDetail(@Path("id") id: String): JsonElement
@GET("logs/scheduler/last-executions")
suspend fun getSchedulerExecutions(@Query("clubId") clubId: String? = null): JsonElement
// NuScore
@POST("nuscore/init-cookies/{code}")
suspend fun initNuscoreCookies(@Path("code") code: String): BaseResponse<JsonElement>
@GET("nuscore/meetinginfo/{code}")
suspend fun getNuscoreMeetingInfo(@Path("code") code: String): JsonElement
@GET("nuscore/meetingdetails/{uuid}")
suspend fun getNuscoreMeetingDetails(@Path("uuid") uuid: String): JsonElement
@PUT("nuscore/validate/{uuid}")
suspend fun validateNuscoreReport(@Path("uuid") uuid: String, @Body body: JsonObject): JsonElement
@PUT("nuscore/submit/{uuid}")
suspend fun submitNuscoreReport(@Path("uuid") uuid: String, @Body body: JsonObject): JsonElement
@POST("nuscore/broadcast-draft")
suspend fun broadcastNuscoreDraft(@Body body: JsonObject): BaseResponse<JsonElement>
}

View File

@@ -0,0 +1,58 @@
package de.trainingstagebuch.app.network
import kotlinx.serialization.json.JsonElement
import de.trainingstagebuch.app.utils.SocketMessageUtils
sealed interface SocketConnectionState {
data object Disconnected : SocketConnectionState
data object Connecting : SocketConnectionState
data class Connected(val attempts: Int) : SocketConnectionState
data class Reconnecting(val attempts: Int, val delayMs: Long) : SocketConnectionState
data class Failed(val reason: String?) : SocketConnectionState
}
data class SocketEvent(
val type: SocketEventType,
val rawType: String,
val payload: JsonElement?
)
enum class SocketEventType(val wireName: String) {
ParticipantAdded("participant:added"),
ParticipantRemoved("participant:removed"),
ParticipantUpdated("participant:updated"),
DiaryNoteAdded("diary:note:added"),
DiaryNoteUpdated("diary:note:updated"),
DiaryNoteDeleted("diary:note:deleted"),
DiaryTagAdded("diary:tag:added"),
DiaryTagRemoved("diary:tag:removed"),
DiaryDateUpdated("diary:date:updated"),
ActivityMemberAdded("activity-member:added"),
ActivityMemberRemoved("activity-member:removed"),
ActivityChanged("activity:changed"),
MemberChanged("member:changed"),
GroupChanged("group:changed"),
TournamentChanged("tournament:changed"),
ScheduleMatchUpdated("schedule:match:updated"),
ScheduleMatchReportSubmitted("schedule:match-report:submitted"),
Unknown("unknown");
companion object {
fun fromWireName(name: String): SocketEventType =
entries.firstOrNull { it.wireName == name } ?: Unknown
}
}
object SocketEventParser {
fun parseSocketIoEvent(rawMessage: String): SocketEvent? {
return SocketMessageUtils.parseSocketIoEvent(rawMessage)
}
fun buildAuthMessage(authCode: String, userId: String): String {
return SocketMessageUtils.buildAuthMessage(authCode, userId)
}
fun buildJoinClubMessage(clubId: String): String {
return SocketMessageUtils.buildJoinClubMessage(clubId)
}
}

View File

@@ -0,0 +1,442 @@
package de.trainingstagebuch.app.repository
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import de.trainingstagebuch.app.utils.JsonSafeUtils
internal object RepositoryMappers {
fun parseErrorPayload(raw: String): BackendError? {
val obj = JsonSafeUtils.parseObject(raw) ?: return null
return BackendError(
code = JsonSafeUtils.getString(obj, "code"),
message = JsonSafeUtils.getString(obj, "error", "message")
)
}
fun mapClubsToHomeData(clubs: JsonElement): HomeData {
val array = JsonSafeUtils.asArray(clubs)
val names = array.mapNotNull { element ->
(element as? JsonObject)
?.get("name")
?.let(JsonSafeUtils::getString)
?.takeIf { it.isNotBlank() }
}
return HomeData(
clubCount = array.size,
clubNames = names
)
}
fun mapMembersToMemberItems(members: JsonElement): List<MemberItem> {
val array = JsonSafeUtils.asArray(members)
return array.mapNotNull { element ->
val obj = element as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id") ?: return@mapNotNull null
val firstName = JsonSafeUtils.getString(obj, "firstName", "firstname").orEmpty().trim()
val lastName = JsonSafeUtils.getString(obj, "lastName", "lastname").orEmpty().trim()
val active = JsonSafeUtils.getString(obj, "active")
?.equals("true", ignoreCase = true)
?: true
val testMembership = JsonSafeUtils.getString(obj, "testMembership")
?.equals("true", ignoreCase = true)
?: false
val contacts = JsonSafeUtils.asArray(obj["contacts"]).mapNotNull { rawContact ->
val contactObj = rawContact as? JsonObject ?: return@mapNotNull null
val type = JsonSafeUtils.getString(contactObj, "type")?.lowercase() ?: return@mapNotNull null
val value = JsonSafeUtils.getString(contactObj, "value") ?: return@mapNotNull null
MemberContactItem(
type = type,
value = value
)
}
val displayName = listOf(firstName, lastName)
.filter { it.isNotBlank() }
.joinToString(" ")
.ifBlank { id }
MemberItem(
id = id,
firstName = firstName,
lastName = lastName,
displayName = displayName,
active = active,
testMembership = testMembership,
contacts = contacts
)
}
}
fun mapMemberGalleryImages(gallery: JsonElement, memberId: String): List<MemberImageItem> {
val array = JsonSafeUtils.asArray(gallery)
return array.mapNotNull { element ->
val obj = element as? JsonObject ?: return@mapNotNull null
val imageId = JsonSafeUtils.getString(obj, "imageId", "id", "_id") ?: return@mapNotNull null
val itemMemberId = JsonSafeUtils.getString(obj, "memberId")
?: runCatching {
val memberObj = obj["member"] as? JsonObject
memberObj?.let { JsonSafeUtils.getString(it, "id") }
}.getOrNull()
?: return@mapNotNull null
if (itemMemberId != memberId) return@mapNotNull null
val url = JsonSafeUtils.getString(obj, "url", "imageUrl", "latestImageUrl", "path")
val isPrimary = JsonSafeUtils.getString(obj, "primary", "isPrimary")
?.equals("true", ignoreCase = true)
?: false
MemberImageItem(
imageId = imageId,
memberId = itemMemberId,
url = url,
isPrimary = isPrimary
)
}.sortedWith(compareByDescending<MemberImageItem> { it.isPrimary }.thenBy { it.imageId })
}
fun mapTrainingGroups(groups: JsonElement): List<TrainingGroupItem> {
return JsonSafeUtils.asArray(groups).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val name = JsonSafeUtils.getString(obj, "name")
?: JsonSafeUtils.getString(obj, "title")
?: id
TrainingGroupItem(id = id, name = name)
}
}
fun mapMemberNotes(notes: JsonElement): List<MemberNoteItem> {
return JsonSafeUtils.asArray(notes).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val content = JsonSafeUtils.getString(obj, "content", "text", "note")
?.trim()
?.takeIf { it.isNotBlank() }
?: return@mapNotNull null
val createdAt = JsonSafeUtils.getString(obj, "createdAt", "created_at", "date")
MemberNoteItem(
id = id,
content = content,
createdAt = createdAt
)
}
}
fun mapMemberTransferConfig(config: JsonObject): MemberTransferConfig {
val loginCredentialsObj = config["loginCredentials"] as? JsonObject
val additional = loginCredentialsObj
?.entries
?.filter { it.key != "username" && it.key != "password" }
?.mapNotNull { entry ->
val value = JsonSafeUtils.getString(entry.value)
if (value.isNullOrBlank()) null else "${entry.key}:$value"
}
?: emptyList()
return MemberTransferConfig(
id = JsonSafeUtils.getString(config, "id"),
server = JsonSafeUtils.getString(config, "server").orEmpty(),
loginEndpoint = JsonSafeUtils.getString(config, "loginEndpoint"),
loginFormat = JsonSafeUtils.getString(config, "loginFormat").orEmpty().ifBlank { "json" },
loginUsername = loginCredentialsObj?.let { JsonSafeUtils.getString(it, "username") },
loginPassword = null,
loginAdditionalField1 = additional.getOrNull(0),
loginAdditionalField2 = additional.getOrNull(1),
transferEndpoint = JsonSafeUtils.getString(config, "transferEndpoint").orEmpty(),
transferMethod = JsonSafeUtils.getString(config, "transferMethod").orEmpty().ifBlank { "POST" },
transferFormat = JsonSafeUtils.getString(config, "transferFormat").orEmpty().ifBlank { "json" },
transferTemplate = JsonSafeUtils.getString(config, "transferTemplate").orEmpty(),
useBulkMode = JsonSafeUtils.getString(config, "useBulkMode")?.equals("true", ignoreCase = true) ?: false,
bulkWrapperTemplate = JsonSafeUtils.getString(config, "bulkWrapperTemplate")
)
}
fun mapMemberTransferSummary(response: JsonObject): MemberTransferSummary {
val transferred = numberOrStringInt(response, "transferred")
val total = numberOrStringInt(response, "total")
val invalidMembers = JsonSafeUtils.asArray(response["invalidMembers"])
.mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val memberObj = obj["member"] as? JsonObject
val firstName = memberObj?.let { JsonSafeUtils.getString(it, "firstName") }.orEmpty()
val lastName = memberObj?.let { JsonSafeUtils.getString(it, "lastName") }.orEmpty()
listOf(firstName, lastName).filter { it.isNotBlank() }.joinToString(" ").ifBlank {
memberObj?.let { JsonSafeUtils.getString(it, "id") } ?: "Unknown"
}
}
val errors = JsonSafeUtils.asArray(response["errors"])
.mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull JsonSafeUtils.getString(raw)
val member = JsonSafeUtils.getString(obj, "member").orEmpty()
val error = JsonSafeUtils.getString(obj, "error").orEmpty()
listOf(member, error).filter { it.isNotBlank() }.joinToString(": ").ifBlank { null }
}
return MemberTransferSummary(
success = JsonSafeUtils.getString(response, "success")?.equals("true", ignoreCase = true) ?: false,
message = JsonSafeUtils.getString(response, "message")
?: JsonSafeUtils.getString(response, "error"),
transferred = transferred,
total = total,
invalidMembers = invalidMembers,
errors = errors
)
}
fun mapClubDetails(club: JsonObject): ClubDetails {
val id = JsonSafeUtils.getString(club, "id", "_id")
val name = JsonSafeUtils.getString(club, "name").orEmpty()
val members = mapMembersToMemberItems(club["members"] ?: JsonArray(emptyList()))
return ClubDetails(
id = id,
name = name,
members = members
)
}
fun mapClubSettings(club: JsonObject): ClubSettingsData {
val greetingText = JsonSafeUtils.getString(club, "greetingText")
?: (club["settings"] as? JsonObject)?.let { JsonSafeUtils.getString(it, "greetingText") }
?: ""
val associationMemberNumber = JsonSafeUtils.getString(club, "associationMemberNumber")
?: (club["settings"] as? JsonObject)?.let { JsonSafeUtils.getString(it, "associationMemberNumber") }
?: ""
return ClubSettingsData(
greetingText = greetingText,
associationMemberNumber = associationMemberNumber
)
}
fun mapClubTrainingGroups(groups: JsonElement): List<ClubTrainingGroup> {
return JsonSafeUtils.asArray(groups).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val name = JsonSafeUtils.getString(obj, "name")?.trim().orEmpty().ifBlank { id }
ClubTrainingGroup(id = id, name = name)
}
}
fun mapClubTrainingTimeGroups(groups: JsonElement): List<ClubTrainingTimeGroup> {
return JsonSafeUtils.asArray(groups).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val name = JsonSafeUtils.getString(obj, "name")?.trim().orEmpty().ifBlank { id }
val times = JsonSafeUtils.asArray(obj["trainingTimes"]).mapNotNull { rawTime ->
val timeObj = rawTime as? JsonObject ?: return@mapNotNull null
val timeId = JsonSafeUtils.getString(timeObj, "id", "_id") ?: return@mapNotNull null
val weekday = JsonSafeUtils.getString(timeObj, "weekday")?.toIntOrNull() ?: 0
val startTime = JsonSafeUtils.getString(timeObj, "startTime").orEmpty()
val endTime = JsonSafeUtils.getString(timeObj, "endTime").orEmpty()
ClubTrainingTime(
id = timeId,
weekday = weekday,
startTime = startTime,
endTime = endTime
)
}
ClubTrainingTimeGroup(
id = id,
name = name,
trainingTimes = times
)
}
}
fun mapPendingApprovals(entries: JsonElement): List<PendingApprovalUser> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val userObj = (obj["user"] as? JsonObject) ?: obj
val id = JsonSafeUtils.getString(userObj, "id", "_id") ?: return@mapNotNull null
val firstName = JsonSafeUtils.getString(userObj, "firstName", "firstname").orEmpty()
val lastName = JsonSafeUtils.getString(userObj, "lastName", "lastname").orEmpty()
val email = JsonSafeUtils.getString(userObj, "email")
PendingApprovalUser(
id = id,
firstName = firstName,
lastName = lastName,
email = email
)
}
}
fun mapDiaryDates(entries: JsonElement): List<DiaryDateEntry> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
mapDiaryDate(raw)
}
}
fun mapDiaryDate(raw: JsonElement): DiaryDateEntry? {
val obj = raw as? JsonObject ?: return null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return null
val date = JsonSafeUtils.getString(obj, "date") ?: return null
val tags = JsonSafeUtils.asArray(obj["diaryTags"]).mapNotNull { rawTag ->
mapTag(rawTag)
}
return DiaryDateEntry(
id = id,
date = date,
trainingStart = JsonSafeUtils.getString(obj, "trainingStart"),
trainingEnd = JsonSafeUtils.getString(obj, "trainingEnd"),
tags = tags
)
}
fun mapDiaryParticipants(entries: JsonElement): List<DiaryParticipant> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val memberId = JsonSafeUtils.getString(obj, "memberId") ?: return@mapNotNull null
val groupId = JsonSafeUtils.getString(obj, "groupId")
DiaryParticipant(id = id, memberId = memberId, groupId = groupId)
}
}
fun mapDiaryActivities(entries: JsonElement): List<DiaryActivityItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
mapDiaryActivity(raw)
}
}
fun mapDiaryActivity(raw: JsonElement): DiaryActivityItem? {
val obj = raw as? JsonObject ?: return null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return null
val description = JsonSafeUtils.getString(obj, "description", "activity")
?.trim()
?.takeIf { it.isNotBlank() }
?: return null
return DiaryActivityItem(id = id, description = description)
}
private fun numberOrStringInt(obj: JsonObject, key: String): Int {
return obj[key]?.let { element ->
JsonSafeUtils.getString(element)?.toIntOrNull()
?: runCatching { element.toString().trim('"').toInt() }.getOrNull()
} ?: 0
}
fun mapTags(entries: JsonElement): List<DiaryTagItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
mapTag(raw)
}
}
fun mapDiaryPlanItems(entries: JsonElement): List<DiaryPlanItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val isTimeblock = JsonSafeUtils.getString(obj, "isTimeblock")
?.equals("true", ignoreCase = true)
?: false
val activity = JsonSafeUtils.getString(obj, "activity", "customActivityName")
?: (obj["predefinedActivity"] as? JsonObject)?.let {
JsonSafeUtils.getString(it, "name", "code")
}
?: ""
val duration = JsonSafeUtils.getString(obj, "duration")
val durationText = JsonSafeUtils.getString(obj, "durationText")
val groupId = JsonSafeUtils.getString(obj, "groupId")
val orderId = JsonSafeUtils.getString(obj, "orderId")?.toIntOrNull()
val predefinedActivityId = JsonSafeUtils.getString(obj, "predefinedActivityId")
?: (obj["predefinedActivity"] as? JsonObject)?.let {
JsonSafeUtils.getString(it, "id", "_id")
}
DiaryPlanItem(
id = id,
activity = activity,
duration = duration,
durationText = durationText,
isTimeblock = isTimeblock,
groupId = groupId,
orderId = orderId,
predefinedActivityId = predefinedActivityId
)
}
}
fun mapDiaryGroups(entries: JsonElement): List<DiaryGroupItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val name = JsonSafeUtils.getString(obj, "name")
?.trim()
?.takeIf { it.isNotBlank() }
?: id
val lead = JsonSafeUtils.getString(obj, "lead").orEmpty()
DiaryGroupItem(id = id, name = name, lead = lead)
}
}
fun mapTag(raw: JsonElement): DiaryTagItem? {
val obj = raw as? JsonObject ?: return null
val nestedTag = obj["tag"] as? JsonObject
val source = nestedTag ?: obj
val id = JsonSafeUtils.getString(source, "id", "_id") ?: return null
val name = JsonSafeUtils.getString(source, "name", "label")
?.trim()
?.takeIf { it.isNotBlank() }
?: return null
return DiaryTagItem(id = id, name = name)
}
fun mapParticipantIds(entries: JsonElement): Set<String> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
JsonSafeUtils.getString(obj, "participantId")
}.toSet()
}
fun mapAccidents(entries: JsonElement): List<DiaryAccidentItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
DiaryAccidentItem(
id = id,
accident = JsonSafeUtils.getString(obj, "accident", "description").orEmpty(),
happenedAt = JsonSafeUtils.getString(obj, "createdAt", "date")
)
}
}
fun mapMemberActivityStats(entries: JsonElement): List<MemberActivityStatItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val activity = JsonSafeUtils.getString(obj, "activity", "name") ?: return@mapNotNull null
val count = JsonSafeUtils.getString(obj, "count", "value")?.toIntOrNull() ?: 0
MemberActivityStatItem(activity = activity, count = count)
}
}
fun mapLastParticipations(entries: JsonElement): List<MemberParticipationItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val date = JsonSafeUtils.getString(obj, "date", "diaryDate") ?: return@mapNotNull null
val activity = JsonSafeUtils.getString(obj, "activity", "name").orEmpty()
MemberParticipationItem(
date = date,
activity = activity
)
}
}
fun mapPredefinedActivities(entries: JsonElement): List<PredefinedActivityItem> {
return JsonSafeUtils.asArray(entries).mapNotNull { raw ->
val obj = raw as? JsonObject ?: return@mapNotNull null
val id = JsonSafeUtils.getString(obj, "id", "_id") ?: return@mapNotNull null
val name = JsonSafeUtils.getString(obj, "name").orEmpty()
val code = JsonSafeUtils.getString(obj, "code")
val duration = JsonSafeUtils.getString(obj, "duration")
val durationText = JsonSafeUtils.getString(obj, "durationText")
PredefinedActivityItem(
id = id,
name = name,
code = code,
duration = duration,
durationText = durationText
)
}
}
}

View File

@@ -0,0 +1,140 @@
package de.trainingstagebuch.app.services
import de.trainingstagebuch.app.repository.DiaryActionResult
import de.trainingstagebuch.app.repository.DiaryAccidentsResult
import de.trainingstagebuch.app.repository.DiaryActivitiesResult
import de.trainingstagebuch.app.repository.DiaryAddActivityResult
import de.trainingstagebuch.app.repository.DiaryActivityParticipantsResult
import de.trainingstagebuch.app.repository.DiaryCreateTagResult
import de.trainingstagebuch.app.repository.DiaryParticipantActionResult
import de.trainingstagebuch.app.repository.DiaryParticipantsResult
import de.trainingstagebuch.app.repository.MemberActivityStatsResult
import de.trainingstagebuch.app.repository.MemberNotesResult
import de.trainingstagebuch.app.repository.DiaryCreateDateResult
import de.trainingstagebuch.app.repository.DiaryDatesResult
import de.trainingstagebuch.app.repository.DiaryGroupsResult
import de.trainingstagebuch.app.repository.DiaryPlanResult
import de.trainingstagebuch.app.repository.DiaryTagsResult
import de.trainingstagebuch.app.repository.MembersResult
import de.trainingstagebuch.app.repository.PredefinedActivitiesResult
import de.trainingstagebuch.app.repository.TrainingstagebuchRepository
class DiaryService(
private val repository: TrainingstagebuchRepository
) {
suspend fun loadDiaryDates(clubId: String): DiaryDatesResult = repository.loadDiaryDates(clubId)
suspend fun createDiaryDate(
clubId: String,
date: String,
trainingStart: String?,
trainingEnd: String?
): DiaryCreateDateResult = repository.createDiaryDate(clubId, date, trainingStart, trainingEnd)
suspend fun updateDiaryTrainingTime(
clubId: String,
dateId: String,
trainingStart: String?,
trainingEnd: String?
): DiaryActionResult = repository.updateDiaryTrainingTime(clubId, dateId, trainingStart, trainingEnd)
suspend fun deleteDiaryDate(clubId: String, dateId: String): DiaryActionResult =
repository.deleteDiaryDate(clubId, dateId)
suspend fun loadMembers(clubId: String): MembersResult = repository.loadMembers(clubId, showAll = false)
suspend fun loadParticipants(dateId: String): DiaryParticipantsResult = repository.loadParticipants(dateId)
suspend fun addParticipant(dateId: String, memberId: String): DiaryParticipantActionResult =
repository.addParticipant(dateId, memberId)
suspend fun removeParticipant(dateId: String, memberId: String): DiaryActionResult =
repository.removeParticipant(dateId, memberId)
suspend fun loadActivities(dateId: String): DiaryActivitiesResult = repository.loadActivities(dateId)
suspend fun addActivity(dateId: String, description: String): DiaryAddActivityResult =
repository.addActivity(dateId, description)
suspend fun loadDiaryMemberNotes(clubId: String, diaryDateId: String, memberId: String): MemberNotesResult =
repository.loadDiaryMemberNotes(clubId, diaryDateId, memberId)
suspend fun addDiaryMemberNote(
clubId: String,
diaryDateId: String,
memberId: String,
content: String
): DiaryActionResult = repository.addDiaryMemberNote(clubId, diaryDateId, memberId, content)
suspend fun deleteDiaryMemberNote(clubId: String, noteId: String): DiaryActionResult =
repository.deleteDiaryMemberNote(clubId, noteId)
suspend fun loadTags(): DiaryTagsResult = repository.loadTags()
suspend fun createTag(name: String): DiaryCreateTagResult = repository.createTag(name)
suspend fun addTagToDiaryDate(clubId: String, diaryDateId: String, tagId: String): DiaryActionResult =
repository.addTagToDiaryDate(clubId, diaryDateId, tagId)
suspend fun removeTagFromDiaryDate(clubId: String, diaryDateId: String, tagId: String): DiaryActionResult =
repository.removeTagFromDiaryDate(clubId, diaryDateId, tagId)
suspend fun loadDiaryPlan(clubId: String, dateId: String): DiaryPlanResult =
repository.loadDiaryPlan(clubId, dateId)
suspend fun addDiaryPlanItem(clubId: String, dateId: String, activity: String, orderId: Int): DiaryActionResult =
repository.addDiaryPlanItem(clubId, dateId, activity, orderId)
suspend fun updateDiaryPlanItem(clubId: String, planItemId: String, activity: String): DiaryActionResult =
repository.updateDiaryPlanItem(clubId, planItemId, activity)
suspend fun deleteDiaryPlanItem(clubId: String, planItemId: String): DiaryActionResult =
repository.deleteDiaryPlanItem(clubId, planItemId)
suspend fun updateDiaryPlanItemOrder(clubId: String, planItemId: String, order: Int): DiaryActionResult =
repository.updateDiaryPlanItemOrder(clubId, planItemId, order)
suspend fun loadDiaryGroups(clubId: String, dateId: String): DiaryGroupsResult =
repository.loadDiaryGroups(clubId, dateId)
suspend fun updateParticipantGroup(dateId: String, memberId: String, groupId: String?): DiaryActionResult =
repository.updateParticipantGroup(dateId, memberId, groupId)
suspend fun createDiaryGroup(clubId: String, dateId: String, name: String, lead: String): DiaryActionResult =
repository.createDiaryGroup(clubId, dateId, name, lead)
suspend fun updateDiaryGroup(groupId: String, clubId: String, dateId: String, name: String, lead: String): DiaryActionResult =
repository.updateDiaryGroup(groupId, clubId, dateId, name, lead)
suspend fun deleteDiaryGroup(groupId: String, clubId: String, dateId: String): DiaryActionResult =
repository.deleteDiaryGroup(groupId, clubId, dateId)
suspend fun createDiaryGroupActivity(
clubId: String,
dateId: String,
groupId: String,
activity: String,
predefinedActivityId: String?
): DiaryActionResult = repository.createDiaryGroupActivity(clubId, dateId, groupId, activity, predefinedActivityId)
suspend fun loadActivityParticipantIds(clubId: String, activityId: String): DiaryActivityParticipantsResult =
repository.loadActivityParticipantIds(clubId, activityId)
suspend fun assignActivityParticipants(clubId: String, activityId: String, participantIds: List<String>): DiaryActionResult =
repository.assignActivityParticipants(clubId, activityId, participantIds)
suspend fun removeActivityParticipant(clubId: String, activityId: String, participantId: String): DiaryActionResult =
repository.removeActivityParticipant(clubId, activityId, participantId)
suspend fun createAccident(clubId: String, dateId: String, accident: String): DiaryActionResult =
repository.createAccident(clubId, dateId, accident)
suspend fun loadAccidents(clubId: String, dateId: String): DiaryAccidentsResult =
repository.loadAccidents(clubId, dateId)
suspend fun loadMemberActivityStats(clubId: String, memberId: String): MemberActivityStatsResult =
repository.loadMemberActivityStats(clubId, memberId)
suspend fun searchPredefinedActivities(term: String, limit: Int = 10): PredefinedActivitiesResult =
repository.searchPredefinedActivities(term, limit)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,339 @@
<resources>
<string name="app_name">Trainingstagebuch</string>
<string name="auth_login_title">Login</string>
<string name="auth_register_title">Registration</string>
<string name="auth_email_label">Email</string>
<string name="auth_password_label">Password</string>
<string name="auth_password_confirm_label">Confirm password</string>
<string name="auth_login_button">Sign in</string>
<string name="auth_register_button">Register</string>
<string name="auth_login_to_register">New here? Register now</string>
<string name="auth_register_to_login">Already have an account? Go to login</string>
<string name="auth_forgot_link">Forgot password?</string>
<string name="auth_forgot_title">Forgot password</string>
<string name="auth_forgot_description">Enter your email. We will send you a reset link.</string>
<string name="auth_forgot_submit">Send reset link</string>
<string name="auth_forgot_success_default">If an account exists, a reset email has been sent</string>
<string name="auth_reset_title">Reset password</string>
<string name="auth_new_password_label">New password</string>
<string name="auth_confirm_password_label">Confirm password</string>
<string name="auth_reset_submit">Save new password</string>
<string name="auth_reset_success_default">Password changed successfully</string>
<string name="auth_back_to_login">Back to login</string>
<string name="auth_activate_title">Activate account</string>
<string name="auth_activate_button">Retry activation</string>
<string name="auth_activate_loading">Activating your account...</string>
<string name="auth_activate_success_default">Account activated successfully</string>
<string name="home_title">Home / Dashboard</string>
<string name="home_loading">Loading home data...</string>
<string name="home_retry">Try again</string>
<string name="home_club_count">Clubs: %1$d</string>
<string name="home_first_club">First club: %1$s</string>
<string name="home_open_current_club">Open current club</string>
<string name="home_open_club_settings">Open club settings</string>
<string name="home_open_pending_approvals">Open approvals</string>
<string name="home_open_diary">Open diary</string>
<string name="create_club_title">Create club</string>
<string name="create_club_name_label">Club name</string>
<string name="create_club_create_button">Create club</string>
<string name="create_club_back_button">Back</string>
<string name="create_club_name_required">Please enter a meaningful club name.</string>
<string name="create_club_success_default">Club created successfully</string>
<string name="show_club_loading">Loading club...</string>
<string name="show_club_title">Club: %1$s</string>
<string name="show_club_members_count">Active members: %1$d</string>
<string name="show_club_no_access">You currently do not have access to this club.</string>
<string name="show_club_access_request_pending">Access request already sent. Please wait for approval.</string>
<string name="show_club_request_access_button">Request access</string>
<string name="show_club_open_requests_count">Open access requests: %1$d</string>
<string name="show_club_open_requests_title">Open requests</string>
<string name="show_club_members_title">Members</string>
<string name="club_settings_title">Club settings</string>
<string name="club_settings_loading">Loading club settings...</string>
<string name="club_settings_greeting_label">Greeting text</string>
<string name="club_settings_association_member_number_label">Association member number</string>
<string name="club_settings_save_button">Save settings</string>
<string name="club_settings_saved_default">Club settings saved</string>
<string name="club_settings_tab_settings">Settings</string>
<string name="club_settings_tab_groups">Groups</string>
<string name="club_settings_tab_times">Times</string>
<string name="club_settings_group_name_label">Group name</string>
<string name="club_settings_group_create_button">Create group</string>
<string name="club_settings_group_name_required">Please enter a group name</string>
<string name="club_settings_group_created">Training group created</string>
<string name="club_settings_group_deleted">Training group deleted</string>
<string name="club_settings_group_updated">Training group updated</string>
<string name="club_settings_time_group_id_label">Group ID</string>
<string name="club_settings_time_weekday_label">Weekday (0-6)</string>
<string name="club_settings_time_start_label">Start (HH:mm)</string>
<string name="club_settings_time_end_label">End (HH:mm)</string>
<string name="club_settings_time_create_button">Create time</string>
<string name="club_settings_time_required">Please provide group, weekday, start and end time</string>
<string name="club_settings_time_created">Training time created</string>
<string name="club_settings_time_deleted">Training time deleted</string>
<string name="club_settings_time_updated">Training time updated</string>
<string name="club_settings_time_row">Day %1$d: %2$s - %3$s</string>
<string name="club_settings_edit_button">Edit</string>
<string name="club_settings_update_button">Save</string>
<string name="club_settings_cancel_button">Cancel</string>
<string name="club_settings_delete_button">Delete</string>
<string name="club_settings_dialog_edit_group_title">Edit training group</string>
<string name="club_settings_dialog_edit_time_title">Edit training time</string>
<string name="club_settings_weekday_sunday">Sunday</string>
<string name="club_settings_weekday_monday">Monday</string>
<string name="club_settings_weekday_tuesday">Tuesday</string>
<string name="club_settings_weekday_wednesday">Wednesday</string>
<string name="club_settings_weekday_thursday">Thursday</string>
<string name="club_settings_weekday_friday">Friday</string>
<string name="club_settings_weekday_saturday">Saturday</string>
<string name="pending_approvals_title">Pending approvals</string>
<string name="pending_approvals_loading">Loading requests...</string>
<string name="pending_approvals_empty">No pending approval requests</string>
<string name="pending_approvals_approve_button">Approve</string>
<string name="pending_approvals_reject_button">Reject</string>
<string name="pending_approvals_action_success">Request updated</string>
<string name="diary_title">Diary</string>
<string name="diary_loading">Loading diary data...</string>
<string name="diary_empty">No diary entries yet</string>
<string name="diary_new_date_label">Date (YYYY-MM-DD)</string>
<string name="diary_training_start_label">Training start (HH:mm)</string>
<string name="diary_training_end_label">Training end (HH:mm)</string>
<string name="diary_create_button">Create date</string>
<string name="diary_times_value">Times: %1$s</string>
<string name="diary_create_success">Diary date created</string>
<string name="diary_date_required">Please provide a date</string>
<string name="diary_select_date_required">Please select a date first</string>
<string name="diary_selected_times_title">Edit selected date</string>
<string name="diary_update_times_button">Save times</string>
<string name="diary_delete_button">Delete date</string>
<string name="diary_update_success">Training times updated</string>
<string name="diary_delete_success">Diary date deleted</string>
<string name="diary_participants_title">Participants (%1$d)</string>
<string name="diary_no_members">No members available</string>
<string name="diary_add_participant_button">Add</string>
<string name="diary_remove_participant_button">Remove</string>
<string name="diary_group_none">No group</string>
<string name="diary_groups_title">Groups (%1$d)</string>
<string name="diary_group_name_label">Group name</string>
<string name="diary_group_lead_label">Lead</string>
<string name="diary_group_create_button">Create group</string>
<string name="diary_groups_empty">No groups available</string>
<string name="diary_group_name_required">Please enter a group name</string>
<string name="diary_group_created">Group created</string>
<string name="diary_group_updated">Group updated</string>
<string name="diary_group_deleted">Group deleted</string>
<string name="diary_group_edit_button">Edit</string>
<string name="diary_group_delete_button">Delete</string>
<string name="diary_group_save_button">Save</string>
<string name="diary_group_cancel_button">Cancel</string>
<string name="diary_group_activity_title">Group activity</string>
<string name="diary_group_activity_input_label">Activity (group)</string>
<string name="diary_group_activity_add_button">Add group activity</string>
<string name="diary_select_group_and_activity">Please select group and activity</string>
<string name="diary_group_activity_added">Group activity added</string>
<string name="diary_activity_assignment_updated">Activity assignment updated</string>
<string name="diary_participant_add_failed">Participant could not be created</string>
<string name="diary_quick_add_button">Quick add</string>
<string name="diary_quick_add_title">Quick add member</string>
<string name="diary_quick_add_firstname_label">First name</string>
<string name="diary_quick_add_lastname_label">Last name</string>
<string name="diary_quick_add_birthdate_label">Birth date</string>
<string name="diary_quick_add_gender_label">Gender</string>
<string name="diary_quick_add_confirm">Create + add</string>
<string name="diary_quick_add_cancel">Cancel</string>
<string name="diary_quick_add_firstname_required">First name is required</string>
<string name="diary_quick_add_success">Member created and added</string>
<string name="diary_accidents_title">Accidents (%1$d)</string>
<string name="diary_accident_input_label">Accident description</string>
<string name="diary_accident_save_button">Save accident</string>
<string name="diary_accident_required">Please enter accident description</string>
<string name="diary_accident_saved">Accident saved</string>
<string name="diary_stats_button">Stats</string>
<string name="diary_stats_title">Member stats</string>
<string name="diary_stats_recent_title">Last participations</string>
<string name="diary_stats_activity_title">Activities</string>
<string name="diary_stats_empty">No data</string>
<string name="diary_stats_close">Close</string>
<string name="diary_participant_added">Participant added</string>
<string name="diary_participant_removed">Participant removed</string>
<string name="diary_participant_group_updated">Participant group updated</string>
<string name="diary_activities_title">Activities (%1$d)</string>
<string name="diary_activities_empty">No activities available</string>
<string name="diary_activity_input_label">Activity description</string>
<string name="diary_add_activity_button">Add activity</string>
<string name="diary_activity_required">Please enter an activity</string>
<string name="diary_activity_added">Activity added</string>
<string name="diary_notes_title">Notes (%1$d)</string>
<string name="diary_no_participants_for_notes">No participants available for notes</string>
<string name="diary_note_input_label">New note</string>
<string name="diary_add_note_button">Add note</string>
<string name="diary_notes_empty">No notes available</string>
<string name="diary_delete_note_button">Delete</string>
<string name="diary_note_required">Please enter a note</string>
<string name="diary_select_note_member_required">Please select participant and date</string>
<string name="diary_note_added">Note saved</string>
<string name="diary_note_deleted">Note deleted</string>
<string name="diary_tags_title">Date tags (%1$d)</string>
<string name="diary_new_tag_input_label">New tag</string>
<string name="diary_create_tag_button">Create and attach tag</string>
<string name="diary_no_tags_available">No tags available</string>
<string name="diary_add_tag_button">Attach</string>
<string name="diary_remove_tag_button">Remove</string>
<string name="diary_tag_name_required">Please enter a tag name</string>
<string name="diary_tag_added">Tag attached</string>
<string name="diary_tag_removed">Tag removed</string>
<string name="diary_plan_title">Training plan (%1$d)</string>
<string name="diary_plan_new_activity_label">New plan activity</string>
<string name="diary_plan_add_button">Add plan item</string>
<string name="diary_plan_empty">No plan items available</string>
<string name="diary_plan_item_added">Plan item added</string>
<string name="diary_plan_item_updated">Plan item updated</string>
<string name="diary_plan_item_deleted">Plan item deleted</string>
<string name="diary_plan_order_updated">Plan order updated</string>
<string name="diary_plan_activity_required">Please enter a plan activity</string>
<string name="diary_plan_timeblock_label">Timeblock</string>
<string name="diary_plan_up_button">Up</string>
<string name="diary_plan_down_button">Down</string>
<string name="diary_plan_edit_button">Edit</string>
<string name="diary_plan_delete_button">Delete</string>
<string name="diary_plan_save_button">Save</string>
<string name="diary_plan_cancel_button">Cancel</string>
<string name="diary_date_cannot_be_deleted">Date can only be deleted when it has no content.</string>
<string name="diary_confirm_delete_title">Delete date</string>
<string name="diary_confirm_delete_message">Do you really want to delete this date?</string>
<string name="diary_confirm_delete_confirm">Delete</string>
<string name="diary_confirm_delete_cancel">Cancel</string>
<string name="members_title">Members</string>
<string name="members_new_button">New</string>
<string name="members_edit_button">Edit</string>
<string name="members_editor_create_title">Create member</string>
<string name="members_editor_edit_title">Edit member</string>
<string name="members_first_name_label">First name</string>
<string name="members_last_name_label">Last name</string>
<string name="members_contacts_title">Contacts</string>
<string name="members_stats_active">Active: %1$d</string>
<string name="members_stats_test">Test: %1$d</string>
<string name="members_stats_inactive">Inactive: %1$d</string>
<string name="members_phone_label">Phone</string>
<string name="members_email_label">Email</string>
<string name="members_add_phone_button">Add phone</string>
<string name="members_add_email_button">Add email</string>
<string name="members_remove_contact_button">Remove</string>
<string name="members_training_groups_title">Training groups</string>
<string name="members_training_groups_none">No groups assigned</string>
<string name="members_add_group_label">Select group</string>
<string name="members_add_group_button">Add to group</string>
<string name="members_remove_group_button">Remove from group</string>
<string name="members_notes_title">Notes</string>
<string name="members_note_input_label">New note</string>
<string name="members_add_note_button">Save note</string>
<string name="members_delete_note_button">Delete</string>
<string name="members_notes_empty">No notes available</string>
<string name="members_group_added_default">Group assigned</string>
<string name="members_group_removed_default">Group removed</string>
<string name="members_save_create_button">Create member</string>
<string name="members_save_update_button">Save member</string>
<string name="members_save_success_default">Member saved</string>
<string name="members_action_deactivate">Deactivate</string>
<string name="members_action_remove_test">Remove test status</string>
<string name="members_action_deactivated_default">Member deactivated</string>
<string name="members_action_test_removed_default">Test status removed</string>
<string name="members_image_upload_button">Upload image</string>
<string name="members_image_set_primary_button">Set primary</string>
<string name="members_image_delete_button">Delete</string>
<string name="members_image_primary_badge">Primary</string>
<string name="members_images_empty">No images available</string>
<string name="members_image_uploaded_default">Image uploaded</string>
<string name="members_image_action_success_default">Image updated</string>
<string name="members_loading">Loading members...</string>
<string name="members_idle">Members view ready</string>
<string name="members_empty">No members found</string>
<string name="members_search_label">Search by name</string>
<string name="members_show_inactive">Show inactive</string>
<string name="members_sort_button">Sort: %1$s</string>
<string name="members_sort_name_asc">Name A-Z</string>
<string name="members_sort_name_desc">Name Z-A</string>
<string name="members_sort_status">Status</string>
<string name="members_item_active">Active</string>
<string name="members_item_test">Test member</string>
<string name="members_item_inactive">Inactive</string>
<string name="common_ok">OK</string>
<string name="common_logout">Logout</string>
<string name="error_unknown">Unknown error</string>
<string name="error_timeout">Request timed out. Please try again.</string>
<string name="error_no_network">No network connection. Please check your connection.</string>
<string name="error_network">Network error. Please try again.</string>
<string name="error_http_4xx">Invalid request (%1$d). Please check your input.</string>
<string name="error_http_5xx">Server error (%1$d). Please try again later.</string>
<string name="error_http_generic">HTTP error (%1$d)</string>
<string name="error_required_login_fields">Please enter email and password</string>
<string name="error_required_register_fields">Please fill all fields</string>
<string name="error_password_mismatch">Passwords do not match</string>
<string name="error_required_email">Please enter email</string>
<string name="error_password_too_short">Password must be at least 6 characters</string>
<string name="error_required_reset_token">Invalid reset token</string>
<string name="error_required_activation_code">Invalid activation code</string>
<string name="error_required_member_name">First name and last name are required</string>
<string name="error_select_member_for_images">Please select a member first</string>
<string name="error_select_member_for_notes">Please select a member first</string>
<string name="error_note_content_required">Note must not be empty</string>
<string name="error_no_current_club">No active club selected</string>
<string name="error_required_transfer_fields">Please provide server, transfer endpoint and transfer template</string>
<string name="error_missing_auth">Missing authentication</string>
<string name="auth_register_success_default">Registration successful</string>
<string name="message_dynamic">%1$s</string>
<string name="error_dynamic">%1$s</string>
<string name="error_dynamic_with_code">%1$s (%2$s)</string>
<string name="member_transfer_title">Member Transfer Settings</string>
<string name="member_transfer_loading">Loading transfer configuration...</string>
<string name="member_transfer_server_label">Server URL</string>
<string name="member_transfer_login_endpoint_label">Login endpoint</string>
<string name="member_transfer_login_format_label">Login format (json/form)</string>
<string name="member_transfer_login_username_label">Login username</string>
<string name="member_transfer_login_password_label">Login password</string>
<string name="member_transfer_login_additional_1_label">Login additional field 1 (key:value)</string>
<string name="member_transfer_login_additional_2_label">Login additional field 2 (key:value)</string>
<string name="member_transfer_endpoint_label">Transfer endpoint</string>
<string name="member_transfer_method_label">Transfer method</string>
<string name="member_transfer_format_label">Transfer format (json/form)</string>
<string name="member_transfer_template_label">Transfer template (JSON)</string>
<string name="member_transfer_bulk_mode_label">Use bulk mode</string>
<string name="member_transfer_bulk_wrapper_label">Bulk wrapper template</string>
<string name="member_transfer_save_button">Save configuration</string>
<string name="member_transfer_delete_button">Delete configuration</string>
<string name="member_transfer_execute_button">Execute transfer</string>
<string name="member_transfer_saved_default">Transfer configuration saved</string>
<string name="member_transfer_deleted_default">Transfer configuration deleted</string>
<string name="member_transfer_execute_success">Member transfer executed successfully</string>
<string name="member_transfer_summary_title">Transfer summary</string>
<string name="member_transfer_summary_transferred">Transferred: %1$d of %2$d</string>
<string name="member_transfer_summary_invalid_members">Invalid members: %1$s</string>
<string name="member_transfer_summary_errors">Errors: %1$s</string>
<string name="placeholder_activate">Activate: %1$s</string>
<string name="placeholder_forgot_password">Forgot Password</string>
<string name="placeholder_reset_password">Reset Password: %1$s</string>
<string name="placeholder_create_club">Create Club</string>
<string name="placeholder_show_club">Show Club: %1$s</string>
<string name="placeholder_members">Members</string>
<string name="placeholder_diary">Diary</string>
<string name="placeholder_pending_approvals">Pending Approvals</string>
<string name="placeholder_schedule">Schedule</string>
<string name="placeholder_tournaments">Tournaments</string>
<string name="placeholder_training_stats">Training Stats</string>
<string name="placeholder_club_settings">Club Settings</string>
<string name="placeholder_predefined_activities">Predefined Activities</string>
<string name="placeholder_mytischtennis_account">MyTischtennis Account</string>
<string name="placeholder_team_management">Team Management</string>
<string name="placeholder_permissions">Permissions</string>
<string name="placeholder_logs">Logs</string>
<string name="placeholder_member_transfer_settings">Member Transfer Settings</string>
<string name="placeholder_personal_settings">Personal Settings</string>
<string name="placeholder_impressum">Impressum</string>
<string name="placeholder_datenschutz">Data Privacy</string>
<string name="diary_accident_item_value">• %1$s</string>
<string name="diary_participation_item_value">%1$s: %2$s</string>
<string name="diary_stat_item_value">%1$s: %2$d</string>
</resources>

View File

@@ -0,0 +1,339 @@
<resources>
<string name="app_name">Trainingstagebuch</string>
<string name="auth_login_title">Anmeldung</string>
<string name="auth_register_title">Registrierung</string>
<string name="auth_email_label">E-Mail</string>
<string name="auth_password_label">Passwort</string>
<string name="auth_password_confirm_label">Passwort wiederholen</string>
<string name="auth_login_button">Einloggen</string>
<string name="auth_register_button">Registrieren</string>
<string name="auth_login_to_register">Neu hier? Jetzt registrieren</string>
<string name="auth_register_to_login">Schon ein Konto? Zum Login</string>
<string name="auth_forgot_link">Passwort vergessen?</string>
<string name="auth_forgot_title">Passwort vergessen</string>
<string name="auth_forgot_description">Gib deine E-Mail ein. Wir senden dir einen Link zum Zurücksetzen.</string>
<string name="auth_forgot_submit">Reset-Link senden</string>
<string name="auth_forgot_success_default">Falls ein Konto existiert, wurde eine E-Mail zum Zurücksetzen gesendet</string>
<string name="auth_reset_title">Passwort zurücksetzen</string>
<string name="auth_new_password_label">Neues Passwort</string>
<string name="auth_confirm_password_label">Passwort bestätigen</string>
<string name="auth_reset_submit">Neues Passwort speichern</string>
<string name="auth_reset_success_default">Passwort erfolgreich geändert</string>
<string name="auth_back_to_login">Zurück zum Login</string>
<string name="auth_activate_title">Account aktivieren</string>
<string name="auth_activate_button">Erneut aktivieren</string>
<string name="auth_activate_loading">Aktivierung wird ausgeführt...</string>
<string name="auth_activate_success_default">Account wurde erfolgreich aktiviert</string>
<string name="home_title">Home / Dashboard</string>
<string name="home_loading">Lade Home-Daten...</string>
<string name="home_retry">Erneut versuchen</string>
<string name="home_club_count">Clubs: %1$d</string>
<string name="home_first_club">Erster Club: %1$s</string>
<string name="home_open_current_club">Aktuellen Club öffnen</string>
<string name="home_open_club_settings">Club-Einstellungen öffnen</string>
<string name="home_open_pending_approvals">Freigaben öffnen</string>
<string name="home_open_diary">Tagebuch öffnen</string>
<string name="create_club_title">Verein erstellen</string>
<string name="create_club_name_label">Vereinsname</string>
<string name="create_club_create_button">Verein anlegen</string>
<string name="create_club_back_button">Zurück</string>
<string name="create_club_name_required">Bitte gib dem Verein einen aussagekräftigen Namen.</string>
<string name="create_club_success_default">Verein erfolgreich erstellt</string>
<string name="show_club_loading">Lade Club...</string>
<string name="show_club_title">Club: %1$s</string>
<string name="show_club_members_count">Aktive Mitglieder: %1$d</string>
<string name="show_club_no_access">Du hast aktuell keinen Zugriff auf diesen Club.</string>
<string name="show_club_access_request_pending">Zugriffsanfrage bereits gestellt. Bitte auf Freigabe warten.</string>
<string name="show_club_request_access_button">Zugriff anfragen</string>
<string name="show_club_open_requests_count">Offene Zugriffsanfragen: %1$d</string>
<string name="show_club_open_requests_title">Offene Anfragen</string>
<string name="show_club_members_title">Mitglieder</string>
<string name="club_settings_title">Club Settings</string>
<string name="club_settings_loading">Lade Club-Einstellungen...</string>
<string name="club_settings_greeting_label">Begrüßungstext</string>
<string name="club_settings_association_member_number_label">Verband-Mitgliedsnummer</string>
<string name="club_settings_save_button">Einstellungen speichern</string>
<string name="club_settings_saved_default">Club-Einstellungen gespeichert</string>
<string name="club_settings_tab_settings">Settings</string>
<string name="club_settings_tab_groups">Gruppen</string>
<string name="club_settings_tab_times">Zeiten</string>
<string name="club_settings_group_name_label">Gruppenname</string>
<string name="club_settings_group_create_button">Gruppe anlegen</string>
<string name="club_settings_group_name_required">Bitte Gruppennamen eingeben</string>
<string name="club_settings_group_created">Trainingsgruppe erstellt</string>
<string name="club_settings_group_deleted">Trainingsgruppe gelöscht</string>
<string name="club_settings_group_updated">Trainingsgruppe aktualisiert</string>
<string name="club_settings_time_group_id_label">Gruppen-ID</string>
<string name="club_settings_time_weekday_label">Wochentag (0-6)</string>
<string name="club_settings_time_start_label">Start (HH:mm)</string>
<string name="club_settings_time_end_label">Ende (HH:mm)</string>
<string name="club_settings_time_create_button">Zeit anlegen</string>
<string name="club_settings_time_required">Bitte Gruppe, Wochentag sowie Start/Ende korrekt ausfüllen</string>
<string name="club_settings_time_created">Trainingszeit erstellt</string>
<string name="club_settings_time_deleted">Trainingszeit gelöscht</string>
<string name="club_settings_time_updated">Trainingszeit aktualisiert</string>
<string name="club_settings_time_row">Tag %1$d: %2$s - %3$s</string>
<string name="club_settings_edit_button">Bearbeiten</string>
<string name="club_settings_update_button">Speichern</string>
<string name="club_settings_cancel_button">Abbrechen</string>
<string name="club_settings_delete_button">Löschen</string>
<string name="club_settings_dialog_edit_group_title">Trainingsgruppe bearbeiten</string>
<string name="club_settings_dialog_edit_time_title">Trainingszeit bearbeiten</string>
<string name="club_settings_weekday_sunday">Sonntag</string>
<string name="club_settings_weekday_monday">Montag</string>
<string name="club_settings_weekday_tuesday">Dienstag</string>
<string name="club_settings_weekday_wednesday">Mittwoch</string>
<string name="club_settings_weekday_thursday">Donnerstag</string>
<string name="club_settings_weekday_friday">Freitag</string>
<string name="club_settings_weekday_saturday">Samstag</string>
<string name="pending_approvals_title">Ausstehende Freigaben</string>
<string name="pending_approvals_loading">Lade Anfragen...</string>
<string name="pending_approvals_empty">Keine offenen Freigabe-Anfragen</string>
<string name="pending_approvals_approve_button">Freigeben</string>
<string name="pending_approvals_reject_button">Ablehnen</string>
<string name="pending_approvals_action_success">Anfrage aktualisiert</string>
<string name="diary_title">Tagebuch</string>
<string name="diary_loading">Lade Tagebuchdaten...</string>
<string name="diary_empty">Noch keine Tagebucheinträge vorhanden</string>
<string name="diary_new_date_label">Datum (YYYY-MM-DD)</string>
<string name="diary_training_start_label">Trainingsstart (HH:mm)</string>
<string name="diary_training_end_label">Trainingsende (HH:mm)</string>
<string name="diary_create_button">Datum anlegen</string>
<string name="diary_times_value">Zeiten: %1$s</string>
<string name="diary_create_success">Tagebuchdatum erstellt</string>
<string name="diary_date_required">Bitte ein Datum angeben</string>
<string name="diary_select_date_required">Bitte zuerst ein Datum auswählen</string>
<string name="diary_selected_times_title">Ausgewähltes Datum bearbeiten</string>
<string name="diary_update_times_button">Zeiten speichern</string>
<string name="diary_delete_button">Datum löschen</string>
<string name="diary_update_success">Trainingszeiten aktualisiert</string>
<string name="diary_delete_success">Tagebuchdatum gelöscht</string>
<string name="diary_participants_title">Teilnehmer (%1$d)</string>
<string name="diary_no_members">Keine Mitglieder verfügbar</string>
<string name="diary_add_participant_button">Hinzufügen</string>
<string name="diary_remove_participant_button">Entfernen</string>
<string name="diary_group_none">Ohne Gruppe</string>
<string name="diary_groups_title">Gruppen (%1$d)</string>
<string name="diary_group_name_label">Gruppenname</string>
<string name="diary_group_lead_label">Leitung</string>
<string name="diary_group_create_button">Gruppe erstellen</string>
<string name="diary_groups_empty">Keine Gruppen vorhanden</string>
<string name="diary_group_name_required">Bitte Gruppennamen eingeben</string>
<string name="diary_group_created">Gruppe erstellt</string>
<string name="diary_group_updated">Gruppe aktualisiert</string>
<string name="diary_group_deleted">Gruppe gelöscht</string>
<string name="diary_group_edit_button">Bearbeiten</string>
<string name="diary_group_delete_button">Löschen</string>
<string name="diary_group_save_button">Speichern</string>
<string name="diary_group_cancel_button">Abbrechen</string>
<string name="diary_group_activity_title">Gruppenaktivität</string>
<string name="diary_group_activity_input_label">Aktivität (Gruppe)</string>
<string name="diary_group_activity_add_button">Gruppenaktivität hinzufügen</string>
<string name="diary_select_group_and_activity">Bitte Gruppe und Aktivität wählen</string>
<string name="diary_group_activity_added">Gruppenaktivität hinzugefügt</string>
<string name="diary_activity_assignment_updated">Aktivitätszuordnung aktualisiert</string>
<string name="diary_participant_add_failed">Teilnehmer konnte nicht erstellt werden</string>
<string name="diary_quick_add_button">Schnell hinzufügen</string>
<string name="diary_quick_add_title">Mitglied schnell hinzufügen</string>
<string name="diary_quick_add_firstname_label">Vorname</string>
<string name="diary_quick_add_lastname_label">Nachname</string>
<string name="diary_quick_add_birthdate_label">Geburtsdatum</string>
<string name="diary_quick_add_gender_label">Geschlecht</string>
<string name="diary_quick_add_confirm">Erstellen + hinzufügen</string>
<string name="diary_quick_add_cancel">Abbrechen</string>
<string name="diary_quick_add_firstname_required">Vorname ist erforderlich</string>
<string name="diary_quick_add_success">Mitglied erstellt und hinzugefügt</string>
<string name="diary_accidents_title">Unfälle (%1$d)</string>
<string name="diary_accident_input_label">Unfallbeschreibung</string>
<string name="diary_accident_save_button">Unfall speichern</string>
<string name="diary_accident_required">Bitte Unfallbeschreibung eingeben</string>
<string name="diary_accident_saved">Unfall gespeichert</string>
<string name="diary_stats_button">Statistik</string>
<string name="diary_stats_title">Mitgliederstatistik</string>
<string name="diary_stats_recent_title">Letzte Teilnahmen</string>
<string name="diary_stats_activity_title">Aktivitäten</string>
<string name="diary_stats_empty">Keine Daten</string>
<string name="diary_stats_close">Schließen</string>
<string name="diary_participant_added">Teilnehmer hinzugefügt</string>
<string name="diary_participant_removed">Teilnehmer entfernt</string>
<string name="diary_participant_group_updated">Teilnehmer-Gruppe aktualisiert</string>
<string name="diary_activities_title">Aktivitäten (%1$d)</string>
<string name="diary_activities_empty">Keine Aktivitäten vorhanden</string>
<string name="diary_activity_input_label">Aktivitätsbeschreibung</string>
<string name="diary_add_activity_button">Aktivität hinzufügen</string>
<string name="diary_activity_required">Bitte eine Aktivität eingeben</string>
<string name="diary_activity_added">Aktivität hinzugefügt</string>
<string name="diary_notes_title">Notizen (%1$d)</string>
<string name="diary_no_participants_for_notes">Keine Teilnehmer für Notizen ausgewählt</string>
<string name="diary_note_input_label">Neue Notiz</string>
<string name="diary_add_note_button">Notiz hinzufügen</string>
<string name="diary_notes_empty">Keine Notizen vorhanden</string>
<string name="diary_delete_note_button">Löschen</string>
<string name="diary_note_required">Bitte eine Notiz eingeben</string>
<string name="diary_select_note_member_required">Bitte Teilnehmer und Datum auswählen</string>
<string name="diary_note_added">Notiz gespeichert</string>
<string name="diary_note_deleted">Notiz gelöscht</string>
<string name="diary_tags_title">Datumstags (%1$d)</string>
<string name="diary_new_tag_input_label">Neues Tag</string>
<string name="diary_create_tag_button">Tag erstellen und zuordnen</string>
<string name="diary_no_tags_available">Keine Tags verfügbar</string>
<string name="diary_add_tag_button">Zuordnen</string>
<string name="diary_remove_tag_button">Entfernen</string>
<string name="diary_tag_name_required">Bitte einen Tag-Namen eingeben</string>
<string name="diary_tag_added">Tag zugeordnet</string>
<string name="diary_tag_removed">Tag entfernt</string>
<string name="diary_plan_title">Trainingsplan (%1$d)</string>
<string name="diary_plan_new_activity_label">Neue Plan-Aktivität</string>
<string name="diary_plan_add_button">Plan-Item hinzufügen</string>
<string name="diary_plan_empty">Keine Plan-Items vorhanden</string>
<string name="diary_plan_item_added">Plan-Item hinzugefügt</string>
<string name="diary_plan_item_updated">Plan-Item aktualisiert</string>
<string name="diary_plan_item_deleted">Plan-Item gelöscht</string>
<string name="diary_plan_order_updated">Plan-Reihenfolge aktualisiert</string>
<string name="diary_plan_activity_required">Bitte eine Plan-Aktivität eingeben</string>
<string name="diary_plan_timeblock_label">Zeitblock</string>
<string name="diary_plan_up_button">Hoch</string>
<string name="diary_plan_down_button">Runter</string>
<string name="diary_plan_edit_button">Bearbeiten</string>
<string name="diary_plan_delete_button">Löschen</string>
<string name="diary_plan_save_button">Speichern</string>
<string name="diary_plan_cancel_button">Abbrechen</string>
<string name="diary_date_cannot_be_deleted">Datum kann nur gelöscht werden, wenn keine Inhalte vorhanden sind.</string>
<string name="diary_confirm_delete_title">Datum löschen</string>
<string name="diary_confirm_delete_message">Möchtest du dieses Datum wirklich löschen?</string>
<string name="diary_confirm_delete_confirm">Löschen</string>
<string name="diary_confirm_delete_cancel">Abbrechen</string>
<string name="members_title">Mitglieder</string>
<string name="members_new_button">Neu</string>
<string name="members_edit_button">Bearbeiten</string>
<string name="members_editor_create_title">Neues Mitglied</string>
<string name="members_editor_edit_title">Mitglied bearbeiten</string>
<string name="members_first_name_label">Vorname</string>
<string name="members_last_name_label">Nachname</string>
<string name="members_contacts_title">Kontakte</string>
<string name="members_stats_active">Aktiv: %1$d</string>
<string name="members_stats_test">Test: %1$d</string>
<string name="members_stats_inactive">Inaktiv: %1$d</string>
<string name="members_phone_label">Telefon</string>
<string name="members_email_label">E-Mail</string>
<string name="members_add_phone_button">Telefon hinzufügen</string>
<string name="members_add_email_button">E-Mail hinzufügen</string>
<string name="members_remove_contact_button">Entfernen</string>
<string name="members_training_groups_title">Trainingsgruppen</string>
<string name="members_training_groups_none">Keine Gruppen zugewiesen</string>
<string name="members_add_group_label">Gruppe auswählen</string>
<string name="members_add_group_button">Zu Gruppe hinzufügen</string>
<string name="members_remove_group_button">Aus Gruppe entfernen</string>
<string name="members_notes_title">Notizen</string>
<string name="members_note_input_label">Neue Notiz</string>
<string name="members_add_note_button">Notiz speichern</string>
<string name="members_delete_note_button">Löschen</string>
<string name="members_notes_empty">Keine Notizen vorhanden</string>
<string name="members_group_added_default">Gruppe zugewiesen</string>
<string name="members_group_removed_default">Gruppe entfernt</string>
<string name="members_save_create_button">Mitglied anlegen</string>
<string name="members_save_update_button">Mitglied speichern</string>
<string name="members_save_success_default">Mitglied gespeichert</string>
<string name="members_action_deactivate">Deaktivieren</string>
<string name="members_action_remove_test">Teststatus entfernen</string>
<string name="members_action_deactivated_default">Mitglied deaktiviert</string>
<string name="members_action_test_removed_default">Teststatus entfernt</string>
<string name="members_image_upload_button">Bild hochladen</string>
<string name="members_image_set_primary_button">Primär</string>
<string name="members_image_delete_button">Löschen</string>
<string name="members_image_primary_badge">Primär</string>
<string name="members_images_empty">Keine Bilder vorhanden</string>
<string name="members_image_uploaded_default">Bild hochgeladen</string>
<string name="members_image_action_success_default">Bild aktualisiert</string>
<string name="members_loading">Lade Mitglieder...</string>
<string name="members_idle">Mitgliederansicht bereit</string>
<string name="members_empty">Keine Mitglieder gefunden</string>
<string name="members_search_label">Suche nach Name</string>
<string name="members_show_inactive">Inaktive anzeigen</string>
<string name="members_sort_button">Sortierung: %1$s</string>
<string name="members_sort_name_asc">Name A-Z</string>
<string name="members_sort_name_desc">Name Z-A</string>
<string name="members_sort_status">Status</string>
<string name="members_item_active">Aktiv</string>
<string name="members_item_test">Testmitglied</string>
<string name="members_item_inactive">Inaktiv</string>
<string name="common_ok">OK</string>
<string name="common_logout">Logout</string>
<string name="error_unknown">Unbekannter Fehler</string>
<string name="error_timeout">Zeitüberschreitung. Bitte erneut versuchen.</string>
<string name="error_no_network">Keine Netzwerkverbindung. Bitte Verbindung prüfen.</string>
<string name="error_network">Netzwerkfehler. Bitte erneut versuchen.</string>
<string name="error_http_4xx">Ungültige Anfrage (%1$d). Bitte Eingaben prüfen.</string>
<string name="error_http_5xx">Serverfehler (%1$d). Bitte später erneut versuchen.</string>
<string name="error_http_generic">HTTP-Fehler (%1$d)</string>
<string name="error_required_login_fields">Bitte E-Mail und Passwort eingeben</string>
<string name="error_required_register_fields">Bitte alle Felder ausfüllen</string>
<string name="error_password_mismatch">Passwörter stimmen nicht überein</string>
<string name="error_required_email">Bitte E-Mail eingeben</string>
<string name="error_password_too_short">Passwort muss mindestens 6 Zeichen haben</string>
<string name="error_required_reset_token">Ungültiger Reset-Token</string>
<string name="error_required_activation_code">Ungültiger Aktivierungscode</string>
<string name="error_required_member_name">Vorname und Nachname sind erforderlich</string>
<string name="error_select_member_for_images">Bitte zuerst ein Mitglied auswählen</string>
<string name="error_select_member_for_notes">Bitte zuerst ein Mitglied auswählen</string>
<string name="error_note_content_required">Notiz darf nicht leer sein</string>
<string name="error_no_current_club">Kein aktiver Club gewählt</string>
<string name="error_required_transfer_fields">Bitte Server, Transfer-Endpunkt und Transfer-Template ausfüllen</string>
<string name="error_missing_auth">Authentifizierung fehlt</string>
<string name="auth_register_success_default">Registrierung erfolgreich</string>
<string name="message_dynamic">%1$s</string>
<string name="error_dynamic">%1$s</string>
<string name="error_dynamic_with_code">%1$s (%2$s)</string>
<string name="member_transfer_title">Member Transfer Settings</string>
<string name="member_transfer_loading">Lade Transfer-Konfiguration...</string>
<string name="member_transfer_server_label">Server URL</string>
<string name="member_transfer_login_endpoint_label">Login Endpoint</string>
<string name="member_transfer_login_format_label">Login Format (json/form)</string>
<string name="member_transfer_login_username_label">Login Username</string>
<string name="member_transfer_login_password_label">Login Password</string>
<string name="member_transfer_login_additional_1_label">Login Zusatzfeld 1 (key:value)</string>
<string name="member_transfer_login_additional_2_label">Login Zusatzfeld 2 (key:value)</string>
<string name="member_transfer_endpoint_label">Transfer Endpoint</string>
<string name="member_transfer_method_label">Transfer Methode</string>
<string name="member_transfer_format_label">Transfer Format (json/form)</string>
<string name="member_transfer_template_label">Transfer Template (JSON)</string>
<string name="member_transfer_bulk_mode_label">Bulk-Modus nutzen</string>
<string name="member_transfer_bulk_wrapper_label">Bulk Wrapper Template</string>
<string name="member_transfer_save_button">Konfiguration speichern</string>
<string name="member_transfer_delete_button">Konfiguration löschen</string>
<string name="member_transfer_execute_button">Transfer ausführen</string>
<string name="member_transfer_saved_default">Transfer-Konfiguration gespeichert</string>
<string name="member_transfer_deleted_default">Transfer-Konfiguration gelöscht</string>
<string name="member_transfer_execute_success">Member-Transfer erfolgreich gestartet</string>
<string name="member_transfer_summary_title">Transfer Ergebnis</string>
<string name="member_transfer_summary_transferred">Übertragen: %1$d von %2$d</string>
<string name="member_transfer_summary_invalid_members">Ungültige Mitglieder: %1$s</string>
<string name="member_transfer_summary_errors">Fehler: %1$s</string>
<string name="placeholder_activate">Activate: %1$s</string>
<string name="placeholder_forgot_password">Forgot Password</string>
<string name="placeholder_reset_password">Reset Password: %1$s</string>
<string name="placeholder_create_club">Create Club</string>
<string name="placeholder_show_club">Show Club: %1$s</string>
<string name="placeholder_members">Members</string>
<string name="placeholder_diary">Diary</string>
<string name="placeholder_pending_approvals">Pending Approvals</string>
<string name="placeholder_schedule">Schedule</string>
<string name="placeholder_tournaments">Tournaments</string>
<string name="placeholder_training_stats">Training Stats</string>
<string name="placeholder_club_settings">Club Settings</string>
<string name="placeholder_predefined_activities">Predefined Activities</string>
<string name="placeholder_mytischtennis_account">MyTischtennis Account</string>
<string name="placeholder_team_management">Team Management</string>
<string name="placeholder_permissions">Permissions</string>
<string name="placeholder_logs">Logs</string>
<string name="placeholder_member_transfer_settings">Member Transfer Settings</string>
<string name="placeholder_personal_settings">Personal Settings</string>
<string name="placeholder_impressum">Impressum</string>
<string name="placeholder_datenschutz">Datenschutz</string>
<string name="diary_accident_item_value">• %1$s</string>
<string name="diary_participation_item_value">%1$s: %2$s</string>
<string name="diary_stat_item_value">%1$s: %2$d</string>
</resources>