Add KDoc to the single-interface library and service API modules

Cover the last remaining interfaces across libraries/audio, libraries/cachestore,
libraries/indicator, libraries/slashcommands, libraries/voiceplayer and
services/apperror, with their members and parameters.

This completes the effort: all 222 in-scope interfaces and their 820 members in
the 60 api modules that hold any now carry documentation.

Notable points: CacheStore applies no expiry of its own and only records when each
entry was written, leaving staleness to the caller; SlashCommandService.parse
never throws, returning NotACommand for ordinary text and an error case for a
malformed command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benoit Marty
2026-08-14 12:04:40 +02:00
parent 9822b3d4f7
commit b74b146917
6 changed files with 78 additions and 1 deletions
@@ -15,6 +15,9 @@ enum class AudioFocusRequester {
MediaViewer, MediaViewer,
} }
/**
* Claims and releases system audio focus, so that the app's own players do not talk over each other or over other apps.
*/
interface AudioFocus { interface AudioFocus {
/** /**
* Request audio focus for the given requester. * Request audio focus for the given requester.
@@ -7,9 +7,33 @@
package io.element.android.libraries.cachestore.api package io.element.android.libraries.cachestore.api
/**
* A generic on-disk key/value cache, where each entry records when it was written so callers can decide for themselves when it is stale.
*/
interface CacheStore { interface CacheStore {
/**
* Stores an entry, replacing any previous one under the same key.
*
* @param key the entry to write.
* @param data the value along with the time it was obtained.
*/
suspend fun storeData(key: String, data: CacheData) suspend fun storeData(key: String, data: CacheData)
/**
* Reads an entry without applying any expiry of its own; judging staleness is up to the caller.
*
* @param key the entry to read.
* @return the value and its timestamp, or `null` when nothing is stored under that key.
*/
suspend fun getData(key: String): CacheData? suspend fun getData(key: String): CacheData?
/**
* Removes one entry.
*
* @param key the entry to delete.
*/
suspend fun deleteData(key: String) suspend fun deleteData(key: String)
/** Empties the whole cache. */
suspend fun deleteAll() suspend fun deleteAll()
} }
@@ -15,9 +15,11 @@ import androidx.compose.runtime.State
* A set of State<Boolean> to observe to display or not the indicators in the UI. * A set of State<Boolean> to observe to display or not the indicators in the UI.
*/ */
interface IndicatorService { interface IndicatorService {
/** Whether to show the red dot on the room list top bar, which aggregates the reasons the user should open the settings. */
@Composable @Composable
fun showRoomListTopBarIndicator(): State<Boolean> fun showRoomListTopBarIndicator(): State<Boolean>
/** Whether to show the red dot on the chat backup setting, i.e. when recovery needs the user's attention. */
@Composable @Composable
fun showSettingChatBackupIndicator(): State<Boolean> fun showSettingChatBackupIndicator(): State<Boolean>
} }
@@ -9,7 +9,19 @@ package io.element.android.libraries.slashcommands.api
import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.Timeline
/**
* Recognises and runs the slash commands the user can type in the composer, such as `/me` or `/join`.
*
* The composer first [parse]s what was typed, then hands the result to whichever proceed method matches its kind; navigation
* commands and the error cases are handled by the composer itself.
*/
interface SlashCommandService { interface SlashCommandService {
/**
* Returns the commands whose name starts with what has been typed, so the composer can offer an autocomplete list.
*
* @param text the current composer content.
* @param isInThread whether the composer is in a thread, since not every command is available there.
*/
suspend fun getSuggestions( suspend fun getSuggestions(
text: String, text: String,
isInThread: Boolean, isInThread: Boolean,
@@ -17,6 +29,11 @@ interface SlashCommandService {
/** /**
* Parse the message and return a SlashCommand. * Parse the message and return a SlashCommand.
* Ordinary text comes back as `NotACommand`, and a malformed or unsupported command as one of the error cases, so this never throws.
*
* @param textMessage the composer content as plain text.
* @param formattedMessage the composer content as HTML, or `null` when unformatted.
* @param isInThreadTimeline whether the composer is in a thread.
*/ */
suspend fun parse( suspend fun parse(
textMessage: CharSequence, textMessage: CharSequence,
@@ -26,6 +43,9 @@ interface SlashCommandService {
/** /**
* Proceed a SlashCommandSendMessage. * Proceed a SlashCommandSendMessage.
*
* @param slashCommand the parsed command, carrying the content to send.
* @param timeline the timeline to send it to.
*/ */
suspend fun proceedSendMessage( suspend fun proceedSendMessage(
slashCommand: SlashCommand.SlashCommandSendMessage, slashCommand: SlashCommand.SlashCommandSendMessage,
@@ -33,7 +53,9 @@ interface SlashCommandService {
): Result<Unit> ): Result<Unit>
/** /**
* Proceed a SlashCommandAdmin. * Proceed a SlashCommandAdmin, i.e. one that acts on the room or its members rather than sending a message.
*
* @param slashCommand the parsed command to run.
*/ */
suspend fun proceedAdmin( suspend fun proceedAdmin(
slashCommand: SlashCommand.SlashCommandAdmin, slashCommand: SlashCommand.SlashCommandAdmin,
@@ -13,7 +13,17 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.MediaSource
import kotlin.time.Duration import kotlin.time.Duration
/**
* Creates the presenter of a single voice message player, one per voice message shown in a timeline.
*/
interface VoiceMessagePresenterFactory { interface VoiceMessagePresenterFactory {
/**
* @param eventId the event carrying the voice message, or `null` while it is still a local echo.
* @param mediaSource where the audio is fetched from.
* @param mimeType the MIME type of the audio, or `null` when the event did not state it.
* @param filename the file name to display, or `null` when the event did not state it.
* @param duration the length of the recording, used to render the waveform before the audio is downloaded.
*/
fun createVoiceMessagePresenter( fun createVoiceMessagePresenter(
eventId: EventId?, eventId: EventId?,
mediaSource: MediaSource, mediaSource: MediaSource,
@@ -11,10 +11,26 @@ package io.element.android.services.apperror.api
import androidx.annotation.StringRes import androidx.annotation.StringRes
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
/**
* Surfaces app-wide error dialogs from anywhere, for the failures that are not tied to the screen the user is on.
*/
interface AppErrorStateService { interface AppErrorStateService {
/** The error to display, if any; observed once at the top of the app rather than per screen. */
val appErrorStateFlow: StateFlow<AppErrorState> val appErrorStateFlow: StateFlow<AppErrorState>
/**
* Shows an error dialog with already resolved text.
*
* @param title the dialog title.
* @param body the dialog message; never put user content or secrets in it.
*/
fun showError(title: String, body: String) fun showError(title: String, body: String)
/**
* Shows an error dialog from string resources, which is the preferred form since it stays localised.
*
* @param titleRes resource id of the dialog title.
* @param bodyRes resource id of the dialog message.
*/
fun showError(@StringRes titleRes: Int, @StringRes bodyRes: Int) fun showError(@StringRes titleRes: Int, @StringRes bodyRes: Int)
} }