Skip to content

Commit fc6624a

Browse files
authored
Definitive pagination implementation (#328)
1 parent 8340951 commit fc6624a

40 files changed

Lines changed: 739 additions & 225 deletions

api/src/main/java/me/devnatan/inventoryframework/RootView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public interface RootView extends VirtualView, Iterable<IFContext> {
6464
* @return The pipeline for this view.
6565
*/
6666
@NotNull
67-
Pipeline<? super VirtualView> getPipeline();
67+
Pipeline<VirtualView> getPipeline();
6868

6969
void open(@NotNull Viewer viewer);
7070

api/src/main/java/me/devnatan/inventoryframework/ViewConfigBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public ViewConfigBuilder size(int size) {
7979
return this;
8080
}
8181

82+
// TODO needs documentation
83+
public ViewConfigBuilder maxSize() {
84+
throw new UnsupportedOperationException("TODO");
85+
}
86+
8287
/**
8388
* Add a modifier to this setting.
8489
*

api/src/main/java/me/devnatan/inventoryframework/component/Component.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public interface Component extends VirtualView {
3838
*
3939
* @return The interaction handler for this component.
4040
*/
41-
@NotNull
4241
InteractionHandler getInteractionHandler();
4342

4443
/**
@@ -55,6 +54,16 @@ public interface Component extends VirtualView {
5554
*/
5655
void updated(@NotNull IFSlotRenderContext context);
5756

57+
/**
58+
* Determines if this component should be updated.
59+
* <p>
60+
* This is a simple precondition to make checking the need for component updates more efficient,
61+
* checking your own conditions before going to more complex methods.
62+
*
63+
* @return {@code true} if this component should be updated or {@code false} otherwise.
64+
*/
65+
boolean shouldBeUpdated();
66+
5867
/**
5968
* Clears this component from the given context.
6069
*

api/src/main/java/me/devnatan/inventoryframework/component/ItemComponent.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public void updated(@NotNull IFSlotRenderContext context) {
6262
updateHandler.accept(context);
6363
}
6464

65+
@Override
66+
public boolean shouldBeUpdated() {
67+
return getRenderHandler() != null;
68+
}
69+
6570
@Override
6671
public void clear(@NotNull IFContext context) {
6772
context.getContainer().removeItem(getPosition());

api/src/main/java/me/devnatan/inventoryframework/component/Pagination.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package me.devnatan.inventoryframework.component;
22

33
import me.devnatan.inventoryframework.state.StateValueHost;
4-
import org.jetbrains.annotations.Nullable;
54

65
/**
76
* Pagination is a host to multiple components that can be paginated, essentially it is a {@link
@@ -32,6 +31,20 @@ public interface Pagination extends ComponentComposition {
3231
*/
3332
int currentPageIndex();
3433

34+
/**
35+
* The number of the next page.
36+
*
37+
* @return The number of the next page at least {@link #lastPage()}.
38+
*/
39+
int nextPage();
40+
41+
/**
42+
* The index of the next page.
43+
*
44+
* @return The index of the next page at least {@link #lastPageIndex()}.
45+
*/
46+
int nextPageIndex();
47+
3548
/**
3649
* The number of the last page.
3750
* <p>
@@ -65,18 +78,20 @@ public interface Pagination extends ComponentComposition {
6578
boolean isLastPage();
6679

6780
/**
68-
* Checks for pages before the current page.
81+
* Checks if a page exists.
6982
*
70-
* @return {@code true} if there are previous pages or {@code false} otherwise.
83+
* @param pageIndex The page index to check.
84+
* @return If exists a page with the specified index.
7185
*/
72-
boolean hasPreviousPage();
86+
boolean hasPage(int pageIndex);
7387

7488
/**
75-
* Checks for pages after the current page.
89+
* Switches to a specific page index.
7690
*
77-
* @return {@code true} if there are next pages or {@code false} otherwise.
91+
* @param pageIndex The page index to switch to.
92+
* @throws IndexOutOfBoundsException If a page with the specified index is not found.
7893
*/
79-
boolean hasNextPage();
94+
void switchTo(int pageIndex);
8095

8196
/**
8297
* Advances to the next page if available.
@@ -108,6 +123,8 @@ public interface Pagination extends ComponentComposition {
108123
*
109124
* @return The layout character target if set or {@code null}.
110125
*/
111-
@Nullable
112-
String getLayoutTarget();
126+
char getLayoutTarget();
127+
128+
// TODO documentation
129+
boolean isDynamic();
113130
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package me.devnatan.inventoryframework.component;
2+
3+
@FunctionalInterface
4+
public interface PaginationElementFactory<T> {
5+
6+
ComponentFactory create(int index, int slot, T value);
7+
}

api/src/main/java/me/devnatan/inventoryframework/context/IFConfinedContext.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,30 @@
44
import me.devnatan.inventoryframework.Viewer;
55
import org.jetbrains.annotations.NotNull;
66

7+
/**
8+
* A confined context is a context derivation wholly subordinated to a parent context that
9+
* represents a closed scope of execution containing only one viewer, that is, when a player
10+
* interacts with an item and throws a click event a subordinate confined context with that player
11+
* as {@link Viewer} of a {@link IFSlotClickContext} is launched.
12+
*/
713
public interface IFConfinedContext extends IFContext {
814

15+
/**
16+
* The parent context of this confined context.
17+
* <p>
18+
* Not all confined contexts have a parent, in which case getting the parent will return the
19+
* instance of that context itself.
20+
*
21+
* @return The parent context or this.
22+
*/
23+
@NotNull
24+
IFContext getParent();
25+
26+
/**
27+
* The viewer in current scope of execution.
28+
*
29+
* @return The {@link Viewer} in the current scope of execution.
30+
*/
931
@NotNull
1032
Viewer getViewer();
1133

@@ -15,7 +37,7 @@ public interface IFConfinedContext extends IFContext {
1537
void closeForPlayer();
1638

1739
/**
18-
* Opens a new view only for the player that is in the execution context of that context.
40+
* Opens a new view only for the player that is in the current scope of execution.
1941
* <p>
2042
* This context will be immediately invalidated if there are no viewers left after opening.
2143
*
@@ -24,7 +46,7 @@ public interface IFConfinedContext extends IFContext {
2446
void openForPlayer(Class<? extends RootView> other);
2547

2648
/**
27-
* Updates the container title for everyone that's viewing it.
49+
* Updates the container title only for the player current scope of execution.
2850
*
2951
* <p>This should not be used before the container is opened, if you need to set the __initial
3052
* title__ use {@link IFOpenContext#modifyConfig()} on open handler instead.
@@ -38,8 +60,8 @@ public interface IFConfinedContext extends IFContext {
3860
void updateTitleForPlayer(@NotNull String title);
3961

4062
/**
41-
* Updates the container title to all viewers in this context, to the initially defined title.
42-
* Must be used after {@link #updateTitleForPlayer(String)} to take effect.
63+
* Resets the container title only for the player current scope of execution to the initially
64+
* defined title. Must be used after {@link #updateTitleForPlayer(String)} to take effect.
4365
*/
4466
void resetTitleForPlayer();
4567
}

api/src/main/java/me/devnatan/inventoryframework/context/IFRenderContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import java.util.function.BiFunction;
55
import me.devnatan.inventoryframework.component.ComponentFactory;
66
import me.devnatan.inventoryframework.internal.LayoutSlot;
7+
import org.jetbrains.annotations.ApiStatus;
78
import org.jetbrains.annotations.NotNull;
89
import org.jetbrains.annotations.UnmodifiableView;
910

1011
public interface IFRenderContext extends IFConfinedContext {
1112

13+
@NotNull
1214
IFContext getParent();
1315

1416
@NotNull
@@ -19,6 +21,9 @@ public interface IFRenderContext extends IFConfinedContext {
1921
@UnmodifiableView
2022
List<LayoutSlot> getLayoutSlots();
2123

24+
@ApiStatus.Internal
25+
void addLayoutSlot(@NotNull LayoutSlot layoutSlot);
26+
2227
@NotNull
2328
@UnmodifiableView
2429
List<BiFunction<Integer, Integer, ComponentFactory>> getAvailableSlotsFactories();

api/src/main/java/me/devnatan/inventoryframework/feature/Feature.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
* which will be taken when the Feature is referenced, and the class of the feature itself is
1717
* private while its key is public for later installation.
1818
*
19-
* <h3>Configuration</h3>
2019
* <p>
2120
* Since features are immutable at runtime, there needs to be a way to pre-define their initial
2221
* values in case it is necessary for them to act together with these values, defined by the user,
@@ -30,7 +29,6 @@
3029
* final class SampleFeatureConfig {}
3130
* </code></pre>
3231
*
33-
* <h3>Preventing instance leak</h3>
3432
* <p>
3533
* It is important to note that features are singleton instances and can only be modified (by
3634
* themselves) once in their entire lifecycle, which is during their installation. The

api/src/main/java/me/devnatan/inventoryframework/internal/ElementFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import me.devnatan.inventoryframework.ViewType;
66
import me.devnatan.inventoryframework.Viewer;
77
import me.devnatan.inventoryframework.component.Component;
8+
import me.devnatan.inventoryframework.component.ComponentBuilder;
89
import me.devnatan.inventoryframework.context.IFContext;
910
import me.devnatan.inventoryframework.context.IFSlotContext;
1011
import me.devnatan.inventoryframework.logging.Logger;
@@ -63,5 +64,12 @@ public abstract <T extends IFSlotContext> T createSlotContext(
6364
@NotNull IFContext parent,
6465
@NotNull Class<?> kind);
6566

67+
/**
68+
* Creates a new platform builder instance.
69+
*
70+
* @return A new platform builder instance.
71+
*/
72+
public abstract ComponentBuilder<?> createComponentBuilder();
73+
6674
public abstract boolean worksInCurrentPlatform();
6775
}

0 commit comments

Comments
 (0)