diff --git a/alerts/.gitignore b/alerts/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/alerts/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/alerts/README.md b/alerts/README.md
new file mode 100644
index 0000000..61cca56
--- /dev/null
+++ b/alerts/README.md
@@ -0,0 +1,75 @@
+Alerts
+=====
+
+### Общее описание
+
+Модуль содержит:
+`AlertDialogManager` - служит для демонстрации AlertDialog с использованием View, необходимо вызвать метод `showAlertDialog`, который
+в качестве агруметов может принимать:
+* `context`,
+* `style` - стиль для элементов дефолтного диалога (по умолчанию R.style.AlertDialogDefault),
+* `title` - Заголовок диалога,
+* `message` - дополнительное сообщение,
+* `positiveButtonText` - текст правой кнопки (по умолчанию "ОК"),
+* `onPositiveAction` - колбэк при нажатии на правую кнопку,
+* `negativeBtnTitle` - текст левой кнопки (по умолчаннию null - в этом случаи не отображается),
+* `onNegativeAction` - колбэк при нажатии на левую кнопку,
+* `dialogLayout` - id кастомного layout (по умолчанию R.layout.dialog_alert).
+
+---
+`ComposableAlertDialog` - служит для демонстрации AlertDialog с использованием Jetpack Compose, необходимо вызвать метод `ShowAlertDialog`, который
+в качестве агруметов может принимать:
+* `isDialogOpen` - индикатор состояния диалога,
+* `title` - Заголовок диалога,
+* `message` - дополнительное сообщение,
+* `positiveButtonText` - текст правой кнопки,
+* `onPositiveAction` - колбэк при нажатии на правую кнопку,
+* `negativeBtnTitle` - текст левой кнопки (по умолчаннию null - в этом случаи не отображается),
+* `onNegativeAction` - колбэк при нажатии на левую кнопку.
+
+Кастомизация Compose версии происходит по средствам инициализации полей: customTitle, customMessage, customConfirmBtn, customNegativeBtn
+
+### Примеры
+
+View версия (ViewableAlertDialog) ok/cancel диалога:
+```kotlin
+alertDialogManager.showAlertDialog(
+ context = activity,
+ title = "Ой, что-то пошло не так",
+ message = "Попробуйте ещё раз",
+ positiveButtonText = "Ещё раз",
+ onPositiveAction = { retryConnection() },
+ negativeBtnTitle = "Отмена"
+)
+```
+
+View версия (ViewableAlertDialog) ok диалога:
+```kotlin
+alertDialogManager.showOkDialog(
+ context = dialog?.window?.decorView?.context ?: throw Exception(),
+ title = "Необходимо изменить настройки",
+ okButtonText = "Ок",
+ onOkAction = {
+ viewModel.dispatchAction(ItemAction.ChangeSettings)
+ }
+)
+```
+
+Для катомизации стилей элементов в дефолтной разметке диалога необходимо создать стиль - наследника от `ThemeOverlay.MaterialComponents.MaterialAlertDialog` и переопределить стили:
+* `materialAlertDialogTitleTextStyle` - стиль для заголока (наследник от `MaterialAlertDialog.MaterialComponents.Title.Text`),
+* `materialAlertDialogBodyTextStyle` - стиль для подзаголовка (наследник от `MaterialAlertDialog.MaterialComponents.Body.Text`),
+* `buttonBarPositiveButtonStyle` - стиль для позитивной кнопки (наследник от `Widget.MaterialComponents.Button.TextButton.Dialog`),
+* `buttonBarNegativeButtonStyle` - стиль для негативной кнопки (наследник от `Widget.MaterialComponents.Button.TextButton.Dialog`).
+
+Compose версия (ComposableAlertDialog):
+```kotlin
+val isDialogOpen = remember { mutableStateOf(false)}
+....
+//Создание диалога
+ComposableAlertDialog
+ .apply { customTitle = { Text(text = "Ой, что-то пошло не так", color = Color.Blue) } }
+ .ShowAlertDialog(isDialogOpen, message = "Проблемы с сетью", positiveButtonText = "ОК")
+....
+//Отображение диалога
+isDialogOpen.value = true
+```
diff --git a/alerts/build.gradle b/alerts/build.gradle
new file mode 100644
index 0000000..6c08de1
--- /dev/null
+++ b/alerts/build.gradle
@@ -0,0 +1,47 @@
+apply from: "../android-configs/lib-config.gradle"
+
+ext {
+ composeVersion = '1.1.1'
+}
+
+android {
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+ implementation("androidx.core:core-ktx")
+ implementation("androidx.constraintlayout:constraintlayout")
+ implementation("com.google.android.material:material")
+ implementation project(":kotlin-extensions")
+
+ implementation "androidx.compose.runtime:runtime:$composeVersion"
+ implementation "androidx.compose.ui:ui:$composeVersion"
+ implementation "androidx.compose.foundation:foundation:$composeVersion"
+ implementation "androidx.compose.foundation:foundation-layout:$composeVersion"
+ implementation "androidx.compose.material:material:$composeVersion"
+ implementation "androidx.compose.runtime:runtime-livedata:$composeVersion"
+ implementation "androidx.compose.ui:ui-tooling:$composeVersion"
+ implementation "com.google.android.material:compose-theme-adapter:1.1.9"
+
+ constraints {
+ implementation("androidx.core:core-ktx") {
+ version {
+ require '1.0.0'
+ }
+ }
+
+ implementation("androidx.constraintlayout:constraintlayout") {
+ version {
+ require '2.2.0-alpha03'
+ }
+ }
+
+ implementation("com.google.android.material:material") {
+ version {
+ require '1.1.0'
+ }
+ }
+ }
+}
diff --git a/alerts/src/main/AndroidManifest.xml b/alerts/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..80ea08a
--- /dev/null
+++ b/alerts/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/alerts/src/main/java/ru/touchin/roboswag/composable_dialog/ComposableAlertDialog.kt b/alerts/src/main/java/ru/touchin/roboswag/composable_dialog/ComposableAlertDialog.kt
new file mode 100644
index 0000000..e8d6c3f
--- /dev/null
+++ b/alerts/src/main/java/ru/touchin/roboswag/composable_dialog/ComposableAlertDialog.kt
@@ -0,0 +1,54 @@
+package ru.touchin.roboswag.composable_dialog
+
+import androidx.compose.material.AlertDialog
+import androidx.compose.material.Text
+import androidx.compose.material.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+
+object ComposableAlertDialog {
+ var customTitle: @Composable (() -> Unit)? = null
+ var customMessage: @Composable (() -> Unit)? = null
+ var customConfirmBtn: @Composable (() -> Unit)? = null
+ var customNegativeBtn: @Composable (() -> Unit)? = null
+
+ @Composable
+ fun ShowAlertDialog(
+ isDialogOpen: MutableState,
+ title: String? = null,
+ message: String? = null,
+ positiveButtonText: String? = null,
+ onPositiveAction: (() -> Unit)? = null,
+ negativeBtnTitle: String? = null,
+ onNegativeAction: (() -> Unit)? = null
+ ) {
+ if (!isDialogOpen.value) return
+
+ AlertDialog(
+ onDismissRequest = { isDialogOpen.value = false },
+ title = customTitle ?: { Text(title.orEmpty()) },
+ text = customMessage ?: { Text(message.orEmpty()) },
+ confirmButton = customConfirmBtn ?: createButton(positiveButtonText.orEmpty()) {
+ onPositiveAction?.invoke()
+ isDialogOpen.value = false
+ },
+ dismissButton = when {
+ customNegativeBtn != null -> customNegativeBtn
+ negativeBtnTitle != null -> createButton(negativeBtnTitle) {
+ onNegativeAction?.invoke()
+ isDialogOpen.value = false
+ }
+ else -> null
+ }
+ )
+ }
+
+ @Composable
+ private fun createButton(text: String, onClickAction: () -> Unit): @Composable (() -> Unit) =
+ {
+ TextButton(onClick = onClickAction) {
+ Text(text)
+ }
+ }
+
+}
diff --git a/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogManager.kt b/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogManager.kt
new file mode 100644
index 0000000..b6df3fd
--- /dev/null
+++ b/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogManager.kt
@@ -0,0 +1,85 @@
+package ru.touchin.roboswag.viewable_dialog
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.view.ContextThemeWrapper
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import ru.touchin.roboswag.alerts.R
+
+class AlertDialogManager {
+
+ @SuppressWarnings("detekt.LongParameterList")
+ fun showAlertDialog(
+ context: Context,
+ style: Int = R.style.AlertDialogDefault,
+ title: String? = null,
+ message: String? = null,
+ positiveButtonText: String = context.getString(R.string.positive_btn),
+ onPositiveAction: (() -> Unit)? = null,
+ negativeBtnTitle: String? = null,
+ onNegativeAction: (() -> Unit)? = null,
+ dialogLayout: Int = R.layout.dialog_alert,
+ cancelable: Boolean = true,
+ onCancelAction: () -> Unit = {}
+ ) {
+ val styledContext = ContextThemeWrapper(context, style)
+
+ MaterialAlertDialogBuilder(styledContext)
+ .setView(LayoutInflater.from(styledContext).inflate(dialogLayout, null))
+ .show()
+ .setupAlertDialog(
+ title = title,
+ message = message,
+ positiveButtonText = positiveButtonText,
+ onPositiveClick = onPositiveAction,
+ negativeButtonText = negativeBtnTitle,
+ onNegativeClick = onNegativeAction,
+ cancelable = cancelable,
+ onCancelAction = onCancelAction
+ )
+ }
+
+ fun showOkDialog(
+ context: Context,
+ style: Int = R.style.AlertDialogDefault,
+ title: String? = null,
+ message: String? = null,
+ okButtonText: String = context.getString(R.string.positive_btn),
+ onOkAction: (() -> Unit)? = null,
+ cancelable: Boolean = true,
+ onCancelAction: () -> Unit = {}
+ ) = showAlertDialog(
+ context = context,
+ style = style,
+ title = title,
+ message = message,
+ positiveButtonText = okButtonText,
+ onPositiveAction = onOkAction,
+ cancelable = cancelable,
+ onCancelAction = onCancelAction
+ )
+
+ private fun AlertDialog.setupAlertDialog(
+ title: String? = null,
+ message: String? = null,
+ positiveButtonText: String,
+ onPositiveClick: (() -> Unit)? = null,
+ negativeButtonText: String? = null,
+ onNegativeClick: (() -> Unit)? = null,
+ cancelable: Boolean = true,
+ onCancelAction: () -> Unit = {}
+ ) {
+ setCancelable(cancelable)
+ setOnDismissListener { onCancelAction() }
+ findViewById(R.id.alert_title)?.setTextOrGone(title)
+ findViewById(R.id.alert_message)?.setTextOrGone(message)
+ findViewById(R.id.alert_positive_button)?.let { buttonView ->
+ setupButton(this, buttonView, positiveButtonText, onPositiveClick)
+ }
+ findViewById(R.id.alert_negative_button)?.let { buttonView ->
+ setupButton(this, buttonView, negativeButtonText, onNegativeClick)
+ }
+ }
+}
diff --git a/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogUtils.kt b/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogUtils.kt
new file mode 100644
index 0000000..07cd8d4
--- /dev/null
+++ b/alerts/src/main/java/ru/touchin/roboswag/viewable_dialog/AlertDialogUtils.kt
@@ -0,0 +1,19 @@
+package ru.touchin.roboswag.viewable_dialog
+
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
+import androidx.core.view.isVisible
+import ru.touchin.extensions.setOnRippleClickListener
+
+fun setupButton(alertDialog: AlertDialog, buttonView: TextView, text: String?, onButtonClick: (() -> Unit)?) {
+ buttonView.setTextOrGone(text)
+ buttonView.setOnRippleClickListener {
+ onButtonClick?.invoke()
+ alertDialog.dismiss()
+ }
+}
+
+fun TextView.setTextOrGone(text: CharSequence?) {
+ isVisible = !text.isNullOrEmpty()
+ setText(text)
+}
diff --git a/alerts/src/main/res/layout/dialog_alert.xml b/alerts/src/main/res/layout/dialog_alert.xml
new file mode 100644
index 0000000..6aec6ce
--- /dev/null
+++ b/alerts/src/main/res/layout/dialog_alert.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/alerts/src/main/res/values/strings.xml b/alerts/src/main/res/values/strings.xml
new file mode 100644
index 0000000..319d46c
--- /dev/null
+++ b/alerts/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+
+ OK
+ Cancel
+
diff --git a/alerts/src/main/res/values/styles.xml b/alerts/src/main/res/values/styles.xml
new file mode 100644
index 0000000..7c8d2be
--- /dev/null
+++ b/alerts/src/main/res/values/styles.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+