import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.BorderFactory; import javax.swing.border.Border; import java.awt.Font; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.BorderLayout; import java.util.List; import java.util.ArrayList; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.Cursor; import cafe.biskuteri.hinoki.Tree; import java.io.IOException; import java.awt.event.ComponentListener; import java.awt.event.ComponentEvent; class NotificationsWindow extends JFrame { private JKomasto primaire; private List notifications; private MastodonApi api; // - -%- - private NotificationsComponent display; // - -%- - private static int ROW_COUNT = NotificationsComponent.ROW_COUNT; // ---%-@-%--- public void displayEntity(Tree entity) { notifications = new ArrayList<>(); for (Tree t: entity) { Notification n = new Notification(); n.id = t.get("id").value; String type = t.get("type").value; if (type.equals("favourite")) n.type = NotificationType.FAVOURITE; else if (type.equals("reblog")) n.type = NotificationType.BOOST; else if (type.equals("mention")) n.type = NotificationType.MENTION; else if (type.equals("follow")) n.type = NotificationType.FOLLOW; else if (type.equals("follow_request")) n.type = NotificationType.FOLLOWREQ; else if (type.equals("poll")) n.type = NotificationType.POLL; else if (type.equals("status")) n.type = NotificationType.ALERT; Tree actor = t.get("account"); String aid, aname, adisp; aid = actor.get("id").value; aname = actor.get("username").value; adisp = actor.get("display_name").value; if (!adisp.isEmpty()) n.actorName = adisp; else n.actorName = aname; n.actorNumId = aid; if (n.type != NotificationType.FOLLOW) { Tree post = t.get("status"); String pid, phtml, ptext; pid = post.get("id").value; phtml = post.get("content").value; ptext = TimelineComponent.textApproximation(phtml); n.postId = pid; n.postText = ptext; } notifications.add(n); } } public void showLatestPage() { fetchPage(null, null); display.showNotifications(notifications); } public void showPrevPage() { assert !notifications.isEmpty(); fetchPage(null, notifications.get(0).id); if (notifications.size() < ROW_COUNT) showLatestPage(); display.showNotifications(notifications); } public void showNextPage() { assert !notifications.isEmpty(); int last = notifications.size() - 1; fetchPage(notifications.get(last).id, null); display.showNotifications(notifications); } // - -%- - private void fetchPage(String maxId, String minId) { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); api.getNotifications( ROW_COUNT, maxId, minId, new RequestListener() { public void connectionFailed(IOException eIo) { eIo.printStackTrace(); } public void requestFailed(int httpCode, Tree json) { System.err.println(httpCode + json.get("error").value); } public void requestSucceeded(Tree json) { displayEntity(json); } } ); display.setCursor(null); repaint(); } // ---%-@-%--- NotificationsWindow(JKomasto primaire) { super("Notifications"); this.primaire = primaire; this.api = primaire.getMastodonApi(); notifications = new ArrayList<>(); display = new NotificationsComponent(this); display.setPreferredSize(new Dimension(256, 260)); setContentPane(display); pack(); setDefaultCloseOperation(DISPOSE_ON_CLOSE); setVisible(true); } } class NotificationsComponent extends JPanel implements ActionListener { private NotificationsWindow primaire; private JButton prev, next; // - -%- - private List rows; // - -%- - static final int ROW_COUNT = 10; // ---%-@-%--- public void showNotifications(List notifications) { assert notifications.size() == rows.size(); for (int o = 0; o < rows.size(); ++o) { Notification n = notifications.get(o); NotificationComponent c = rows.get(o); c.setName(n.actorName); switch (n.type) { case MENTION: c.setType("mentioned"); break; case BOOST: c.setType("boosted"); break; case FAVOURITE: c.setType("favourited"); break; case FOLLOW: c.setType("followed"); break; case FOLLOWREQ: c.setType("req. follow"); break; case POLL: c.setType("poll ended"); break; case ALERT: c.setType("posted"); break; } c.setText(n.postText); } } // - -%- - public void actionPerformed(ActionEvent eA) { if (eA.getSource() == prev) primaire.showPrevPage(); if (eA.getSource() == next) primaire.showNextPage(); } // ---%-@-%--- NotificationsComponent(NotificationsWindow primaire) { this.primaire = primaire; Border b = BorderFactory.createEmptyBorder(8, 8, 8, 8); rows = new ArrayList<>(); for (int n = ROW_COUNT; n > 0; --n) rows.add(new NotificationComponent()); prev = new JButton("<"); next = new JButton(">"); prev.addActionListener(this); next.addActionListener(this); JPanel centre = new JPanel(); centre.setLayout(new GridLayout(ROW_COUNT, 1)); for (NotificationComponent c: rows) centre.add(c); Box bottom = Box.createHorizontalBox(); bottom.add(Box.createGlue()); bottom.add(prev); bottom.add(Box.createHorizontalStrut(8)); bottom.add(next); bottom.setBorder(b); setLayout(new BorderLayout()); add(centre); add(bottom, BorderLayout.SOUTH); } } class NotificationComponent extends JComponent implements ComponentListener { private JLabel type; private JLabel name, text; // ---%-@-%--- public void setType(String n) { type.setText(n); } public void setName(String n) { name.setText(n); } public void setText(String n) { text.setText(n); } // - -%- - public void componentResized(ComponentEvent eC) { int w = getWidth(), h = getHeight(); name.setPreferredSize(new Dimension(w * 7 / 20, h)); type.setPreferredSize(new Dimension(w * 6 / 20, h)); text.setPreferredSize(new Dimension(w * 5 / 20, h)); name.setMaximumSize(new Dimension(w * 7 / 20, h)); type.setMaximumSize(new Dimension(w * 6 / 20, h)); text.setMaximumSize(new Dimension(w * 5 / 20, h)); } public void componentShown(ComponentEvent eC) { } public void componentHidden(ComponentEvent eC) { } public void componentMoved(ComponentEvent eC) { } // ---%-@-%--- NotificationComponent() { Font f = new Font("Dialog", Font.PLAIN, 12); Font f1 = f.deriveFont(Font.PLAIN, 14); Font f2 = f.deriveFont(Font.PLAIN, 11); Font f3 = f.deriveFont(Font.ITALIC, 14); Color c = new Color(0, 0, 0, 25); Border b1 = BorderFactory.createMatteBorder(0, 0, 1, 0, c); name = new JLabel(); type = new JLabel(); text = new JLabel(); name.setFont(f1); type.setFont(f2); text.setFont(f3); type.setHorizontalAlignment(JLabel.RIGHT); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); add(Box.createHorizontalStrut(4)); add(name); add(Box.createHorizontalStrut(8)); add(type); add(Box.createHorizontalStrut(8)); add(text); add(Box.createHorizontalStrut(4)); this.addComponentListener(this); setBorder(b1); } }