internal void Push(IScreen source, IScreen newScreen) { if (stack.Contains(newScreen)) { throw new ScreenAlreadyEnteredException(); } if (source == null && stack.Count > 0) { throw new InvalidOperationException($"A source must be provided when pushing to a non-empty {nameof(ScreenStack)}"); } if (newScreen.AsDrawable().RemoveWhenNotAlive) { throw new ScreenWillBeRemovedOnPushException(newScreen.GetType()); } // Suspend the current screen, if there is one if (source != null && source != stack.Peek()) { throw new ScreenNotCurrentException(nameof(Push)); } var newScreenDrawable = newScreen.AsDrawable(); if (newScreenDrawable.IsLoaded) { throw new InvalidOperationException("A screen should not be loaded before being pushed."); } if (suspendImmediately) { suspend(source, newScreen); } stack.Push(newScreen); ScreenPushed?.Invoke(source, newScreen); // this needs to be queued here before the load is begun so it preceed any potential OnSuspending event (also attached to OnLoadComplete). newScreenDrawable.OnLoadComplete += _ => newScreen.OnEntering(new ScreenTransitionEvent(source, newScreen)); if (source == null) { // this is the first screen to be loaded. if (LoadState >= LoadState.Ready) { LoadScreen(this, newScreenDrawable, () => finishPush(null, newScreen)); } else { log($"scheduling push {getTypeString(newScreen)}"); Schedule(() => finishPush(null, newScreen)); } } else { LoadScreen((CompositeDrawable)source, newScreenDrawable, () => finishPush(source, newScreen)); } }
internal void Push(IScreen source, IScreen newScreen) { if (stack.Contains(newScreen)) { throw new ScreenAlreadyEnteredException(); } if (source == null && stack.Count > 0) { throw new InvalidOperationException($"A source must be provided when pushing to a non-empty {nameof(ScreenStack)}"); } if (newScreen.AsDrawable().RemoveWhenNotAlive) { throw new ScreenWillBeRemovedOnPushException(newScreen.GetType()); } // Suspend the current screen, if there is one if (source != null) { if (source != stack.Peek()) { throw new ScreenNotCurrentException(nameof(Push)); } source.OnSuspending(newScreen); source.AsDrawable().Expire(); } // Push the new screen stack.Push(newScreen); ScreenPushed?.Invoke(source, newScreen); void finishLoad() { if (!newScreen.ValidForPush) { exitFrom(null); return; } AddInternal(newScreen.AsDrawable()); newScreen.OnEntering(source); } if (source != null) { LoadScreen((CompositeDrawable)source, newScreen.AsDrawable(), finishLoad); } else if (LoadState >= LoadState.Ready) { LoadScreen(this, newScreen.AsDrawable(), finishLoad); } else { Schedule(finishLoad); } }
internal void Push(IScreen source, IScreen newScreen) { if (stack.Contains(newScreen)) { throw new ScreenAlreadyEnteredException(); } if (source == null && stack.Count > 0) { throw new InvalidOperationException($"A source must be provided when pushing to a non-empty {nameof(ScreenStack)}"); } if (newScreen.AsDrawable().RemoveWhenNotAlive) { throw new ScreenWillBeRemovedOnPushException(newScreen.GetType()); } // Suspend the current screen, if there is one if (source != null && source != stack.Peek()) { throw new ScreenNotCurrentException(nameof(Push)); } if (suspendImmediately) { suspend(source, newScreen); } stack.Push(newScreen); ScreenPushed?.Invoke(source, newScreen); var newScreenDrawable = newScreen.AsDrawable(); if (source == null) { // this is the first screen to be loaded. if (LoadState >= LoadState.Ready) { LoadScreen(this, newScreenDrawable, () => finishPush(null, newScreen)); } else { Schedule(() => finishPush(null, newScreen)); } } else { LoadScreen((CompositeDrawable)source, newScreenDrawable, () => finishPush(source, newScreen)); } }