Skip to content

Commit

Permalink
A still WIP dashboard config screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Matyrobbrt committed Feb 21, 2022
1 parent 5231af8 commit 2c5b72d
Show file tree
Hide file tree
Showing 27 changed files with 691 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.mcmoddev.mmdbot.dashboard.common.listener.MultiPacketListener;
import com.mcmoddev.mmdbot.dashboard.common.listener.PacketListener;
import com.mcmoddev.mmdbot.dashboard.common.listener.PacketWaiter;
import com.mcmoddev.mmdbot.dashboard.common.packet.HasIDPacket;
import com.mcmoddev.mmdbot.dashboard.common.packet.HasResponse;
import com.mcmoddev.mmdbot.dashboard.common.packet.Packet;
import com.mcmoddev.mmdbot.dashboard.common.packet.PacketHandler;
Expand Down Expand Up @@ -94,6 +95,18 @@ public static void sendPacket(Packet packet) {
CLIENT.invokeIfNotNull(c -> c.sendTCP(packet));
}

public static <R extends Packet, P extends HasResponse<R> & Packet> PacketProcessorBuilder<R> sendAndAwaitResponseWithID(Function<PacketID, P> packetCreator) {
final var packetID = PacketID.generateRandom();
final var pkt = packetCreator.apply(packetID);
return new PacketProcessorBuilder<>(pkt, pkt.getResponsePacketClass())
.withPredicate(p -> {
if (p instanceof HasIDPacket withId) {
return packetID.equals(withId.getPacketID());
}
return true;
});
}

public static <R extends Packet, P extends HasResponse<R> & Packet> PacketProcessorBuilder<R> sendAndAwaitResponse(P packet) {
return new PacketProcessorBuilder<>(packet, packet.getResponsePacketClass());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mcmoddev.mmdbot.dashboard.client.controller.config;

import com.mcmoddev.mmdbot.dashboard.BotTypeEnum;
import com.mcmoddev.mmdbot.dashboard.util.DashConfigType;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public abstract class ConfigBoxController {

protected final BotTypeEnum botType;
protected final DashConfigType type;
protected final String configName;
protected final String path;
protected final String[] comments;

public abstract void init();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mcmoddev.mmdbot.dashboard.client.controller.config;

import com.mcmoddev.mmdbot.dashboard.BotTypeEnum;
import com.mcmoddev.mmdbot.dashboard.client.DashboardClient;
import com.mcmoddev.mmdbot.dashboard.client.util.Constants;
import com.mcmoddev.mmdbot.dashboard.common.packet.PacketID;
import com.mcmoddev.mmdbot.dashboard.packets.UpdateConfigPacket;
import com.mcmoddev.mmdbot.dashboard.packets.requests.RequestConfigValuePacket;
import com.mcmoddev.mmdbot.dashboard.util.DashConfigType;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.text.Font;

public class DefaultConfigBoxController extends ConfigBoxController {

public DefaultConfigBoxController(final BotTypeEnum botType, final DashConfigType type, final String configName, final String path, final String[] comments) {
super(botType, type, configName, path, comments);
}

@FXML
private Label configNameLabel;
@FXML
private Label commentsLabel;
@FXML
private TextField valueField;

@Override
public void init() {
configNameLabel.setText(configName);
commentsLabel.setText(Constants.LINE_JOINER.join(comments));
configNameLabel.setFont(Font.font(20));
DashboardClient.sendAndAwaitResponseWithID((PacketID id) ->
new RequestConfigValuePacket(id, botType, type, configName, path))
.withPlatformAction(pkt -> valueField.setText(pkt.value().toString()))
.queue();
}

@FXML
public void onUpdateValueClick(Event e) {
DashboardClient.sendAndAwaitGenericResponse(id -> new UpdateConfigPacket(id, botType, type, configName, path, valueField.getText()))
.queue();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ public static void makeMainPageScene(Stage stage) {
final var image = new ImageView(data.avatarUrl());
image.setFitWidth(50);
image.setFitHeight(50);
StyleUtils.setRoundedCorners(image, 4);
final var nameText = new Text(data.username() + "#" + data.discriminator());
final var box = new HBox(7, image, nameText);
StyleUtils.setBackgroundColour(box, Color.LIGHTGRAY);
box.setOnMouseClicked(e -> BotStage.STAGES.get(botType).createAndShowStage(data));
botNodes.add(box);
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mcmoddev.mmdbot.dashboard.client.scenes.bot;

import com.mcmoddev.mmdbot.dashboard.util.DashConfigType;

record ConfigEntry(DashConfigType type, String configName, String path, String[] comments) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.mcmoddev.mmdbot.dashboard.client.scenes.bot;

import com.google.common.base.Suppliers;
import com.mcmoddev.mmdbot.dashboard.BotTypeEnum;
import com.mcmoddev.mmdbot.dashboard.client.DashboardApplication;
import com.mcmoddev.mmdbot.dashboard.client.controller.config.ConfigBoxController;
import com.mcmoddev.mmdbot.dashboard.util.BotUserData;
import com.mcmoddev.mmdbot.dashboard.util.DashConfigType;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultBotStage implements BotStage {

private final Map<String, List<ConfigEntry>> configs;
private final BotTypeEnum botType;

public DefaultBotStage(final Map<String, List<ConfigEntry>> configs, final BotTypeEnum botType) {
this.configs = configs;
this.botType = botType;
}

@Override
public void createAndShowStage(final BotUserData botUserData) {
final var configTab = new Tab("Configs");
configTab.setContent(Suppliers.memoize(() -> {
final var configNamesPane = new TabPane(configs.entrySet().stream()
.map(e -> {
final var tab = new Tab(e.getKey());
final var box = new VBox(4);
box.getChildren().addAll(e.getValue().stream()
.sorted(Comparator.comparing(ConfigEntry::path))
.map(this::makeConfigBox).toList());

final var scrollPane = new ScrollPane(box);
scrollPane.setFitToHeight(true);

final var root = new BorderPane(scrollPane);
root.setPadding(new Insets(15));
tab.setContent(root);

return tab;
}).toArray(Tab[]::new));
configNamesPane.setSide(Side.LEFT);
configNamesPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
configNamesPane.setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
return new VBox(configNamesPane);
}).get());

final var pane = new TabPane(configTab);
pane.setMaxWidth(-1);
final var stage = new Stage();
pane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
pane.setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
stage.setTitle("%s configuration".formatted(botType.getNiceName()));
stage.getIcons().add(new Image(botUserData.avatarUrl()));
stage.setScene(new Scene(new HBox(pane)));
stage.setResizable(true);
stage.setFullScreen(true);
stage.showAndWait();
}

public final Node makeConfigBox(ConfigEntry entry) {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(DashboardApplication.class.getResource("/guis/config_box/" + entry.type().getConfigBoxName()));
final var constructor = getConstructor(entry.type().getControllerClassName());
final var controller = constructor.invoke(botType, entry.type(), entry.configName(), entry.path(), entry.comments());
fxmlLoader.setController(controller);
final Node toRet = fxmlLoader.load();
((ConfigBoxController) fxmlLoader.getController()).init();
return toRet;
} catch (Throwable e) {
// If something is wrong, let it crash
throw new RuntimeException(e);
}
}

private static final Map<String, MethodHandle> CONSTRUCTORS = new HashMap<>();
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

public static MethodHandle getConstructor(String className) {
return CONSTRUCTORS.computeIfAbsent(className, k -> {
try {
final var clz = Class.forName(className);
final var methodType = MethodType.methodType(void.class, BotTypeEnum.class, DashConfigType.class, String.class, String.class, String[].class);
return LOOKUP.findConstructor(clz, methodType);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package com.mcmoddev.mmdbot.dashboard.client.scenes.bot;

import com.mcmoddev.mmdbot.dashboard.util.BotUserData;
import com.google.common.collect.ImmutableMap;
import com.mcmoddev.mmdbot.dashboard.BotTypeEnum;
import com.mcmoddev.mmdbot.dashboard.util.DashConfigType;

public final class MMDBotStage implements BotStage {
import java.util.List;
import java.util.Map;

MMDBotStage() {}
public final class MMDBotStage extends DefaultBotStage {

@Override
public void createAndShowStage(BotUserData botUserData) {
private static final ConfigEntry THING = new ConfigEntry(DashConfigType.STRING, "prefix", "commands.prefix.main", new String[] {"The prefix of the bot"});

public static final Map<String, List<ConfigEntry>> CONFIGS = new ImmutableMap.Builder<String, List<ConfigEntry>>()
.put("someConfig", List.of(
new ConfigEntry(DashConfigType.STRING, "botOwner", "bot.owner", new String[] {"Something, yes"})
))
.put("anotherConfig", List.of(
THING, THING, THING, THING,THING, THING, THING, THING, THING, THING, THING, THING, THING
))
.build();

MMDBotStage() {
super(CONFIGS, BotTypeEnum.MMDBOT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mcmoddev.mmdbot.dashboard.client.util;

import com.google.common.base.Joiner;
import lombok.experimental.UtilityClass;

@UtilityClass
public class Constants {

public static final Joiner LINE_JOINER = Joiner.on("\n");

}
23 changes: 23 additions & 0 deletions dashboard/src/client/resources/guis/config_box/default.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="141.0" stylesheets="@../../themes/dark.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label fx:id="configNameLabel" alignment="CENTER" prefHeight="27.0" prefWidth="600.0" text="Cfg name" textAlignment="CENTER">
<font>
<Font size="23.0" />
</font></Label>
<Label fx:id="commentsLabel" text="Comments" textAlignment="CENTER" />
<TextField fx:id="valueField" promptText="Value" text="Current Value" />
<Button mnemonicParsing="false" onAction="#onUpdateValueClick" text="Update value" />
</children>
<styleClass>
<String fx:value="config_box" />
<String fx:value="default" />
</styleClass>
</VBox>
4 changes: 4 additions & 0 deletions dashboard/src/client/resources/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@
-fx-background-color: rgb(74, 74, 74);
-fx-font-family: Monospaced;
}
.config_box.default {
-fx-border-color: red;
-fx-border-radius: 5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,32 @@
import javax.annotation.Nullable;

public enum BotTypeEnum {
THE_COMMANDER("thecommander"),
THE_LISTENER("thelistener"),
THE_WATCHER("thewatcher"),
THE_COMMANDER("thecommander", "The Commander"),
THE_LISTENER("thelistener", "The Listener"),
THE_WATCHER("thewatcher", "The Watcher"),

/**
* @deprecated The bot split
*/
@Deprecated(forRemoval = true)
MMDBOT("mmdbot");
MMDBOT("mmdbot", "MMDBot");

private final String name;
private final String niceName;

BotTypeEnum(final String name) {
BotTypeEnum(final String name, final String niceName) {
this.name = name;
this.niceName = niceName;
}

public String getName() {
return name;
}

public String getNiceName() {
return niceName;
}

@Nullable
public static BotTypeEnum byName(String name) {
for (var type : values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import com.mcmoddev.mmdbot.dashboard.util.BotUserData;
import com.mcmoddev.mmdbot.dashboard.util.Credentials;
import com.mcmoddev.mmdbot.dashboard.util.GenericResponse;
import com.mcmoddev.mmdbot.dashboard.util.UpdateConfigContext;

import javax.annotation.Nullable;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
Expand Down Expand Up @@ -55,4 +57,10 @@ static void setInstance(ServerBridge instance) {

@Nullable
BotUserData getBotData(BotTypeEnum botType);

boolean isUserAuthenticated(InetSocketAddress address);

GenericResponse updateConfig(UpdateConfigContext configContext, PacketContext packetContext);

Object getConfigValue(BotTypeEnum botType, String configName, String path);
}
Loading

0 comments on commit 2c5b72d

Please sign in to comment.