Skip to content

Conversation

@Calvicii
Copy link
Contributor

@Calvicii Calvicii commented Jul 8, 2025

Adds PreferencesGroup and every child of Adw.ActionRow.

@Calvicii
Copy link
Contributor Author

Calvicii commented Jul 8, 2025

This PR is not ready yet. As of right now I have added PreferencesGroup and SwitchRow. Both work really well but I find my implementation of SwitchRow a bit hacky. It involves looking through the children of SwitchRow to find the switch itself and connect to its state-set signal. Unfortunately, this was the only method I found to prevent the switch from diverging from the app's state. I followed what we did with Gtk.Switch. If anyone has a better idea I would be happy to discuss it.

@MMarco94

@Calvicii
Copy link
Contributor Author

Calvicii commented Jul 16, 2025

I've added Adw.ActionRow but I couldn't find a nice way to set activatable widget. Maybe a onActivate parameter would be better?

@Calvicii
Copy link
Contributor Author

I was thinking maybe we could add a Modifier named id that way we could add an activableWidget parameter and set it to the id of the widget like they do in normal Gtk. I'm not sure if this is doable.

Adw.ActionRow {
    title: _("Show Toast");
    activatable-widget: toast_button;

    [suffix]
    Button toast_button {
        halign: center;
        valign: center;
        label: _("show toast");
        icon-name: "bread-symbolic";
    }
 }


children.forEach { child ->
widget.addPrefix(child)
widget.activatableWidget = child
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand. Is activatableWidget always the last children?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it so the last inserted widget is the activatable one because I couldn't think of a better way to handle activatable widget right now.

@MMarco94
Copy link
Collaborator

About the issue with the active state, I am not familiar with the problem enough.

Can you give me an example of an use case for activatableWidget?

@Calvicii
Copy link
Contributor Author

Basically, an ActionRow is activated when you click on it and when there is something to activate. For example, when you click on a SwitchRow it activates the switch. If I click directly on the switch it does not count as an activation for the SwitchRow.

Screencast.From.2025-07-19.16-05-20.mp4

The problem I have with ActionRow is that there can be multiple widgets that are activatable like buttons. When this is the case we need to select which of these widgets will activate once you click on the ActionRow itself. (clicking on an individual widget will activate it like any other button) This is why the Adw widget provides the activatableWidget property on ActionRow. It enables you to choose which of these widgets is activated. The problem is that this property takes a Gtk widget as its value and we deal with composable functions. I need to find a way to tell the function which widget is the activatable one. Maybe like this?

ActionRow(
    title = "Toast",
    subtitle = "Launches a toast",
    prefix = {
        Activatable {
            IconButton(
                ImageSource.Icon("bread-symbolic"),
                modifier = Modifier.alignment(Align.CENTER),
                onClick = {
                    logger.info { "Launch a toast" }

                    val toast = Toast().apply {
                        title = "A toast"
                    }

                    dismissAllToasts()
                    addToast(toast)
                },
            )
        }
    }
    suffix = {
        IconButton(
            ImageSource.Icon("bread-symbolic"),
            modifier = Modifier.alignment(Align.CENTER),
            onClick = {
                logger.info { "Launch a toast" }

                val toast = Toast().apply {
                    title = "A toast"
                }

                dismissAllToasts()
                addToast(toast)
            },
        )
    },
)

Where suffix and prefix expose and Activatable function that takes a composable function as parameter and makes that widget the activatable one. Let me know what you think.

I have made all the other requested changes.

And thank you for taking the time to help me with this!

@MMarco94
Copy link
Collaborator

Got it.

What about, instead of adding the Activatable function, the inplicit context adds a Modifier.activateWithActionRow() function?

That way, the widget can be set using the Modifier?

@Calvicii
Copy link
Contributor Author

Tell me what you think of this new commit. I added a modifier only accessible by the children of prefix and suffix.

)
}

private class AdwActionRowSlotContainer(actionRow: AdwActionRow, private val slot: ActionRowSlot) :
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an alternative to slot, you could pass a lambda that does addPrefix / addSuffix.

But this works too

@MMarco94
Copy link
Collaborator

Changes LGTM, thanks!

The PR is still marked as draft. LMK if you want to make further changes, otherwise I can merge it

@Calvicii Calvicii marked this pull request as ready for review August 25, 2025 21:34
@luleyleo
Copy link
Contributor

Can this be merged now?

@Calvicii
Copy link
Contributor Author

Yes its all good on my side

@Calvicii
Copy link
Contributor Author

I added the last child of ActionRow (SpinRow).

@Calvicii Calvicii requested a review from MMarco94 September 22, 2025 15:45
@MineKing9534
Copy link

MineKing9534 commented Sep 24, 2025

I think EntryRow is an essential feature for PreferencesGroup that is still missing

@Calvicii
Copy link
Contributor Author

Yes, but EntryRow is not a child of ActionRow. I will create another PR for it.

@MMarco94 MMarco94 merged commit f64c079 into compose4gtk:main Sep 29, 2025
2 checks passed
@MMarco94
Copy link
Collaborator

Thanks! Merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants