> ## Documentation Index
> Fetch the complete documentation index at: https://mahmoud-b28887f9.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# KPdfSaveState: observe the PDF save and export flow

> KPdfSaveState tracks the SDK-managed save flow — from export preparation through the platform file picker to confirmed save, cancellation, or error.

`KPdfSaveState` is a sealed interface that models the full lifecycle of saving the current PDF to a user-chosen location on the device. Collect it from `KPdfViewerState.saveState` (a `StateFlow`) to drive progress indicators, confirmation banners, and error handling. Trigger the flow by calling `viewerState.requestSave()`. The SDK then serialises the document, opens the platform native file-save picker, and progresses through the states below until a terminal state (`Success`, `Cancelled`, or `Error`) is reached. The state resets to `Idle` at the start of each new save request.

## Variants

<ResponseField name="Idle" type="data object">
  No save operation is in progress. This is the initial state and the state the SDK returns to after the next `requestSave()` call replaces the previous terminal state.
</ResponseField>

<ResponseField name="Exporting" type="data object">
  The SDK is serialising the current PDF into bytes in preparation for writing. Display a loading indicator while in this state. The platform file picker has not opened yet.
</ResponseField>

<ResponseField name="AwaitingDestination" type="data class">
  Serialisation is complete and the platform file-save picker is open. The user has not yet chosen a destination.

  <ResponseField name="requestId" type="Long" required>
    Unique identifier for this save request. Use it to correlate `AwaitingDestination`, `Success`, and `Cancelled` events when multiple save requests could be in flight.
  </ResponseField>

  <ResponseField name="suggestedFileName" type="String" required>
    The file name the SDK pre-filled in the picker, derived from the document title or a default such as `document.pdf`.
  </ResponseField>

  <ResponseField name="mimeType" type="String" required>
    The MIME type proposed to the picker, typically `application/pdf`.
  </ResponseField>
</ResponseField>

<ResponseField name="Success" type="data class">
  The user selected a destination and the file was written successfully.

  <ResponseField name="requestId" type="Long" required>
    The identifier of the completed save request, matching the `AwaitingDestination.requestId` for the same flow.
  </ResponseField>

  <ResponseField name="suggestedFileName" type="String" required>
    The file name that was used when the file was written.
  </ResponseField>

  <ResponseField name="mimeType" type="String" required>
    The MIME type of the saved file.
  </ResponseField>

  <ResponseField name="location" type="String?" required>
    A platform-specific URI or path string for the saved file, if the platform makes it available. `null` on platforms that do not expose the final path.
  </ResponseField>
</ResponseField>

<ResponseField name="Cancelled" type="data class">
  The user dismissed the file-save picker without choosing a destination. No file was written.

  <ResponseField name="requestId" type="Long" required>
    The identifier of the cancelled request.
  </ResponseField>

  <ResponseField name="suggestedFileName" type="String" required>
    The file name that was proposed to the picker.
  </ResponseField>

  <ResponseField name="mimeType" type="String" required>
    The MIME type that was proposed to the picker.
  </ResponseField>
</ResponseField>

<ResponseField name="Error" type="data class">
  The save flow failed — either during serialisation or after the user chose a destination.

  <ResponseField name="reason" type="KPdfError" required>
    A sealed `KPdfError` value describing the failure. Check `reason.message` for a human-readable description.
  </ResponseField>

  <ResponseField name="suggestedFileName" type="String?" required>
    The file name that was in use when the error occurred, if available.
  </ResponseField>

  <ResponseField name="mimeType" type="String?" required>
    The MIME type that was in use when the error occurred, if available.
  </ResponseField>
</ResponseField>

## Reacting to save state in Compose

Collect `saveState` with `collectAsState()` and branch on each variant to update your UI. Call `requestSave()` from a button or toolbar action to start the flow — `KPdfViewerToolbar` does this automatically when `showSave` is `true`.

```kotlin theme={null}
@Composable
fun SaveControls(viewerState: KPdfViewerState) {
    val saveState by viewerState.saveState.collectAsState()

    Button(onClick = { viewerState.requestSave() }) {
        Text("Save PDF")
    }

    when (val state = saveState) {
        KPdfSaveState.Idle -> Unit

        KPdfSaveState.Exporting -> {
            LinearProgressIndicator()
            Text("Preparing PDF…")
        }

        is KPdfSaveState.AwaitingDestination -> {
            Text("Choose where to save "${state.suggestedFileName}"")
        }

        is KPdfSaveState.Success -> {
            Text("Saved successfully.")
            state.location?.let { Text("Location: $it") }
        }

        is KPdfSaveState.Cancelled -> {
            Text("Save cancelled.")
        }

        is KPdfSaveState.Error -> {
            Text("Save failed: ${state.reason.message}")
        }
    }
}
```

## Notes

* `KPdfViewerState.saveState` is a `StateFlow<KPdfSaveState>`, so collecting it is safe on the first frame and never suspends.
* The `Exporting` → `AwaitingDestination` transition happens on a background dispatcher; do not block the main thread waiting for it.
  * If you use `rememberPdfViewerState`, the native file picker is already wired automatically. You only need to observe the state and react to `Success` or `Error`.
* `requestId` is a monotonically increasing `Long`. If the user triggers multiple rapid saves, each request receives a distinct identifier so you can safely ignore stale terminal states.
