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 @@ + + + + + + + + + +