/* copyright This file is part of JKomasto2. Written in 2022 by Usawashi This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . copyright */ 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)); } }