Here is my code but it's not a workign sample code. just wish to have this checked out if in theory my assumptions are correct or not
struct ContentView: View {
@State var dark = PrefTool.instance.getBoolean(Keyword.DARK_MODE)
@State var show = false
@StateObject var navigationManager = SidebarNavigationManager()
@StateObject var appData = AppData()
@StateObject var toolbarData = ToolbarData()
var body: some View {
NavigationStack(path: $appData.path) {
ZStack(alignment: .leading) {
VStack(spacing: 0) {
HStack {
Button(action: {
withAnimation(.default) {
show.toggle()
}
}) {
Image(systemName: "line.3.horizontal")
}
Text("Home")
Spacer()
ToolbarView()
OverflowMenu()
.padding([.leading], Default.instance.PADDING_BETWEEN_MENU_ITEM)
}
.padding()
.foregroundColor(.primary)
.overlay(Rectangle().stroke(Color.primary.opacity(0.1), lineWidth: 1).shadow(radius: 3).edgesIgnoringSafeArea(.top))
MainContent(navigationManager: navigationManager)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
HStack {
SideMenuView(show: $show, navigationManager: navigationManager)
.preferredColorScheme(dark ? .dark : .light)
.offset(x: self.show ? 0 : -UIScreen.main.bounds.width / 1.2)
Spacer(minLength: 0)
Rectangle().stroke(.clear).frame(width: show ? UIScreen.main.bounds.width - (UIScreen.main.bounds.width / 1.2) : 0)
.contentShape(Rectangle())
.onTapGesture {
if (show) {
withAnimation(.default) {
show.toggle()
}
}
}
}
.background(Color.primary.opacity(self.show ? (self.dark ? 0.05 : 0.2) : 0))
}
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
.environmentObject(appData)
.environmentObject(toolbarData)
}
}
and ToolbarView and ToolbarData
struct ToolbarView: View {
@EnvironmentObject var toolbarData: ToolbarData
var body: some View {
HStack {
if let item = toolbarData.toolbarItem, item.visible {
Button {
item.action()
} label: {
if let iconLink = item.iconLink {
NavigationLink(destination: iconLink) {
Image(systemName: item.icon)
}
}
else {
Image(systemName: item.icon)
}
}
.disabled(item.disabled)
.opacity(item.opacity)
.padding([.leading, .trailing], Default.instance.PADDING_BETWEEN_MENU_ITEM)
}
}
}
}
final class ToolbarData: ObservableObject {
@Published var toolbarItem: ToolbarItemProperties?
func disableToolbarItem(_ toolbarItem: ToolbarItemProperties?, _ disabled: Bool) {
if let toolbarItem {
objectWillChange.send()
toolbarItem.disabled = disabled
}
}
func disableToolbarItem(_ toolbarItem: ToolbarItemProperties?, _ disabled: Bool, _ deadline: DispatchTime) {
if let toolbarItem {
DispatchQueue.main.asyncAfter(deadline: deadline) {
self.objectWillChange.send()
toolbarItem.disabled = disabled
}
}
}
func resetMenuItems() {
toolbarItem = nil
}
}
in a custom view e.g. MainContent in the code above. i do something from a button click like this
toolbarData.disableToolbarItem(toolbarData.toolbarItem, true, .now())
The thing is, only the ToolbarView() should be rebuilt. somehow, the whole ContentView() gets rebuilt instead. This should not behave like this right? Since only the ToolbarData is updated. Thoughts?