Skip to content

Commit

Permalink
iPad, upon project first open: better re-rendering when a Group Layer…
Browse files Browse the repository at this point in the history
…'s Scroll Enabled input is set true (#640)

* Remove some log statements

* Use @bindable var when passing down LayerInputObservers in LayerInspectorView
  • Loading branch information
pianostringquartet authored Dec 12, 2024
1 parent 1e58990 commit f629bc5
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 73 deletions.
84 changes: 59 additions & 25 deletions Stitch/Graph/LayerInspector/LayerInspectorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ struct LayerInspectorView: View {
if !filteredInputs.isEmpty {
LayerInspectorInputsSectionView(
sectionName: sectionName,
layerInputs: filteredInputs,
layerInputs: .init(layerInputs: filteredInputs),
graph: graph,
nodeId: node
)
Expand Down Expand Up @@ -193,13 +193,59 @@ enum LayerInspectorSectionName: String, Equatable, Hashable {
typography = "Typography",
stroke = "Stroke",
rotation = "Rotation",
// shadow = "Shadow",
layerEffects = "Layer Effects"
}

// Named Tuple
typealias LayerInputAndObserver = (layerInput: LayerInputPort,
portObserver: LayerInputObserver)
@Observable
final class LayerInputAndObserver {
let layerInput: LayerInputPort
let portObserver: LayerInputObserver

init(layerInput: LayerInputPort,
portObserver: LayerInputObserver) {
self.layerInput = layerInput
self.portObserver = portObserver
}
}

@Observable
final class LayerInputsAndObservers {
let layerInputs: [LayerInputAndObserver]

init(layerInputs: [LayerInputAndObserver]) {
self.layerInputs = layerInputs
}
}

struct LayerInspectorInputView: View {

// `@Bindable var` (vs. `let`) seems to improve a strange issue where toggling scroll-enabled input on iPad would update the LayerInputObserver's blockedFields set but not re-render the view.
@Bindable var layerInput: LayerInputAndObserver
@Bindable var graph: GraphState
let nodeId: NodeId

var body: some View {
let layerInputObserver: LayerInputObserver = layerInput.portObserver

let blockedFields = layerInputObserver.blockedFields

let allFieldsBlockedOut = layerInputObserver
.fieldValueTypes.first?
.fieldObservers.allSatisfy({ $0.isBlocked(blockedFields)})
?? false

if !allFieldsBlockedOut {
LayerInspectorInputPortView(layerInputObserver: layerInputObserver,
graph: graph,
nodeId: nodeId)
.modifier(LayerPropertyRowOriginReader(graph: graph,
layerInput: layerInput.layerInput))
} else {
EmptyView()
}
}

}

// This view now needs to receive the inputs it will be listing,
// rather than receiving the entire layer node.
Expand All @@ -208,7 +254,7 @@ struct LayerInspectorInputsSectionView: View {
let sectionName: LayerInspectorSectionName

// This section's layer inputs, filtered to excluded any not supported by this specific layer.
let layerInputs: [LayerInputAndObserver]
@Bindable var layerInputs: LayerInputsAndObservers
@Bindable var graph: GraphState
let nodeId: NodeId

Expand All @@ -217,23 +263,10 @@ struct LayerInspectorInputsSectionView: View {

var body: some View {
Section(isExpanded: $expanded) {
ForEach(layerInputs, id: \.layerInput) { layerInput in
let layerInputObserver: LayerInputObserver = layerInput.portObserver

let blockedFields = layerInputObserver.blockedFields

let allFieldsBlockedOut = layerInputObserver
.fieldValueTypes.first?
.fieldObservers.allSatisfy({ $0.isBlocked(blockedFields)})
?? false

if !allFieldsBlockedOut {
LayerInspectorInputPortView(layerInputObserver: layerInputObserver,
graph: graph,
nodeId: nodeId)
.modifier(LayerPropertyRowOriginReader(graph: graph,
layerInput: layerInput.layerInput))
}
ForEach(layerInputs.layerInputs, id: \.layerInput) { (layerInput: LayerInputAndObserver) in
LayerInspectorInputView(layerInput: layerInput,
graph: graph,
nodeId: nodeId)
}
.transition(.slideInAndOut(edge: .top))
} header: {
Expand Down Expand Up @@ -267,7 +300,7 @@ struct LayerInspectorInputsSectionView: View {
self.expanded.toggle()
dispatch(LayerInspectorSectionToggled(section: sectionName))

layerInputs.forEach { layerInput in
layerInputs.layerInputs.forEach { layerInput in
if case let .layerInput(x) = graph.graphUI.propertySidebar.selectedProperty,
x.layerInput == layerInput.layerInput {
graph.graphUI.propertySidebar.selectedProperty = nil
Expand Down Expand Up @@ -328,6 +361,7 @@ extension GraphState {
node: NodeId,
inputs: LayerInputObserverDict,
outputs: [OutputLayerNodeRowData])? {
// log("getLayerInspectorData called")

// Any time orderedSidebarLayers changes, that will retrigger LayerInspector
guard !self.orderedSidebarLayers.isEmpty else {
Expand All @@ -336,7 +370,7 @@ extension GraphState {

var inspectorFocusedLayers = self.layersSidebarViewModel.selectionState.primary

log("getLayerInspectorData: inspectorFocusedLayers: \(inspectorFocusedLayers)")
// log("getLayerInspectorData: inspectorFocusedLayers: \(inspectorFocusedLayers)")

#if DEV_DEBUG
// For debug
Expand Down
2 changes: 1 addition & 1 deletion Stitch/Graph/Node/Model/RowData/LayerInputType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,7 @@ extension LayerInputPort {
case .deviceAppearance:
return useShortLabel ? "Appearance" : "Device Appearance"
case .scrollContentSize:
return "Content Size"
return useShortLabel ? "Content" : "Content Size"
case .scrollXEnabled:
return "Scroll X Enabled"
case .scrollJumpToXStyle:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ struct NativeScrollGestureView<T: View>: View {
@MainActor
var hasScrollInteraction: Bool {
let _hasScrollInteraction = layerViewModel.isScrollXEnabled || layerViewModel.isScrollYEnabled
log("NativeScrollGestureView: hasScrollInteraction: _hasScrollInteraction: \(_hasScrollInteraction)")
// log("NativeScrollGestureView: hasScrollInteraction: _hasScrollInteraction: \(_hasScrollInteraction)")
return _hasScrollInteraction
}

var body: some View {
// logInView("NativeScrollGestureView: var body")
if hasScrollInteraction {
view()
.modifier(NativeScrollGestureViewInner(
Expand Down Expand Up @@ -127,7 +126,6 @@ struct NativeScrollGestureViewInner: ViewModifier {
@State var viewId: UUID = .init()

func body(content: Content) -> some View {
// logInView("NativeScrollGestureViewInner: var body")

ScrollView(self.scrollAxes) {

Expand All @@ -138,8 +136,6 @@ struct NativeScrollGestureViewInner: ViewModifier {
.frame(height: self.customContentHeight)

// factor out parent-scroll's offset, so that view does not move unless we explicitly connect scroll interaction node's output to the layer's position input
// .offset(x: self.scrollOffset.x,
// y: self.scrollOffset.y)
.offset(x: self.finalScrollOffset.x,
y: self.finalScrollOffset.y)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,5 @@ struct PreviewAbsoluteShapeLayerModifier: ViewModifier {
size: size,
parentSize: parentSize,
minimumDragDistance: DEFAULT_MINIMUM_DRAG_DISTANCE))

// .modifier(NativeScrollGestureView(
// layerViewModel: viewModel,
// graph: graph))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ struct PreviewCommonModifierWithoutFrame: ViewModifier {
size: sizeForAnchoringAndGestures,
parentSize: parentSize,
minimumDragDistance: minimumDragDistance))

// .modifier(NativeScrollGestureView(
// layerViewModel: layerViewModel,
// graph: graph))
}
}

23 changes: 1 addition & 22 deletions Stitch/Graph/PrototypePreview/Layer/View/Type/PreviewGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ struct PreviewGroupLayer: View {

var body: some View {

logInView("PreviewGroupLayer: var body")

groupLayer

// TODO: add "child alignment" input on Group Layer node? or find some other solution for how a group with an orientation can position children that have static sizes
Expand Down Expand Up @@ -242,30 +240,11 @@ struct PreviewGroupLayer: View {
size: _size,
parentSize: parentSize,
minimumDragDistance: DEFAULT_MINIMUM_DRAG_DISTANCE))

// .modifier(NativeScrollGestureView(
// layerViewModel: layerViewModel,
// graph: graph))
}

@ViewBuilder
private var groupLayer: some View {
logInView("PreviewGroupLayer: groupLayer")
// PreviewLayersView(document: document,
// graph: graph,
// layers: layersInGroup,
// // This Group's size will be the `parentSize` for the `layersInGroup`
// parentSize: _size,
// parentId: interactiveLayer.id.layerNodeId,
// parentOrientation: orientation,
// parentSpacing: spacing,
// parentCornerRadius: cornerRadius,
// // i.e. if this view (a LayerGroup) uses .hug, then its children will not use their own .position values.
// parentUsesHug: usesHug,
// noFixedSizeForLayerGroup: noFixedSizeForLayerGroup,
// parentGridData: gridData,
// isGhostView: !isPinnedViewRendering)


NativeScrollGestureView(layerViewModel: layerViewModel,
graph: graph,
isClipped: isClipped,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ extension ProjectSidebarObservable {
func sidebarItemTapped(id: Self.ItemID,
shiftHeld: Bool,
commandHeld: Bool) {
log("sidebarItemTapped: id: \(id)")
log("sidebarItemTapped: shiftHeld: \(shiftHeld)")
// log("sidebarItemTapped: id: \(id)")
// log("sidebarItemTapped: shiftHeld: \(shiftHeld)")

let originalSelections = self.selectionState.primary

// Set sidebar to be focused:
self.graphDelegate?.graphUI.isSidebarFocused = true

log("sidebarItemTapped: originalSelections: \(originalSelections)")
// log("sidebarItemTapped: originalSelections: \(originalSelections)")

if shiftHeld, originalSelections.isEmpty {
// Special case: if no current selections, shift-click just selects from the top to the clicked item; and the shift-clicked item counts as the 'last selected item'
Expand All @@ -49,7 +49,7 @@ extension ProjectSidebarObservable {
!originalSelections.isEmpty,
let lastClickedItemId = self.selectionState.lastFocused {

log("sidebarItemTapped: shift select")
// log("sidebarItemTapped: shift select")

guard let clickedItem = self.retrieveItem(id),
let lastClickedItem = self.retrieveItem(lastClickedItemId) else {
Expand All @@ -58,7 +58,7 @@ extension ProjectSidebarObservable {
return
}

log("sidebarItemTapped: lastClickedItemId: \(lastClickedItemId)")
// log("sidebarItemTapped: lastClickedItemId: \(lastClickedItemId)")

let flatList = self.items.flattenedItems

Expand All @@ -84,12 +84,12 @@ extension ProjectSidebarObservable {
// If we ended up selecting the exact same as the original,
// then we actually DE-SELECTED the range.
let newSelections = self.selectionState.primary
log("sidebarItemTapped: selected range: newSelections: \(newSelections)")
// log("sidebarItemTapped: selected range: newSelections: \(newSelections)")
if newSelections == originalSelections {
log("sidebarItemTapped: selected range; will wipe inspectorFocusedLayers")
// log("sidebarItemTapped: selected range; will wipe inspectorFocusedLayers")

itemsBetween.forEach { itemBetween in
log("sidebarItemTapped: will remove item Between \(itemBetween)")
// log("sidebarItemTapped: will remove item Between \(itemBetween)")
self.selectionState.primary.remove(itemBetween.id)
}
}
Expand All @@ -99,11 +99,11 @@ extension ProjectSidebarObservable {
self.graphDelegate?.deselectAllCanvasItems()

} else {
log("sidebarItemTapped: did not have itemsBetween")
// log("sidebarItemTapped: did not have itemsBetween")
// TODO: this can happen when just-clicked == last-clicked, but some apps do not any deselection etc.
// If we shift click the last-clicked item, then remove everything in the island?
if clickedItem.id == lastClickedItem.id {
log("clicked the same item as the last clicked; will deselect original island and select only last selected")
// log("clicked the same item as the last clicked; will deselect original island and select only last selected")
originalIsland.forEach {
self.selectionState.primary.remove($0.id)
}
Expand All @@ -122,7 +122,7 @@ extension ProjectSidebarObservable {

else if commandHeld {

log("sidebarItemTapped: command select")
// log("sidebarItemTapped: command select")

let alreadySelected = self.selectionState.primary.contains(id)

Expand All @@ -141,7 +141,7 @@ extension ProjectSidebarObservable {
}

} else {
log("sidebarItemTapped: normal select")
// log("sidebarItemTapped: normal select")

self.selectionState.resetEditModeSelections()

Expand Down

0 comments on commit f629bc5

Please sign in to comment.