diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Component.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Component.java
index b1381e2e..8cf9d163 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Component.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Component.java
@@ -110,6 +110,11 @@ public interface Component extends VirtualView {
// TODO Needs documentation
boolean shouldRender(IFContext context);
+ /**
+ * Updates this component.
+ */
+ void update();
+
/**
* Checks if two components area intersects with each other.
*
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/ItemComponent.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/ItemComponent.java
index 5c6211f5..87a1c24d 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/ItemComponent.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/ItemComponent.java
@@ -176,8 +176,15 @@ public void updated(@NotNull IFSlotRenderContext context) {
@Override
public void clear(@NotNull IFContext context) {
((IFRenderContext) context).getContainer().removeItem(getPosition());
+ }
+
+ @Override
+ public void update() {
+ if (isManagedExternally())
+ throw new IllegalStateException(
+ "This component is externally managed by another component and cannot be updated directly");
- setVisible(false);
+ if (root instanceof IFContext) ((IFContext) root).updateComponent(this);
}
@Override
@@ -193,6 +200,8 @@ public void clicked(@NotNull Component component, @NotNull IFSlotClickContext co
@Override
public boolean isVisible() {
+ if (root instanceof Component) return ((Component) root).isVisible() && isVisible;
+
return isVisible;
}
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Pagination.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Pagination.java
index 1b171781..759471f6 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Pagination.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/Pagination.java
@@ -1,5 +1,9 @@
package me.devnatan.inventoryframework.component;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
import me.devnatan.inventoryframework.state.StateValue;
import me.devnatan.inventoryframework.state.StateValueHost;
import org.jetbrains.annotations.ApiStatus;
@@ -128,20 +132,103 @@ public interface Pagination extends ComponentComposition, StateValue {
char getLayoutTarget();
/**
+ * Lazy pagination usually have a {@link java.util.function.Function} as source provider and
+ * this provider is only called again to set the current internal source when an explicit
+ * update is called. This kind of pagination is used to replicate a static-like pagination since
+ * it can use a Function to provide some information to composite the source that'll be built
+ * but will never change again.
+ *
+ * So, when this method returns true the only way to update the current source as a
+ * whole is triggering an update somehow e.g. by calling {@link #update()}.
+ *
+ * Page switches will not trigger the source provider to re-apply the current internal source.
+ *
* This is an internal inventory-framework API that should not be used from outside of
* this library. No compatibility guarantees are provided.
*/
@ApiStatus.Internal
- boolean isDynamic();
+ boolean isLazy();
/**
- * If the pagination data is being loaded or not.
+ * Static pagination is a type of pagination that usually have a {@link java.util.Collection} or
+ * something else as source provider and this source provider is called only on first render to
+ * set the current source as a whole, and never called again on the entire Pagination lifecycle.
*
- * Only changes if {@link #isDynamic()} is true.
+ * This is an internal inventory-framework API that should not be used from outside of
+ * this library. No compatibility guarantees are provided.
+ */
+ @ApiStatus.Internal
+ boolean isStatic();
+
+ /**
+ * Computed pagination usually have a {@link java.util.function.Function}-like as source provider
+ * and this provider is called each time this component is updated or the page is changed so the
+ * current as a whole will always be the result of the source provider, regardless the {@link #currentPage() current page}.
+ *
+ * This is an internal inventory-framework API that should not be used from outside of
+ * this library. No compatibility guarantees are provided.
+ */
+ @ApiStatus.Internal
+ boolean isComputed();
+
+ /**
+ * Asynchronous pagination can have a mix of all others {@link #isStatic() static}, {@link #isLazy() lazy} and {@link #isComputed() computed}
+ * types of pagination source, that is:
+ *
+ * Have a CompletableFuture as source? Then it's static.
+ * Have a Function or Supplier as source? Type will be defined by implementation.
+ *
+ *
+ * {@link java.util.concurrent.CompletableFuture} is the type of the source provider or something
+ * that results in a CompletableFuture. Pagination source type is defined by the implementation.
+ *
+ * Internally asynchronous pagination also have a {@link #isLoading() loading state} that
+ * tracks the loading state of the future and changes based on future completion.
+ *
+ * This is an internal inventory-framework API that should not be used from outside of
+ * this library. No compatibility guarantees are provided.
+ */
+ @ApiStatus.Internal
+ boolean isAsync();
+
+ /**
+ * If the pagination data is being loaded.
*
*
This API is experimental and is not subject to the general compatibility guarantees
* such API may be changed or may be removed completely in any further release.
+ *
+ * @return Loading state of the pagination.
+ * Always false when {@link #isStatic()} is true.
*/
@ApiStatus.Experimental
boolean isLoading();
+
+ /**
+ * Gets all elements in a given page index based of the specified source.
+ *
+ * @param index The page index.
+ * @param pageSize Number of elements that each page can have.
+ * @param pagesCount Pre-calculated total number of pages available (set zero if not available).
+ * @param src The source to split.
+ * @return All elements in a page.
+ * @throws IndexOutOfBoundsException If the specified index is {@code < 0} or
+ * exceeds the pages count.
+ */
+ static List> splitSourceForPage(int index, int pageSize, int pagesCount, List> src) {
+ if (src.isEmpty()) return Collections.emptyList();
+
+ if (src.size() <= pageSize) return new ArrayList<>(src);
+ if (index < 0 || (pagesCount > 0 && index > pagesCount))
+ throw new IndexOutOfBoundsException(String.format(
+ "Page index must be between the range of 0 and %d. Given: %d", pagesCount - 1, index));
+
+ final List contents = new LinkedList<>();
+ final int base = index * pageSize;
+ int until = base + pageSize;
+ if (until > src.size()) until = src.size();
+
+ for (int i = base; i < until; i++) contents.add(src.get(i));
+
+ return contents;
+ }
}
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationElementConsumer.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationValueConsumer.java
similarity index 64%
rename from inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationElementConsumer.java
rename to inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationValueConsumer.java
index db7432e4..8153c751 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationElementConsumer.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/component/PaginationValueConsumer.java
@@ -3,14 +3,16 @@
import org.jetbrains.annotations.NotNull;
/**
- * Represents an pagination element mapping operation that accepts three arguments and returns no result.
+ * Represents a pagination element mapping operation that accepts three arguments and returns no result.
+ *
* This is a {@link FunctionalInterface functional interface} whose functional method is {@link #accept(Object, Object, int, Object)}.
- * @param The type of the pagination context
- * @param The builder used to build the paginated element
+ *
+ * @param The type of the pagination context
+ * @param The builder used to build the paginated element
* @param The value that represents the current element being paginated
*/
@FunctionalInterface
-public interface PaginationElementConsumer {
+public interface PaginationValueConsumer {
/**
* Performs this operation on the given arguments.
@@ -20,5 +22,5 @@ public interface PaginationElementConsumer {
* @param index The index of the element being paginated in the pagination
* @param value The value that represents the current element being paginated
*/
- void accept(@NotNull Context context, @NotNull Builder builder, int index, @NotNull V value);
+ void accept(@NotNull C context, @NotNull B builder, int index, @NotNull V value);
}
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFContext.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFContext.java
index 61c01aea..190c7a5c 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFContext.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFContext.java
@@ -167,18 +167,6 @@ public interface IFContext extends VirtualView, StateValueHost {
*/
void update();
- /**
- * Checks if a component positioned in a given index is marked for removal.
- *
- * This is an internal inventory-framework API that should not be used from outside of
- * this library. No compatibility guarantees are provided.
- *
- * @param componentIndex The index of the component to be checked if it's marked for removal.
- * @return If the component in the specified index (if any) is marked for removal.
- */
- @ApiStatus.Internal
- boolean isMarkedForRemoval(int componentIndex);
-
/**
* Data defined when a context is created, usually this is data set when the context is
* opened for a viewer.
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFRenderContext.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFRenderContext.java
index 6c06d549..d498d136 100644
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFRenderContext.java
+++ b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFRenderContext.java
@@ -54,4 +54,11 @@ public interface IFRenderContext extends IFConfinedContext {
*/
@NotNull
ViewContainer getContainer();
+
+ /**
+ * This is an internal inventory-framework API that should not be used from outside of
+ * this library. No compatibility guarantees are provided.
+ */
+ @ApiStatus.Internal
+ boolean isRendered();
}
diff --git a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFUpdateContext.java b/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFUpdateContext.java
deleted file mode 100644
index c3027bec..00000000
--- a/inventory-framework-api/src/main/java/me/devnatan/inventoryframework/context/IFUpdateContext.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package me.devnatan.inventoryframework.context;
-
-public interface IFUpdateContext extends IFContext {}
diff --git a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/component/PaginationImpl.java b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/component/PaginationImpl.java
index f0709b7c..e1d07765 100644
--- a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/component/PaginationImpl.java
+++ b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/component/PaginationImpl.java
@@ -4,7 +4,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -27,25 +26,24 @@
@VisibleForTesting
public class PaginationImpl extends AbstractStateValue implements Pagination, InteractionHandler {
- private final List components = new LinkedList<>();
- private final @NotNull IFContext host;
+ private List components = new ArrayList<>();
+ private final IFContext host;
+ private boolean visible;
// --- User provided ---
private final char layoutTarget;
- private final @NotNull Object sourceProvider;
- private final @NotNull PaginationElementFactory elementFactory;
+ private final Object sourceProvider;
+ private final PaginationElementFactory elementFactory;
private final BiConsumer pageSwitchHandler;
// --- Internal ---
private int currPageIndex;
- private final boolean dynamic;
+ private final boolean isLazy, isStatic, isComputed, isAsync;
private boolean pageWasChanged;
private boolean initialized;
private int pagesCount;
- /**
- * The number of elements that each page can have. -1 means uninitialized.
- */
+ // Number of elements that each page can have. -1 means uninitialized.
private int pageSize = -1;
// Changes when dynamic data source is used and being loaded
@@ -59,18 +57,18 @@ public class PaginationImpl extends AbstractStateValue implements Pagination, In
*/
private Function _srcFactory;
- /**
- * Current page source. Only {@code null} before first pagination render.
- */
+ // Current page source, null before first pagination render.
private List> currSource;
public PaginationImpl(
- @NotNull State> state,
- @NotNull IFContext host,
+ State> state,
+ IFContext host,
char layoutTarget,
- @NotNull Object sourceProvider,
- @NotNull PaginationElementFactory elementFactory,
- BiConsumer pageSwitchHandler) {
+ Object sourceProvider,
+ PaginationElementFactory elementFactory,
+ BiConsumer pageSwitchHandler,
+ boolean isAsync,
+ boolean isComputed) {
super(state);
this.host = host;
this.layoutTarget = layoutTarget;
@@ -78,58 +76,76 @@ public PaginationImpl(
this.elementFactory = elementFactory;
this.pageSwitchHandler = pageSwitchHandler;
this.currSource = convertSourceProvider();
- this.dynamic = !(sourceProvider instanceof Collection);
+ this.isComputed = isComputed;
+ this.isAsync = isAsync;
+ this.isStatic = sourceProvider instanceof Collection || isAsync;
+ this.isLazy =
+ !isStatic && !isComputed && (sourceProvider instanceof Function || sourceProvider instanceof Supplier);
}
/**
* Tries to access and load the source to the current page.
*
- * If this pagination {@link #isDynamic() is dynamic} it tries to get the current data source
- * dynamically or asynchronously and waits for its completion.
+ * If this pagination {@link #isLazy() is lazy} it tries to get the current data source
+ * dynamically or asynchronously and waits for its completion. For static pagination it returns
+ * immediately with the source.
*
- * For static pagination it returns immediately with the source.
- *
- * On asynchronous pagination the source update job will be inherited by the user provided one.
- *
- * When job gets done the {@link #currSource} is updated with the result of the computation.
+ * On asynchronous pagination the source update job will be inherited by the user provided one
+ * and when job gets done the {@link #currSource} is updated with the result of the computation.
*
* @return A CompletableFuture with the current pagination source as result.
* @throws IllegalStateException In static pagination when the current source wasn't yet defined.
*/
- @SuppressWarnings("unchecked")
private CompletableFuture> loadSourceForTheCurrentPage() {
- // Static pagination we just get the current source here since it will be always the same
- if (!isDynamic()) {
- if (currSource == null) throw new IllegalStateException("User provided pagination source cannot be null");
-
- if (!initialized) pagesCount = calculatePagesCount(currSource);
+ /*
+ * In lazy pagination **that was already initialized (already rendered before)** we must
+ * use the current data source as source of truth to ensure that page switching do not
+ * re-trigger pagination data factory since it will always return the source as a whole,
+ * the original one, and not the source for the switched page.
+ */
+ final boolean reuseLazy = isLazy() && initialized;
+
+ if ((isStatic() || reuseLazy) && !isComputed()) {
+ // For unknown reasons already initialized but source is null, external modification?
+ if (initialized && currSource == null)
+ throw new IllegalStateException("User provided pagination source cannot be null");
+ else {
+ // Lazy pagination have pages count calculated on first render as a computed flow
+ if (!isLazy()) pagesCount = calculatePagesCount(currSource);
+ }
- return CompletableFuture.completedFuture(splitSourceForPage(currPageIndex, currSource));
+ return CompletableFuture.completedFuture(
+ Pagination.splitSourceForPage(currPageIndex, getPageSize(), getPagesCount(), currSource));
}
- CompletableFuture> job = new CompletableFuture<>();
isLoading = true;
simulateStateUpdate();
- final Object source = _srcFactory.apply(host);
- if (source instanceof CompletableFuture) {
- job = (CompletableFuture>) source;
- } else {
- // Here we are covering the dynamic rendering that's can be the usage of factories like
- // `Supplier` and Function<..., List> so we just cast the result here
- job.complete((List>) source);
- }
-
// TODO Do some error treatment here, even if we expect to the user to handle it
- job.thenAccept(this::updateSource).whenComplete((result, exception) -> {
+ return createProvidedNewSource().handle((result, exception) -> {
+ updateSource(result);
isLoading = false;
simulateStateUpdate();
+
+ if (isLazy()) return Pagination.splitSourceForPage(currPageIndex, getPageSize(), getPagesCount(), result);
+ else return result;
});
+ }
+
+ @SuppressWarnings("unchecked")
+ private CompletableFuture> createProvidedNewSource() {
+ CompletableFuture> job = new CompletableFuture<>();
+
+ final Object source = _srcFactory.apply(host);
+ if (isAsync()) job = (CompletableFuture>) source;
+ else if (isComputed() || isLazy()) job.complete((List>) source);
+ else throw new IllegalArgumentException("Unhandled pagination source");
+
return job;
}
/**
- * Updates the current source and the number of availalbe pages count based on that source.
+ * Updates the current source and the number of available pages count based on that source.
*
* @param newSource The new data source.
*/
@@ -168,33 +184,6 @@ public int getPageSize() {
return pageSize;
}
- /**
- * Gets all elements in a given page index based on the current data source.
- *
- * @param index The page index.
- * @param src The source to split.
- * @return All elements in a page.
- * @throws IndexOutOfBoundsException If the specified index is {@code < 0} or
- * exceeds the {@link #getPagesCount() pages count}.
- */
- private List> splitSourceForPage(int index, List> src) {
- if (src.isEmpty()) return Collections.emptyList();
-
- if (src.size() <= pageSize) return new ArrayList<>(src);
- if (index < 0 || index > getPagesCount())
- throw new IndexOutOfBoundsException(String.format(
- "Page index must be between the range of 0 and %d. Given: %d", getPagesCount() - 1, index));
-
- final List contents = new LinkedList<>();
- final int base = index * pageSize;
- int until = base + pageSize;
- if (until > src.size()) until = src.size();
-
- for (int i = base; i < until; i++) contents.add(src.get(i));
-
- return contents;
- }
-
/**
* Loads pagination components using container boundaries, no constraints.
*
@@ -205,13 +194,12 @@ private List> splitSourceForPage(int index, List> src) {
* @param context The render context.
* @param pageContents Elements of the current page.
*/
- private void loadComponentsForUnconstrainedPagination(IFRenderContext context, List> pageContents) {
+ private void addComponentsForUnconstrainedPagination(IFRenderContext context, List> pageContents) {
final ViewContainer container = context.getContainer();
pageSize = container.getSize();
- final int lastSlot = container.getLastSlot();
-
- for (int i = container.getFirstSlot(); i < Math.min(lastSlot + 1, pageContents.size()); i++) {
+ final int lastSlot = Math.min(container.getLastSlot() + 1 /* inclusive */, pageContents.size());
+ for (int i = container.getFirstSlot(); i < lastSlot; i++) {
final Object value = pageContents.get(i);
final ComponentFactory factory = elementFactory.create(context, i, i, value);
getComponentsInternal().add(factory.create());
@@ -227,12 +215,13 @@ private void loadComponentsForUnconstrainedPagination(IFRenderContext context, L
* @param context The render context.
* @param pageContents Elements of the current page.
*/
- private void loadComponentsForLayeredPagination(IFRenderContext context, List> pageContents) {
+ private void addComponentsForLayeredPagination(IFRenderContext context, List> pageContents) {
if (pageContents.isEmpty()) return;
+ final LayoutSlot targetLayoutSlot = getLayoutSlotForCurrentTarget(context);
final int elementsLen = pageContents.size();
int iterationIndex = 0;
- for (final int position : getLayoutSlotForCurrentTarget(context).getPositions()) {
+ for (final int position : targetLayoutSlot.getPositions()) {
final Object value = pageContents.get(iterationIndex++);
final ComponentFactory factory = elementFactory.create(context, iterationIndex, position, value);
final Component component = factory.create();
@@ -305,8 +294,8 @@ private List> convertSourceProvider() {
*/
private CompletableFuture> loadCurrentPage(IFRenderContext context) {
return loadSourceForTheCurrentPage().thenAccept(pageContents -> {
- if (context.getConfig().getLayout() != null) loadComponentsForLayeredPagination(context, pageContents);
- else loadComponentsForUnconstrainedPagination(context, pageContents);
+ if (context.getConfig().getLayout() != null) addComponentsForLayeredPagination(context, pageContents);
+ else addComponentsForUnconstrainedPagination(context, pageContents);
});
}
@@ -343,7 +332,8 @@ public int getPosition() {
@Override
public void render(@NotNull IFSlotRenderContext context) {
if (!initialized) {
- final IFRenderContext root = (IFRenderContext) context.getParent();
+ setVisible(true);
+ final IFRenderContext root = context.getParent();
updatePageSize(root);
loadCurrentPage(root).thenRun(() -> renderChild(context));
initialized = true;
@@ -359,15 +349,18 @@ private void renderChild(IFSlotRenderContext context) {
@Override
public void updated(@NotNull IFSlotRenderContext context) {
+ final IFRenderContext renderContext = context.getParent();
+
// If page was changed all components will be removed, so don't trigger update on them
if (pageWasChanged) {
- final IFRenderContext renderContext = (IFRenderContext) context.getParent();
- clearChild(renderContext, true);
+ getComponentsInternal().forEach(child -> child.clear(renderContext));
+ components = new ArrayList<>();
+ getComponentsInternal().clear();
loadCurrentPage(renderContext).thenRun(() -> {
render(context);
simulateStateUpdate();
- pageWasChanged = false;
});
+ pageWasChanged = false;
return;
}
@@ -386,22 +379,11 @@ private void simulateStateUpdate() {
@Override
public void clear(@NotNull IFContext context) {
- // Only clear components if page was changed to not make the clear operation inconsistent
if (!pageWasChanged) {
getComponentsInternal().forEach(child -> child.clear(context));
return;
}
- clearChild(context, false);
- }
-
- private void clearChild(IFContext context, boolean bulk) {
- if (bulk) {
- getComponentsInternal().forEach(child -> child.clear(context));
- getComponentsInternal().clear();
- return;
- }
-
final Iterator childIterator = getComponentsInternal().iterator();
while (childIterator.hasNext()) {
Component child = childIterator.next();
@@ -480,6 +462,7 @@ public boolean isLastPage() {
@Override
public boolean hasPage(int pageIndex) {
+ if (isComputed()) return true;
if (pageIndex < 0) return false;
return pageIndex < getPagesCount();
}
@@ -525,8 +508,23 @@ public char getLayoutTarget() {
}
@Override
- public boolean isDynamic() {
- return dynamic;
+ public boolean isLazy() {
+ return isLazy;
+ }
+
+ @Override
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ @Override
+ public boolean isComputed() {
+ return isComputed;
+ }
+
+ @Override
+ public boolean isAsync() {
+ return isAsync;
}
@Override
@@ -542,31 +540,21 @@ public Iterator iterator() {
@Override
public boolean isVisible() {
- for (final Component children : this) {
- if (!children.isVisible()) return false;
- }
-
- return true;
+ return visible;
}
@Override
public void setVisible(boolean visible) {
+ this.visible = visible;
getComponentsInternal().forEach(component -> component.setVisible(visible));
}
@Override
public void clicked(@NotNull Component component, @NotNull IFSlotClickContext context) {
- final List components = getComponentsInternal();
- if (components.isEmpty()) return;
- if (components.size() == 1) {
- final Component child = components.get(0);
- if (child.getInteractionHandler() != null && child.getInteractionHandler() != null) {
- child.getInteractionHandler().clicked(component, context);
- }
- return;
- }
+ // Lock child interactions while page is being updated
+ if (pageWasChanged) return;
- for (final Component child : components) {
+ for (final Component child : getComponentsInternal()) {
if (child.getInteractionHandler() == null) continue;
if (child.isContainedWithin(context.getClickedSlot())) {
child.getInteractionHandler().clicked(component, context);
@@ -585,6 +573,11 @@ public boolean shouldRender(IFContext context) {
return true;
}
+ @Override
+ public void update() {
+ ((IFContext) getRoot()).updateComponent(this);
+ }
+
@VisibleForTesting
List getComponentsInternal() {
return components;
@@ -598,7 +591,7 @@ public boolean equals(Object o) {
return getLayoutTarget() == that.getLayoutTarget()
&& currPageIndex == that.currPageIndex
&& getPageSize() == that.getPageSize()
- && isDynamic() == that.isDynamic()
+ && isLazy() == that.isLazy()
&& pageWasChanged == that.pageWasChanged
&& Objects.equals(sourceProvider, that.sourceProvider)
&& Objects.equals(pageSwitchHandler, that.pageSwitchHandler);
@@ -612,7 +605,7 @@ public int hashCode() {
pageSwitchHandler,
currPageIndex,
getPageSize(),
- isDynamic(),
+ isLazy(),
pageWasChanged);
}
@@ -626,7 +619,7 @@ public String toString() {
+ pageSwitchHandler + ", currPageIndex="
+ currPageIndex + ", pageSize="
+ pageSize + ", dynamic="
- + dynamic + ", pageWasChanged="
+ + isLazy + ", pageWasChanged="
+ pageWasChanged + ", _srcFactory="
+ _srcFactory + ", currSource="
+ currSource + "} "
diff --git a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/context/AbstractIFContext.java b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/context/AbstractIFContext.java
index d753bf35..71c961b0 100644
--- a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/context/AbstractIFContext.java
+++ b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/context/AbstractIFContext.java
@@ -1,9 +1,7 @@
package me.devnatan.inventoryframework.context;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -23,7 +21,6 @@
abstract class AbstractIFContext extends DefaultStateValueHost implements IFContext {
private final List components = new LinkedList<>();
- private final Deque markedForRemoval = new ArrayDeque<>();
private final Map indexedViewers = new HashMap<>();
protected ViewConfig config;
@@ -83,7 +80,7 @@ public void removeComponent(@NotNull Component component) {
}
}
- private IFSlotRenderContext createRenderContext(@NotNull Component component) {
+ private IFSlotRenderContext createSlotRenderContext(@NotNull Component component) {
if (!(this instanceof IFRenderContext))
throw new InventoryFrameworkException("Slot render context cannot be created from non-render parent");
@@ -116,12 +113,12 @@ public void renderComponent(@NotNull Component component) {
return;
}
- component.render(createRenderContext(component));
+ component.render(createSlotRenderContext(component));
}
@Override
public void updateComponent(@NotNull Component component) {
- component.updated(createRenderContext(component));
+ component.updated(createSlotRenderContext(component));
}
@Override
@@ -129,11 +126,6 @@ public void update() {
getRoot().getPipeline().execute(StandardPipelinePhases.UPDATE, this);
}
- @Override
- public final boolean isMarkedForRemoval(int componentIndex) {
- return markedForRemoval.contains(componentIndex);
- }
-
@Override
public final boolean isShared() {
return getIndexedViewers().size() > 1;
diff --git a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptor.java b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptor.java
index 5d3fbfd9..3c2aab7e 100644
--- a/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptor.java
+++ b/inventory-framework-core/src/main/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptor.java
@@ -3,7 +3,6 @@
import java.util.List;
import me.devnatan.inventoryframework.VirtualView;
import me.devnatan.inventoryframework.component.Component;
-import me.devnatan.inventoryframework.context.IFContext;
import me.devnatan.inventoryframework.context.IFRenderContext;
/**
@@ -15,11 +14,12 @@ public final class UpdateInterceptor implements PipelineInterceptor
public void intercept(PipelineContext pipeline, VirtualView subject) {
if (!(subject instanceof IFRenderContext)) return;
- final IFContext context = (IFContext) subject;
+ final IFRenderContext context = (IFRenderContext) subject;
+ if (!context.isRendered()) return;
+
final List componentList = context.getComponents();
- for (int i = 0; i < componentList.size(); i++) {
- final Component component = componentList.get(i);
- if (context.isMarkedForRemoval(i)) {
+ for (final Component component : componentList) {
+ if (!component.isVisible()) {
component.clear(context);
continue;
}
diff --git a/inventory-framework-core/src/test/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptorTest.java b/inventory-framework-core/src/test/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptorTest.java
index fb76ccc6..5bd0d8c5 100644
--- a/inventory-framework-core/src/test/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptorTest.java
+++ b/inventory-framework-core/src/test/java/me/devnatan/inventoryframework/pipeline/UpdateInterceptorTest.java
@@ -3,11 +3,9 @@
import static me.devnatan.inventoryframework.TestUtils.createContextMock;
import static me.devnatan.inventoryframework.TestUtils.createRootMock;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -15,7 +13,6 @@
import me.devnatan.inventoryframework.RootView;
import me.devnatan.inventoryframework.ViewContainer;
import me.devnatan.inventoryframework.VirtualView;
-import me.devnatan.inventoryframework.component.Component;
import me.devnatan.inventoryframework.component.ItemComponent;
import me.devnatan.inventoryframework.context.IFContext;
import me.devnatan.inventoryframework.context.IFRenderContext;
@@ -23,29 +20,6 @@
public class UpdateInterceptorTest {
- @Test
- void clearWhenMarkedForRemoval() {
- Pipeline pipeline = new Pipeline<>(StandardPipelinePhases.UPDATE);
- pipeline.intercept(StandardPipelinePhases.UPDATE, new UpdateInterceptor());
-
- RootView root = createRootMock();
- IFContext context = createContextMock(root, IFRenderContext.class);
- when(context.isShared()).thenReturn(true);
- ViewContainer container = mock(ViewContainer.class);
- when(context.getContainer()).thenReturn(container);
-
- Component component = mock(Component.class);
- when(context.isMarkedForRemoval(anyInt())).thenReturn(true);
- when(context.getComponents()).thenReturn(Collections.singletonList(component));
- when(root.getContexts()).thenReturn(Collections.singleton(context));
-
- pipeline.execute(StandardPipelinePhases.UPDATE, context);
-
- verify(component, times(1)).clear(eq(context));
- verify(component, never()).updated(any());
- verify(component, never()).render(any());
- }
-
@Test
void neverRenderIfItemDoNotHaveRenderHandler() {
Pipeline pipeline = new Pipeline<>(StandardPipelinePhases.UPDATE);
diff --git a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/IFViewFrame.java b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/IFViewFrame.java
index ef3b2629..9f65506a 100644
--- a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/IFViewFrame.java
+++ b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/IFViewFrame.java
@@ -42,8 +42,7 @@ protected IFViewFrame() {}
return getRegisteredViews().values().stream()
.filter(view -> view.getClass().equals(type))
.findFirst()
- .orElseThrow(() ->
- new IllegalArgumentException(String.format("View not found or not registered: %s", type)));
+ .orElseThrow(() -> new IllegalArgumentException(String.format("View not registered: %s", type)));
}
/**
diff --git a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PaginationStateBuilder.java b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PaginationStateBuilder.java
index a1bc4d3c..9c72238c 100644
--- a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PaginationStateBuilder.java
+++ b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PaginationStateBuilder.java
@@ -3,27 +3,30 @@
import java.util.function.BiConsumer;
import me.devnatan.inventoryframework.component.*;
import me.devnatan.inventoryframework.context.IFContext;
-import me.devnatan.inventoryframework.context.IFSlotContext;
import me.devnatan.inventoryframework.internal.LayoutSlot;
import me.devnatan.inventoryframework.state.State;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings("rawtypes")
public final class PaginationStateBuilder<
- Context extends IFContext,
- SlotContext extends IFSlotContext,
- Builder extends ItemComponentBuilder & ComponentFactory,
- V> {
+ Context extends IFContext, Builder extends ItemComponentBuilder & ComponentFactory, V> {
private final PlatformView root;
private final Object sourceProvider;
private char layoutTarget = LayoutSlot.FILLED_RESERVED_CHAR;
private PaginationElementFactory elementFactory;
private BiConsumer pageSwitchHandler;
+ private final boolean async, computed;
PaginationStateBuilder(PlatformView root, Object sourceProvider) {
+ this(root, sourceProvider, false, false);
+ }
+
+ PaginationStateBuilder(PlatformView root, Object sourceProvider, boolean async, boolean computed) {
this.root = root;
this.sourceProvider = sourceProvider;
+ this.async = async;
+ this.computed = computed;
}
/**
@@ -38,9 +41,8 @@ public final class PaginationStateBuilder<
* @param itemFactory The item factory.
* @return This pagination state builder.
*/
- public PaginationStateBuilder itemFactory(
- @NotNull BiConsumer itemFactory) {
- return itemFactory(((context, builder, index, value) -> itemFactory.accept(builder, value)));
+ public PaginationStateBuilder itemFactory(@NotNull BiConsumer itemFactory) {
+ return elementFactory(((context, builder, index, value) -> itemFactory.accept(builder, value)));
}
/**
@@ -52,16 +54,16 @@ public PaginationStateBuilder itemFactory(
*
* This function is called for every single paginated element.
*
- * @param itemFactory The item factory.
+ * @param elementConsumer The element consumer.
* @return This pagination state builder.
*/
- public PaginationStateBuilder itemFactory(
- @NotNull PaginationElementConsumer itemFactory) {
+ public PaginationStateBuilder elementFactory(
+ @NotNull PaginationValueConsumer elementConsumer) {
this.elementFactory = (context, index, slot, value) -> {
@SuppressWarnings("unchecked")
Builder builder = (Builder) root.getElementFactory().createComponentBuilder(context);
builder.withSlot(slot).withExternallyManaged(true);
- itemFactory.accept(context, builder, index, value);
+ elementConsumer.accept(context, builder, index, value);
return builder;
};
return this;
@@ -79,7 +81,7 @@ public PaginationStateBuilder itemFactory(
* @param layoutTarget The target layout character.
* @return This pagination state builder.
*/
- public PaginationStateBuilder layoutTarget(char layoutTarget) {
+ public PaginationStateBuilder layoutTarget(char layoutTarget) {
this.layoutTarget = layoutTarget;
return this;
}
@@ -93,7 +95,7 @@ public PaginationStateBuilder layoutTarget(cha
* @param pageSwitchHandler The page switch handler.
* @return This pagination state builder.
*/
- public PaginationStateBuilder onPageSwitch(
+ public PaginationStateBuilder onPageSwitch(
@NotNull BiConsumer pageSwitchHandler) {
this.pageSwitchHandler = pageSwitchHandler;
return this;
@@ -111,7 +113,7 @@ public State build() {
"Element factory from #buildPaginationState(...) cannot be null. Set it using %s or %s.",
"#elementFactory(PaginationElementFactory)", "#itemFactory(BiConsumer)"));
- return root.buildPaginationState(this);
+ return root.createPaginationState(this);
}
PlatformView getRoot() {
@@ -133,4 +135,12 @@ PaginationElementFactory getElementFactory() {
BiConsumer getPageSwitchHandler() {
return pageSwitchHandler;
}
+
+ boolean isAsync() {
+ return async;
+ }
+
+ boolean isComputed() {
+ return computed;
+ }
}
diff --git a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java
index ec0a1947..6f7cad0b 100644
--- a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java
+++ b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/PlatformView.java
@@ -17,6 +17,7 @@
import me.devnatan.inventoryframework.context.IFSlotClickContext;
import me.devnatan.inventoryframework.context.IFSlotContext;
import me.devnatan.inventoryframework.context.PlatformContext;
+import me.devnatan.inventoryframework.context.PlatformRenderContext;
import me.devnatan.inventoryframework.internal.ElementFactory;
import me.devnatan.inventoryframework.internal.PlatformUtils;
import me.devnatan.inventoryframework.pipeline.AvailableSlotInterceptor;
@@ -252,6 +253,7 @@ public void removeContext(@NotNull TContext context) {
@ApiStatus.Internal
public void renderContext(@NotNull TRenderContext context) {
getPipeline().execute(context);
+ ((PlatformRenderContext, ?>) context).setRendered();
@SuppressWarnings("rawtypes")
final PlatformView view = (PlatformView) context.getRoot();
@@ -516,184 +518,181 @@ protected final State initialState() {
}
/**
- * Creates a new unmodifiable static pagination state.
+ * Creates a new immutable pagination with static data source.
*
* @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param elementConsumer The function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
* @return A new immutable pagination state.
*/
protected final State paginationState(
- @NotNull List super T> sourceProvider, @NotNull BiConsumer itemFactory) {
+ @NotNull List super T> sourceProvider,
+ @NotNull PaginationValueConsumer elementConsumer) {
return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ .elementFactory(elementConsumer)
.build();
}
/**
- * Creates a new unmodifiable static pagination state.
+ * Creates a new unmodifiable computed pagination state.
*
- * @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param sourceProvider Data source for pagination.
+ * @param valueConsumer Function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new unmodifiable pagination state.
*/
- protected final State paginationState(
- @NotNull List super T> sourceProvider,
- @NotNull PaginationElementConsumer itemFactory) {
- return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ protected final State computedPaginationState(
+ @NotNull Function> sourceProvider,
+ @NotNull PaginationValueConsumer valueConsumer) {
+ return this.buildComputedPaginationState(sourceProvider)
+ .elementFactory(valueConsumer)
.build();
}
/**
- * Creates a new unmodifiable dynamic pagination state.
+ * Creates a new unmodifiable computed pagination state with asynchronous data source.
+ *
+ * This API is experimental and is not subject to the general compatibility guarantees
+ * such API may be changed or may be removed completely in any further release.
*
* @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param valueConsumer The function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new unmodifiable pagination state.
*/
- protected final State paginationState(
- @NotNull Function> sourceProvider, @NotNull BiConsumer itemFactory) {
- return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ @ApiStatus.Experimental
+ protected final State computedAsyncPaginationState(
+ @NotNull Function>> sourceProvider,
+ @NotNull PaginationValueConsumer valueConsumer) {
+ return this.buildComputedAsyncPaginationState(sourceProvider)
+ .elementFactory(valueConsumer)
.build();
}
/**
- * Creates a new unmodifiable dynamic pagination state.
+ * Creates a new unmodifiable lazy pagination state.
*
- * @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param sourceProvider Data source for pagination.
+ * @param valueConsumer Function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new unmodifiable pagination state.
*/
- protected final State paginationState(
+ protected final State lazyPaginationState(
@NotNull Function> sourceProvider,
- @NotNull PaginationElementConsumer itemFactory) {
- return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ @NotNull PaginationValueConsumer valueConsumer) {
+ return this.buildLazyPaginationState(sourceProvider)
+ .elementFactory(valueConsumer)
.build();
}
/**
- * Creates a new unmodifiable dynamic pagination state.
+ * Creates a new unmodifiable lazy pagination state.
*
- * @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param sourceProvider Data source for pagination.
+ * @param valueConsumer Function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new unmodifiable pagination state.
*/
- protected final State paginationState(
- @NotNull Supplier> sourceProvider, @NotNull BiConsumer itemFactory) {
- return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ protected final State lazyPaginationState(
+ @NotNull Supplier> sourceProvider,
+ @NotNull PaginationValueConsumer valueConsumer) {
+ return this.buildLazyPaginationState(sourceProvider)
+ .elementFactory(valueConsumer)
.build();
}
/**
- * Creates a new unmodifiable dynamic pagination state.
+ * Creates a new unmodifiable lazy pagination state with asynchronous data source.
+ *
+ * This API is experimental and is not subject to the general compatibility guarantees
+ * such API may be changed or may be removed completely in any further release.
*
* @param sourceProvider The data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
+ * @param valueConsumer The function for creating pagination items, this function is called for
* each paged element (item) on a page.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new unmodifiable pagination state.
*/
- protected final State paginationState(
- @NotNull Supplier> sourceProvider,
- @NotNull PaginationElementConsumer itemFactory) {
- return this.buildPaginationState(sourceProvider)
- .itemFactory(itemFactory)
+ @ApiStatus.Experimental
+ protected final State lazyAsyncPaginationState(
+ @NotNull Function>> sourceProvider,
+ @NotNull PaginationValueConsumer valueConsumer) {
+ return this.buildLazyAsyncPaginationState(sourceProvider)
+ .elementFactory(valueConsumer)
.build();
}
/**
- * Creates a new unmodifiable asynchronous pagination state.
- *
- * This API is experimental and is not subject to the general compatibility guarantees
- * such API may be changed or may be removed completely in any further release.
+ * Creates a new unmodifiable static pagination state builder.
*
- * @param sourceProvider The asynchronous data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
- * each paged element (item) on a page.
+ * @param sourceProvider The data source for pagination.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new pagination state builder.
*/
- @ApiStatus.Experimental
- protected final State asyncPaginationState(
- @NotNull Function>> sourceProvider,
- @NotNull BiConsumer itemFactory) {
- return this.buildAsyncPaginationState(sourceProvider)
- .itemFactory(itemFactory)
- .build();
+ protected final PaginationStateBuilder buildPaginationState(
+ @NotNull List super T> sourceProvider) {
+ return new PaginationStateBuilder<>(this, sourceProvider);
}
/**
- * Creates a new unmodifiable asynchronous pagination state.
- *
- * This API is experimental and is not subject to the general compatibility guarantees
- * such API may be changed or may be removed completely in any further release.
+ * Creates a new unmodifiable dynamic pagination state builder.
*
- * @param sourceProvider The asynchronous data source for pagination.
- * @param itemFactory The function for creating pagination items, this function is called for
- * each paged element (item) on a page.
+ * @param sourceProvider The data source for pagination.
* @param The pagination data type.
- * @return A new immutable pagination state.
+ * @return A new pagination state builder.
*/
- @ApiStatus.Experimental
- protected final State asyncPaginationState(
- @NotNull Function>> sourceProvider,
- @NotNull PaginationElementConsumer itemFactory) {
- return this.buildAsyncPaginationState(sourceProvider)
- .itemFactory(itemFactory)
- .build();
+ protected final PaginationStateBuilder buildComputedPaginationState(
+ @NotNull Function> sourceProvider) {
+ return new PaginationStateBuilder<>(this, sourceProvider, false, true);
}
/**
- * Creates a new unmodifiable static pagination state builder.
+ * Creates a new unmodifiable computed pagination state builder with asynchronous data source.
+ *
+ * This API is experimental and is not subject to the general compatibility guarantees
+ * such API may be changed or may be removed completely in any further release.
*
* @param sourceProvider The data source for pagination.
* @param The pagination data type.
* @return A new pagination state builder.
*/
- protected final PaginationStateBuilder buildPaginationState(
- @NotNull List super T> sourceProvider) {
- return new PaginationStateBuilder<>(this, sourceProvider);
+ @ApiStatus.Experimental
+ protected final PaginationStateBuilder buildComputedAsyncPaginationState(
+ @NotNull Function>> sourceProvider) {
+ return new PaginationStateBuilder<>(this, sourceProvider, true, true);
}
/**
- * Creates a new unmodifiable dynamic pagination state builder.
+ * Creates a new unmodifiable lazy pagination state builder.
*
* @param sourceProvider The data source for pagination.
* @param The pagination data type.
* @return A new pagination state builder.
*/
- protected final PaginationStateBuilder buildPaginationState(
+ protected final PaginationStateBuilder buildLazyPaginationState(
@NotNull Supplier> sourceProvider) {
- return new PaginationStateBuilder<>(this, sourceProvider);
+ return new PaginationStateBuilder<>(this, sourceProvider, false, false);
}
/**
- * Creates a new unmodifiable dynamic pagination state builder.
+ * Creates a new unmodifiable lazy pagination state builder.
*
* @param sourceProvider The data source for pagination.
* @param The pagination data type.
* @return A new pagination state builder.
*/
- protected final PaginationStateBuilder buildPaginationState(
+ protected final PaginationStateBuilder buildLazyPaginationState(
@NotNull Function> sourceProvider) {
- return new PaginationStateBuilder<>(this, sourceProvider);
+ return new PaginationStateBuilder<>(this, sourceProvider, false, false);
}
/**
- * Creates a new unmodifiable asynchronous pagination state builder.
+ * Creates a new unmodifiable lazy pagination state builder with asynchronous data source.
*
* This API is experimental and is not subject to the general compatibility guarantees
* such API may be changed or may be removed completely in any further release.
@@ -703,23 +702,24 @@ protected final PaginationStateBuilder PaginationStateBuilder buildAsyncPaginationState(
+ protected final PaginationStateBuilder buildLazyAsyncPaginationState(
@NotNull Function>> sourceProvider) {
- return new PaginationStateBuilder<>(this, sourceProvider);
+ return new PaginationStateBuilder<>(this, sourceProvider, true, false);
}
- final State buildPaginationState(
- @NotNull PaginationStateBuilder builder) {
+ final State createPaginationState(@NotNull PaginationStateBuilder builder) {
requireNotInitialized();
final long id = State.next();
@SuppressWarnings("unchecked")
final StateValueFactory factory = (host, state) -> new PaginationImpl(
state,
- (TContext) host,
+ (IFContext) host,
builder.getLayoutTarget(),
builder.getSourceProvider(),
(PaginationElementFactory) builder.getElementFactory(),
- (BiConsumer) builder.getPageSwitchHandler());
+ (BiConsumer) builder.getPageSwitchHandler(),
+ builder.isAsync(),
+ builder.isComputed());
final State state = new PaginationState(id, factory);
stateRegistry.registerState(state, this);
diff --git a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/context/PlatformRenderContext.java b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/context/PlatformRenderContext.java
index d931ad2b..44578fa0 100644
--- a/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/context/PlatformRenderContext.java
+++ b/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/context/PlatformRenderContext.java
@@ -37,6 +37,7 @@ public abstract class PlatformRenderContext
// --- Inherited ---
private final ViewContainer container;
+ private boolean rendered;
// --- Properties ---
private final List componentBuilders = new ArrayList<>();
@@ -326,4 +327,18 @@ public final void resetTitleForPlayer() {
tryThrowDoNotWorkWithSharedContext("resetTitleForEveryone()");
super.resetTitleForPlayer();
}
+
+ @Override
+ public final boolean isRendered() {
+ return rendered;
+ }
+
+ /**
+ * This is an internal inventory-framework API that should not be used from outside of
+ * this library. No compatibility guarantees are provided.
+ */
+ @ApiStatus.Internal
+ public final void setRendered() {
+ this.rendered = true;
+ }
}
diff --git a/inventory-framework-test/src/main/java/me/devnatan/inventoryframework/component/FakeComponent.java b/inventory-framework-test/src/main/java/me/devnatan/inventoryframework/component/FakeComponent.java
index 4a96210b..a13e5b9b 100644
--- a/inventory-framework-test/src/main/java/me/devnatan/inventoryframework/component/FakeComponent.java
+++ b/inventory-framework-test/src/main/java/me/devnatan/inventoryframework/component/FakeComponent.java
@@ -87,6 +87,9 @@ public boolean shouldRender(IFContext context) {
return false;
}
+ @Override
+ public void update() {}
+
@Override
public void clicked(@NotNull Component component, @NotNull IFSlotClickContext context) {}
}