Skip to content

Instantly share code, notes, and snippets.

@tors42
Created April 30, 2024 22:34
Show Gist options
  • Save tors42/aa9e36aac0ddc56f3ec2ac5cc88d9930 to your computer and use it in GitHub Desktop.
Save tors42/aa9e36aac0ddc56f3ec2ac5cc88d9930 to your computer and use it in GitHub Desktop.
Java tool to give time to opponent
if (! Files.exists(Path.of("chariot.jar"))) {
Files.write(Path.of("chariot.jar"), URI.create(
"https://repo1.maven.org/maven2/io/github/tors42/chariot/0.0.87/chariot-0.0.87.jar"
).toURL().openStream().readAllBytes());
}
/env --class-path chariot.jar
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.prefs.Preferences;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import chariot.*;
import chariot.Client.AuthOk;
import chariot.model.Event.*;
var prefs = Preferences.userRoot().node("zen");
var scopes = Set.of(Client.Scope.challenge_read, Client.Scope.challenge_write);
var client = Client.load(prefs);
if (client instanceof ClientAuth auth) {
if (! auth.scopes().containsAll(scopes)) {
auth.clearAuth(prefs);
client = Client.load(prefs);
}
}
var frame = new JFrame("Zen");
var loginPanel = new JPanel();
var loginInfo = new JTextArea("""
In order to be able to give more time to opponents,
this application needs authorization.
It will need two permissions:
"challenge:read" - to find ongoing games
"challenge:write" - to give time in games
""");
var loginButton = new JButton("Login");
var logoutButton = new JButton("Logout");
var timePanel = new JPanel();
var timePanelInner = new JPanel();
var timeSpinner = new JSpinner(new SpinnerNumberModel(15, 5, 60, 5));
var giveTimeButton = new JButton("Give Time");
var ongoingGames = new JComboBox<String>();
ongoingGames.getModel().addListDataListener(new ListDataListener() {
public void intervalAdded(ListDataEvent e) { updateButton(); }
public void intervalRemoved(ListDataEvent e) { updateButton(); }
public void contentsChanged(ListDataEvent e) { updateButton(); }
void updateButton() {
SwingUtilities.invokeLater(() -> giveTimeButton.setEnabled(ongoingGames.getItemCount() > 0));
}
});
giveTimeButton.setEnabled(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
if (client instanceof ClientAuth) {
frame.getContentPane().add(timePanel, BorderLayout.CENTER);
logoutButton.setEnabled(true);
loginButton.setEnabled(false);
} else {
frame.getContentPane().add(loginPanel, BorderLayout.CENTER);
logoutButton.setEnabled(false);
loginButton.setEnabled(true);
}
loginPanel.setLayout(new BorderLayout());
loginPanel.add(loginInfo, BorderLayout.CENTER);
loginPanel.add(loginButton, BorderLayout.SOUTH);
timePanelInner.setLayout(new BoxLayout(timePanelInner, BoxLayout.Y_AXIS));
timePanelInner.add(ongoingGames);
timePanelInner.add(timeSpinner);
timePanelInner.add(giveTimeButton);
timePanel.setLayout(new BorderLayout());
timePanel.add(timePanelInner, BorderLayout.CENTER);
timePanel.add(logoutButton, BorderLayout.SOUTH);
Consumer<ClientAuth> clientHasAuthorized = auth -> {
var running = new AtomicBoolean(true);
giveTimeButton.addActionListener(__ -> auth.challenges().addTimeToGame(ongoingGames.getItemAt(ongoingGames.getSelectedIndex()), (Integer) timeSpinner.getValue()));
Thread.ofPlatform().name("GameStartListener").start(() -> auth.challenges().connect().stream().takeWhile(__ -> running.get()).forEach(event -> {
switch(event) {
case GameStartEvent start -> SwingUtilities.invokeLater(() -> ongoingGames.addItem(start.id()));
case GameStopEvent stop -> SwingUtilities.invokeLater(() -> ongoingGames.removeItem(stop.id()));
default -> {}
}
}));
var logoutListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
logoutButton.removeActionListener(this);
running.set(false);
auth.revokeToken();
auth.clearAuth(prefs);
SwingUtilities.invokeLater(() -> {
frame.getContentPane().remove(timePanel);
frame.getContentPane().add(loginPanel, BorderLayout.CENTER);
loginButton.setEnabled(true);
logoutButton.setEnabled(false);
frame.pack();
});
}
};
logoutButton.addActionListener(logoutListener);
};
ActionListener loginAction = __ -> {
Consumer<URI> uriHandler = Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)
? uri -> { try { Desktop.getDesktop().browse(uri); } catch (java.io.IOException e) {} }
: uri -> JOptionPane.showInternalMessageDialog(frame, "Visit the following URL to authorize the application:\n\n" + uri);
var result = Client.basic().withPkce(uriHandler,
pkce -> pkce.scope(scopes.toArray(Client.Scope[]::new)));
if (result instanceof AuthOk(var auth)) {
auth.store(prefs);
SwingUtilities.invokeLater(() -> {
frame.getContentPane().remove(loginPanel);
frame.getContentPane().add(timePanel, BorderLayout.CENTER);
loginButton.setEnabled(false);
logoutButton.setEnabled(true);
frame.pack();
clientHasAuthorized.accept(auth);
});
}
};
loginButton.addActionListener(loginAction);
if (client instanceof ClientAuth auth) {
clientHasAuthorized.accept(auth);
}
frame.setMinimumSize(new Dimension(200, 100));
frame.pack();
frame.setVisible(true);
@tors42
Copy link
Author

tors42 commented Apr 30, 2024

Java can be downloaded at https://jdk.java.net/ for instance,
and then run with jshell,

$ jshell zen-give-time.jsh

A window with a login button shows up, and after logging in one can give time to opponents in ongoing games.

zen-give-time.webm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment