Skip to content

Commit

Permalink
fix(calendar): Fix decade and year view scrolling on wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Jun 1, 2021
1 parent 3b2caaf commit 819e28e
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Text;
using Windows.Foundation;
using Windows.UI.Core;
using Uno;
using Uno.Extensions;
using Uno.Extensions.Specialized;
Expand Down Expand Up @@ -386,7 +387,8 @@ internal void ScrollItemIntoView(int index, ScrollIntoViewAlignment alignment, d
sv.ChangeView(
horizontalOffset: null,
verticalOffset: newOffset,
zoomFactor: null);
zoomFactor: null,
forceSynchronous);

// Makes sure the container of the requested date is materialized before the end of this method
base_MeasureOverride(_lastLayoutedViewport.Size);
Expand Down Expand Up @@ -599,6 +601,7 @@ private Size base_MeasureOverride(Size availableSize)
#endif
_layoutStrategy.EndMeasure();
}

VisibleIndicesUpdated?.Invoke(this, null);

_layoutStrategy.EstimatePanelExtent(
Expand Down Expand Up @@ -655,7 +658,7 @@ private static void OnEffectiveViewportChanged(FrameworkElement sender, Effectiv
// (We bypass the SetItemMinimumSize in the CalendarPanel_Partial.MeasureOverride if m_type is **not** CalendarPanelType.Primary)
that._layoutStrategy.SetViewportSize(that.GetLayoutViewport().Size, out var needsMeasure);

if (needsMeasure || Math.Abs(that._effectiveViewport.Y - that._lastLayoutedViewport.Y) > 100)
if (needsMeasure || Math.Abs(that._effectiveViewport.Y - that._lastLayoutedViewport.Y) > (that._lastLayoutedViewport.Height / that.Rows) * .75)
{
that.InvalidateMeasure();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Windows.Foundation;
using Uno.UI.Xaml;
using Microsoft.Extensions.Logging;
using Uno.UI.Extensions;

namespace Windows.UI.Xaml.Controls
{
Expand All @@ -21,6 +22,9 @@ public partial class ScrollContentPresenter : ContentPresenter, IScrollContentPr
private ScrollBarVisibility _horizontalScrollBarVisibility;
private bool _eventsRegistered;

private (double? horizontal, double? vertical)? _pendingScrollTo;
private FrameworkElement _rootEltUsedToProcessScrollTo;

internal Size ScrollBarSize
{
get
Expand Down Expand Up @@ -179,25 +183,71 @@ private protected override void OnUnloaded()
{
base.OnUnloaded();
UnregisterEventHandler("scroll", (EventHandler)OnScroll, GenericEventHandlers.RaiseEventHandler);

if (_rootEltUsedToProcessScrollTo is {} rootElt)
{
rootElt.LayoutUpdated -= TryProcessScrollTo;
_rootEltUsedToProcessScrollTo = null;
}
}

public void ScrollTo(double? horizontalOffset, double? verticalOffset, bool disableAnimation)
=> WindowManagerInterop.ScrollTo(HtmlId, horizontalOffset, verticalOffset, disableAnimation);
/// <inheritdoc />
internal override void OnLayoutUpdated()
{
base.OnLayoutUpdated();

private void OnScroll(object sender, EventArgs args)
TryProcessScrollTo();
}

public void ScrollTo(double? horizontalOffset, double? verticalOffset, bool disableAnimation)
{
var left = GetProperty("scrollLeft");
var top = GetProperty("scrollTop");
_pendingScrollTo = (horizontalOffset, verticalOffset);

if (!double.TryParse(left, NumberStyles.Number, CultureInfo.InvariantCulture, out var horizontalOffset))
WindowManagerInterop.ScrollTo(HtmlId, horizontalOffset, verticalOffset, disableAnimation);

if (_pendingScrollTo.HasValue)
{
horizontalOffset = 0;
// The scroll to was not processed by the native SCP, we need to re-request ScrollTo a bit later.
// This happen has soon as the native SCP element is not in a valid state (like un-arranged or hidden).

if (_rootEltUsedToProcessScrollTo is null && Window.Current.RootElement is FrameworkElement rootFwElt)
{
_rootEltUsedToProcessScrollTo = rootFwElt;
rootFwElt.LayoutUpdated += TryProcessScrollTo;
}

// As the native ScrollTo is going to be async, we manually raise the event with the provided values.
// If those values are invalid, the browser will raise the final event anyway.
(TemplatedParent as ScrollViewer)?.OnScrollInternal(
horizontalOffset ?? GetNativeHorizontalOffset(),
verticalOffset ?? GetNativeVerticalOffset(),
isIntermediate: false
);
}
if (!double.TryParse(top, NumberStyles.Number, CultureInfo.InvariantCulture, out var verticalOffset))
}

private void TryProcessScrollTo(object sender, object e)
=> TryProcessScrollTo();

private void TryProcessScrollTo()
{
if (_pendingScrollTo is { } scrollTo)
{
WindowManagerInterop.ScrollTo(HtmlId, scrollTo.horizontal, scrollTo.vertical, disableAnimation: true);
}
}

private void OnScroll(object sender, EventArgs args)
{
if (IsArrangeDirty && _pendingScrollTo.HasValue)
{
verticalOffset = 0;
// When the native element of the SCP is becoming "valid" with a non 0 offset, it will raise a scroll event.
// But if we have a manual scroll request pending, we need to mute it and wait for the next layout updated.
return;
}

_pendingScrollTo = default;

// We don't have any information from the DOM 'scroll' event about the intermediate vs. final state.
// We could try to rely on the IsPointerPressed state to detect when the user is scrolling and use it.
// This would however not include scrolling due to the inertia which should also be flagged as intermediate.
Expand All @@ -210,12 +260,22 @@ private void OnScroll(object sender, EventArgs args)
var isIntermediate = false;

(TemplatedParent as ScrollViewer)?.OnScrollInternal(
horizontalOffset,
verticalOffset,
GetNativeHorizontalOffset(),
GetNativeVerticalOffset(),
isIntermediate
);
}

private double GetNativeHorizontalOffset()
=> double.TryParse(GetProperty("scrollLeft"), NumberStyles.Number, CultureInfo.InvariantCulture, out var horizontalOffset)
? horizontalOffset
: 0;

private double GetNativeVerticalOffset()
=> double.TryParse(GetProperty("scrollTop"), NumberStyles.Number, CultureInfo.InvariantCulture, out var verticalOffset)
? verticalOffset
: 0;

void IScrollContentPresenter.OnMinZoomFactorChanged(float newValue) { }

void IScrollContentPresenter.OnMaxZoomFactorChanged(float newValue) { }
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/FrameworkElement.EffectiveViewport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private void ReconfigureViewportPropagation(IFrameworkElement_EffectiveViewport
}
else
{
TRACE_EFFECTIVE_VIEWPORT("New child requested viewport propagation which has already been enabled. Force updating all children.");
TRACE_EFFECTIVE_VIEWPORT("New child requested viewport propagation which has already been enabled, forwarding current viewport to it.");

// We are already subscribed, the parent won't send any update (and our _parentViewport is expected to be up-to-date).
// But if this "reconfigure" was made for a new child (child != null), we have to initialize its own _parentViewport.
Expand Down

0 comments on commit 819e28e

Please sign in to comment.