mirror of
https://gitlab.com/biskuteri-cafe/JKomasto2.git
synced 2024-11-20 04:54:50 +01:00
e6fea4c061
(Before this, JKomasto and sometimes the Mastodon web client would get '411 Record Not Found' when submitting the same text after deleting and redrafting. Presumably the Mastodon server caches both whether an idempotency key was fulfilled and which post it leads to, and for some reason it looks up the second and fails.)
428 lines
11 KiB
Java
428 lines
11 KiB
Java
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JTextArea;
|
|
import javax.swing.JScrollPane;
|
|
import java.awt.Graphics;
|
|
import java.awt.Cursor;
|
|
import java.awt.Image;
|
|
import java.awt.Dimension;
|
|
import java.awt.Color;
|
|
import java.awt.Shape;
|
|
import java.awt.Font;
|
|
import java.awt.FontMetrics;
|
|
import java.awt.geom.Ellipse2D;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.ActionEvent;
|
|
|
|
class
|
|
ProfileWindow extends JFrame {
|
|
|
|
private JKomasto
|
|
primaire;
|
|
|
|
private MastodonApi
|
|
api;
|
|
|
|
private Account
|
|
account;
|
|
|
|
// - -%- -
|
|
|
|
private ProfileComponent
|
|
display;
|
|
|
|
// ---%-@-%---
|
|
|
|
public void
|
|
use(Account account)
|
|
{
|
|
this.account = account;
|
|
|
|
account.resolveAvatar();
|
|
display.setAvatar(account.avatar);
|
|
|
|
display.setAccountID(account.id);
|
|
display.setDisplayName(account.name);
|
|
|
|
int n1 = account.followedCount;
|
|
int n2 = account.followerCount;
|
|
display.setFollowedAndFollowers(n1 + " & " + n2);
|
|
|
|
int n3 = account.postCount;
|
|
String hs;
|
|
if (n3 >= 1000) hs = "~" + (n3 / 1000) + "K";
|
|
else if (n3 >= 300) hs = "~" + (n3 / 100) + "00";
|
|
else hs = Integer.toString(n3);
|
|
hs += " posts since ";
|
|
switch (account.creationDate.getMonth())
|
|
{
|
|
case JANUARY: hs += "Jan"; break;
|
|
case FEBRUARY: hs += "Feb"; break;
|
|
case MARCH: hs += "Mar"; break;
|
|
case APRIL: hs += "Apr"; break;
|
|
case MAY: hs += "May"; break;
|
|
case JUNE: hs += "Jun"; break;
|
|
case JULY: hs += "Jul"; break;
|
|
case AUGUST: hs += "Aug"; break;
|
|
case SEPTEMBER: hs += "Sept"; break;
|
|
case OCTOBER: hs += "Oct"; break;
|
|
case NOVEMBER: hs += "Nov"; break;
|
|
case DECEMBER: hs += "Dec"; break;
|
|
/*
|
|
* (悪) We're hardcoding for English right now,
|
|
* but later we need to localise properly using
|
|
* Month#getDisplayName. Right now I'm just
|
|
* finishing this component ASAP for English.
|
|
*/
|
|
}
|
|
hs += " " + account.creationDate.getYear();
|
|
display.setHistory(hs);
|
|
|
|
for (int i = 1; i <= 4; ++i)
|
|
{
|
|
if (i > account.fields.length)
|
|
{
|
|
display.setField(i, "", "");
|
|
continue;
|
|
}
|
|
String[] field = account.fields[i - 1];
|
|
display.setField(i, field[0], field[1]);
|
|
}
|
|
|
|
display.setDescription(account.description);
|
|
|
|
setTitle(account.name + " - JKomasto");
|
|
}
|
|
|
|
// - -%- -
|
|
|
|
public void
|
|
seePosts()
|
|
{
|
|
display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
|
|
|
TimelineWindow w = new TimelineWindow(primaire);
|
|
w.showAuthorPosts(account.numId);
|
|
w.showLatestPage();
|
|
w.setLocationRelativeTo(this);
|
|
w.setVisible(true);
|
|
|
|
display.setCursor(null);
|
|
}
|
|
|
|
// ---%-@-%---
|
|
|
|
ProfileWindow(JKomasto primaire)
|
|
{
|
|
super("Profile window - JKomasto");
|
|
|
|
this.primaire = primaire;
|
|
this.api = primaire.getMastodonApi();
|
|
|
|
this.display = new ProfileComponent(this);
|
|
add(display);
|
|
pack();
|
|
|
|
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
|
}
|
|
|
|
}
|
|
|
|
class
|
|
ProfileComponent extends JPanel
|
|
implements ActionListener {
|
|
|
|
private ProfileWindow
|
|
primaire;
|
|
|
|
// - -5- -
|
|
|
|
private Image
|
|
avatar;
|
|
|
|
private JLabel
|
|
accountIdLabel,
|
|
accountId,
|
|
displayNameLabel,
|
|
displayName,
|
|
followedLabel,
|
|
followed,
|
|
historyLabel,
|
|
history,
|
|
field1Label,
|
|
field1,
|
|
field2Label,
|
|
field2,
|
|
field3Label,
|
|
field3,
|
|
field4Label,
|
|
field4;
|
|
|
|
private JTextArea
|
|
description;
|
|
|
|
private JScrollPane
|
|
scroll;
|
|
|
|
private JButton
|
|
seePosts;
|
|
|
|
private int
|
|
dx1, dx2, dx3, dx4, dy1, dy2, dy3, dy4;
|
|
|
|
// ---%-@-%---
|
|
|
|
public void
|
|
setAvatar(Image avatar)
|
|
{
|
|
this.avatar = avatar;
|
|
}
|
|
|
|
public void
|
|
setAccountID(String id)
|
|
{
|
|
accountId.setText(id);
|
|
}
|
|
|
|
public void
|
|
setDisplayName(String name)
|
|
{
|
|
displayName.setText(name);
|
|
}
|
|
|
|
public void
|
|
setFollowedAndFollowers(String text)
|
|
{
|
|
followed.setText(text);
|
|
}
|
|
|
|
public void
|
|
setHistory(String text)
|
|
{
|
|
history.setText(text);
|
|
}
|
|
|
|
public void
|
|
setField(int index, String name, String value)
|
|
{
|
|
assert index >= 1 && index <= 4;
|
|
JLabel label = null, field = null;
|
|
switch (index)
|
|
{
|
|
case 1: label = field1Label; field = field1; break;
|
|
case 2: label = field2Label; field = field2; break;
|
|
case 3: label = field3Label; field = field3; break;
|
|
case 4: label = field4Label; field = field4; break;
|
|
}
|
|
label.setText(name);
|
|
field.setText(value);
|
|
}
|
|
|
|
public void
|
|
setDescription(String html)
|
|
{
|
|
description.setText(html);
|
|
}
|
|
|
|
// - -%- -
|
|
|
|
public void
|
|
actionPerformed(ActionEvent eA)
|
|
{
|
|
assert eA.getSource() == seePosts;
|
|
primaire.seePosts();
|
|
}
|
|
|
|
protected void
|
|
paintComponent(Graphics g)
|
|
{
|
|
g.clearRect(0, 0, getWidth(), getHeight());
|
|
|
|
int w = getWidth(), h = getHeight();
|
|
|
|
int aw = 256;
|
|
int ah = 256;
|
|
int ax = (w - aw) / 2;
|
|
int ay = 10;
|
|
int acx = ax + (aw / 2);
|
|
int acy = ay + (ah / 2);
|
|
Shape defaultClip = g.getClip();
|
|
g.setClip(new Ellipse2D.Float(ax, ay, aw, ah));
|
|
g.drawImage(avatar, ax, ay, aw, ah, this);
|
|
g.setClip(defaultClip);
|
|
|
|
g.setColor(new Color(0, 0, 0, 50));
|
|
g.fillRect(0, acy - dy1, acx - dx1, 2);
|
|
g.fillRect(0, acy - dy2, acx - dx2, 2);
|
|
g.fillRect(0, acy + dy3, acx - dx3, 2);
|
|
g.fillRect(0, acy + dy4, acx - dx4, 2);
|
|
g.fillRect(acx + dx1, acy - dy1, w - (acx + dx1), 2);
|
|
g.fillRect(acx + dx2, acy - dy2, w - (acx + dx2), 2);
|
|
g.fillRect(acx + dx3, acy + dy3, w - (acx + dx3), 2);
|
|
g.fillRect(acx + dx4, acy + dy4, w - (acx + dx4), 2);
|
|
|
|
((java.awt.Graphics2D)g).setRenderingHint(
|
|
java.awt.RenderingHints.KEY_ANTIALIASING,
|
|
java.awt.RenderingHints.VALUE_ANTIALIAS_ON
|
|
);
|
|
}
|
|
|
|
public void
|
|
doLayout()
|
|
{
|
|
final double TAU = 2 * Math.PI;
|
|
|
|
int w = getWidth(), h = getHeight();
|
|
int aw = 256;
|
|
int ah = 256;
|
|
int ax = (w - aw) / 2;
|
|
int ay = 10;
|
|
int acx = ax + (aw / 2);
|
|
int acy = ay + (ah / 2);
|
|
|
|
dx1 = (int)((aw * 11/20) * Math.cos(TAU * 45 / 360));
|
|
dx2 = (int)((aw * 11/20) * Math.cos(TAU * 15 / 360));
|
|
dx3 = dx2;
|
|
dx4 = dx1;
|
|
dy1 = (int)((ah / 2) * Math.sin(TAU * 45 / 360));
|
|
dy2 = (int)((ah / 2) * Math.sin(TAU * 15 / 360));
|
|
dy3 = dy2;
|
|
dy4 = dy1;
|
|
|
|
FontMetrics fm = getFontMetrics(field1.getFont());
|
|
int lh = fm.getAscent() * 9 / 8;
|
|
|
|
accountIdLabel.setLocation(10, acy - dy1 - lh - 1);
|
|
accountId.setLocation(10, acy - dy1 + 1);
|
|
accountIdLabel.setSize(acx - dx1 - 16, lh);
|
|
accountId.setSize(acx - dx1 - 24, lh);
|
|
|
|
displayNameLabel.setLocation(10, acy - dy2 - lh - 1);
|
|
displayName.setLocation(10, acy - dy2 + 1);
|
|
displayNameLabel.setSize(acx - dx2 - 16, lh);
|
|
displayName.setSize(acx - dx2 - 24, lh);
|
|
|
|
followedLabel.setLocation(10, acy + dy3 - lh - 1);
|
|
followed.setLocation(10, acy + dy3 + 1);
|
|
followedLabel.setSize(acx - dx3 - 24, lh);
|
|
followed.setSize(acx - dx3 - 16, lh);
|
|
|
|
historyLabel.setLocation(10, acy + dy4 - lh - 1);
|
|
history.setLocation(10, acy + dy4 + 1);
|
|
historyLabel.setSize(acx - dx4 - 24, lh);
|
|
history.setSize(acx - dx4 - 16, lh);
|
|
|
|
field1Label.setLocation(acx + dx1 + 16, acy - dy1 - lh - 1);
|
|
field1.setLocation(acx + dx1 + 24, acy - dy1 + 1);
|
|
field1Label.setSize(w - 10 - (acy + dx1 + 16), lh);
|
|
field1.setSize(w - 10 - (acy + dx1 + 24), lh);
|
|
|
|
field2Label.setLocation(acx + dx2 + 16, acy - dy2 - lh - 1);
|
|
field2.setLocation(acx + dx2 + 24, acy - dy2 + 1);
|
|
field2Label.setSize((w - 10) - (acy + dx2 + 16), lh);
|
|
field2.setSize((w - 10) - (acy + dx2 + 24), lh);
|
|
|
|
field3Label.setLocation(acx + dx3 + 24, acy + dy3 - lh - 1);
|
|
field3.setLocation(acx + dx3 + 16, acy + dy3 + 1);
|
|
field3Label.setSize((w - 10) - (acy + dx3 + 24), lh);
|
|
field3.setSize((w - 10) - (acy + dx3 + 16), lh);
|
|
|
|
field4Label.setLocation(acx + dx4 + 24, acy + dy4 - lh - 1);
|
|
field4.setLocation(acx + dx4 + 16, acy + dy4 + 1);
|
|
field4Label.setSize((w - 10) - (acy + dx4 + 24), lh);
|
|
field4.setSize((w - 10) - (acy + dx4 + 16), lh);
|
|
|
|
seePosts.setLocation(10, h - 10 - 24);
|
|
seePosts.setSize((w - 40) / 4, 24);
|
|
|
|
scroll.setLocation(10, (ay + ah) + 10);
|
|
scroll.setSize(w - 20, seePosts.getY() - 10 - scroll.getY());
|
|
}
|
|
|
|
// ---%-@-%---
|
|
|
|
ProfileComponent(ProfileWindow primaire)
|
|
{
|
|
this.primaire = primaire;
|
|
|
|
Font f1 = new Font("VL Gothic", Font.PLAIN, 16);
|
|
Font f2 = new Font("VL Gothic", Font.PLAIN, 14);
|
|
|
|
int a = JLabel.RIGHT;
|
|
accountIdLabel = new JLabel("Account ID", a);
|
|
accountId = new JLabel("", a);
|
|
displayNameLabel = new JLabel("Display name", a);
|
|
displayName = new JLabel("", a);
|
|
followedLabel = new JLabel("Followed & followers", a);
|
|
followed = new JLabel("", a);
|
|
historyLabel = new JLabel("History", a);
|
|
history = new JLabel("", a);
|
|
field1Label = new JLabel("");
|
|
field1 = new JLabel("");
|
|
field2Label = new JLabel("");
|
|
field2 = new JLabel("");
|
|
field3Label = new JLabel("");
|
|
field3 = new JLabel("");
|
|
field4Label = new JLabel("");
|
|
field4 = new JLabel("");
|
|
|
|
accountIdLabel.setFont(f1);
|
|
accountId.setFont(f1);
|
|
displayNameLabel.setFont(f1);
|
|
displayName.setFont(f1);
|
|
followedLabel.setFont(f1);
|
|
followed.setFont(f1);
|
|
historyLabel.setFont(f1);
|
|
history.setFont(f2);
|
|
field1Label.setFont(f1);
|
|
field1.setFont(f2);
|
|
field2Label.setFont(f1);
|
|
field2.setFont(f2);
|
|
field3Label.setFont(f1);
|
|
field3.setFont(f2);
|
|
field4Label.setFont(f1);
|
|
field4.setFont(f2);
|
|
|
|
description = new JTextArea();
|
|
description.setEditable(false);
|
|
description.setLineWrap(true);
|
|
description.setBackground(null);
|
|
description.setFont(f1);
|
|
|
|
scroll = new JScrollPane(
|
|
description,
|
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
|
);
|
|
scroll.setBorder(null);
|
|
|
|
seePosts = new JButton("See posts");
|
|
seePosts.addActionListener(this);
|
|
|
|
setLayout(null);
|
|
add(accountIdLabel);
|
|
add(accountId);
|
|
add(displayNameLabel);
|
|
add(displayName);
|
|
add(followedLabel);
|
|
add(followed);
|
|
add(historyLabel);
|
|
add(history);
|
|
add(field1Label);
|
|
add(field1);
|
|
add(field2Label);
|
|
add(field2);
|
|
add(field3Label);
|
|
add(field3);
|
|
add(field4Label);
|
|
add(field4);
|
|
add(scroll);
|
|
add(seePosts);
|
|
setPreferredSize(new Dimension(640, 480));
|
|
}
|
|
|
|
}
|