Merge pull request #7426 from element-hq/feature/bma/documentation

Add KDoc to all the interfaces of the api modules
This commit is contained in:
Benoit Marty
2026-08-14 13:46:28 +02:00
committed by GitHub
187 changed files with 2750 additions and 37 deletions
@@ -12,15 +12,34 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import kotlinx.coroutines.flow.Flow
/**
* Queues the full-screen announcements shown to the user once, such as the notice about a new feature.
*
* A dismissed announcement is remembered so it is not shown again.
*/
interface AnnouncementService {
/**
* Queues an announcement, unless the user has already dismissed it.
*
* @param announcement the announcement to show.
*/
suspend fun showAnnouncement(announcement: Announcement)
/**
* Records that the user dismissed an announcement, so it is not queued again.
*
* @param announcement the announcement that was dismissed.
*/
suspend fun onAnnouncementDismissed(announcement: Announcement)
/** The announcements still waiting to be shown, in the order they should appear. */
fun announcementsToShowFlow(): Flow<List<Announcement>>
/**
* Use this composable to render the announcement UI in Fullscreen.
* Draws nothing while there is no announcement to show.
*
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
@@ -8,6 +8,9 @@
package io.element.android.features.cachecleaner.api
/**
* Removes the temporary files holding decrypted content, so plaintext media does not linger on disk.
*/
interface CacheCleaner {
/**
* Clear the cache subdirs holding temporarily decrypted content (such as media and voice messages).
@@ -10,6 +10,9 @@ package io.element.android.features.call.api
import kotlinx.coroutines.flow.StateFlow
/**
* Tracks the call the user is currently in on this device, so unrelated parts of the app can react to it.
*/
interface CurrentCallService {
/**
* The current call state flow, which will be updated when the active call changes.
@@ -18,5 +18,11 @@ import io.element.android.libraries.matrix.ui.media.contentvalidation.ContentVal
* This will only process media when a [ContentScanner] is provided when building the client in Pro.
*/
fun interface ContentScannerService {
/**
* Starts scanning the given media, reporting the verdict of each one through [contentValidationState] rather than by returning.
*
* @param mediaSources the media to scan.
* @param contentValidationState where the outcome of each scan is published for the UI to observe.
*/
fun scan(mediaSources: List<MediaSource>, contentValidationState: ContentValidationState)
}
@@ -15,9 +15,21 @@ import io.element.android.libraries.architecture.FeatureEntryPoint
import io.element.android.libraries.matrix.api.core.RoomId
interface CreateRoomEntryPoint : FeatureEntryPoint {
/**
* Configures the create-room flow before it is started, since it serves rooms and spaces from the same screens.
*/
interface Builder {
/**
* @param isSpace true to create a space rather than a room.
*/
fun setIsSpace(isSpace: Boolean): Builder
/**
* @param parentSpaceId the space the new room should be added to once created.
*/
fun setParentSpace(parentSpaceId: RoomId): Builder
/** Builds the node with the options configured so far. */
fun build(): Node
}
@@ -15,11 +15,41 @@ import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.wellknown.api.ElementWellKnown
import kotlinx.coroutines.flow.Flow
/**
* Exposes the restrictions and customisations an enterprise deployment can impose: allowed homeservers, branding, push gateways and more.
*
* On a standard build this reports permissive defaults, so callers do not need to branch on the build type themselves.
*/
interface EnterpriseService {
/** Whether this build is an enterprise one; `false` for the public app. */
val isEnterpriseBuild: Boolean
/**
* Whether the given session belongs to an enterprise deployment, which can be true even on a standard build.
*
* @param sessionId the session to check.
*/
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
/**
* Rewrites the authentication server URL when the deployment requires a different one from the one advertised.
*
* @param url the URL to rewrite.
* @param homeserver the homeserver the URL belongs to.
* @param urlContentFetcher used to read the deployment configuration; a client that is not authenticated yet also works.
*/
suspend fun tweakMasUrl(url: String, homeserver: String, urlContentFetcher: UrlContentFetcher): String
/**
* The homeservers the user is allowed to sign in to; an empty list, or one containing [ANY_ACCOUNT_PROVIDER], means no restriction.
*/
fun defaultHomeserverList(): List<String>
/**
* Whether the user is allowed to sign in to a given homeserver, according to [defaultHomeserverList].
*
* @param homeserverUrl the server the user is trying to use.
*/
suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean
/**
@@ -29,17 +59,38 @@ interface EnterpriseService {
*/
suspend fun overrideBrandColor(sessionId: SessionId?, brandColor: String?)
/**
* The brand color to apply, or `null` when the default theme color should be used.
*
* @param sessionId the session to read the color of, or `null` for the color used when no session is active.
*/
fun brandColorsFlow(sessionId: SessionId?): Flow<Color?>
/**
* The full light and dark color palettes derived from the brand color.
*
* @param sessionId the session to read the colors of, or `null` for the colors used when no session is active.
*/
fun semanticColorsFlow(sessionId: SessionId?): Flow<SemanticColorsLightDark>
/** The push gateway to register with when using Firebase, or `null` to use the app default. */
fun firebasePushGateway(): String?
/** The push gateway to register with when using UnifiedPush, or `null` to use the app default. */
fun unifiedPushDefaultPushGateway(): String?
/**
* Where bug reports should be submitted, which an enterprise deployment can redirect or disable entirely.
*
* @param sessionId the session to read the setting of, or `null` for the setting used when no session is active.
*/
fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl>
/**
* Gets Notification Channel to use for the noisy notifications of the provided session.
* Returns `null` when the session has no dedicated channel and the app-wide one should be used.
*
* @param sessionId the session whose channel is requested.
*/
fun getNoisyNotificationChannelId(sessionId: SessionId): String?
@@ -50,6 +101,9 @@ interface EnterpriseService {
/**
* Gets the Element Server Suite (ESS) config endpoint URL for the given domain.
* Returns `null` when this build does not read its configuration from an ESS deployment.
*
* @param domain the server whose configuration endpoint is requested.
*/
fun essConfigEndpointUrl(domain: String): String?
@@ -8,11 +8,25 @@
package io.element.android.features.enterprise.api
/**
* The session-scoped counterpart of [EnterpriseService], answering the same kind of questions for the session it belongs to.
*
* [init] must have run before the other members return meaningful answers.
*/
interface SessionEnterpriseService {
/** Whether Element Call may be used on this session, which a deployment can turn off. */
suspend fun isElementCallAvailable(): Boolean
/**
* Rewrites the authentication server URL for this session; see [EnterpriseService.tweakMasUrl].
*
* @param url the URL to rewrite.
*/
suspend fun tweakMasUrl(url: String): String
/** Whether the homeserver forbids creating encrypted rooms, in which case the app must not offer the option. */
suspend fun isEncryptionDisabledByHomeserver(): Boolean
/** Loads the deployment configuration of this session; to be called once when the session starts. */
suspend fun init()
}
@@ -15,9 +15,21 @@ import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
* Wrapper to fetch the remote enterprise configuration for a given [SessionId], either from a local cache or from a remote source.
*/
interface RemoteEnterpriseConfigProvider {
/**
* Returns the configuration of a session, served from the cache when possible.
* A stale entry is reported as outdated while a refresh runs in the background, so this rarely waits on the network.
*
* @param sessionId the session whose configuration is requested.
*/
suspend fun get(sessionId: SessionId): WellknownRetrieverResult<RemoteEnterpriseConfig>
/**
* Creates a provider, which needs a fetcher because the configuration is read over HTTP.
*/
interface Factory {
/**
* @param urlContentFetcher used to perform the request; a client that is not authenticated yet also works.
*/
fun create(urlContentFetcher: UrlContentFetcher): RemoteEnterpriseConfigProvider
}
}
@@ -11,6 +11,9 @@ package io.element.android.features.invite.api
import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.coroutines.flow.Flow
/**
* Remembers which invitations the user has already looked at, so that only genuinely new ones are highlighted in the room list.
*/
interface SeenInvitesStore {
/**
* Returns a flow of seen room IDs of invitation.
@@ -32,7 +35,7 @@ interface SeenInvitesStore {
suspend fun markAsUnSeen(roomId: RoomId)
/**
* Delete the store.
* Delete the store, so every invitation counts as unseen again.
*/
suspend fun clear()
}
@@ -10,6 +10,9 @@ package io.element.android.features.invite.api.acceptdecline
import io.element.android.features.invite.api.InviteData
/**
* Events sent to the accept/decline invite presenter, from whichever screen is showing the invitation.
*/
interface AcceptDeclineInviteEvents {
data class AcceptInvite(val invite: InviteData) : AcceptDeclineInviteEvents
data class DeclineInvite(val invite: InviteData, val blockUser: Boolean, val shouldConfirm: Boolean) : AcceptDeclineInviteEvents
@@ -12,7 +12,20 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.libraries.matrix.api.core.RoomId
/**
* Renders the confirmation dialogs and error states of accepting or declining an invitation; it draws nothing until such an event is sent.
*
* Embedded by every screen that can act on an invitation, so the behaviour stays identical between the invite list and a room preview.
*/
fun interface AcceptDeclineInviteView {
/**
* Draws whichever dialog the current state calls for.
*
* @param state the state produced by the accept/decline presenter.
* @param onAcceptInviteSuccess called once the room has been joined, so the host screen can navigate into it.
* @param onDeclineInviteSuccess called once the invitation has been declined.
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
state: AcceptDeclineInviteState,
@@ -8,6 +8,9 @@
package io.element.android.features.invitepeople.api
/**
* Events the invite people UI sends to its presenter through [InvitePeopleState.eventSink].
*/
interface InvitePeopleEvents {
data object SendInvites : InvitePeopleEvents
data object CloseSearch : InvitePeopleEvents
@@ -13,7 +13,14 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.JoinedRoom
interface InvitePeoplePresenter : Presenter<InvitePeopleState> {
/**
* Creates a presenter for one invite flow.
*/
interface Factory {
/**
* @param joinedRoom the room to invite into, or `null` when the room does not exist yet, as when inviting from a direct message.
* @param roomId the id of the room to invite into.
*/
fun create(
joinedRoom: JoinedRoom?,
roomId: RoomId,
@@ -11,7 +11,16 @@ package io.element.android.features.invitepeople.api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
/**
* Renders the invite people UI, so that other screens can embed it without depending on its implementation.
*/
interface InvitePeopleRenderer {
/**
* Draws the invite list and its search field.
*
* @param state the state produced by [InvitePeoplePresenter].
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
state: InvitePeopleState,
@@ -11,10 +11,22 @@ package io.element.android.features.invitepeople.api
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
/**
* State of the invite people UI, produced by an [InvitePeoplePresenter] and consumed by an [InvitePeopleRenderer].
*/
interface InvitePeopleState {
/** Whether the send button should be enabled, i.e. at least one user is selected and the user has the permission. */
val canInvite: Boolean
/** Whether the search field currently has focus, which the host screen uses to adapt its own layout. */
val isSearchActive: Boolean
/** Progress of the invite request, so the UI can show a loader and surface failures. */
val sendInvitesAction: AsyncAction<Unit>
/** Progress of turning a direct message into a room, which happens when inviting a third person into a DM. */
val createRoomFromDmAction: AsyncAction<RoomId>
/** Where the UI sends its events. */
val eventSink: (InvitePeopleEvents) -> Unit
}
@@ -11,7 +11,16 @@ package io.element.android.features.knockrequests.api.banner
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
/**
* Renders the banner shown at the top of a room when people are waiting to join it.
*/
interface KnockRequestsBannerRenderer {
/**
* Draws the banner, or nothing when there is no pending request or the user cannot moderate the room.
*
* @param modifier layout modifier for the container.
* @param onViewRequestsClick called when the user asks to see the full list of requests.
*/
@Composable
fun View(modifier: Modifier, onViewRequestsClick: () -> Unit)
}
@@ -10,6 +10,9 @@ package io.element.android.features.leaveroom.api
import io.element.android.libraries.matrix.api.core.RoomId
/**
* Events sent to the leave room presenter through [LeaveRoomState.eventSink].
*/
interface LeaveRoomEvent {
data class LeaveRoom(val roomId: RoomId, val needsConfirmation: Boolean) : LeaveRoomEvent
}
@@ -12,7 +12,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.libraries.matrix.api.core.RoomId
/**
* Renders the confirmation dialogs of the leave room flow; it draws nothing until the host screen sends a leave event.
*/
fun interface LeaveRoomRenderer {
/**
* Draws whichever dialog the current state calls for.
*
* @param state the state produced by the leave room presenter.
* @param onSelectNewOwners called when the user is the last owner of a room that still has other members, and must promote someone before leaving.
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
state: LeaveRoomState,
@@ -10,7 +10,11 @@ package io.element.android.features.leaveroom.api
import androidx.compose.runtime.Immutable
/**
* State of the leave room flow, which is only the confirmation dialogs: the screen it is hosted in owns the rest of the UI.
*/
@Immutable
interface LeaveRoomState {
/** Where the host screen sends its events to start or confirm leaving a room. */
val eventSink: (LeaveRoomEvent) -> Unit
}
@@ -8,6 +8,10 @@
package io.element.android.features.location.api
/**
* Tells whether the location features can be used at all, which depends on the build having a map provider configured.
*/
interface LocationService {
/** Whether location sharing and map rendering are available; `false` disables the whole feature in the UI. */
fun isServiceAvailable(): Boolean
}
@@ -16,6 +16,17 @@ import io.element.android.libraries.wellknown.api.MapTilerConfig
* Builds an URL for a 3rd party service provider static maps API.
*/
interface StaticMapUrlBuilder {
/**
* Builds the URL of a map image centred on the given coordinates.
*
* @param lat latitude of the centre of the map.
* @param lon longitude of the centre of the map.
* @param zoom zoom level to render at.
* @param darkMode whether to request the dark map style.
* @param width width of the image in density independent pixels.
* @param height height of the image in density independent pixels.
* @param density screen density, used to request a matching pixel size.
*/
fun build(
lat: Double,
lon: Double,
@@ -26,6 +37,7 @@ interface StaticMapUrlBuilder {
density: Float,
): String
/** Whether a map provider is configured for this build; the URLs are unusable when it is not. */
fun isServiceAvailable(): Boolean
}
@@ -19,6 +19,12 @@ import io.element.android.libraries.wellknown.api.MapTilerConfig
* Used for rendering dynamic maps.
*/
interface TileServerStyleUriBuilder {
/**
* Builds the style URI the map view loads its tiles from.
*
* @param customMapStyleUrl the style advertised by the homeserver, or `null` to use the one built into the app.
* @param darkMode whether to request the dark map style.
*/
fun build(
customMapTilerConfig: MapTilerConfig?,
darkMode: Boolean,
@@ -12,6 +12,9 @@ import io.element.android.libraries.matrix.api.core.RoomId
import kotlinx.coroutines.flow.StateFlow
import kotlin.time.Duration
/**
* Owns the live location shares running on this device, across every room, and the foreground service that feeds them GPS updates.
*/
interface ActiveLiveLocationShareManager {
/** All rooms currently sharing live location on this device. */
val sharingRoomIds: StateFlow<Set<RoomId>>
@@ -27,6 +30,9 @@ interface ActiveLiveLocationShareManager {
* Starts live location sharing in the given room.
* Calls room.startLiveLocationShare() on the SDK, registers the share,
* and starts the foreground GPS service if not already running.
*
* @param roomId the room to start sharing the location in.
* @param duration how long the share should last before it expires on its own.
*/
suspend fun startShare(roomId: RoomId, duration: Duration): Result<Unit>
@@ -34,6 +40,8 @@ interface ActiveLiveLocationShareManager {
* Stops live location sharing in the given room.
* Calls room.stopLiveLocationShare() on the SDK, removes the share,
* and stops the foreground service if no shares remain.
*
* @param roomId the room to stop sharing the location in.
*/
suspend fun stopShare(roomId: RoomId): Result<Unit>
}
@@ -17,6 +17,9 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
/**
* Exposes the app lock state: whether a PIN or biometric lock is set up, whether it is mandatory, and whether the app is locked right now.
*/
interface LockScreenService {
/**
* The current lock state of the app.
@@ -8,6 +8,13 @@
package io.element.android.features.login.api
/**
* Extracts the login parameters from a link, so that a deployment can hand out a URL that pre-fills the sign-in screen.
*/
interface LoginIntentResolver {
/**
* @param uriString the link the app was opened with.
* @return the account provider and login hint to pre-fill, or `null` when the link is not a login link.
*/
fun parse(uriString: String): LoginParams?
}
@@ -8,6 +8,14 @@
package io.element.android.features.login.api.accesscontrol
/**
* Enforces the restriction an enterprise deployment can put on which account providers the user may sign in to.
*/
interface AccountProviderAccessControl {
/**
* Whether sign-in to this provider is permitted; `true` on a build with no such restriction.
*
* @param accountProviderUrl the server the user is trying to use.
*/
suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String): Boolean
}
@@ -10,7 +10,17 @@ package io.element.android.features.logout.api.direct
import androidx.compose.runtime.Composable
/**
* Renders the confirmation dialogs of logging out directly, in particular the warning shown when the user would lose their room keys.
*
* It draws nothing until the host screen sends a logout event.
*/
fun interface DirectLogoutView {
/**
* Draws whichever dialog the current state calls for.
*
* @param state the state produced by the direct logout presenter.
*/
@Composable
fun Render(state: DirectLogoutState)
}
@@ -17,5 +17,6 @@ import io.element.android.libraries.textcomposer.model.MessageComposerMode
* the composer is in a thread, if it's editing a message, etc.
*/
interface MessageComposerContext {
/** What the composer is currently doing: writing a new message, editing one, replying, or composing in a thread. */
val composerMode: MessageComposerMode
}
@@ -50,7 +50,16 @@ interface MessagesEntryPoint : FeatureEntryPoint {
callback: Callback,
): Node
/**
* Lets callers outside this feature drive an already created messages node, for navigation that has to happen after it is attached.
*/
interface NodeProxy {
/**
* Opens a thread on top of the messages screen, suspending until the thread node is attached.
*
* @param threadId the thread to open.
* @param focusedEventId the event to scroll to within the thread, or `null` to open at the latest message.
*/
suspend fun attachThread(threadId: ThreadId, focusedEventId: EventId?)
}
}
@@ -10,4 +10,9 @@ package io.element.android.features.messages.api.pinned
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
/**
* A [TimelineProvider] whose active timeline holds the pinned events of the room, rather than its live events.
*
* It exists as its own type so that it can be injected where only the pinned timeline is wanted.
*/
interface PinnedEventsTimelineProvider : TimelineProvider
@@ -11,9 +11,16 @@ package io.element.android.features.messages.api.timeline
import androidx.compose.runtime.Composable
import io.element.android.wysiwyg.utils.HtmlConverter
/**
* Provides the converter that turns message HTML into styled text.
*
* The converter depends on the current theme and typography, so [Update] must be composed before [provide] is called.
*/
interface HtmlConverterProvider {
/** Rebuilds the converter from the current Compose theme; call this once, high in the composition of a screen that renders messages. */
@Composable
fun Update()
/** Returns the converter built by the last [Update] call. */
fun provide(): HtmlConverter
}
@@ -12,7 +12,13 @@ import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.timeline.Timeline
fun interface VoiceMessageComposerPresenter : Presenter<VoiceMessageComposerState> {
/**
* Creates a presenter for one voice message composer.
*/
interface Factory {
/**
* @param timelineMode the timeline the recording will be sent to, which matters for threads in particular.
*/
fun create(timelineMode: Timeline.Mode): VoiceMessageComposerPresenter
}
}
@@ -11,6 +11,13 @@ package io.element.android.features.poll.api.actions
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.Timeline
/**
* Closes a poll so no further answers are accepted, wrapping the timeline call so the analytics are captured in one place.
*/
interface EndPollAction {
/**
* @param timeline the timeline the poll lives in.
* @param pollStartId the poll start event to close.
*/
suspend fun execute(timeline: Timeline, pollStartId: EventId): Result<Unit>
}
@@ -11,7 +11,15 @@ package io.element.android.features.poll.api.actions
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.Timeline
/**
* Sends the current user's answer to a poll, wrapping the timeline call so the analytics are captured in one place.
*/
interface SendPollResponseAction {
/**
* @param timeline the timeline the poll lives in.
* @param pollStartId the poll start event being answered.
* @param answerId the id of the chosen answer.
*/
suspend fun execute(
timeline: Timeline,
pollStartId: EventId,
@@ -12,7 +12,16 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
/**
* Turns the poll content of a timeline event into the state the poll UI renders.
*/
interface PollContentStateFactory {
/**
* Convenience overload that reads the editability and ownership from the timeline item itself.
*
* @param eventTimelineItem the timeline item carrying the poll.
* @param content the poll content of that item.
*/
suspend fun create(eventTimelineItem: EventTimelineItem, content: PollContent): PollContentState {
return create(
eventId = eventTimelineItem.eventId,
@@ -21,5 +30,12 @@ interface PollContentStateFactory {
content = content,
)
}
/**
* @param eventId the poll start event, or `null` while the poll is still a local echo.
* @param isEditable whether the current user may still edit the poll.
* @param isOwn whether the poll was created by the current user.
* @param content the poll question, answers and votes.
*/
suspend fun create(eventId: EventId?, isEditable: Boolean, isOwn: Boolean, content: PollContent): PollContentState
}
@@ -11,6 +11,9 @@ package io.element.android.features.preferences.api
import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.coroutines.flow.Flow
/**
* Announces that a session's cache has been cleared, since clearing it destroys the client and the app has to react.
*/
interface CacheService {
/**
* A flow of [SessionId], can let the app to know when the
@@ -14,6 +14,11 @@ import androidx.compose.ui.Modifier
* Component for rendering extra developer options in the preferences screen.
*/
interface ExtraDeveloperOptionsRenderer {
/**
* Draws the extra options. The standard build binds a no-op implementation, so only the builds that actually add options provide a real one.
*
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(modifier: Modifier)
}
@@ -10,6 +10,10 @@ package io.element.android.features.rageshake.api
import kotlinx.coroutines.flow.Flow
/**
* Tells whether bug reporting is available, which an enterprise deployment can turn off.
*/
fun interface RageshakeFeatureAvailability {
/** Whether the rageshake and bug report entry points should be offered to the user. */
fun isAvailable(): Flow<Boolean>
}
@@ -10,6 +10,9 @@ package io.element.android.features.rageshake.api.logs
import java.io.File
/**
* Deletes the log files the app writes, used to keep them from growing without bound and to clear them on request.
*/
interface LogFilesRemover {
/**
* Perform the log files removal.
@@ -10,6 +10,11 @@ package io.element.android.features.rageshake.api.reporter
import java.io.File
/**
* Uploads bug reports, including the log files the app has been writing.
*
* Progress and the outcome are reported through the listener passed to [sendBugReport] rather than by returning or throwing.
*/
interface BugReporter {
/**
* Send a bug report.
@@ -35,17 +40,21 @@ interface BugReporter {
)
/**
* Provide the log directory.
* Provide the log directory, i.e. where the rotating log files are written.
*/
fun logDirectory(): File
/**
* Set the current tracing log level.
* Set the current tracing log level, so it can be reported alongside the bug.
*
* @param logLevel the log level currently in effect.
*/
fun setCurrentTracingLogLevel(logLevel: String)
/**
* Save the logcat.
*
* @return the file the logcat was written to, or `null` when it could not be captured.
*/
fun saveLogCat(): File?
}
@@ -22,8 +22,18 @@ fun interface ChangeRoomMemberRolesEntryPoint : FeatureEntryPoint {
listType: ChangeRoomMemberRolesListType,
): Node
/**
* Lets a caller outside this feature wait for the role change to finish, which is needed when leaving a room depends on it.
*/
interface NodeProxy {
/** The room whose member roles are being changed. */
val roomId: RoomId
/**
* Suspends until the user finishes or abandons the flow.
*
* @return true when roles were actually changed, false when the user backed out.
*/
suspend fun waitForCompletion(): Boolean
}
}
@@ -10,6 +10,9 @@ package io.element.android.features.roommembermoderation.api
import io.element.android.libraries.matrix.api.user.MatrixUser
/**
* Events sent to the moderation presenter through [RoomMemberModerationState.eventSink].
*/
interface RoomMemberModerationEvents {
data class ShowActionsForUser(val user: MatrixUser) : RoomMemberModerationEvents
data class ProcessAction(val action: ModerationAction, val targetUser: MatrixUser) : RoomMemberModerationEvents
@@ -12,7 +12,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.libraries.matrix.api.user.MatrixUser
/**
* Renders the moderation action sheet and its confirmation dialogs; it draws nothing until the host screen asks for a member's actions.
*/
interface RoomMemberModerationRenderer {
/**
* Draws whichever sheet or dialog the current state calls for.
*
* @param state the state produced by the moderation presenter.
* @param onSelectAction called when the user picks an action, so the host screen can navigate if that action needs its own screen.
* @param onAvatarClick called when the user taps the member's avatar, or `null` to make it non-interactive.
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
state: RoomMemberModerationState,
@@ -10,9 +10,15 @@ package io.element.android.features.roommembermoderation.api
import androidx.compose.runtime.Immutable
/**
* State of the member moderation flow, which is the action sheet and the confirmation dialogs shown for a room member.
*/
@Immutable
interface RoomMemberModerationState {
/** Which moderation actions the current user is allowed to perform, so the UI can hide or disable the rest. */
val permissions: RoomMemberModerationPermissions
/** Where the host screen sends its events to open the actions of a member or run one of them. */
val eventSink: (RoomMemberModerationEvents) -> Unit
}
@@ -11,5 +11,8 @@ package io.element.android.features.share.api
* Post-processing to be done once a [ShareIntentData] has been consumed.
*/
fun interface OnSharedData {
/**
* @param data the shared content that has just been handled, so any temporary copy of it can be released.
*/
operator fun invoke(data: ShareIntentData)
}
@@ -9,10 +9,14 @@ package io.element.android.features.share.api
import android.content.Intent
/**
* Recognises the intents another app uses to share content into this one, and resolves what was shared.
*/
interface ShareIntentHandler {
/**
* This methods aims to handle incoming share intents and parse its data.
*
* @param intent the intent the app was started with.
* @return the [ShareIntentData] if it could be resolved, or null.
*/
fun handleIncomingShareIntent(
@@ -13,6 +13,11 @@ import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.user.MatrixUser
/**
* Opens a direct message with a user, reusing the existing room when there is one.
*
* Progress is reported into the state passed in, so the caller only has to render it.
*/
interface StartDMAction {
/**
* Try to find an existing DM with the given user, or create one if none exists.
@@ -11,6 +11,12 @@ package io.element.android.features.userprofile.api
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.core.UserId
/**
* Creates the user profile presenter, so that other features can show a profile without depending on this one's implementation.
*/
fun interface UserProfilePresenterFactory {
/**
* @param userId the user whose profile is shown.
*/
fun create(userId: UserId): Presenter<UserProfileState>
}
@@ -12,7 +12,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import kotlinx.collections.immutable.ImmutableList
/**
* Renders the contents of a text file, used by the log viewer in the developer options.
*/
fun interface TextFileViewer {
/**
* Draws the file, one row per line.
*
* @param lines the already-read contents of the file.
* @param modifier layout modifier for the container.
*/
@Composable
fun Render(
lines: ImmutableList<String>,