Skip to content

refactor(conversations): read the conversation types from the server - #6650

Merged
mahibi merged 2 commits into
masterfrom
refactor/noid/conversationPresetsEndpoint
Sep 7, 2026
Merged

refactor(conversations): read the conversation types from the server#6650
mahibi merged 2 commits into
masterfrom
refactor/noid/conversationPresetsEndpoint

Conversation

@AndyScherzinger

@AndyScherzinger AndyScherzinger commented Sep 4, 2026

Copy link
Copy Markdown
Member

The conversation type cards were hardcoded, so which types an installation offers, the parameters
they apply and the values an administrator configured as the default were all ignored.
docs/capabilities.md describes conversation-presets as "should be used by clients", so the list
now comes from GET /ocs/v2.php/apps/spreed/api/v1/presets/room and the grid renders whatever it
reports. A type the server adds needs no app change beyond an icon and a label.

Parameters are applied in the order the server documents: the administrator configured defaults,
then the selected type, then the parameters the user chose. Selecting a type drops the user's choices
for the parameters that type defines, so a type can still configure the visibility of a conversation.

The hardcoded parameter table from the previous PR is deleted; only its shape survives, which was the
point of introducing it there.

This PR is stacked on #6649 and targets its branch, not master. GitHub retargets it to master
once that one merges. The three missing conversation types (webinar, presentation, classified) follow
in the next PR on top of this one.

🖼️ Screenshots

🏚️ Before 🏡 After
B A

🚧 TODO

  • screenshots in light and dark, and with a non-default server primary colour

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

Capabilities checked: conversation-presets gates the whole section, announcement-preset plus the
administrator check gate the announcement type. The presets endpoint is API v1 by its own route
definition, unlike the v4 room endpoints.

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

🤖 Generated with Claude Code

https://claude.ai/code/session_014YnDswTbCmRrVETnwE4twB

@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch from ac1ee9b to 11427d7 Compare September 4, 2026 18:29
@AndyScherzinger AndyScherzinger added enhancement New feature or request 3. to review Waiting for reviews AI assisted labels Sep 4, 2026
@AndyScherzinger
AndyScherzinger force-pushed the bugfix/noid/conversationCreationParameters branch from eb2dcca to b6bd25c Compare September 5, 2026 06:39
@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch from 11427d7 to 094f236 Compare September 5, 2026 06:39
@AndyScherzinger
AndyScherzinger force-pushed the bugfix/noid/conversationCreationParameters branch from b6bd25c to 0d12eca Compare September 5, 2026 10:47
@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch from 094f236 to 2b80ea9 Compare September 5, 2026 10:47
@AndyScherzinger
AndyScherzinger force-pushed the bugfix/noid/conversationCreationParameters branch from 0d12eca to 86afe4c Compare September 7, 2026 06:35
@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch from 2b80ea9 to b398f3d Compare September 7, 2026 06:35
@mahibi
mahibi force-pushed the bugfix/noid/conversationCreationParameters branch from 6f175b7 to f916e09 Compare September 7, 2026 09:01
@AndyScherzinger
AndyScherzinger force-pushed the bugfix/noid/conversationCreationParameters branch from f916e09 to bfd84fb Compare September 7, 2026 09:21
@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch 2 times, most recently from 9039f52 to 0280b71 Compare September 7, 2026 13:44
Base automatically changed from bugfix/noid/conversationCreationParameters to master September 7, 2026 14:00
The conversation type cards were hardcoded, so the presets an installation
offers, the parameters they apply and the values an administrator configured as
the default were all ignored. They now come from the presets endpoint, and the
grid renders whatever it reports.

Parameters are applied in the documented order: the administrator configured
defaults, then the selected type, then the parameters the user chose. Selecting
a type drops the choices the user made for the parameters that type defines, so
a type can still configure the visibility of a conversation.

Assisted-by: Claude Code:claude-opus-5
Claude-Session: https://claude.ai/code/session_014YnDswTbCmRrVETnwE4twB
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
CapabilitiesUtil.isAdmin read config => conversations => is-admin, a capability
the server does not publish, so it always returned false. Its last caller is
gone now that the presets endpoint decides which conversation types a user is
offered.

Assisted-by: Claude Code:claude-opus-5
Claude-Session: https://claude.ai/code/session_014YnDswTbCmRrVETnwE4twB
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
@AndyScherzinger
AndyScherzinger force-pushed the refactor/noid/conversationPresetsEndpoint branch from 0280b71 to 04e2c46 Compare September 7, 2026 14:06
@AndyScherzinger AndyScherzinger added this to the 25.0.0 milestone Sep 7, 2026
@AndyScherzinger

Copy link
Copy Markdown
Member Author

/backport to stable-25.0.x

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

APK file: https://github.com/nextcloud/talk-android/actions/runs/34131149409/artifacts/10022352511
To test this change/fix you can simply download above APK file and install and test it in parallel to your existing Nextcloud app.
qrcode (please click on link to get QR code displayed)

@mahibi
mahibi self-requested a review September 7, 2026 15:57
@mahibi

mahibi commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Just a summary from claude which might help whenever coming back to this PR:

The problem this branch solves

Before this branch, the four "conversation type" cards (Default / Voice room / Channel / Announcement) and what settings each one applied were hardcoded in the Android app (ConversationPresetParameters — deleted in this branch). If the server admin wanted to change what "Channel" means, or add a new type, or restrict who could create an "Announcement," the Android app
would need a code update. This branch flips that: the server now hands the client a list of conversation types and their settings at runtime via a new GET .../presets/room endpoint, and the client just renders whatever it's given.

The three building blocks

  • Preset — one "conversation type" the server offers, as a self-contained recipe: a name, a description, and a bag of settings it wants applied. Modeled as ConversationPresetModel:
data class ConversationPresetModel( 
	val identifier: String, 
	val name: String, 
	val description: String,
	val parameters: Map<String, Int>
) 

The server returns a list of these — normally something like default, voiceroom, channel, announcement, plus the two special ones below. The client turns each into a selectable card (ConversationPresetCards.kt).

  • Identifier — the short string key that names a preset ("default", "channel", ...), collected in ConversationPresetId. It's how code says "give me that preset out of the list" — e.g. presets.parametersFor(ConversationPresetId.CHANNEL).

  • Parameter — one individual setting a preset can dial in — "is this room listable?", "can guests @mention everyone?" etc. Each has its own key, collected in ConversationParameter ("listable", "mentionPermissions", ...). A preset's parameters map is just {key -> value} pairs for the dials it cares about. These get folded onto CreateConversationParams — the object that's
    actually sent to the server when the room gets created — one dial at a time via withParameters(...).

The two special identifiers

Most identifiers (channel, voiceroom, ...) are ordinary, user-pickable conversation types. Two are not — they're structural, and parametersFor() treats them differently:

CreateConversationParams()
.withParameters(parametersOf(DEFAULT)) // ① admin-wide baseline 
.withParameters(parametersOf(identifier))// ② the type the user picked
.withParameters(chosenByUser)// ③ switches the user flipped by hand 
.withParameters(parametersOf(FORCED))// ④ admin override, always wins 
  • default is the baseline layer, applied first (①). It holds whatever an admin has configured as the server-wide defaults (e.g. "mentions are moderator-only unless a preset says otherwise"). Every other preset only needs to override the handful of fields that make it distinct — anything it stays silent on falls through to default's value. That's the "the selected
    preset overrides the administrator configured default" test: channel overrides listable, but its silence on mentionPermissions lets default's value survive.
  • forced is the opposite end — applied last (④), after even the user's own manual choices. It represents settings an admin has locked down server-wide, that the server will enforce regardless of what the client sends. Since the client can't beat it anyway, it's folded in last so it always wins, and it's also read separately by the ViewModel (pinnedParameters) so the
    UI can grey out/disable a switch the admin has pinned — instead of letting the user toggle something that'll silently be overwritten. It's also the one identifier selectable() filters out of the card list, since it's not a real "conversation type" a user chooses — it's a rule that rides along on top of whichever type they do choose.

End-to-end flow

  1. ConversationCreationViewModel loads the preset list on screen open (loadPresets(), tracked via presetsJob so retries don't race).
  2. The UI renders the selectable presets (forced hidden) as cards; picking one calls updateConversationPreset(identifier).
  3. Any manual switch the user flips (visibility, guest access, ...) is recorded in parametersChosenByUser — but only for the fields not pinned by forced (the switch is disabled otherwise).
  4. Whenever preset or user choice changes, recomputeParams() re-folds all four layers into CreateConversationParams.
  5. ConversationCreator sends that as the actual room-creation request.

The CreateConversationParamsTest suite exercises each layer of that fold in isolation — untouched fields staying put, a preset overriding the default, the user overriding the preset, forced overriding the user, and an unknown/out-of-range value being ignored rather than crashing the request.

@mahibi
mahibi merged commit 01474e3 into master Sep 7, 2026
16 of 19 checks passed
@mahibi
mahibi deleted the refactor/noid/conversationPresetsEndpoint branch September 7, 2026 17:27
@mahibi mahibi modified the milestones: 25.0.0, 25.1.0 Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews AI assisted enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants