Skip to content

Commit

Permalink
AlertDialog support
Browse files Browse the repository at this point in the history
  • Loading branch information
cl3m committed Jan 22, 2021
1 parent 8a9c445 commit c003974
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 26 deletions.
1 change: 0 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx4096M
kotlin.code.style=official
xcodeproj=./iosApp
android.useAndroidX=true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.rouge41.kmm.compose

import androidx.compose.material.contentColorFor
import androidx.compose.material.AlertDialog as _AlertDialog

actual typealias DialogProperties = androidx.compose.ui.window.DialogProperties

@Composable
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
actual fun AlertDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
modifier: Modifier = Modifier,
dismissButton: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
shape: Shape? = null,
backgroundColor: Color? = null,
contentColor: Color? = null,
properties: DialogProperties? = null
) = _AlertDialog(onDismissRequest = onDismissRequest, confirmButton = confirmButton, modifier = modifier, dismissButton = dismissButton,
title = title, text = text, shape = shape ?: MaterialTheme.shapes.medium, backgroundColor = backgroundColor ?: MaterialTheme.colors.surface,
contentColor = if (backgroundColor != null) contentColorFor(backgroundColor) else contentColorFor(MaterialTheme.colors.surface), properties = properties)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.rouge41.kmm.compose

expect interface DialogProperties

@Composable
expect fun AlertDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
modifier: Modifier = Modifier,
dismissButton: @Composable (() -> Unit)? = null,
title: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null,
shape: Shape? = null,
backgroundColor: Color? = null,
contentColor: Color? = null,
properties: DialogProperties? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.rouge41.kmm.compose

import platform.Foundation.NSLog
import platform.UIKit.*

actual interface DialogProperties

@Composable
actual fun AlertDialog(
onDismissRequest: () -> Unit,
confirmButton: @Composable () -> Unit,
modifier: Modifier,
dismissButton: @Composable (() -> Unit)?,
title: @Composable (() -> Unit)?,
text: @Composable (() -> Unit)?,
shape: Shape?,
backgroundColor: Color?,
contentColor: Color?,
properties: DialogProperties?
) {
val alertController = ComposeAlertController()
addController(alertController) {
dismissButton?.let {
it.invoke()
val onClick = alertController.onClick
val action = UIAlertAction.actionWithTitle(alertController.text, 1) { onClick() }
alertController.alert.addAction(action)
}

confirmButton.invoke()
val onClick = alertController.onClick
val action = UIAlertAction.actionWithTitle(alertController.text, 0) { onClick() }
alertController.alert.addAction(action)
title?.let {
it()
alertController.alert.title = alertController.text
}
text?.let {
it()
alertController.alert.message = alertController.text
}
}

getCurrentController().presentViewController(alertController.alert, true) { }
}

class ComposeAlertController() : UIViewController(nibName = null, bundle = null) {
var text = ""
var onClick: () -> Unit = {}
val alert = UIAlertController.alertControllerWithTitle(null, null, 1)
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,34 +52,40 @@ actual fun Button(
contentPadding: PaddingValues?,
content: @Composable RowScope.() -> Unit
) {
val container = ComposeSystemButton.createOrReuse(onClick)
modifier.margin(10.dp).padding(0.dp).setup(container)
modifier.background(Color.Transparent).setup(container.button)
if (border != null) {
if (border.brush is SolidColor) {
container.layer.borderColor = border.brush.value.toUIColor()?.CGColor
}
container.layer.borderWidth = border.width.value.toDouble()
val controller = getCurrentController()
if (controller is ComposeAlertController) {
controller.onClick = onClick
content.invoke(iosRowScope())
} else {
container.layer.borderWidth = 0.0
}
if (shape != null && shape is RoundedCornerShape) {
val container = ComposeSystemButton.createOrReuse(onClick)
modifier.margin(10.dp).padding(0.dp).setup(container)
modifier.background(Color.Transparent).setup(container.button)
if (border != null) {
if (border.brush is SolidColor) {
container.layer.borderColor = border.brush.value.toUIColor()?.CGColor
}
container.layer.borderWidth = border.width.value.toDouble()
} else {
container.layer.borderWidth = 0.0
}
if (shape != null && shape is RoundedCornerShape) {
if (colors != null && colors is DefaultButtonColors) {
colors.backgroundColor.toUIColor()?.let { container.backgroundColor = it }
} else {
container.backgroundColor = getHostingView().tintColor
container.button.tintColor = UIColor.whiteColor
container.button.titleLabel?.textColor = UIColor.whiteColor
}
//TODO: Use UIBezierPath
container.layer.cornerRadius = (shape.topLeft as Dp).value.toDouble()
}
if (colors != null && colors is DefaultButtonColors) {
colors.backgroundColor.toUIColor()?.let { container.backgroundColor = it }
} else {
container.backgroundColor = getHostingView().tintColor
container.button.tintColor = UIColor.whiteColor
container.button.titleLabel?.textColor = UIColor.whiteColor
}
//TODO: Use UIBezierPath
container.layer.cornerRadius = (shape.topLeft as Dp).value.toDouble()
}
if (colors != null && colors is DefaultButtonColors) {
colors.backgroundColor.toUIColor()?.let { container.backgroundColor = it }
}
container.button.enabled = enabled
addSubview(container) {
addSubview(container.button) { content.invoke(iosRowScope()) }
container.button.enabled = enabled
addSubview(container) {
addSubview(container.button) { content.invoke(iosRowScope()) }
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rouge41.kmm.compose

import cocoapods.YogaKit.*
import platform.Foundation.NSLog
import platform.UIKit.*


Expand Down Expand Up @@ -28,9 +29,12 @@ actual fun Text(
/*onTextLayout: (TextLayoutResult) -> Unit,*/
style: TextStyle?
) {
val controller = getCurrentController()
val view = getCurrentView()
val color = if (color != Color.Unspecified) color else style?.color
if (view is UIButton) {
if (controller is ComposeAlertController) {
controller.text = text
} else if (view is UIButton) {
view.setTitle(text, 0)
color?.let { view.setTitleColor(it.toUIColor(), 0) }
view.titleLabel?.font = (style ?: TextStyle()).toUIFont(overrideFontSize = if (fontSize != TextUnit.Unspecified) fontSize else null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ fun DrawerNavigation(state: MutableState<Boolean>, resources: Resources) {
Demo.Layout -> Layout()
Demo.Images -> Images(resources)
Demo.Buttons -> Buttons()
Demo.Alert -> Alert()
Demo.TextStyles -> Column { TextStyles() }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum class Demo {
Images,
PeopleInSpace,
Buttons,
Alert,
// Below are dropped in navigation demos
BottomNavigation,
Navigation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fun Raw(state: MutableState<Boolean>, resources: Resources) {
Demo.TextStyles -> SafeArea { TextStyles() }
Demo.Images -> SafeArea { Images(resources) }
Demo.Buttons -> SafeArea { Buttons() }
Demo.Alert -> SafeArea { Alert() }
Demo.BottomNavigation -> BottomNavigation(state, resources)
Demo.Navigation -> Navigation(state, resources)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.rouge41.kmm.compose.test.demos

import com.rouge41.kmm.compose.*

// FROM https://raw.githubusercontent.com/vinaygaba/Learn-Jetpack-Compose-By-Example/master/app/src/main/java/com/example/jetpackcompose/material/AlertDialogActivity.kt

@Composable
fun Alert() {
Column {
// Here, ClickableText is a @Composable function which is going to describe the
// contents of this activity that will be rendered on the screen.
ClickableText()
}
}


// We represent a Composable function by annotating it with the @Composable annotation. Composable
// functions can only be called from within the scope of other composable functions. We should
// think of composable functions to be similar to lego blocks - each composable function is in turn
// built up of smaller composable functions.
@Composable
fun ClickableText() {
// Reacting to state changes is core to how Jetpack Compose works. This state variable "showPopup"
// is used to control whether the popup should be shown. The value is toggled every time the
// text "Click to see dialog" is clicked. Every time the value of this variable changes,
// the relevant sub-composables that use showPopup are automatically recomposed.
var variable by remember { mutableStateOf("not clicked") }
var showPopup by remember { mutableStateOf(false) }
// Column with clickable modifier wraps the child composable and enables it to react to a click
// through the onClick callback similar to the onClick listener that we are accustomed to
// on Android.
// Here, we just change the value of showPopup to be true every time we click on the text that
// says "Click to see Popup"
Button(onClick = { showPopup = true }, content = {
// The Text composable is pre-defined by the Compose UI library; you can use this
// composable to render text on the screen
Text(
text = "Click to see dialog", modifier = Modifier.padding(16.dp),
style = TextStyle(
fontSize = 16.sp,
fontFamily = FontFamily.Serif
)
)
})

Text(if (showPopup) "ShowPopup = true" else "ShopPopup = false")
Text(variable)

// A lambda that toggles the showPopup value to off. We pass it to the onDismiss equivalent
// callback of the AlertDialog.
val onPopupDismissed = { showPopup = false }

// We want to show the popup only if the showPopup variable is toggled to true. Since Jetpack
// Compose uses the declarative way of programming, we can easily decide what needs to shows
// vs hidden based on which branch of code is being executed. In this example, we display the
// AlertDialog only when the showPopup variable is set to true or else this branch is not
// executed at all and thus the alert dialog remains hidden.
if (showPopup) {
// Predefined composable provided by the material implementations of Jetpack Compose. It
// shows a simple alert dialog on the screen if this code path is executed (i.e showPopup
// variable is true)
AlertDialog(
onDismissRequest = onPopupDismissed,
title = {
Text("Confirmation")
},
text = {
Text("Congratulations! You just clicked the text successfully")
},
dismissButton = {
Button(
onClick = {
onPopupDismissed()
variable = "Cancel clicked"
}
) {
Text(text = "Cancel")
}
}
,confirmButton = {
// Button is a pre-defined Material Design implementation of a contained button -
// https://material.io/design/components/buttons.html#contained-button.
Button(
onClick = {
onPopupDismissed()
variable = "Ok clicked"
}
) {
// The Button composable allows you to provide child composables that inherit
// this button functionality.
// The Text composable is pre-defined by the Compose UI library; you can use this
// composable to render text on the screen
Text(text = "Ok")
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ actual fun Navigation(state: MutableState<Boolean>, resources: Resources) {
Demo.Layout -> SafeArea { Layout() }
Demo.Buttons -> SafeArea { Buttons() }
Demo.Images -> SafeArea { Images(resources) }
Demo.Alert -> SafeArea { Alert() }
Demo.TextStyles -> SafeArea { Column { TextStyles() } }
}
}
Expand Down

0 comments on commit c003974

Please sign in to comment.