Skip to content

Navigating Between Views

Natan Vieira edited this page Sep 14, 2023 · 22 revisions

Navigating between views using InventoryFramework is pretty simple and straightforward, but there's some "little things" that you must understand about Data Transitivity and Shared Contexts before really diving into it.

Basic Usage

Let's get started with the most basic usage of navigation between views, we have the following views:

"A" view with a DIAMOND item on it that navigates to "B";

Screenshot 2023-09-13 at 21 21 44
// A.java
@Override
public void onInit(ViewConfigBuilder config) {
    config.title("A");
}

@Override
public void onFirstRender(RenderContext render) {
    // Moves player to "B" view on click
    render.firstSlot(new ItemStack(Material.DIAMOND))
        .onClick(click -> click.openForPlayer(B.class));
}

"B" view with a REDSTONE item on it that navigates back to "A";

Screenshot 2023-09-13 at 21 23 01
// B.java
@Override
public void onInit(ViewConfigBuilder config) {
    config.title("B");
}

@Override
public void onFirstRender(RenderContext render) {
    // Moves player to back to "A" view on click
    render.firstSlot(new ItemStack(Material.REDSTONE))
        .onClick(click -> click.openForPlayer(A.class));
}

And how it's working? What we have done?

Take a look inside the onClick method of each item, we have a openForPlayer method. That method is responsible for opening a view to the player that clicked on the item. Its signature is similar to ViewFrame's open but without the view class parameter. Pretty simple.


openForPlayer vs. openForEveryone

You've probably noticed that there is a another function called openForEveryone, it's also used to navigate between views, but... For shared contexts. Learn more about Shared Contexts.

In short, the difference is that: openForPlayer considers the subject of the context launched at that moment, that is, if you are opening within an onClick the context is SlotClickContext whose current player is the one who clicked on the item, then the next view will be displayed for that player.

Now, with shared context and using openForEveryone, the next screen will be opened to all players present in that context.

Creating Flows with back() and onResume

Inventory Framework has a feature that make possible to return to the previous view using a method called back(), it's works exactly like a browser history and it's especially useful when...

  • You don't know which view the player is coming from;
  • Cannot access the view (e.g. SomeView.class is not available) so is not possible to use openForPlayer(...))
  • Your view can be opened from different views, not just one, so there is no way to directly reference a single view to return.

So let's take a look, we will use a code similiar from Basic Usage topic but replacing openForPlayer in "B" view by back() and REDSTONE item by a GLOWSTONE_DUST.

// B.java
@Override
public void onInit(ViewConfigBuilder config) {
    config.title("B");
}

@Override
public void onFirstRender(RenderContext render) {
    // Moves player to back to the previous view on click
    render.firstSlot(new ItemStack(Material.GLOWSTONE_DUST))
        .onClick(click -> click.back());
}

"Welcome Back" message on resume

onResume is a method that is called when a player comes back from a view that used back() to navigate, so:

  1. Player go to "B" from "A" using openForPlayer(B.class)
  2. Player goes back to "A" using back()
  3. onResume is called on "A".

Resume have two parameters: origin that called back() and target that's the view who player is going back to. In our case origin context will have "B" as root and target will have "A" as root.

You can do cool things with that like changing the title of current view from "A" to "Welcome Back"!!

// A.java
@Override
public void onResume(Context origin, Context target) {
    // Use `target` here since its the current context
    target.updateTitleForPlayer("Welcome back!");
}

Considerations about back()

Different from ViewFrame's open, context's back() actually opens the view to the player but it doesn't perform rendering, instead, once player uses openForPlayer or openForEveryone a snapshot of his context is stored internally and when back() is called it's resumed exactly the same way it was before so:

  • onOpen nor onFirstRender is called;
  • All states will have the same value they had before open.

Let's see it in practice, we'll create a counter state that holds a initial int value of 0, before player get's navigated to "B" view, we'll change the value of this counter to 1.

private final MutableIntState counterState = mutableState(0);

// B.java
@Override
public void onInit(ViewConfigBuilder config) {
    config.title("B");
}

@Override
public void onOpen(OpenContext open) {
    int currentCount = counterState.get(open);

    // This code changes the current title to 
    open.modifyConfig().title("B (count = " + currentCount + ")")
}

@Override
public void onFirstRender(RenderContext render) {
    // Moves player to back to the previous view on click
    render.firstSlot(new ItemStack(Material.GLOWSTONE_DUST))
        .onClick(click -> click.back());
}

We have a Counter code sample that uses a State Management to create a counter, take a look at it!

Checking when a player comes back

Data Transitivity

Data transitivity during navigation between screens can simplify data resolution so that it is not necessary to re-declare each piece of data at each navigation.

In the "Opening and Closing" in Basic Usage or "Initial State" in Advanced State Management teaches you how to apply initial data when a view is opened, this data disappears when the view closes, however, you can keep it in case of transition from one screen to another.

Welcome to the Inventory Framework documentation.

▶️ Introduction

🧩 Core Topics

💡 Built-In Features

🧰 Extra Features

🤓 Advanced Usage

⚙️ Internal Mechanisms

You can find practical examples in the examples directory.

Clone this wiki locally