david-swift / SettingsKit-macOS

Add a settings window to a SwiftUI macOS app
https://david-swift.github.io/SettingsKit-macOS/
MIT License
87 stars 2 forks source link

Menus in the sidebar #6

Closed longseespace closed 1 year ago

longseespace commented 1 year ago

Overview

This is more of a question than a feature request though. The actions is working great, however, it's common to show a dropdown menu when clicking on the Plus button, or when clicking on the options

Like this:

CleanShot 2023-08-02 at 13 20 46@2x

How can I achieve this with SettingsKit?

I can see that the ToolbarAction body is a Button. Maybe we should allow developers to specify the body or to create a custom ToolbarAction (make it a protocol maybe)?

@david-swift

david-swift commented 1 year ago

Currently, it's not possible in SettingsKit.

As a dropdown menu button is maybe something that is required quite often, I could imagine adding a new structure for dropdown menus, maybe like the following:

ToolbarGroup {
    ToolbarMenu("Add (Menu)", systemSymbol: .plusApp) {
        Button("Some Action") { print("Some Action") }
        Button("Another Action") { print("Another Action") }
    }
}

I could also add a structure for custom views in the toolbar, with the option to add the hover animation of SettingsKit.

ToolbarGroup {
    ToolbarContent(background: true) {
        Text("A simple text")
    }
}

Is that ok, @longseespace? The ToolbarContent accepting a view would require less code than having to create a custom type that conforms to a protocol.

longseespace commented 1 year ago

That looks perfect!! Thanks 🙏

david-swift commented 1 year ago

I've started implementing those features.

In the following clip, one can see a custom view and a menu in the toolbar:

https://github.com/david-swift/SettingsKit-macOS/assets/106754840/3d206fd0-2c04-4d0d-8952-661043617546

The menu is defined in the following way:

ToolbarGroup {
    ToolbarMenu(.init(), systemSymbol: .plus) {
        Button("+1") {
            testCount += 1
        }
        /// ...
    }
    // ...
}

The implementation of the custom view is a bit different from the one I showed in the previous comment as the background is always set for the whole group and not for a single action:

ToolbarGroup {
    ProgressView(value: 0.5)
        .padding()
}
.spacer()

It's possible to remove the background from any ToolbarGroup by setting the background argument in the initializer to false.


There is one problem with the implementation of the ToolbarMenu. The button menu style which allows treating a Menu's label like a button label (with .buttonStyle(_:), etc.) is available in macOS 13 or later, but not in macOS 12. I cannot use the older, deprecated MenuButton as that button expands in the width, making the button in the toolbar as wide as possible. The only solution I can think of is displaying the MenuButton's content on a popover which is presented when the button is clicked (in macOS 12).

Do you have another idea, @longseespace? If not, how could that popover look like?

david-swift commented 1 year ago

The background hover effect can be completely disabled for any ToolbarGroup using the new background argument (ToolbarGroup(background: false) { }), which could also make the look a bit more minimal (#3) if that is wished.

longseespace commented 1 year ago

@david-swift honestly I don't know what it should look like in macOS 12 😅

longseespace commented 1 year ago

Don't want to be pushy but is there any progress on this @david-swift 😅

david-swift commented 1 year ago

Yeah, sorry, I've been on Linux working on SwiftGui and kind of forgot that issue.

So there wasn't really any progress. That's what the popover looks like that I created three days ago (for macOS 12):

https://github.com/david-swift/SettingsKit-macOS/assets/106754840/d7db7f04-420b-41f2-ae5c-d828e35766b8

What do you think about it?

longseespace commented 1 year ago

That looks good. Although would be better if the popover point to the middle of the + symbol. It's a little shifted to the left 😁

Didn't know you're also working on Linux 😳

david-swift commented 1 year ago

Oh, I didn't notice that, thanks! I've corrected that, the popover points now to the middle.

You can update to ColibriComponents 0.1.10 to be able to add menus and custom views to the sidebar and to SettingsKit 0.1.12 to get the new standard actions function with an "Add" menu instead of a button.

longseespace commented 1 year ago

@david-swift the latest version doesn't seem to compile. This is the error I got (tested on the TestApp too)

Cannot infer contextual base in reference to member 'colibriCornerRadius'
Reference to member 'rect' cannot be resolved without a contextual type

Related code in the ColibriComponents

public func customToolbarBackground(visible: Bool) -> some View {
        background(
            .secondary.opacity(visible ? .toolbarGroupSecondaryBackground : 0),
            in: .rect(cornerRadius: .colibriCornerRadius)
        )
    }
david-swift commented 1 year ago

Strange, I downloaded the source code from the latest release and could build TestApp without getting this error. I also tried using one of my app projects and it worked.

I'm on macOS 14 (Xcode 15.0 Beta 5), so I'll try building it in my macOS 13 VM for reproducing the error you get.

david-swift commented 1 year ago

I could reproduce it in my macOS 13 VM! I'll fix it.

david-swift commented 1 year ago

Could you test whether you can build the main branch of ColibriComponents?

longseespace commented 1 year ago

@david-swift I can build both the ColibriComponents and the TestApp but the Plus button looks funny now.

CleanShot 2023-08-05 at 20 09 25@2x

david-swift commented 1 year ago

Hm, it works for me under macOS 14:

https://github.com/david-swift/SettingsKit-macOS/assets/106754840/9357eaa1-7f31-4a44-bfa5-6d2c1593eaf1

If the button menu style does not work on macOS 13 , I have to set the solution with the popover for macOS 12 and 13.

longseespace commented 1 year ago

@david-swift I was able to make it work with this code. Can you confirm on macOS 14?

File: https://github.com/david-swift/ColibriComponents-macOS/blob/main/Sources/ColibriComponents/Model/Data/ToolbarMenu.swift

/// The action's view.
/// - Parameter padding: The horizontal padding around the button.
/// - Returns: A view containing the action button.
public func body(padding: Edge.Set) -> AnyView {
    let label = Label {
        Text(title)
    } icon: {
        icon
    }

    return .init(
        Group {
            if #available(macOS 13, *) {
                Menu {
                    content
                } label: {
                    label
                        .customToolbarItem(padding: padding)
                        .border(.red)
                }
                .menuStyle(.borderlessButton)
                .menuIndicator(.hidden)
                .frame(width: .customToolbarSideLength)
                .padding(padding, .customToolbarPadding)
            } else {
                ToolbarMenuView(label: label, content: content, padding: padding)
            }
        }
        .buttonStyle(CustomToolbarButton())
        .help(title)
    )
}
david-swift commented 1 year ago

Yes, it works perfectly, thank you very much! The borderlessButton menu style seems to be available for macOS 12 as well, so we can remove the availability check and the ToolbarMenuView!

david-swift commented 1 year ago

Okay, so before I release version 0.1.11 - does everything work fine now with the main branch?

longseespace commented 1 year ago

Yes. All's good now

david-swift commented 1 year ago

You can update to ColibriComponents 0.1.11 in order to get the improved menus.