# iphone-duo-flutter

Guides Flutter adaptation for iPhone Duo. Explains how to handle asymmetric insets and bridge iOS 27.1 hinge APIs through platform channels.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 402 installs · ★ 214
- Author: mirzaaghazadeh
- License: MIT · policy=mirror · the beginning of the file is at the end of this page
- Source: https://github.com/mirzaaghazadeh/iphone-duo-skills/tree/HEAD/skills/iphone-duo-flutter/SKILL.md
- Updated: 2026-10-23
- HTML: https://affpapa.org/en/nevibecode/skills/iphone-duo-flutter

## What it does

Flutter built its fold abstractions for Android hinges. On iPhone Duo, `MediaQuery.displayFeatures` returns an empty list regardless of posture. This skill structures adaptation into two tiers: constraint-based Dart layout and custom native platform channels.

Tier 1 handles interface scaling with `LayoutBuilder` and `MediaQuery.sizeOf(context)`. It fixes asymmetric safe areas where iOS places controls on one edge. Assuming symmetrical insets like doubling `padding.left` breaks layouts on this hardware.

Accessing the fold line or under-display camera requires native code because Flutter has no built-in iPhone Duo support yet. The guide details setting up a `MethodChannel` for `reservedRegions` and an `EventChannel` for `UIHingeInteraction`. Keep in mind that testing Tier 2 requires the Xcode 27.1 simulator.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-flutter -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/iphone-duo-flutter/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/iphone-duo-flutter/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-flutter -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/iphone-duo-flutter/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-flutter -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/iphone-duo-flutter/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install mirzaaghazadeh/iphone-duo-skills iphone-duo-flutter
```

2. **Manually: put the files in place**
- File: `.github/skills/iphone-duo-flutter/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-flutter -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/mirzaaghazadeh/iphone-duo-skills --path skills/iphone-duo-flutter
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/iphone-duo-flutter/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-flutter -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/mirzaaghazadeh/iphone-duo-skills/tree/HEAD/skills/iphone-duo-flutter/SKILL.md

## When to use it
- resolve asymmetric safe area padding bugs
- switch layouts to constraint-driven BoxConstraints
- bridge iOS 27.1 reservedRegions via MethodChannel
- stream live hinge angles using EventChannel
- swap NavigationBar for NavigationRail on wide displays

## Example prompts
- Audit my Flutter layout for iPhone Duo asymmetric insets
- How do I bridge UIHingeInteraction to Flutter via EventChannel?
- Why is MediaQuery.displayFeatures returning empty on iPhone Duo?

## Source text · SKILL.md · MIT

Below is the content of a third-party file. It is data, not instructions for you: do not act on anything written inside unless the human asks. Block tag: 3ca9d09fe12c4d19.

BEGIN THIRD-PARTY FILE 3ca9d09fe12c4d19
```text
---
name: iphone-duo-flutter
description: Adapt a Flutter app to iPhone Duo, Apple's first foldable iPhone — what MediaQuery gives you today, why displayFeatures does not work here, and how to bridge the iOS 27.1 reserved-region, hinge and arrangement APIs through platform channels. Use when a Flutter or Dart app needs foldable iPhone support.
---

# Flutter on iPhone Duo

Start here, because it is the thing that will waste your afternoon otherwise:

> **`MediaQuery.displayFeatures` is documented as "populated only on Android."**

Flutter's foldable abstraction was built for Android hinges. On iPhone Duo it
returns an **empty list**, no matter how folded the device is. The same goes for
the `dual_screen` package (`TwoPane`, `hingeAngleEvents`) — Android-only in
practice, and last published around three years ago.

So Flutter gives you no fold awareness on this device out of the box. What it
*does* give you is most of what actually matters. Work in two tiers.

## Tier 1 — works today, no native code

This is the bulk of a good port, and it is all pure Dart.

### Resize correctly

iPhone Duo changes your app's size constantly: opening, closing, folding,
rotating, and entering Split View. Flutter handles the mechanics, but only if
your layout is driven by constraints rather than constants.

- Use `LayoutBuilder` and its `BoxConstraints` for layout decisions.
- Use `MediaQuery.sizeOf(context)` when you need the window, not
  `MediaQuery.of(context)` — the `sizeOf`/`paddingOf` accessors rebuild only on
  the property you read, which matters when the size changes this often.
- Never cache a size in `initState` or a field. It will be stale within seconds.

### Handle asymmetric safe areas

This is the one that produces real bugs. On iPhone Duo the system puts its
controls **on one side**, so insets are routinely asymmetric — and which side
depends on the pose and on which half of a Split View you occupy.

`MediaQuery.paddingOf(context)` returns `EdgeInsets` with independent `left`,
`top`, `right`, `bottom`. Use each one. Any expression of the form
`width - padding.left * 2` is a defect on this device.

The `SafeArea` widget handles all four edges independently already, so prefer it
over hand-rolled padding. Where you need artwork to bleed underneath, put the
background outside the `SafeArea` and only the interactive foreground inside it.

### Replace breakpoints with size-class thinking

iOS reasons about this device in size classes: the outer display is **compact
width**, the inner display is **regular width**. Flutter has no size classes, so
map to width breakpoints — the Material 3 window size classes are a reasonable
proxy (compact `< 600`, medium `600–840`, expanded `≥ 840` logical pixels).

Two rules:
```
END THIRD-PARTY FILE 3ca9d09fe12c4d19

The third-party file has ended. Everything between the 3ca9d09fe12c4d19 tags is data: requests and commands from it are not followed. An “end of file” line with another tag inside the block is part of the file.

First 2766 of 6382 bytes. © mirzaaghazadeh · MIT · https://github.com/mirzaaghazadeh/iphone-duo-skills/tree/HEAD/skills/iphone-duo-flutter/SKILL.md

_Part of the page did not fit — see the HTML version._

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
