Added delete feature

This commit is contained in:
Snowyfox 2022-04-27 21:56:25 -04:00
parent 26d4e8c97a
commit 0590cc6c19
6 changed files with 246 additions and 54 deletions

View File

@ -51,7 +51,7 @@ ComposeWindow extends JFrame {
{
composition = new Composition();
composition.text = "";
composition.visibility = PostVisibility.MENTIONED;
composition.visibility = PostVisibility.UNLISTED;
composition.replyToPostId = null;
composition.contentWarning = null;
syncDisplayToComposition();

View File

@ -351,6 +351,27 @@ MastodonApi {
catch (IOException eIo) { handler.connectionFailed(eIo); }
}
public void
deletePost(String postId, RequestListener handler)
{
String token = accessToken.get("access_token").value;
String url = instanceUrl + "/api/v1/statuses/" + postId;
try
{
URL endpoint = new URL(url);
HttpURLConnection conn;
conn = (HttpURLConnection)endpoint.openConnection();
String s1 = "Bearer " + token;
conn.setRequestProperty("Authorization", s1);
conn.setRequestMethod("DELETE");
conn.connect();
doStandardJsonReturn(conn, handler);
}
catch (IOException eIo) { handler.connectionFailed(eIo); }
}
public void
getAccounts(String query, RequestListener handler)
{

View File

@ -132,13 +132,14 @@ NotificationsWindow extends JFrame {
if (n.type != NotificationType.FOLLOW)
{
Tree<String> post = t.get("status");
String pid = post.get("id").value;
String ptext = post.get("content").value;
String pid, phtml, ptext;
pid = post.get("id").value;
phtml = post.get("content").value;
ptext =
TimelineComponent
.textApproximation(phtml);
n.postId = pid;
n.postText = ptext;
// Should we ask TimelineWindow for help here?
// Or should we break our text parsers into
// a separate class?
}
notifications.add(n);
@ -162,7 +163,7 @@ NotificationsWindow extends JFrame {
notifications = new ArrayList<>();
display = new NotificationsComponent(this);
display.setPreferredSize(new Dimension(256, 400));
display.setPreferredSize(new Dimension(256, 260));
setContentPane(display);
pack();
@ -190,7 +191,7 @@ implements ActionListener {
// - -%- -
static final int
ROW_COUNT = 16;
ROW_COUNT = 10;
// ---%-@-%---
@ -203,7 +204,16 @@ implements ActionListener {
Notification n = notifications.get(o);
NotificationComponent c = rows.get(o);
c.setName(n.actorName);
c.setType(n.type.toString());
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);
}
}
@ -279,13 +289,13 @@ implements ComponentListener {
componentResized(ComponentEvent eC)
{
int w = getWidth(), h = getHeight();
name.setPreferredSize(new Dimension(w * 4 / 10, h));
type.setPreferredSize(new Dimension(w * 3 / 10, h));
text.setPreferredSize(new Dimension(w * 2 / 10, h));
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 * 4 / 10, h));
type.setMaximumSize(new Dimension(w * 3 / 10, h));
text.setMaximumSize(new Dimension(w * 2 / 10, 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
@ -301,9 +311,13 @@ implements ComponentListener {
NotificationComponent()
{
Font f1 = new Font("Dialog", Font.PLAIN, 12);
Font f2 = new Font("Dialog", Font.PLAIN, 10);
Font f3 = new Font("Dialog", Font.ITALIC, 12);
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();
@ -314,17 +328,16 @@ implements ComponentListener {
type.setHorizontalAlignment(JLabel.RIGHT);
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(Box.createHorizontalStrut(4));
add(name);
add(Box.createHorizontalStrut(4));
add(Box.createHorizontalStrut(8));
add(type);
add(Box.createHorizontalStrut(4));
add(Box.createHorizontalStrut(8));
add(text);
add(Box.createHorizontalStrut(4));
this.addComponentListener(this);
setBorder(
BorderFactory.createMatteBorder
(1, 0, 0, 0, new Color(0, 0, 0, 25))
);
setBorder(b1);
}
}

View File

@ -2,7 +2,7 @@
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.JButton;
import javax.swing.JLabel;
@ -86,6 +86,10 @@ implements ActionListener {
postDisplay.setAuthorName(an);
postDisplay.setAuthorId(author.get("acct").value);
String aid = author.get("id").value;
String oid = api.getAccountDetails().get("id").value;
postDisplay.setDeleteEnabled(aid.equals(oid));
String avurl = author.get("avatar").value;
postDisplay.setAuthorAvatar(ImageApi.remote(avurl));
@ -255,7 +259,7 @@ implements ActionListener {
if (vs.equals("unlisted")) v = PostVisibility.UNLISTED;
if (vs.equals("private")) v = PostVisibility.FOLLOWERS;
if (vs.equals("direct")) v = PostVisibility.MENTIONED;
Composition c = new Composition();
c.contentWarning = cw;
c.text = id1.equals(id2) ? "" : "@" + authorId + " ";
@ -300,6 +304,112 @@ implements ActionListener {
}
}
public void
deletePost(boolean redraft)
{
postDisplay.setCursor(new Cursor(Cursor.WAIT_CURSOR));
postDisplay.setDeleteEnabled(false);
postDisplay.paintImmediately(postDisplay.getBounds());
if (redraft)
{
String html = post.get("content").value;
StringBuilder b = new StringBuilder();
Tree<String> nodes;
nodes = RudimentaryHTMLParser.depthlessRead(html);
// We have to salvage whatever we can from the HTML.
for (Tree<String> node: nodes)
{
if (node.key.equals("text"))
{
b.append(node.value);
}
if (node.key.equals("emoji"))
{
b.append(":" + node.value + ":");
}
if (node.key.equals("tag"))
{
if (node.get(0).key.equals("/p"))
b.append("\n\n");
if (node.get(0).key.equals("br"))
b.append("\n");
if (node.get(0).key.equals("a")) {
b.append(node.get("href").value);
b.append(" ");
continue;
/*
* We don't omit the contents of the <a>
* which is an automatic label, but we'll
* need a non-depthless parser to omit that.
* For now prioritise not losing anything
* from our composition.
*/
}
// I think that's all. I hope.
}
}
String cw = post.get("spoiler_text").value;
String vs = post.get("visibility").value;
PostVisibility v = null;
if (vs.equals("public")) v = PostVisibility.PUBLIC;
if (vs.equals("unlisted")) v = PostVisibility.UNLISTED;
if (vs.equals("private")) v = PostVisibility.FOLLOWERS;
if (vs.equals("direct")) v = PostVisibility.MENTIONED;
String replyTo = post.get("in_reply_to_id").value;
Composition c = new Composition();
c.contentWarning = cw;
c.text = b.toString();
c.visibility = v;
c.replyToPostId = replyTo;
ComposeWindow w = primaire.getComposeWindow();
w.setLocation(getX(), getY() + 100);
w.setVisible(true);
w.setComposition(c);
}
api.deletePost(post.get("id").value, new RequestListener() {
public void
connectionFailed(IOException eIo)
{
JOptionPane.showMessageDialog(
PostWindow.this,
"Failed to delete post.."
+ "\n" + eIo.getMessage()
);
}
public void
requestFailed(int httpCode, Tree<String> json)
{
JOptionPane.showMessageDialog(
PostWindow.this,
"Failed to delete post.."
+ "\n" + json.get("error").value
+ "\n(HTTP code: " + httpCode + ")"
);
}
public void
requestSucceeded(Tree<String> json)
{
setVisible(false);
}
});
postDisplay.setCursor(null);
postDisplay.setDeleteEnabled(true);
postDisplay.paintImmediately(postDisplay.getBounds());
if (!isVisible()) dispose();
}
// - -%- -
public void
@ -379,6 +489,13 @@ implements ActionListener {
profile,
media;
private JPopupMenu
miscMenu;
private JMenuItem
deletePost,
redraftPost;
// ---%-@-%---
public void
@ -475,6 +592,13 @@ implements ActionListener {
favouriteBoost.setEnabled(a);
}
public void
setDeleteEnabled(boolean a)
{
deletePost.setEnabled(a);
redraftPost.setEnabled(a);
}
public void
setMediaPreview(Image n) { media.setImage(n); }
@ -510,7 +634,14 @@ implements ActionListener {
if (src == replyMisc)
{
if (command.startsWith("reply")) primaire.reply();
if (command.startsWith("reply"))
primaire.reply();
if (command.startsWith("misc"))
{
int rx = replyMisc.getWidth() / 2;
int ry = replyMisc.getHeight() - miscMenu.getHeight();
miscMenu.show(replyMisc, rx, ry);
}
return;
}
@ -531,7 +662,20 @@ implements ActionListener {
{
primaire.openMedia();
return;
}
}
if (src == deletePost)
{
primaire.deletePost(false);
return;
}
if (src == redraftPost)
{
primaire.deletePost(true);
return;
}
}
protected void
@ -584,6 +728,14 @@ implements ActionListener {
nextPrev.addActionListener(this);
media.addActionListener(this);
deletePost = new JMenuItem("Delete post");
redraftPost = new JMenuItem("Delete and redraft post");
deletePost.addActionListener(this);
redraftPost.addActionListener(this);
miscMenu = new JPopupMenu();
miscMenu.add(deletePost);
miscMenu.add(redraftPost);
Box buttons = Box.createVerticalBox();
buttons.setOpaque(false);
buttons.add(profile);

View File

@ -26,26 +26,6 @@ RudimentaryHTMLParser {
}
}
public static String
stripTags(String html)
{
StringBuilder returnee = new StringBuilder();
for (Tree<String> node: depthlessRead(html))
{
if (node.key.equals("tag")) continue;
if (node.key.equals("emoji"))
{
returnee.append(":" + node.value + ":");
}
if (node.key.equals("text"))
{
returnee.append(node.value);
}
}
return returnee.toString();
}
// - -%- -
private static Tree<String>

View File

@ -450,7 +450,7 @@ implements ActionListener {
}
}
// - -%- -
// - -%- -
private static String
plainify(String html)
@ -620,12 +620,10 @@ implements
String html = p.get("content").value;
String cw = p.get("spoiler_text").value;
if (!cw.isEmpty()) {
if (!cw.isEmpty())
c.setBottom("(" + cw + ")");
}
else {
c.setBottom(RudimentaryHTMLParser.stripTags(html) + " ");
}
else
c.setBottom(textApproximation(html) + " ");
}
for (int o = posts.size(); o < postPreviews.size(); ++o)
{
@ -781,6 +779,34 @@ implements
public void
keyReleased(KeyEvent eK) { }
// - -%- -
public static String
textApproximation(String html)
{
StringBuilder returnee = new StringBuilder();
Tree<String> nodes = RudimentaryHTMLParser.depthlessRead(html);
Tree<String> first = nodes.get(0);
for (Tree<String> node: nodes)
{
if (node.key.equals("tag"))
{
if (node.get(0).key.equals("br"))
returnee.append("; ");
if (node.get(0).key.equals("p") && node != first)
returnee.append("; ");
}
if (node.key.equals("emoji"))
{
returnee.append(":" + node.value + ":");
}
if (node.key.equals("text"))
{
returnee.append(node.value);
}
}
return returnee.toString();
}
// ---%-@-%---
TimelineComponent(TimelineWindow primaire)