Compare commits

...

2 Commits

Author SHA1 Message Date
William278 47243552dd More work on list item and display logic 2 years ago
William 7d19e316ac
v2 work, introduce ListItem api 2 years ago

@ -4,13 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="1adcdbad-26db-47ae-b8e5-83088ba9f2ff" name="Changes" comment="Port to MineDown-adventure, run on the Adventure platform">
<change afterPath="$PROJECT_DIR$/HEADER" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
<list default="true" id="1adcdbad-26db-47ae-b8e5-83088ba9f2ff" name="Changes" comment="Add license header">
<change beforePath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/ListOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/ListOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/PaginatedList.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/PaginatedList.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/PaginationException.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/PaginationException.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/StringListItem.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/net/william278/paginedown/StringListItem.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/test/java/net/william278/paginedown/PaginatedListTests.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/test/java/net/william278/paginedown/PaginatedListTests.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@ -39,13 +36,7 @@
<path>
<item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
<item name="PagineDown" type="f1a62948:ProjectNode" />
<item name="Tasks" type="e4a08cd1:TasksNode" />
</path>
<path>
<item name="" type="6a2764b6:ExternalProjectsStructure$RootNode" />
<item name="PagineDown" type="f1a62948:ProjectNode" />
<item name="Tasks" type="e4a08cd1:TasksNode" />
<item name="other" type="c8890929:TasksNode$1" />
<item name="Run Configurations" type="7b0102dc:RunConfigurationsNode" />
</path>
</expand>
<select />
@ -57,11 +48,17 @@
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Interface" />
<option value="Class" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="master" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
@ -73,27 +70,27 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false",
"ignore.virus.scanning.warn.message": "true",
"last_opened_file_path": "C:/Users/William/IdeaProjects/PagineDown",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/William/IdeaProjects/PagineDown&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></component>
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Users\William\IdeaProjects\PagineDown" />
</key>
</component>
<component name="RunManager" selected="Gradle.PagineDown [updateLicenses]">
<component name="RunManager" selected="Gradle.PaginatedListTests">
<configuration name="PaginatedListTests" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
<ExternalSystemSettings>
<option name="executionName" />
@ -170,8 +167,8 @@
</list>
<recent_temporary>
<list>
<item itemvalue="Gradle.PagineDown [updateLicenses]" />
<item itemvalue="Gradle.PaginatedListTests" />
<item itemvalue="Gradle.PagineDown [updateLicenses]" />
</list>
</recent_temporary>
</component>
@ -193,7 +190,9 @@
<workItem from="1663673518837" duration="364000" />
<workItem from="1663674390006" duration="614000" />
<workItem from="1663691764514" duration="215000" />
<workItem from="1682892261503" duration="407000" />
<workItem from="1682892261503" duration="428000" />
<workItem from="1682895713181" duration="1834000" />
<workItem from="1682944023150" duration="1675000" />
</task>
<task id="LOCAL-00001" summary="Make gradlew executable">
<created>1660688283740</created>
@ -258,7 +257,14 @@
<option name="project" value="LOCAL" />
<updated>1663673808922</updated>
</task>
<option name="localTasksCounter" value="10" />
<task id="LOCAL-00010" summary="Add license header">
<created>1682892686593</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1682892686594</updated>
</task>
<option name="localTasksCounter" value="11" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -286,6 +292,7 @@
<MESSAGE value="Add example image to README" />
<MESSAGE value="Update image" />
<MESSAGE value="Port to MineDown-adventure, run on the Adventure platform" />
<option name="LAST_COMMIT_MESSAGE" value="Port to MineDown-adventure, run on the Adventure platform" />
<MESSAGE value="Add license header" />
<option name="LAST_COMMIT_MESSAGE" value="Add license header" />
</component>
</project>

@ -5,7 +5,7 @@ plugins {
}
group 'net.william278'
version '1.1'
version '2.0'
defaultTasks 'licenseFormat', 'build'
repositories {

@ -0,0 +1,10 @@
package net.william278.paginedown;
import org.jetbrains.annotations.NotNull;
public interface ListItem {
@NotNull
String toItemString();
}

@ -22,14 +22,16 @@ package net.william278.paginedown;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Options, including placeholder strings, used to generate a {@link PaginatedList} of items
*/
public class ListOptions {
public class ListOptions<I extends ListItem> {
@NotNull
protected String headerFormat = "[Viewing %topic%](%color%) [(%first_item_on_page_index%-%last_item_on_page_index% of](%color%) [%total_items%](%color% bold)[)](%color%)";
protected String headerFormat = "%order_control_button% [%topic% (%first_item_on_page_index%-%last_item_on_page_index% of %total_items%):](%color%) (%filter_buttons%)";
@NotNull
protected String footerFormat = "%previous_page_button%Page [%current_page%](%color%)/[%total_pages%](%color%)%next_page_button% %page_jumpers%";
@NotNull
@ -46,6 +48,11 @@ public class ListOptions {
protected String pageJumperCurrentPageFormat = "[%current_page%](%color%)";
@NotNull
protected String pageJumperPageFormat = "[%target_page_index%](show_text=&7Jump to page %target_page_index% run_command=/%command% %target_page_index%)";
protected String ascendingSortButtonFormat = "[▲](white show_text=&7Sort items ascendingly run_command=/%command% %target_sort% %current_page%)";
protected String descendingSortButtonFormat = "[▼](white show_text=&7Sort items descendingly run_command=/%command% %target_sort% %current_page%)";
protected String filterSeparator = "/";
protected String filterButtonFormat = "[%filter_name%](show_text=&7Filter by %filter_name% run_command=/%command% %target_filter% %current_page%)";
protected String filterButtonActiveFormat = "[%filter_name%](%color% show_text=&7Filter by %filter_name% run_command=/%command% %target_filter% %current_page%)";
@NotNull
protected String topic = "List";
@NotNull
@ -58,135 +65,146 @@ public class ListOptions {
@NotNull
protected String itemSeparator = "\n";
protected int itemsPerPage = 10;
protected int pageJumperStartButtons = 3;
protected int pageJumperEndButtons = 3;
@SuppressWarnings("unchecked")
protected List<SortOption<I>> availableSortOptions = new ArrayList<>() {{
add((SortOption<I>) SortOption.NAME);
}};
private ListOptions() {
}
@SuppressWarnings("rawtypes")
@NotNull
public static Builder builder() {
return new Builder<>();
}
@SuppressWarnings("unused")
public static class Builder {
public static class Builder<I extends ListItem> {
@NotNull
private final ListOptions options = new ListOptions();
private final ListOptions<I> options = new ListOptions<>();
protected Builder() {
}
@NotNull
public Builder setHeaderFormat(@NotNull String headerFormat) {
public Builder<I> setHeaderFormat(@NotNull String headerFormat) {
options.headerFormat = headerFormat;
return this;
}
@NotNull
public Builder setFooterFormat(@NotNull String footerFormat) {
public Builder<I> setFooterFormat(@NotNull String footerFormat) {
options.footerFormat = footerFormat;
return this;
}
@NotNull
public Builder setItemSeparator(@NotNull String itemSeparator) {
public Builder<I> setItemSeparator(@NotNull String itemSeparator) {
options.itemSeparator = itemSeparator;
return this;
}
@NotNull
public Builder setThemeColor(@NotNull Color themeColor) {
public Builder<I> setThemeColor(@NotNull Color themeColor) {
options.themeColor = themeColor;
return this;
}
@NotNull
public Builder setSpaceAfterHeader(final boolean spaceAfterHeader) {
public Builder<I> setSpaceAfterHeader(final boolean spaceAfterHeader) {
options.spaceAfterHeader = spaceAfterHeader;
return this;
}
@NotNull
public Builder setSpaceBeforeFooter(final boolean spaceBeforeFooter) {
public Builder<I> setSpaceBeforeFooter(final boolean spaceBeforeFooter) {
options.spaceBeforeFooter = spaceBeforeFooter;
return this;
}
@NotNull
public Builder setItemsPerPage(final int itemsPerPage) {
public Builder<I> setItemsPerPage(final int itemsPerPage) {
options.itemsPerPage = itemsPerPage;
return this;
}
@NotNull
public Builder setTopic(@NotNull String topic) {
public Builder<I> setTopic(@NotNull String topic) {
options.topic = topic;
return this;
}
@NotNull
public Builder setCommand(@NotNull String command) {
public Builder<I> setCommand(@NotNull String command) {
options.command = command;
return this;
}
@NotNull
public Builder setEscapeItemsMineDown(final boolean escapeItemsMineDown) {
public Builder<I> setEscapeItemsMineDown(final boolean escapeItemsMineDown) {
options.escapeItemsMineDown = escapeItemsMineDown;
return this;
}
@NotNull
public Builder setPageJumpersFormat(@NotNull String pageJumpersFormat) {
public Builder<I> setPageJumpersFormat(@NotNull String pageJumpersFormat) {
options.pageJumpersFormat = pageJumpersFormat;
return this;
}
@NotNull
public Builder setPageJumperPageSeparator(@NotNull String pageJumperPageSeparator) {
public Builder<I> setPageJumperPageSeparator(@NotNull String pageJumperPageSeparator) {
options.pageJumperPageSeparator = pageJumperPageSeparator;
return this;
}
@NotNull
public Builder setPageJumperPageFormat(@NotNull String pageJumperPageFormat) {
public Builder<I> setPageJumperPageFormat(@NotNull String pageJumperPageFormat) {
options.pageJumperPageFormat = pageJumperPageFormat;
return this;
}
@NotNull
public Builder setPageJumperGroupSeparator(@NotNull String pageJumperGroupSeparator) {
public Builder<I> setPageJumperGroupSeparator(@NotNull String pageJumperGroupSeparator) {
options.pageJumperGroupSeparator = pageJumperGroupSeparator;
return this;
}
@NotNull
public Builder setPageJumperCurrentPageFormat(@NotNull String pageJumperCurrentPageFormat) {
public Builder<I> setPageJumperCurrentPageFormat(@NotNull String pageJumperCurrentPageFormat) {
options.pageJumperCurrentPageFormat = pageJumperCurrentPageFormat;
return this;
}
@NotNull
public Builder setPreviousButtonFormat(@NotNull String previousButtonFormat) {
public Builder<I> setPreviousButtonFormat(@NotNull String previousButtonFormat) {
options.previousButtonFormat = previousButtonFormat;
return this;
}
@NotNull
public Builder setNextButtonFormat(@NotNull String nextButtonFormat) {
public Builder<I> setNextButtonFormat(@NotNull String nextButtonFormat) {
options.nextButtonFormat = nextButtonFormat;
return this;
}
@NotNull
public Builder setPageJumperStartButtons(final int pageJumperStartButtons) {
public Builder<I> setPageJumperStartButtons(final int pageJumperStartButtons) {
options.pageJumperStartButtons = pageJumperStartButtons;
return this;
}
@NotNull
public Builder setPageJumperEndButtons(final int pageJumperEndButtons) {
public Builder<I> setPageJumperEndButtons(final int pageJumperEndButtons) {
options.pageJumperEndButtons = pageJumperEndButtons;
return this;
}
@NotNull
public ListOptions build() {
public ListOptions<I> build() {
return options;
}
}

@ -23,8 +23,7 @@ package net.william278.paginedown;
import de.themoep.minedown.adventure.MineDown;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.StringJoiner;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -44,19 +43,19 @@ import java.util.stream.Collectors;
* @see ListOptions
*/
@SuppressWarnings("unused")
public class PaginatedList {
public class PaginatedList<I extends ListItem> {
/**
* {@link ListOptions} to be used for generating the list
*/
@NotNull
private final ListOptions options;
private final ListOptions<I> options;
/**
* A list of items to be paginated; can be MineDown formatted
*/
@NotNull
private final List<String> items;
private final List<I> items;
/**
* Private constructor used by {@code #get(List, ListOptions)}
@ -64,8 +63,8 @@ public class PaginatedList {
* @param items a list of items to be paginated
* @param options {@link ListOptions} to be used for generating list pages
*/
private PaginatedList(@NotNull List<String> items, @NotNull ListOptions options) {
this.items = items;
private PaginatedList(@NotNull Collection<I> items, @NotNull ListOptions<I> options) {
this.items = new ArrayList<>(items);
this.options = options;
}
@ -75,9 +74,10 @@ public class PaginatedList {
* @param items The {@link List} of items to paginate
* @return A new {@link PaginatedList}
*/
@SuppressWarnings("unchecked")
@NotNull
public static PaginatedList of(@NotNull List<String> items) {
return new PaginatedList(items, new ListOptions.Builder().build());
public static <I extends ListItem> PaginatedList<I> of(@NotNull Collection<I> items) {
return of(items, ListOptions.builder().build());
}
/**
@ -88,8 +88,8 @@ public class PaginatedList {
* @return A new {@link PaginatedList}
*/
@NotNull
public static PaginatedList of(@NotNull List<String> items, @NotNull ListOptions options) {
return new PaginatedList(items, options);
public static <I extends ListItem> PaginatedList<I> of(@NotNull Collection<I> items, @NotNull ListOptions<I> options) {
return new PaginatedList<>(items, options);
}
@ -101,9 +101,33 @@ public class PaginatedList {
* @param page The page number to get
* @return A {@link MineDown} object, for formatting the list
*/
@NotNull
public MineDown getNearestValidPage(final int page, boolean ascending, @NotNull SortOption<I> option) {
return getPage(Math.max(1, Math.min(getTotalPages(), page)), ascending, option);
}
@SuppressWarnings("unchecked")
@NotNull
public MineDown getNearestValidPage(final int page, boolean ascending) {
return getNearestValidPage(page, ascending, (SortOption<I>) SortOption.NAME);
}
@NotNull
public MineDown getNearestValidPage(final int page) {
return getPage(Math.max(1, Math.min(getTotalPages(), page)));
return getNearestValidPage(page, true);
}
/**
* Returns a {@link MineDown} formatted message to be sent to a player of the paginated list for the specified page
* <p>List formats and options from the {@link ListOptions} are applied to generate the list.
*
* @param page The page number to get
* @return A {@link MineDown} object, for formatting the list
* @throws PaginationException If the page number is out of bounds
*/
@NotNull
public MineDown getPage(final int page, boolean ascending, @NotNull SortOption<I> option) throws PaginationException {
return new MineDown(getRawPage(page, ascending, option));
}
/**
@ -114,8 +138,23 @@ public class PaginatedList {
* @return A {@link MineDown} object, for formatting the list
* @throws PaginationException If the page number is out of bounds
*/
@SuppressWarnings("unchecked")
@NotNull
public MineDown getPage(final int page, boolean ascending) throws PaginationException {
return getPage(page, ascending, (SortOption<I>) SortOption.NAME);
}
/**
* Returns a {@link MineDown} formatted message to be sent to a player of the paginated list for the specified page
* <p>List formats and options from the {@link ListOptions} are applied to generate the list.
*
* @param page The page number to get
* @return A {@link MineDown} object, for formatting the list
* @throws PaginationException If the page number is out of bounds
*/
@NotNull
public MineDown getPage(final int page) throws PaginationException {
return new MineDown(getRawPage(page));
return getPage(page, true);
}
/**
@ -127,7 +166,7 @@ public class PaginatedList {
* @throws PaginationException If the page number is out of bounds
*/
@NotNull
public String getRawPage(final int page) throws PaginationException {
public String getRawPage(final int page, final boolean ascending, final SortOption<I> option) throws PaginationException {
if (page < 1) {
throw new PaginationException("Page index must be >= 1");
}
@ -137,28 +176,40 @@ public class PaginatedList {
final StringJoiner menuJoiner = new StringJoiner("\n");
if (!options.headerFormat.isBlank()) {
menuJoiner.add(formatPageString(options.headerFormat, page));
menuJoiner.add(formatPageString(options.headerFormat, page, ascending, option));
if (options.spaceAfterHeader) {
menuJoiner.add("");
}
}
final List<I> items = option.sort(this.items, ascending);
if (options.escapeItemsMineDown) {
menuJoiner.add(getItemsForPage(page).stream().map(MineDown::escape)
menuJoiner.add(getItemsForPage(items, page).stream().map(MineDown::escape)
.collect(Collectors.joining(options.itemSeparator)));
} else {
menuJoiner.add(String.join(options.itemSeparator, getItemsForPage(page)));
menuJoiner.add(String.join(options.itemSeparator, getItemsForPage(items, page)));
}
if (!options.footerFormat.isBlank()) {
if (options.spaceBeforeFooter) {
menuJoiner.add("");
}
menuJoiner.add(formatPageString(options.footerFormat, page));
menuJoiner.add(formatPageString(options.footerFormat, page, ascending, option));
}
return menuJoiner.toString();
}
@SuppressWarnings("unchecked")
@NotNull
public String getRawPage(final int page, final boolean ascending) {
return getRawPage(page, ascending, (SortOption<I>) SortOption.NAME);
}
@NotNull
public String getRawPage(final int page) {
return getRawPage(page, true);
}
/**
* Returns the total number of pages
*
@ -171,12 +222,15 @@ public class PaginatedList {
/**
* Returns the items to be displayed on the specified page
*
* @param page The page number to get
* @param items The items to paginate
* @param page The page number to get
* @return The sub-list of items to be shown on a given page
*/
@NotNull
private List<String> getItemsForPage(final int page) {
return items.subList((page - 1) * options.itemsPerPage, Math.min(items.size(), page * options.itemsPerPage));
private List<String> getItemsForPage(@NotNull List<I> items, int page) {
return items.subList((page - 1) * options.itemsPerPage, Math.min(items.size(), page * options.itemsPerPage))
.stream().map(ListItem::toItemString)
.collect(Collectors.toList());
}
/**
@ -187,7 +241,7 @@ public class PaginatedList {
* @return The formatted page string
*/
@NotNull
private String formatPageString(@NotNull String format, int page) {
private String formatPageString(@NotNull String format, int page, boolean ascending, @NotNull SortOption<I> option) {
final StringBuilder convertedFormat = new StringBuilder();
StringBuilder currentPlaceholder = new StringBuilder();
boolean readingPlaceholder = false;
@ -195,54 +249,36 @@ public class PaginatedList {
if (c == '%') {
if (readingPlaceholder) {
switch (currentPlaceholder.toString().toLowerCase()) {
case "topic":
convertedFormat.append(formatPageString(options.topic, page));
break;
case "color":
convertedFormat.append(String.format("#%02x%02x%02x", options.themeColor.getRed(), options.themeColor.getGreen(), options.themeColor.getBlue()));
break;
case "first_item_on_page_index":
convertedFormat.append(((page - 1) * options.itemsPerPage) + 1);
break;
case "last_item_on_page_index":
convertedFormat.append(((page - 1) * options.itemsPerPage) + getItemsForPage(page).size());
break;
case "total_items":
convertedFormat.append(items.size());
break;
case "current_page":
convertedFormat.append(page);
break;
case "total_pages":
convertedFormat.append(getTotalPages());
break;
case "previous_page_button":
case "topic" -> convertedFormat.append(formatPageString(options.topic, page, ascending, option));
case "color" ->
convertedFormat.append(String.format("#%02x%02x%02x", options.themeColor.getRed(), options.themeColor.getGreen(), options.themeColor.getBlue()));
case "first_item_on_page_index" ->
convertedFormat.append(((page - 1) * options.itemsPerPage) + 1);
case "last_item_on_page_index" ->
convertedFormat.append(((page - 1) * options.itemsPerPage) + getItemsForPage(items, page).size());
case "total_items" -> convertedFormat.append(items.size());
case "current_page" -> convertedFormat.append(page);
case "total_pages" -> convertedFormat.append(getTotalPages());
case "previous_page_button" -> {
if (page > 1) {
convertedFormat.append(formatPageString(options.previousButtonFormat, page));
convertedFormat.append(formatPageString(options.previousButtonFormat, page, ascending, option));
}
break;
case "next_page_button":
}
case "next_page_button" -> {
if (page < getTotalPages()) {
convertedFormat.append(formatPageString(options.nextButtonFormat, page));
convertedFormat.append(formatPageString(options.nextButtonFormat, page, ascending, option));
}
break;
case "next_page_index":
convertedFormat.append(page + 1);
break;
case "previous_page_index":
convertedFormat.append(page - 1);
break;
case "command":
convertedFormat.append(options.command);
break;
case "page_jumpers":
}
case "next_page_index" -> convertedFormat.append(page + 1);
case "previous_page_index" -> convertedFormat.append(page - 1);
case "command" -> convertedFormat.append(options.command);
case "page_jumpers" -> {
if (getTotalPages() > 2) {
convertedFormat.append(formatPageString(options.pageJumpersFormat, page));
convertedFormat.append(formatPageString(options.pageJumpersFormat, page, ascending, option));
}
break;
case "page_jump_buttons": {
convertedFormat.append(getPageJumperButtons(page));
break;
}
case "page_jump_buttons" -> {
convertedFormat.append(getPageJumperButtons(page, ascending, option));
}
}
} else {
@ -267,13 +303,15 @@ public class PaginatedList {
* @return The formatted page jumper
*/
@NotNull
private String formatPageJumper(final int page) {
return formatPageString(options.pageJumperPageFormat.replaceAll("%target_page_index%",
Integer.toString(page)), page);
private String formatPageJumper(final int page, final boolean ascending, @NotNull SortOption<I> option) {
return formatPageString(
options.pageJumperPageFormat.replaceAll("%target_page_index%", Integer.toString(page)),
page, ascending, option
);
}
@NotNull
protected String getPageJumperButtons(final int page) {
protected String getPageJumperButtons(final int page, final boolean ascending, @NotNull SortOption<I> option) {
final StringJoiner pageGroups = new StringJoiner(options.pageJumperGroupSeparator);
StringJoiner pages = new StringJoiner(options.pageJumperPageSeparator);
int lastPage = 1;
@ -284,9 +322,9 @@ public class PaginatedList {
pages = new StringJoiner(options.pageJumperPageSeparator);
}
if (page == i) {
pages.add(formatPageString(options.pageJumperCurrentPageFormat, i));
pages.add(formatPageString(options.pageJumperCurrentPageFormat, i, ascending, option));
} else {
pages.add(formatPageString(formatPageJumper(i), i));
pages.add(formatPageString(formatPageJumper(i, ascending, option), i, ascending, option));
}
lastPage = i;
}

@ -19,7 +19,7 @@
package net.william278.paginedown;
public class PaginationException extends RuntimeException {
public class PaginationException extends IllegalStateException {
public PaginationException(String message) {
super(message);

@ -0,0 +1,36 @@
package net.william278.paginedown;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class SortOption<I extends ListItem> {
private final String name;
private final Comparator<I> sortFunction;
public static final SortOption<? extends ListItem> NAME = new SortOption<>("name", Comparator.comparing(ListItem::toItemString));
public SortOption(@NotNull String name, @NotNull Comparator<I> sortFunction) {
this.name = name;
this.sortFunction = sortFunction;
}
@NotNull
public List<I> sort(Collection<I> items, boolean ascending) {
final List<I> sortedItems = new ArrayList<>(items);
sortedItems.sort(sortFunction);
if (!ascending) {
Collections.reverse(sortedItems);
}
return sortedItems;
}
@NotNull
public String getName() {
return name;
}
public boolean matchesName(@NotNull String name) {
return getName().equalsIgnoreCase(name);
}
}

@ -0,0 +1,18 @@
package net.william278.paginedown;
import org.jetbrains.annotations.NotNull;
public final class StringListItem implements ListItem {
private final String item;
public StringListItem(@NotNull String item) {
this.item = item;
}
@Override
@NotNull
public String toItemString() {
return item;
}
}

@ -25,13 +25,14 @@ import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("ALL")
public class PaginatedListTests {
// Generates dummy list data for testing
private List<String> generateListData(final int size, final String format) {
final ArrayList<String> dummyData = new ArrayList<>();
// Generates a test list of StringListItems
private List<StringListItem> generateListData(final int size, final String format) {
final ArrayList<StringListItem> dummyData = new ArrayList<>();
for (int i = 0; i < size; i++) {
dummyData.add(format.replaceAll("#", String.valueOf(i + 1)));
dummyData.add(new StringListItem(format.replaceAll("#", String.valueOf(i + 1))));
}
return dummyData;
}
@ -44,55 +45,60 @@ public class PaginatedListTests {
@Test
public void testPageItemDividing() {
final int pageCount = PaginatedList.of(generateListData(40, "Item #"),
new ListOptions.Builder()
.setItemsPerPage(10)
.build()
final int pageCount = PaginatedList.of(
generateListData(40, "Item #"),
ListOptions.builder().setItemsPerPage(10).build()
).getTotalPages();
Assertions.assertEquals(4, pageCount);
}
@Test
public void testPageJumperButtonsOnLongList() {
final PaginatedList longList = PaginatedList.of(generateListData(200, "Item #"),
new ListOptions.Builder()
final PaginatedList<StringListItem> longList = PaginatedList.of(
generateListData(200, "Item #"),
ListOptions.builder()
.setItemsPerPage(10)
.setPageJumperStartButtons(2)
.setPageJumperEndButtons(2)
.setPageJumperPageFormat("%target_page_index%")
.setPageJumperCurrentPageFormat("%current_page%")
.build());
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(2));
Assertions.assertEquals("1|2…6…19|20", longList.getPageJumperButtons(6));
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(20));
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(1));
.build()
);
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(2, true, (SortOption<StringListItem>) SortOption.NAME));
Assertions.assertEquals("1|2…6…19|20", longList.getPageJumperButtons(6, true, (SortOption<StringListItem>) SortOption.NAME));
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(20, true, (SortOption<StringListItem>) SortOption.NAME));
Assertions.assertEquals("1|2…19|20", longList.getPageJumperButtons(1, true, (SortOption<StringListItem>) SortOption.NAME));
}
@Test
public void testPageJumperButtonsOnMediumList() {
final PaginatedList mediumList = PaginatedList.of(generateListData(45, "Item #"),
new ListOptions.Builder()
final PaginatedList<StringListItem> mediumList = PaginatedList.of(
generateListData(45, "Item #"),
ListOptions.builder()
.setItemsPerPage(10)
.setPageJumperStartButtons(2)
.setPageJumperEndButtons(2)
.setPageJumperPageFormat("%target_page_index%")
.setPageJumperCurrentPageFormat("%current_page%")
.build());
Assertions.assertEquals("1|2…4|5", mediumList.getPageJumperButtons(1));
Assertions.assertEquals("1|2|3|4|5", mediumList.getPageJumperButtons(3));
Assertions.assertEquals("1|2…4|5", mediumList.getPageJumperButtons(5));
.build()
);
Assertions.assertEquals("1|2…4|5", mediumList.getPageJumperButtons(1, true, (SortOption<StringListItem>) SortOption.NAME));
Assertions.assertEquals("1|2|3|4|5", mediumList.getPageJumperButtons(3, true, (SortOption<StringListItem>) SortOption.NAME));
Assertions.assertEquals("1|2…4|5", mediumList.getPageJumperButtons(5, true, (SortOption<StringListItem>) SortOption.NAME));
}
@Test
public void testPageJumperButtonsOnShortList() {
final PaginatedList shortList = PaginatedList.of(generateListData(20, "Item #"),
new ListOptions.Builder()
final PaginatedList<StringListItem> shortList = PaginatedList.of(
generateListData(20, "Item #"),
ListOptions.builder()
.setItemsPerPage(10)
.setPageJumperStartButtons(2)
.setPageJumperEndButtons(2)
.setPageJumperPageFormat("%target_page_index%")
.setPageJumperCurrentPageFormat("%current_page%")
.build());
Assertions.assertEquals("1|2", shortList.getPageJumperButtons(2));
.build()
);
Assertions.assertEquals("1|2", shortList.getPageJumperButtons(2, true, (SortOption<StringListItem>) SortOption.NAME));
}
}

Loading…
Cancel
Save