# `DalaDev.FileTransfer`
[🔗](https://github.com/ohhi-vn/dala_dev/blob/main/lib/dala_dev/file_transfer.ex#L1)

Transfers files and folders between the dev machine and connected mobile devices.

Supports push, pull, sync (bidirectional with delete), and ls operations
across Android devices, iOS simulators, and physical iOS devices.

## Folder transfer

Folders are transferred as atomic tar archives on Android (to preserve
SELinux context and avoid per-file overhead). On iOS Simulator, `cp -r` is
used directly. On iOS Physical, `xcrun devicectl` handles directory copies.

## Sync

`sync/3` computes a local<->remote diff based on file sizes and mtimes, then
transfers only changed files and optionally deletes remote files that don't
exist locally.

## Path conventions

Relative paths resolve against the app's files directory on device:
- Android: /data/data/<bundle_id>/files/
- iOS Simulator: <sim_data>/Documents/
- iOS Physical: Documents/ (relative to app container)

Absolute paths (starting with /) are used as-is (rooted Android only).

# `sync_action`

```elixir
@type sync_action() ::
  {:push, String.t()} | {:pull, String.t()} | {:delete, String.t()}
```

# `sync_result`

```elixir
@type sync_result() :: {:ok, [sync_action()]} | {:error, String.t()}
```

# `transfer_result`

```elixir
@type transfer_result() :: {:ok, String.t()} | {:error, String.t()}
```

# `ls`

```elixir
@spec ls(
  String.t(),
  keyword()
) :: {:ok, [String.t()]} | {:error, String.t()}
```

Lists files in a directory on a device. Returns `{:ok, files}` or `{:error, reason}`.

# `pull`

```elixir
@spec pull(String.t(), String.t(), keyword()) :: [transfer_result()]
```

Pulls a file or directory from a device to the local machine.

## Options

  * `:device` - Source device ID (required for multiple devices)
  * `:on_conflict` - `:overwrite` (default), `:skip`, or `:rename`
  * `:progress` - `true` to print per-file progress (default: `false`)

# `push`

```elixir
@spec push(String.t(), String.t(), keyword()) :: [transfer_result()]
```

Pushes a local file or directory to connected device(s).

## Options

  * `:device` - Target device ID (optional, targets all if omitted)
  * `:on_conflict` - `:overwrite` (default), `:skip`, or `:rename`
  * `:progress` - `true` to print per-file progress (default: `false`)

# `sync`

```elixir
@spec sync(String.t(), String.t(), keyword()) :: [sync_result()]
```

Synchronizes a local directory with a remote directory on device(s).

Computes a diff based on file sizes and modification times, then:
- Pushes files that are new or changed locally
- Pulls files that are new or changed on device
- Optionally deletes remote files that don't exist locally

## Options

  * `:device` - Target device ID (optional, targets all if omitted)
  * `:delete` - `true` to delete remote files not present locally (default: `false`)
  * `:dry_run` - `true` to print actions without executing (default: `false`)
  * `:progress` - `true` to print per-file progress (default: `false`)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
