Skip to content

Commit

Permalink
First version of the Forms rewrite
Browse files Browse the repository at this point in the history
The next version will split the implementation from the api
  • Loading branch information
Tim203 committed Oct 29, 2020
1 parent f8939ca commit c910234
Show file tree
Hide file tree
Showing 37 changed files with 1,559 additions and 1,112 deletions.
2 changes: 1 addition & 1 deletion common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
177 changes: 177 additions & 0 deletions common/src/main/java/org/geysermc/common/form/CustomForm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/

package org.geysermc.common.form;

import com.google.gson.annotations.JsonAdapter;
import lombok.Getter;
import org.geysermc.common.form.component.*;
import org.geysermc.common.form.response.CustomFormResponse;
import org.geysermc.common.form.util.FormAdaptor;
import org.geysermc.common.form.util.FormImage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Getter
@JsonAdapter(FormAdaptor.class)
public final class CustomForm extends Form {
private final String title;
private final FormImage icon;
private final List<Component> content;

private CustomForm(String title, FormImage icon, List<Component> content) {
super(Form.Type.CUSTOM_FORM);

this.title = title;
this.icon = icon;
this.content = Collections.unmodifiableList(content);
}

public static Builder builder() {
return new Builder();
}

public static CustomForm of(String title, FormImage icon, List<Component> content) {
return new CustomForm(title, icon, content);
}

public CustomFormResponse parseResponse(String data) {
if (isClosed(data)) {
return CustomFormResponse.closed();
}
return CustomFormResponse.of(this, data);
}

public static final class Builder extends Form.Builder<Builder, CustomForm> {
private final List<Component> components = new ArrayList<>();
private FormImage icon;

public Builder icon(FormImage.Type type, String data) {
icon = FormImage.of(type, data);
return this;
}

public Builder iconPath(String path) {
return icon(FormImage.Type.PATH, path);
}

public Builder iconUrl(String url) {
return icon(FormImage.Type.URL, url);
}

public Builder component(Component component) {
components.add(component);
return this;
}

public Builder dropdown(DropdownComponent.Builder dropdownBuilder) {
return component(dropdownBuilder.translateAndBuild(this::translate));
}

public Builder dropdown(String text, int defaultOption, String... options) {
List<String> optionsList = new ArrayList<>();
for (String option : options) {
optionsList.add(translate(option));
}
return component(DropdownComponent.of(translate(text), optionsList, defaultOption));
}

public Builder dropdown(String text, String... options) {
return dropdown(text, -1, options);
}

public Builder input(String text, String placeholder, String defaultText) {
return component(InputComponent.of(
translate(text), translate(placeholder), translate(defaultText)
));
}

public Builder input(String text, String placeholder) {
return component(InputComponent.of(translate(text), translate(placeholder)));
}

public Builder input(String text) {
return component(InputComponent.of(translate(text)));
}

public Builder label(String text) {
return component(LabelComponent.of(translate(text)));
}

public Builder slider(String text, float min, float max, int step, float defaultValue) {
return component(SliderComponent.of(text, min, max, step, defaultValue));
}

public Builder slider(String text, float min, float max, int step) {
return slider(text, min, max, step, -1);
}

public Builder slider(String text, float min, float max, float defaultValue) {
return slider(text, min, max, -1, defaultValue);
}

public Builder slider(String text, float min, float max) {
return slider(text, min, max, -1, -1);
}

public Builder stepSlider(StepSliderComponent.Builder stepSliderBuilder) {
return component(stepSliderBuilder.translateAndBuild(this::translate));
}

public Builder stepSlider(String text, int defaultStep, String... steps) {
List<String> stepsList = new ArrayList<>();
for (String option : steps) {
stepsList.add(translate(option));
}
return component(StepSliderComponent.of(translate(text), stepsList, defaultStep));
}

public Builder stepSlider(String text, String... steps) {
return stepSlider(text, -1, steps);
}

public Builder toggle(String text, boolean defaultValue) {
return component(ToggleComponent.of(translate(text), defaultValue));
}

public Builder toggle(String text) {
return component(ToggleComponent.of(translate(text)));
}

@Override
public CustomForm build() {
CustomForm form = of(title, icon, components);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}

form.setResponseHandler(responseHandler);
return form;
}
}
}
137 changes: 137 additions & 0 deletions common/src/main/java/org/geysermc/common/form/Form.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/

package org.geysermc.common.form;

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.geysermc.common.form.response.FormResponse;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;

@Getter
public abstract class Form {
protected static final Gson GSON = new Gson();
private final Type type;

@Getter(AccessLevel.NONE)
protected String hardcodedJsonData = null;

@Setter protected Consumer<String> responseHandler;

public Form(Type type) {
this.type = type;
}

public String getJsonData() {
if (hardcodedJsonData != null) {
return hardcodedJsonData;
}
return GSON.toJson(this);
}

public abstract FormResponse parseResponse(String response);

@SuppressWarnings("unchecked")
public <T extends FormResponse> T parseResponseAs(String response) {
return (T) parseResponse(response);
}

public boolean isClosed(String response) {
return response == null || response.isEmpty() || response.equalsIgnoreCase("null");
}

@Getter
@RequiredArgsConstructor
public enum Type {
@SerializedName("form")
SIMPLE_FORM(SimpleForm.class),
@SerializedName("modal")
MODAL_FORM(ModalForm.class),
@SerializedName("custom_form")
CUSTOM_FORM(CustomForm.class);

private static final Type[] VALUES = values();
private final Class<? extends Form> typeClass;

public static Type getByOrdinal(int ordinal) {
return ordinal < VALUES.length ? VALUES[ordinal] : null;
}
}

public static abstract class Builder<T extends Builder<T, F>, F extends Form> {
protected String title = "";

protected BiFunction<String, String, String> translationHandler = null;
protected BiConsumer<F, String> biResponseHandler;
protected Consumer<String> responseHandler;
protected String locale;

public T title(String title) {
this.title = translate(title);
return self();
}

public T translator(BiFunction<String, String, String> translator, String locale) {
this.translationHandler = translator;
this.locale = locale;
return title(title);
}

public T translator(BiFunction<String, String, String> translator) {
return translator(translator, locale);
}

public T responseHandler(BiConsumer<F, String> responseHandler) {
biResponseHandler = responseHandler;
return self();
}

public T responseHandler(Consumer<String> responseHandler) {
this.responseHandler = responseHandler;
return self();
}

public abstract F build();

protected String translate(String text) {
if (translationHandler != null && text != null && !text.isEmpty()) {
return translationHandler.apply(text, locale);
}
return text;
}

@SuppressWarnings("unchecked")
protected T self() {
return (T) this;
}
}
}
Loading

0 comments on commit c910234

Please sign in to comment.