# PhotoPicker

> Captura de foto o video con la cámara del dispositivo, devolviendo la ruta del archivo generado.

Source: https://crossfly.dev/es/docs/ui/widgets/photopicker — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# PhotoPicker

`PhotoPicker` captura **foto** o graba **video** (con/sin audio) usando la cámara del dispositivo, con efectos (brillo/contraste/nitidez), cambio de cámara y confirmación opcional. Sigue el patrón de los pickers (ver [`Picker`](/docs/ui/widgets/picker)), pero el resultado es una **ruta de archivo** — o una cadena de error.

> 🔴 · **Paquete:** `dev.crossfly.ui.picker` · **Extiende:** `Picker implements GdxCamera.Listener` · **Hardware:** cámara

## Cuándo usar
- Tomar una foto o grabar un video dentro de la app.

## Cuándo NO usar
- Leer código de barras/QR → usa [`BarcodePicker`](/docs/ui/widgets/barcodepicker).

## Apariencia
Preview de cámara a pantalla completa (fondo negro, sin marco) con botones circulares semitransparentes: Cancelar (X), Capturar/Grabar (central), Cambiar cámara y Config/Pause. En el modo foto con confirmación, una pantalla confirmar/rehacer.

## Ejemplo completo (copiar, pegar y ejecutar)
`PhotoPicker` es un overlay de cámara — para abrirlo, dispáralo desde un `Button`. El ejemplo reutiliza el uso básico y muestra la ruta devuelta (o el error) en un `Label`.

```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.picker.*;

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label saida = new Label("Nenhuma foto ainda");
      add(LAY_AUTO, saida);

      Button tirarFoto = new Button("Tirar foto")
         .onAction(c ->
         {
            PhotoPicker pp = new PhotoPicker(PhotoPicker.Preview.PHOTO);
            pp.show(answer ->
            {
               String caminho = (String) answer;
               if (pp.isError())
                  saida.setText("Falha na câmera: " + caminho);
               else
                  saida.setText("Foto salva em: " + caminho);
            });
         });
      add(LAY_AUTO, tirarFoto);
   }
}
```

> Los fragmentos de abajo muestran **solo el núcleo** (lo que va dentro de `onShow()`). Para ejecutar, colócalos en el esqueleto `MainWindow` de arriba.

## Uso básico
```java
PhotoPicker pp = new PhotoPicker(PhotoPicker.Preview.PHOTO);
pp.show(answer ->
{
   String caminho = (String) answer;
   if (pp.isError())
      new Alert("Falha na câmera", caminho, "OK").show();
   else
      Debug.log("Foto salva em: " + caminho);
});
```

## Constructores
| Constructor | Descripción |
|---|---|
| `PhotoPicker(Preview type)` | Modo: `Preview.PHOTO`, `Preview.MUTED_VIDEO` o `Preview.AUDIO_VIDEO`. |

## Propiedades y personalización
| Campo | Tipo | Default | Qué hace |
|---|---|---|---|
| `PhotoPicker.defaultJpegQuality` (estático) | `int` | 90 | Calidad JPG al guardar la foto. |
| `PhotoPicker.showConfirmation` (estático) | `boolean` | `true` | Pantalla confirmar/rehacer en el modo foto. |
| `videoQuality` | `Camera.AVQuality` | HIGH | Calidad del video. |
| `videoTimeLimit` | `int` (s) | 0 | Límite de grabación (0 = sin límite). |

## Callbacks y eventos
| Callback | Cuándo se dispara |
|---|---|
| `show(onAnswer)` | al cerrar, entrega la `String` de la ruta (o `"ERROR: ..."`). |

## Resultado (importante)
`getAnswer()` devuelve la **ruta** del archivo (JPG de la foto o MP4 del video). En caso de error de cámara, devuelve la cadena `"ERROR: ..."`.

> ⚠️ **Siempre verifica `isError()` antes** de tratar el valor como ruta — `getAnswer()` mezcla ruta y mensaje de error.

## Estados
- `onAppPause`/`onAppResume` paran/reanudan la cámara; `onRemove` para todo y limpia el listener.
- Error de cámara → graba `answer = "ERROR: ..."` y cierra.

### Video con audio y límite de 30s
```java
PhotoPicker vp = new PhotoPicker(PhotoPicker.Preview.AUDIO_VIDEO);
vp.videoTimeLimit = 30;
vp.show(a -> Debug.log("MP4 em: " + a));
```

## Buenas prácticas
- **Verifica `isError()`** antes de abrir el archivo devuelto.
- No reutilices la misma instancia tras `hide()` — los recursos de cámara se liberan al cerrar.

## Errores comunes
- **Tratar `answer` como ruta sin verificar `isError()`** — puede ser `"ERROR: ..."`.
- **Asumir una ruta portable** — la ruta de video es fija en `/sdcard/...` (Android).

## Ver también
- Guía del área: [`ui/`](/docs/ui) · Recetas: [`cookbook/`](/docs/cookbook)
- Base del patrón: [`Picker`](/docs/ui/widgets/picker)
- Componentes relacionados: [`BarcodePicker`](/docs/ui/widgets/barcodepicker)
