Created
April 30, 2024 22:34
-
-
Save tors42/aa9e36aac0ddc56f3ec2ac5cc88d9930 to your computer and use it in GitHub Desktop.
Java tool to give time to opponent
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Java can be downloaded at https://jdk.java.net/ for instance,
and then run with
jshell
,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