bdaralan / BDUIKnit

A Swift Package Manager packed with SwiftUI custom reusable UI components and extensions.
MIT License
23 stars 1 forks source link

[Idea] - Toggle Button Tray #5

Open satan87 opened 4 years ago

satan87 commented 4 years ago

Hello,

I have an idea for a Toggle Button Tray. For now, to add a button to active / deactivate a feature we go with a @State variable and a toggle code.

Maybe it is worth creating a specific Toggle button with a binding to a State variable.

Actual

@State private var displayOnlyFavorite = false
let favoriteItem = BDButtonTrayItem(title: "Favorite", systemImage: "star") { item in
            item.systemImage = self.displayOnlyFavorite ? "star" : "star.fill"
            self.displayOnlyFavorite.toggle()
            self.reloadLocations()
        }

        favoriteItem.activeColor = Color.yellow
        favoriteItem.inactiveColor = Color.yellow

Idea

@State private var displayOnlyFavorite = false
let favoriteItem = BDButtonTrayToggleItem(title: "Favorite", systemImage: "star", systemImageToggled: "star.fill", toggle: $displayOnlyFavorite) { item in
self.reloadLocations()
        }

Nicolas

bdaralan commented 4 years ago

Hi Nicolas,

This is actually a good idea. I can see the use case and how you want the item to react to @State variable.

However, BDButtonTrayItem is a view model to render BDButtonTrayItemView behind the scene so I think having several of similar objects is not a good idea. At least that is what I think at the moment, from a framework perspective.

But I hear you, so to allow extendibility, what I would consider doing instead, is to either:

Thank you for the idea, it allows me to refine the framework and make it better.

satan87 commented 4 years ago

I would vote for the protocol BDButtonTrayItemProtocol, with a default implementation for the Toggle case.

bdaralan commented 4 years ago

Now that I think about it, protocol might not work well because we cannot constrain a property to be, say @Published

For example

protocol BDButtonTrayItemProtocol: ObservableObject {

    // can constrain to have setter and getter
    // but cannot constraint that it must be an @Published var σ(^_^;) 
    var title: String { set get } 
}

I think remove final is probably a way to go. In your case, you can do something like this.

class FavoriteButtonTrayItem: BDButtonTrayItem {

    @Binding var favorited: Bool {
        didSet { systemImage = favorited ? "star.fill" : "star" }
    }

    init(favorite: Binding<Bool>) {
        _favorited = favorite
        super.init(...)
    }
}