biskuteri-cafe-JKomasto2/ComposeWindow.java
Snowyfox e4f13ad8c8 Added attempt at using AttributedString.
Somewhat works now, but I think we'll abandon it..
2022-05-14 18:04:46 -04:00

408 lines
10 KiB
Java

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JButton;
import javax.swing.Box;
import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.border.Border;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.Cursor;
import java.awt.Color;
import javax.swing.event.CaretListener;
import javax.swing.event.CaretEvent;
import cafe.biskuteri.hinoki.Tree;
import java.io.IOException;
class
ComposeWindow extends JFrame {
private JKomasto
primaire;
private MastodonApi
api;
// - -%- -
private Composition
composition;
private ComposeComponent
display;
// ---%-@-%---
public synchronized void
setComposition(Composition composition)
{
assert composition != null;
this.composition = composition;
syncDisplayToComposition();
}
public synchronized void
newComposition()
{
composition = new Composition();
composition.text = "";
composition.visibility = PostVisibility.UNLISTED;
composition.replyToPostId = null;
composition.contentWarning = null;
syncDisplayToComposition();
}
public synchronized void
submit()
{
syncCompositionToDisplay();
if (composition.replyToPostId != null)
assert !composition.replyToPostId.trim().isEmpty();
if (composition.contentWarning != null)
assert !composition.contentWarning.trim().isEmpty();
display.setSubmitting(true);
api.submit(
composition.text, composition.visibility,
composition.replyToPostId, composition.contentWarning,
new RequestListener() {
public void
connectionFailed(IOException eIo)
{
JOptionPane.showMessageDialog(
ComposeWindow.this,
"Tried to submit post, failed..."
+ "\n" + eIo.getMessage()
);
}
public void
requestFailed(int httpCode, Tree<String> json)
{
JOptionPane.showMessageDialog(
ComposeWindow.this,
"Tried to submit post, failed..."
+ "\n" + json.get("error").value
+ "\n(HTTP error code: " + httpCode + ")"
);
}
public void
requestSucceeded(Tree<String> json)
{
newComposition();
}
}
);
display.setSubmitting(false);
}
// - -%- -
private synchronized void
syncDisplayToComposition()
{
display.setText(composition.text);
display.setReplyToPostId(composition.replyToPostId);
display.setVisibility(stringFor(composition.visibility));
display.setContentWarning(composition.contentWarning);
}
private synchronized void
syncCompositionToDisplay()
{
composition.text = display.getText();
composition.visibility =
visibilityFrom(display.getVisibility());
composition.replyToPostId =
nonEmpty(display.getReplyToPostId());
composition.contentWarning =
nonEmpty(display.getContentWarning());
}
// - -%- -
private static String
nonEmpty(String s)
{
if (s.trim().isEmpty()) return null;
return s;
}
// ---%-@-%---
ComposeWindow(JKomasto primaire)
{
super("Submit a new post");
this.primaire = primaire;
this.api = primaire.getMastodonApi();
getContentPane().setPreferredSize(new Dimension(360, 270));
pack();
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
display = new ComposeComponent(this);
newComposition();
setContentPane(display);
setIconImage(primaire.getProgramIcon());
}
// - -%- -
private static final String
stringFor(PostVisibility visibility)
{
switch (visibility)
{
case PUBLIC: return "Public";
case UNLISTED: return "Unlisted";
case FOLLOWERS: return "Followers";
case MENTIONED: return "Mentioned";
}
assert false; return null;
}
private static final PostVisibility
visibilityFrom(String string)
{
if (string.equals("Public"))
return PostVisibility.PUBLIC;
if (string.equals("Unlisted"))
return PostVisibility.UNLISTED;
if (string.equals("Followers"))
return PostVisibility.FOLLOWERS;
if (string.equals("Mentioned"))
return PostVisibility.MENTIONED;
assert false; return null;
}
}
class
ComposeComponent extends JPanel
implements ActionListener, CaretListener, KeyListener {
private ComposeWindow
primaire;
// - -%- -
private JTextArea
text;
private JTextField
reply, contentWarning;
private JLabel
textLength;
private JComboBox<String>
visibility;
private JButton
submit;
// ---%-@-%---
public void
setText(String text)
{
this.text.setText(text);
}
public void
setReplyToPostId(String postId)
{
this.reply.setText(postId);
}
public void
setVisibility(String visibility)
{
if (visibility.equals("Public"))
this.visibility.setSelectedIndex(0);
else if (visibility.equals("Unlisted"))
this.visibility.setSelectedIndex(1);
else if (visibility.equals("Followers"))
this.visibility.setSelectedIndex(2);
else if (visibility.equals("Mentioned"))
this.visibility.setSelectedIndex(3);
}
public void
setContentWarning(String contentWarning)
{
this.contentWarning.setText(contentWarning);
}
public String
getText()
{
return text.getText();
}
public String
getReplyToPostId()
{
return reply.getText();
}
public String
getContentWarning()
{
return contentWarning.getText();
}
public String
getVisibility()
{
return (String)visibility.getSelectedItem();
}
public void
setSubmitting(boolean submitting)
{
if (submitting)
{
text.setEnabled(false);
visibility.setEnabled(false);
submit.setEnabled(false);
setCursor(new Cursor(Cursor.WAIT_CURSOR));
}
else
{
text.setEnabled(true);
visibility.setEnabled(true);
submit.setEnabled(true);
setCursor(null);
}
}
// - -%- -
public void
actionPerformed(ActionEvent eA) { primaire.submit(); }
public void
caretUpdate(CaretEvent eCa) { updateTextLength(); }
public void
keyPressed(KeyEvent eK) { updateTextLength(); }
public void
keyReleased(KeyEvent eK) { }
public void
keyTyped(KeyEvent eK) { }
private void
updateTextLength()
{
int length = text.getText().length();
/*
* The web interface doesn't do this expensive thing.
* It has an upwards counter, incremented by I'm not
* sure what. Presumably they have some control over
* the text input. I'd rather not, cause I use a
* Japanese IME, I'm going to see how laggy this is.
* It raises our app's system requirements, but, I was
* going to transition it to multithreading anyways,
* I don't think we're going to be very cheap.. Which
* sucks, but the Mastodon API is not helping us here.
*/
textLength.setText(Integer.toString(length));
/*
* Another thing I could do is temporarily move the
* caret to the end and then find its position, then
* seek back. Not sure how much that would help, but
* if this is too laggy, that's what I'd try next.
*/
}
// ---%-@-%---
ComposeComponent(ComposeWindow primaire)
{
this.primaire = primaire;
Border b1 = BorderFactory.createEmptyBorder(8, 8, 8, 8);
Border b2 = BorderFactory.createEmptyBorder(4, 4, 4, 4);
Border b3 = BorderFactory.createLineBorder(Color.GRAY);
Border bc = BorderFactory.createCompoundBorder(b3, b2);
reply = new JTextField();
JLabel replyLabel = new JLabel("In reply to: ");
replyLabel.setLabelFor(reply);
contentWarning = new JTextField();
JLabel cwLabel = new JLabel("Content warning: ");
cwLabel.setLabelFor(contentWarning);
JPanel top = new JPanel();
top.setOpaque(false);
top.setLayout(new GridLayout(2, 2, 8, 0));
top.add(replyLabel);
top.add(reply);
top.add(cwLabel);
top.add(contentWarning);
textLength = new JLabel("0");
textLength.setFont(textLength.getFont().deriveFont(14f));
visibility = new JComboBox<>(new String[] {
"Public",
"Unlisted",
"Followers",
"Mentioned"
// Where should we be saving strings..
});
visibility.setPreferredSize(new Dimension(64, 24));
submit = new JButton("Submit");
submit.addActionListener(this);
Box bottom = Box.createHorizontalBox();
bottom.add(Box.createGlue());
bottom.add(textLength);
bottom.add(Box.createHorizontalStrut(12));
bottom.add(visibility);
bottom.add(Box.createHorizontalStrut(12));
bottom.add(submit);
text = new JTextArea();
text.setLineWrap(true);
text.setWrapStyleWord(true);
text.setFont(text.getFont().deriveFont(16f));
text.setBorder(bc);
text.addCaretListener(this);
text.addKeyListener(this);
setLayout(new BorderLayout(0, 8));
add(top, BorderLayout.NORTH);
add(text, BorderLayout.CENTER);
add(bottom, BorderLayout.SOUTH);
setBorder(b1);
}
}