Skip to main content
Version: Next ๐Ÿšง

Feedback UI

Fedo ships two UI entry points on each platform:

Android (Compose)iOS (SwiftUI)
Full feedback board (list, details, editor)FedoFeedbackScreen()FedoFeedbackView()
Submission-only sheetFedoCreateFeedbackSheet().presentFedoCreateFeedback(isPresented:)

Signatureโ€‹

@Composable
fun FedoFeedbackScreen(
modifier: Modifier = Modifier,
onDismiss: () -> Unit,
)
ParameterTypeDescription
modifierModifierCompose modifier for sizing/padding
onDismiss() -> UnitCalled when user navigates back from the root screen

Screensโ€‹

The board manages its own internal navigation with three screens (identical on both platforms):

1. Feedback Listโ€‹

  • Shows feedback items in a vertical list with pull-to-refresh
  • Status filter: All, In review, Planned, In progress, Shipped, Closed (tabs on Android; a toolbar menu with a count per status on iOS)
  • FAB to create new feedback
  • Vote buttons on each item
Fedo feedback board on Android: feature request list with vote counts and status filter tabs
Android
Fedo feedback board on iOS: feature request list with vote counts and an All ยท 63 status filter menu in the toolbar
iOS

The board follows each platform's own conventions, so Android and iOS look different by design.

2. Feedback Detailsโ€‹

  • Full feedback description
  • Vote on the feedback
  • Edit/delete own feedback (when status allows)
  • Comments and threaded replies (see Comments and replies)
Fedo feedback details on Android: an 8 comments header, a comment marked You with a reply thread three levels deep under it, a Comment deleted placeholder, a Show 2 more replies link, and a Replying to @Alex strip above the Add a reply field
Android
Fedo feedback details on iOS: a comment marked You with a reply thread three levels deep under it, a Comment deleted placeholder, a Show 2 more replies link, and a Replying to @Alex strip above the Add a reply field
iOS

Comments and repliesโ€‹

Replies are part of FedoFeedbackScreen() and FedoFeedbackView() and add no API, so there is nothing to set up. Both platforms behave the same unless noted.

  • Replying. Each comment has a Reply button. Tapping it focuses the comment field and shows a "Replying to @name" strip above it. The strip's close button cancels the reply and keeps what the user typed.

  • Nesting. Users can reply to replies, with no practical depth limit. Indentation stops at three levels; deeper replies show "โ†ณ Replying to @name" instead.

  • Order. Top-level comments are newest first. Replies inside a thread are oldest first, so a thread reads like a conversation.

  • Loading. Top-level comments load in pages as the user scrolls, and the list ends with "You're all caught up". Each thread shows its first replies inline and the rest behind a "Show n more replies" row. If a load fails, a Retry row takes its place.

  • Deleting. A deleted comment that has replies becomes a "Comment deleted" placeholder, and its replies stay. A deleted comment without replies is removed. The delete confirmation says which of the two will happen. Replies are comments: users edit and delete their own replies the same way as their own comments.

  • Count. The comment count includes replies and deleted placeholders.

  • Errors. When a reply can't be posted, the user sees one of these messages (a snackbar on Android, a toast on iOS):

    • "This comment was deleted." The comment being replied to was deleted in the meantime.
    • "This thread can't take more replies." The thread is nested too deep.
    • "Replies aren't available on this board." The board's plan no longer includes replies.

    The draft is kept and the "Replying to" strip closes, so sending again posts it as a top-level comment. For the first and last, the comments reload.

Plansโ€‹

Replying is a Plus and Pro feature (pricing). Your plan decides it; you can't turn it on or off yourself. On Starter there is no Reply button and no "Replying to" strip. Replies that already exist stay visible but can't be replied to. Top-level comments, editing and deleting work as usual. The SDK reads this from the server, so a plan change applies without an app update.

Older app versionsโ€‹

Users on an SDK before 0.5.0 (0.4.x and older) share the same board but can't reply. They see replies as flat comments starting with reply to @name "โ€ฆ", or with reply to a deleted comment when the comment being replied to was deleted. Replies a user wrote themselves (from a newer app version) show without this prefix. Older versions don't show deleted placeholders, so their comment count can be higher than the number of comments they see.

3. Feedback Editorโ€‹

  • Create new feedback (title + description)
  • Edit existing feedback (pre-populated fields)
  • Validation before submit
  • Asks before discarding unsaved changes
Fedo feedback editor on Android in edit mode: close button, Update button, title field with 21/200 counter, optional details field with 0/5000 counter, and a Posts go to the team for review note
Android

Back navigation is automatic. On Android:

  • Editor โ†’ Details / List
  • Details โ†’ List
  • List โ†’ onDismiss fires

The onDismiss lambda is only called when the user presses back on the root list screen. Your app handles this by popping its own navigation stack.

On iOS there is no onDismiss: FedoFeedbackView pushes onto your NavigationStack, so the system back button pops it for you.

State handlingโ€‹

The screen handles loading, error, and empty states internally. No extra UI work needed.

In the comments, a page or a set of replies that fails to load leaves a Retry row in its place. A reply that fails to post keeps the user's draft (see Comments and replies).

If the SDK has not been initialized, FedoFeedbackScreen() renders a full-screen "Fedo not initialized" placeholder in place of the board. On iOS, FedoFeedbackView() shows a "Feedback isn't available right now" placeholder and logs an error to OSLog. Neither crashes.


Feedback Sheetโ€‹

The submission sheet is built per platform. On Android, FedoCreateFeedbackSheet() renders a self-contained creation form (title + details fields) as a ModalBottomSheet, with its own submit state and validation - no navigation setup or FedoFeedbackScreen() host required. On iOS, the equivalent is the .presentFedoCreateFeedback(isPresented:) view modifier, which presents the same sheet without requiring a NavigationStack or FedoFeedbackView host. Use it when you want a lightweight "suggest a feature" entry point (e.g. from a menu or FAB) instead of the full feedback flow.

Signatureโ€‹

@Composable
fun FedoCreateFeedbackSheet(
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
)
ParameterTypeDescription
onDismiss() -> UnitCalled when the sheet is dismissed by the user (swipe/scrim/close button) or automatically after a successful submit
modifierModifierCompose modifier applied to the ModalBottomSheet container

There's no visible param - toggle composition yourself:

@Composable
fun MyScreen() {
var showFeedbackSheet by remember { mutableStateOf(false) }

Button(onClick = { showFeedbackSheet = true }) {
Text("Suggest a feature")
}

if (showFeedbackSheet) {
FedoCreateFeedbackSheet(
onDismiss = { showFeedbackSheet = false }
)
}
}

On success, the form is replaced with a brief thank-you message before the sheet auto-dismisses, which fires onDismiss.

info

If Fedo.initialize has not been called, FedoCreateFeedbackSheet() shows the same "Fedo not initialized" error inside the sheet, while FedoFeedbackScreen() shows it full-screen. On iOS, the sheet shows the same "Feedback isn't available right now" placeholder as FedoFeedbackView(). On both platforms, calls to user-management methods (setUserID, setUserEmail, etc.) are silent no-ops โ€” they do not throw.

Fedo create-feedback bottom sheet on Android: submission form with title and details fields
Android