AppBarRow/AppBarColumnによるAdaptiveなボタン配置

Compose Material3 1.4.0 から `AppBarRow` / `AppBarColumn` というオーバーフローした時に自動で省略してくれる API が追加されました。これを使うことでアクションの配置の Adaptive 対応がしやすくなります。

![ezgif-6aeeca75c7ca8b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/0db92048-5436-463d-ad3a-86103219a141.gif)


## 実装

`AppBarRow` / `AppBarColumn` は以下のようなシンプルな引数になっています。

- `overflowIndicator` は Menu アイコンを表示する Slot
- `maxItemCount` はアイテムの最大表示数
  - デフォルトの場合は画面に収まりきるまでの最大数を表示
- `AppBarRowScope` / `AppBarColumnScope` では以下の 3 パターンのアイテムが設定可能
  - `clickableItem` 
  - `toggleableItem`
  - `customItem`


```kotlin
fun AppBarRow(
    overflowIndicator: @Composable (AppBarMenuState) -> Unit,
    modifier: Modifier = Modifier,
    maxItemCount: Int = Int.MAX_VALUE,
    content: AppBarRowScope.() -> Unit,
)

fun AppBarColumn(
    overflowIndicator: @Composable (AppBarMenuState) -> Unit,
    modifier: Modifier = Modifier,
    maxItemCount: Int = Int.MAX_VALUE,
    content: AppBarColumnScope.() -> Unit,
)
```

`maxItemCount` を画面サイズで変えることによって Adaptive な表示にすることができます。

```kotlin
val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
val maxItemCount = if (windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND)) {
    5
} else {
    3
}
AppBarRow(
    maxItemCount = maxItemCount,
    overflowIndicator = {
        ...
    },
) {
    ...
}
```

|Phone|Tablet|
|:--:|:--:|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/cce8c11b-da49-4e37-bed2-6b7e17ccaf80.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/298b57c6-3cac-4e96-b860-64f27941306c.png)|

この `AppBarRow` / `AppBarColumn` を `TopAppBar` や `FloatingToolbar` に使うことでアクションの配置を省略してくれるようになります。

### AppBar(TopAppBar) で使う場合

```kotlin
TopAppBar(
    title = {
        Text("Title", maxLines = 1, overflow = TextOverflow.Ellipsis)
    },
    navigationIcon = {
        IconButton(
            onClick = { ... }
        ) {
            Icon(
                painterResource(R.drawable.ic_arrow_back),
                contentDescription = "Back",
            )
        }
    },
    actions = {
        val windowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
        val maxItemCount =
            if (windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND)) {
                5
            } else {
                3
            }
        AppBarRow(
            maxItemCount = maxItemCount,
            overflowIndicator = { menuState ->
                IconButton(onClick = { menuState.show() }) {
                    Icon(
                        painterResource(R.drawable.ic_more_vert),
                        contentDescription = "Other options",
                    )
                }
            },
        ) {
            clickableItem(
                onClick = { ... },
                icon = {
                    Icon(
                        painterResource(R.drawable.ic_search),
                        contentDescription = null,
                    )
                },
                label = "Search",
            )
        
            toggleableItem(
                checked = isFavorited,
                onCheckedChange = {
                    isFavorited = !isFavorited
                },
                icon = {
                    Icon(
                        painterResource(
                            if (isFavorited) {
                                R.drawable.ic_favorite_filled
                            } else {
                                R.drawable.ic_favorite
                            }
                        ),
                        contentDescription = null,
                    )
                },
                label = if (isFavorited) {
                    "Remove from favotites"
                } else {
                    "Add to favorites"
                },
            )

            ...
        }
    },
)
```

### FloatingToolbar で使う場合

```kotlin
HorizontalFloatingToolbar(
    modifier = Modifier.align(Alignment.BottomCenter).offset(y = -FloatingToolbarDefaults.ScreenOffset),
    expanded = true,
    leadingContent = { ... },
    trailingContent = {
        AppBarRow(
            overflowIndicator = { menuState ->
                IconButton(onClick = { menuState.show() }) {
                    Icon(
                        painterResource(R.drawable.ic_more_vert),
                        contentDescription = "Other options",
                    )
                }
            },
        ) {
            clickableItem(
                onClick = { ... },
                icon = {
                    Icon(
                        painterResource(R.drawable.ic_arrow_back),
                        contentDescription = null,
                    )
                },
                label = "Back",
            )

            clickableItem(
                onClick = { ... },
                icon = {
                    Icon(
                        painterResource(R.drawable.ic_arrow_forward),
                        contentDescription = null,
                    )
                },
                label = "Forward",
            )

            toggleableItem(
                checked = isFavorited,
                onCheckedChange = {
                    isFavorited = !isFavorited
                },
                icon = {
                    Icon(
                        painterResource(
                            if (isFavorited) {
                                R.drawable.ic_favorite_filled
                            } else {
                                R.drawable.ic_favorite
                            }
                        ),
                        contentDescription = null,
                    )
                },
                label = if (isFavorited) {
                    "Remove from favotites"
                } else {
                    "Add to favorites"
                },
            )
            ...
        }
    },
    content = {
        FilledIconButton(
            modifier = Modifier.width(64.dp),
            onClick = { ... }
        ) {
            Icon(painterResource(R.drawable.ic_add), contentDescription = "Add")
        }
    }
)
```