Skip to content

Latest commit

 

History

History
183 lines (147 loc) · 6.86 KB

AnotherSample.md

File metadata and controls

183 lines (147 loc) · 6.86 KB

Components - sample walkthrough, part 2

Let's take a look at another similar example of using Aurora commands.

The setup has the same multiline text area and a vertical button strip with four buttons. Each button corresponds to bold, italic, underline and strikethrough content style. When clicked, the presence of the matching style is toggled. For code brevity, each style is applied on the whole text, and not on individual spans.

For example, clicking the bold button shows this:

And then clicking the italic button shows this:

Note how both bold and italic buttons show up as selected.

Content setup

As before, we start with the overall definition of our application and window content:

fun main() = auroraApplication {
  val state = rememberWindowState(
      placement = WindowPlacement.Floating,
      position = WindowPosition.Aligned(Alignment.Center),
      size = DpSize(600.dp, 320.dp)
  )

  AuroraWindow(
      skin = marinerSkin(),
      title = "Text styling demo",
      icon = radiance_menu(),
      iconFilterStrategy = IconFilterStrategy.ThemedFollowText,
      state = state,
      windowTitlePaneConfiguration = AuroraWindowTitlePaneConfigurations.AuroraPlain(),
      onCloseRequest = ::exitApplication,
  ) {
      // Here we'll have our data models

      Row(
          modifier = Modifier.fillMaxSize().padding(6.dp),
          horizontalArrangement = Arrangement.spacedBy(12.dp)
      ) {
        // Here we'll have the box for the buttons
        // And here we'll have the TextFieldValueProjection
      }
  }
}

For the data models, we start with setting up our TextFieldValue:

val text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " +
        "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" +
        " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " +
        "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " +
        "voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
        "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui " +
        "officia deserunt mollit anim id est laborum."

var bold by remember { mutableStateOf(false) }
var italic by remember { mutableStateOf(false) }
var underline by remember { mutableStateOf(false) }
var strikethrough by remember { mutableStateOf(false) }

val spanStyle by derivedStateOf {
    SpanStyle(
        fontWeight = if (bold) FontWeight.Bold else FontWeight.Normal,
        fontStyle = if (italic) FontStyle.Italic else FontStyle.Normal,
        textDecoration = when {
            underline && strikethrough -> TextDecoration.combine(
                listOf(TextDecoration.Underline, TextDecoration.LineThrough)
            )
            underline -> TextDecoration.Underline
            strikethrough -> TextDecoration.LineThrough
            else -> null
        }
    )
}

val textFieldValue by derivedStateOf {
    TextFieldValue(
        annotatedString = AnnotatedString(
            text = text,
            spanStyle = spanStyle
        )
    )
}

Here, we have a block of text (note that in this example the text area is again not going to be editable, so we do not use mutableStateOf for the text itself). In this demo we are going to be changing the individual style bits (bold, italic, underline, strikethrough), so we set up a mutable variable for each one, then use derivedStateOf to wrap a correspondingly configured SpanStyle, and finish with a derivedStateOf to wrap our TextFieldValue. Whenever the any of the basic styling boolean bits changes, that change will cause recomposition and update of spanStyle and textFieldValue.

In order to add our read-only text area, we use Aurora's text field projection:

TextFieldValueProjection(
    contentModel = TextFieldValueContentModel(
        value = textFieldValue,
        readOnly = true,
        onValueChange = {}
    ),
    presentationModel = TextFieldPresentationModel(showBorder = false)
).project(modifier = Modifier.weight(1.0f, true))

And now let's take a look at configuring and displaying the command buttons that will change the style bits.

Commands

We start with our commands

// Bold style command
val commandBold = Command(
    text = "Bold",
    icon = format_text_bold(),
    isActionToggle = true,
    isActionToggleSelected = bold,
    onTriggerActionToggleSelectedChange = { bold = it }
)

// Italic style command
val commandItalic = Command(
    text = "Italic",
    icon = format_text_italic(),
    isActionToggle = true,
    isActionToggleSelected = italic,
    onTriggerActionToggleSelectedChange = { italic = it }
)

// Underline style command
val commandUnderline = Command(
    text = "Underline",
    icon = format_text_underline(),
    isActionToggle = true,
    isActionToggleSelected = underline,
    onTriggerActionToggleSelectedChange = { underline = it }
)

// Strikethrough style command
val commandStrikethrough = Command(
    text = "Strikethrough",
    icon = format_text_strikethrough(),
    isActionToggle = true,
    isActionToggleSelected = strikethrough,
    onTriggerActionToggleSelectedChange = { strikethrough = it }
)

Each one is mapped to configure its current isActionToggleSelected state based on the presense of the matching style bit, as well as updating that bit in the onTriggerActionToggleSelectedChange lambda.

Whenever one of these buttons is clicked, its lambda updates the underlying boolean variable, which causes the recomposition and update of the button itself, as well as the text area itself with the newly updated span style:

Command strip

The same way as in our first example, we are now ready to create the content model and the presentation model for our command button strip:

CommandButtonStripProjection(
    contentModel = CommandGroup(
        commands = listOf(
            commandBold,
            commandItalic,
            commandUnderline,
            commandStrikethrough
        )
    ),
    presentationModel = CommandStripPresentationModel(
        orientation = StripOrientation.Vertical,
        commandPresentationState = CommandButtonPresentationState.Small,
        horizontalGapScaleFactor = 0.75f
    )
).project()

Next

Continue to the command overview.