JetpackComposeのAlertDialogをMaterialAlertDialogに近づける

## はじめに
AndroidViewで実装されたAlertDialogをCompose化する際に、
「BeforeとAfterを見比べると、何か違う…」ということがありました。

本記事では、ComposeのAlertDialogをAndroidViewのAlertDialogに近づけるにはどうすればいいかを調査します。

本記事では、以下を使用します。
- Material2
- MaterialAlertDialogBuilder / AndroidView
- AlertDialog / JetpackCompose

間違いや不備等ございましたら、ご指摘いただけますと幸いです。

## 比較

|  AndroidView  |  JetpackCompose  |
| :-: | :-: |
|  <img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/cc58e67f-f4bc-2c68-ac0f-a48d7da3cb4c.png" width = 300>  |  <img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/57ed14ce-b341-1ab4-95b0-ae2315b088ed.png" width = 300>  |

以下、AlertDialogを実装しているコードです。
ライブラリで用意されているものに、テキストをセットしただけのものです。

```kotlin
//AndroidView
MaterialAlertDialogBuilder(requireContext())
            .setTitle("タイトル")
            .setMessage("テキスト")
            .setPositiveButton("OK", null)
            .setNegativeButton("Cancel", null)
```

```kotlin
//JetpackCompose
AlertDialog(
        onDismissRequest = { },
        title = {
            Text(text = "タイトル")
        },
        text = {
            Text("テキスト")
        },
        confirmButton = {
            TextButton(
                onClick = { }
            ) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(
                onClick = { }
            ) {
                Text(text = "Cancel")
            }
        },
    )
```

### 何が違うのか
大きく異なるのは
- 背景の濃度
- elevationの有無
- ダイアログのサイズ

かと思います。

## ComposeでもMaterialAlertDialogを再現したい
MaterialAlertDialogの背景濃度等を調べてComposeに適用できれば、目的は達成されそうです。
ところで、ComposeのAlertDialogは、DialogのcontentにAlertDialogContenteを渡しており、テキストやボタンをよしなに配置してくれています。
```kotlin
@Composable
fun AlertDialog(
    onDismissRequest: () -> Unit,
    buttons: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    title: (@Composable () -> Unit)? = null,
    text: @Composable (() -> Unit)? = null,
    shape: Shape = MaterialTheme.shapes.medium,
    backgroundColor: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(backgroundColor),
    properties: DialogProperties = DialogProperties()
) {
    Dialog(
        onDismissRequest = onDismissRequest,
        properties = properties
    ) {
        // ダイアログ内のコンポーネントをよしなに配置
        AlertDialogContent(
            buttons = buttons,
            modifier = modifier,
            title = title,
            text = text,
            shape = shape,
            backgroundColor = backgroundColor,
            contentColor = contentColor
        )
    }
}
```
[AlertDialogContentの実装](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/AlertDialog.kt)

つまり、AlertDialogを使用してもAlertDialogContentを直接操作できないため、カスタマイズするのは難しそうです。

従って、Dialogを使用し、contentに自作したレイアウトを渡す必要があります。

## 背景の濃度を調べる
よく調べてみると、Material Designの公式に、デフォルト値の記載がありました。
https://m2.material.io/components/dialogs/android#full-screen-dialog
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/7edf556f-6dd5-5927-f8d6-6d762fe5727a.png" width = 500>
dimAmountを32%に設定するとよさそうです。

## エレベーションを調べる
公式より、`ThemeOverlay.MaterialComponents.MaterialAlertDialog`を調べます。
こちらを辿っていくと、以下が見つかります。

```xml
<style name="Base.V21.ThemeOverlay.AppCompat.Dialog" parent="Base.V7.ThemeOverlay.AppCompat.Dialog">
    <!-- abc_floating_window_z = 16 -->
    <item name="android:windowElevation">@dimen/abc_floating_window_z</item> 
</style>
```

elevationを16dpに設定するとよさそうです。

## サイズを調べる
公式に、insetの値が記載されています。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/c908b880-dde4-9080-dd8d-5a916cb2342b.png" width = 500>
(左右marginを24dpにすればいいのかな…と思ったのですが、どう見ても幅広だったので、最終的にはそれっぽい値を設定しました。)

Dialog / AlertDialogでは、引数に`DialogProperties`が渡されています。
その中の`usePlatformDefaultWidth`をfalseにすると、デフォルト幅を変更することができます。

## AlertDialogの代わりにDialogで実装する
背景の濃度とElevationの値がわかったので、それらを適用したDialogを実装します。

先述の通り、AlertDialogContentを使用できないため、レイアウトは自力で実装します。
[こちら](https://m2.material.io/components/dialogs#specs)とMaterialAlertDialogの画像とAlertDialogの実装を参考に、それっぽく実装しました。

若干の違いはあるものの、背景濃度とElevationが同じなため、
ぱっと見区別はつかないのではないでしょうか？！

|  AndroidView  |  JetpackCompose  |
| :-: | :-: |
|  <img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/cc58e67f-f4bc-2c68-ac0f-a48d7da3cb4c.png" width = 300>  |  <img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/bff481ca-92c4-1d24-d67c-3f9c59274720.png" width = 300>  |

<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780537/36019a9e-5e2c-85cf-abe1-6c6f34c85feb.gif" width = 300>

以下、Dialogの実装コードです。
```kotlin
Dialog(
        onDismissRequest = {},
        properties = DialogProperties(
            // widthを自由に設定する
            usePlatformDefaultWidth = false
        )
    ) {
        Surface(
            modifier = Modifier
                .fillMaxWidth()
                // それっぽい左右マージン
                .padding(horizontal = 36.dp),
            shape = MaterialTheme.shapes.medium,
            color = MaterialTheme.colors.surface,
            contentColor = contentColorFor(MaterialTheme.colors.surface),
            // Elevationの設定
            elevation = 16.dp
        ) {
            // 背景濃度の設定
            (LocalView.current.parent as DialogWindowProvider).window.setDimAmount(0.32f)
            Column {
                Box(
                    modifier = Modifier
                        .padding(start = 24.dp, end = 24.dp)
                        .height(40.dp),
                    contentAlignment = Alignment.BottomStart
                ) {
                    Column {
                        Text(
                            text = "タイトル",
                            style = MaterialTheme.typography.subtitle1
                        )
                    }
                }
                Box(
                    modifier = Modifier
                        .padding(start = 24.dp, end = 24.dp)
                        .height(36.dp),
                    contentAlignment = Alignment.BottomStart
                ) {
                    Text(
                        text = "テキスト",
                        style = MaterialTheme.typography.body2
                    )
                }
                Spacer(modifier = Modifier.height(28.dp))
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 8.dp),
                    horizontalArrangement = Arrangement.End
                ) {
                    TextButton(
                        onClick = { }
                    ) {
                        Text(text = "CANCEL")
                    }
                    Spacer(modifier = Modifier.width(8.dp))
                    TextButton(
                        onClick = { }
                    ) {
                        Text(text = "OK")
                    }
                }
            }
        }
    }
```

## 終わりに
本記事は、とにかく**MaterialAlertDialogっぽく**することを目標にしました。
そのため、謎の左右マージンを設定していたり、文字数が増えたらレイアウト崩れしそうな実装をしております。スペースもちゃんと計算しておりません。

ComposeのDialogのデフォルト値を調べる！が真の目標だったのですが、なかなかちょっと見つけられなかったので、今後の課題にします。