mirror of
https://gitlab.com/biskuteri-cafe/JKomasto2.git
synced 2024-11-20 03:54:50 +01:00
Added reactive updating to TimelineWindow and NotificationsWindow
Thread unsafe, will probably explode eventually
This commit is contained in:
parent
db304ad2df
commit
4ed5b3536c
@ -32,8 +32,8 @@ JKomasto {
|
||||
private NotificationsWindow
|
||||
notificationsWindow;
|
||||
|
||||
private TimelineWindowUpdater
|
||||
timelineWindowUpdater;
|
||||
private WindowUpdater
|
||||
windowUpdater;
|
||||
|
||||
private MastodonApi
|
||||
api;
|
||||
@ -46,22 +46,14 @@ JKomasto {
|
||||
public void
|
||||
finishedLogin()
|
||||
{
|
||||
autoViewWindow.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
timelineWindow.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
notificationsWindow.showLatestPage();
|
||||
timelineWindow.showLatestPage();
|
||||
timelineWindow.setLocationByPlatform(true);
|
||||
notificationsWindow.showLatestPage();
|
||||
timelineWindow.setVisible(true);
|
||||
loginWindow.dispose();
|
||||
|
||||
autoViewWindow.setTitle("Auto view - JKomasto");
|
||||
//autoViewWindow.setVisible(true);
|
||||
|
||||
loginWindow.dispose();
|
||||
autoViewWindow.setCursor(null);
|
||||
timelineWindow.setCursor(null);
|
||||
|
||||
timelineWindowUpdater.addWindow(timelineWindow);
|
||||
}
|
||||
|
||||
public PostWindow
|
||||
@ -76,10 +68,16 @@ JKomasto {
|
||||
public NotificationsWindow
|
||||
getNotificationsWindow() { return notificationsWindow; }
|
||||
|
||||
public WindowUpdater
|
||||
getWindowUpdater() { return windowUpdater; }
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
public static void
|
||||
main(String... args) { new JKomasto(); }
|
||||
main(String... args)
|
||||
{
|
||||
new JKomasto().loginWindow.setVisible(true);
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
@ -87,6 +85,7 @@ JKomasto {
|
||||
JKomasto()
|
||||
{
|
||||
api = new MastodonApi();
|
||||
windowUpdater = new WindowUpdater(this);
|
||||
|
||||
timelineWindow = new TimelineWindow(this);
|
||||
composeWindow = new ComposeWindow(this);
|
||||
@ -95,15 +94,16 @@ JKomasto {
|
||||
mediaWindow = new ImageWindow();
|
||||
notificationsWindow = new NotificationsWindow(this);
|
||||
|
||||
autoViewWindow.setTitle("Auto view - JKomasto");
|
||||
|
||||
composeWindow.dispose();
|
||||
autoViewWindow.dispose();
|
||||
timelineWindow.dispose();
|
||||
mediaWindow.dispose();
|
||||
notificationsWindow.dispose();
|
||||
loginWindow.setLocationByPlatform(true);
|
||||
loginWindow.setVisible(true);
|
||||
|
||||
timelineWindowUpdater = new TimelineWindowUpdater(this);
|
||||
timelineWindow.setLocationByPlatform(true);
|
||||
loginWindow.setLocationByPlatform(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import java.io.FileWriter;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
class
|
||||
MastodonApi {
|
||||
@ -440,6 +441,7 @@ MastodonApi {
|
||||
public void
|
||||
monitorTimeline(
|
||||
TimelineType type, ServerSideEventsListener handler)
|
||||
throws InterruptedException
|
||||
{
|
||||
String token = accessToken.get("access_token").value;
|
||||
|
||||
@ -474,11 +476,16 @@ MastodonApi {
|
||||
|
||||
input = new InputStreamReader(conn.getInputStream());
|
||||
BufferedReader br = new BufferedReader(input);
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
String line = br.readLine();
|
||||
if (line != null) handler.lineReceived(line);
|
||||
}
|
||||
}
|
||||
catch (ClosedByInterruptException eIt)
|
||||
{
|
||||
throw new InterruptedException();
|
||||
}
|
||||
catch (IOException eIo) { handler.connectionFailed(eIo); }
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,9 @@ NotificationsWindow extends JFrame {
|
||||
private NotificationsComponent
|
||||
display;
|
||||
|
||||
private boolean
|
||||
showingLatest;
|
||||
|
||||
// - -%- -
|
||||
|
||||
private static int
|
||||
@ -48,7 +51,7 @@ NotificationsWindow extends JFrame {
|
||||
// ---%-@-%---
|
||||
|
||||
public void
|
||||
displayEntity(Tree<String> entity)
|
||||
readEntity(Tree<String> entity)
|
||||
{
|
||||
notifications = new ArrayList<>();
|
||||
for (Tree<String> t: entity)
|
||||
@ -97,20 +100,45 @@ NotificationsWindow extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
refresh()
|
||||
{
|
||||
String firstId = null;
|
||||
if (!showingLatest)
|
||||
{
|
||||
assert !notifications.isEmpty();
|
||||
firstId = notifications.get(0).id;
|
||||
}
|
||||
|
||||
if (fetchPage(firstId, null))
|
||||
{
|
||||
if (notifications.size() < ROW_COUNT) showLatestPage();
|
||||
display.showNotifications(notifications);
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
showLatestPage()
|
||||
{
|
||||
fetchPage(null, null);
|
||||
display.showNotifications(notifications);
|
||||
if (fetchPage(null, null))
|
||||
{
|
||||
display.showNotifications(notifications);
|
||||
showingLatest = true;
|
||||
primaire.getWindowUpdater().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
showPrevPage()
|
||||
{
|
||||
assert !notifications.isEmpty();
|
||||
fetchPage(null, notifications.get(0).id);
|
||||
if (notifications.size() < ROW_COUNT) showLatestPage();
|
||||
display.showNotifications(notifications);
|
||||
if (fetchPage(null, notifications.get(0).id))
|
||||
{
|
||||
if (notifications.size() < ROW_COUNT) showLatestPage();
|
||||
display.showNotifications(notifications);
|
||||
showingLatest = false;
|
||||
primaire.getWindowUpdater().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
@ -118,41 +146,51 @@ NotificationsWindow extends JFrame {
|
||||
{
|
||||
assert !notifications.isEmpty();
|
||||
int last = notifications.size() - 1;
|
||||
fetchPage(notifications.get(last).id, null);
|
||||
display.showNotifications(notifications);
|
||||
if (fetchPage(notifications.get(last).id, null))
|
||||
{
|
||||
display.showNotifications(notifications);
|
||||
showingLatest = false;
|
||||
primaire.getWindowUpdater().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
// - -%- -
|
||||
|
||||
private void
|
||||
private boolean
|
||||
fetchPage(String maxId, String minId)
|
||||
{
|
||||
display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
api.getNotifications(
|
||||
ROW_COUNT, maxId, minId,
|
||||
new RequestListener() {
|
||||
class Handler implements RequestListener {
|
||||
|
||||
public void
|
||||
connectionFailed(IOException eIo)
|
||||
{
|
||||
eIo.printStackTrace();
|
||||
}
|
||||
boolean
|
||||
succeeded = false;
|
||||
|
||||
public void
|
||||
requestFailed(int httpCode, Tree<String> json)
|
||||
{
|
||||
System.err.println(httpCode + json.get("error").value);
|
||||
}
|
||||
// -=%=-
|
||||
|
||||
public void
|
||||
requestSucceeded(Tree<String> json)
|
||||
{
|
||||
displayEntity(json);
|
||||
}
|
||||
}
|
||||
);
|
||||
public void
|
||||
connectionFailed(IOException eIo)
|
||||
{
|
||||
eIo.printStackTrace();
|
||||
}
|
||||
|
||||
public void
|
||||
requestFailed(int httpCode, Tree<String> json)
|
||||
{
|
||||
System.err.println(httpCode + json.get("error").value);
|
||||
}
|
||||
|
||||
public void
|
||||
requestSucceeded(Tree<String> json)
|
||||
{
|
||||
readEntity(json);
|
||||
succeeded = true;
|
||||
}
|
||||
}
|
||||
Handler handler = new Handler();
|
||||
api.getNotifications(ROW_COUNT, maxId, minId, handler);
|
||||
display.setCursor(null);
|
||||
repaint();
|
||||
return handler.succeeded;
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
@ -55,6 +55,9 @@ implements ActionListener {
|
||||
private MastodonApi
|
||||
api;
|
||||
|
||||
private WindowUpdater
|
||||
windowUpdater;
|
||||
|
||||
private TimelinePage
|
||||
page;
|
||||
|
||||
@ -78,6 +81,9 @@ implements ActionListener {
|
||||
private JMenuItem
|
||||
flipToNewestPost;
|
||||
|
||||
private boolean
|
||||
showingLatest;
|
||||
|
||||
// - -%- -
|
||||
|
||||
private static final int
|
||||
@ -158,10 +164,14 @@ implements ActionListener {
|
||||
public void
|
||||
refresh()
|
||||
{
|
||||
assert page.posts != null;
|
||||
assert page.posts.size() != 0;
|
||||
Tree<String> first = page.posts.get(0);
|
||||
String firstId = first.get("id").value;
|
||||
String firstId = null;
|
||||
if (!showingLatest)
|
||||
{
|
||||
assert page.posts != null;
|
||||
assert page.posts.size() != 0;
|
||||
Tree<String> first = page.posts.get(0);
|
||||
firstId = first.get("id").value;
|
||||
}
|
||||
|
||||
display.setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
api.getTimelinePage(
|
||||
@ -241,6 +251,8 @@ implements ActionListener {
|
||||
requestSucceeded(Tree<String> json)
|
||||
{
|
||||
readEntity(json);
|
||||
showingLatest = true;
|
||||
windowUpdater.add(TimelineWindow.this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -294,6 +306,8 @@ implements ActionListener {
|
||||
return;
|
||||
}
|
||||
readEntity(json);
|
||||
showingLatest = false;
|
||||
windowUpdater.remove(TimelineWindow.this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -345,6 +359,8 @@ implements ActionListener {
|
||||
return;
|
||||
}
|
||||
readEntity(json);
|
||||
showingLatest = false;
|
||||
windowUpdater.remove(TimelineWindow.this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -639,6 +655,7 @@ implements ActionListener {
|
||||
{
|
||||
this.primaire = primaire;
|
||||
this.api = primaire.getMastodonApi();
|
||||
this.windowUpdater = primaire.getWindowUpdater();
|
||||
|
||||
getContentPane().setPreferredSize(new Dimension(320, 460));
|
||||
pack();
|
||||
|
@ -1,230 +0,0 @@
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import cafe.biskuteri.hinoki.Tree;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import java.net.URL;
|
||||
|
||||
class
|
||||
TimelineWindowUpdater {
|
||||
|
||||
private JKomasto
|
||||
primaire;
|
||||
|
||||
private MastodonApi
|
||||
api;
|
||||
|
||||
// - -%- -
|
||||
|
||||
private List<TimelineWindow>
|
||||
timelineUpdatees;
|
||||
|
||||
private List<NotificationsWindow>
|
||||
notificationUpdatees;
|
||||
|
||||
private StringBuilder
|
||||
event, data;
|
||||
|
||||
private Clip
|
||||
notificationSound;
|
||||
|
||||
// - -%- -
|
||||
|
||||
private Thread
|
||||
spublic,
|
||||
user;
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
public void
|
||||
addWindow(TimelineWindow updatee)
|
||||
{
|
||||
timelineUpdatees.add(updatee);
|
||||
|
||||
Connection c = new Connection();
|
||||
c.type = updatee.getTimelineType();
|
||||
switch (c.type)
|
||||
{
|
||||
case FEDERATED:
|
||||
case LOCAL:
|
||||
if (spublic != null) return;
|
||||
spublic = new Thread(c);
|
||||
spublic.start();
|
||||
break;
|
||||
case HOME:
|
||||
if (user != null) return;
|
||||
user = new Thread(c);
|
||||
user.start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
addWindow(NotificationsWindow updatee)
|
||||
{
|
||||
notificationUpdatees.add(updatee);
|
||||
|
||||
Connection c = new Connection();
|
||||
c.type = TimelineType.HOME;
|
||||
if (user != null) return;
|
||||
user = new Thread(c);
|
||||
user.start();
|
||||
}
|
||||
|
||||
public void
|
||||
removeWindow(TimelineWindow updatee)
|
||||
{
|
||||
timelineUpdatees.remove(updatee);
|
||||
}
|
||||
|
||||
public void
|
||||
removeWindow(NotificationsWindow updatee)
|
||||
{
|
||||
notificationUpdatees.remove(updatee);
|
||||
}
|
||||
|
||||
// - -%- -
|
||||
|
||||
private void
|
||||
handle(TimelineType type, String event, String data)
|
||||
{
|
||||
assert !data.isEmpty();
|
||||
if (event.isEmpty()) return;
|
||||
|
||||
boolean newPost = event.equals("update");
|
||||
boolean newNotif = event.equals("notification");
|
||||
if (!(newPost || newNotif)) return;
|
||||
|
||||
for (TimelineWindow updatee: filter(type)) {
|
||||
updatee.showLatestPage();
|
||||
}
|
||||
for (NotificationsWindow updatee: notificationUpdatees) {
|
||||
updatee.showLatestPage();
|
||||
}
|
||||
|
||||
if (newNotif)
|
||||
{
|
||||
notificationSound.setFramePosition(0);
|
||||
notificationSound.start();
|
||||
}
|
||||
}
|
||||
|
||||
private List<TimelineWindow>
|
||||
filter(TimelineType type)
|
||||
{
|
||||
List<TimelineWindow> returnee = new ArrayList<>();
|
||||
for (TimelineWindow updatee: timelineUpdatees)
|
||||
if (updatee.getTimelineType() == type)
|
||||
returnee.add(updatee);
|
||||
return returnee;
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
private class
|
||||
Connection
|
||||
implements Runnable, ServerSideEventsListener {
|
||||
|
||||
private TimelineType
|
||||
type;
|
||||
|
||||
// -=-
|
||||
|
||||
private StringBuilder
|
||||
event, data;
|
||||
|
||||
// -=%=-
|
||||
|
||||
public void
|
||||
run()
|
||||
{
|
||||
event = new StringBuilder();
|
||||
data = new StringBuilder();
|
||||
api.monitorTimeline(type, this);
|
||||
// monitorTimeline should not return
|
||||
// until the connection is closed.
|
||||
}
|
||||
|
||||
public void
|
||||
lineReceived(String line)
|
||||
{
|
||||
if (line.startsWith(":")) return;
|
||||
|
||||
if (line.isEmpty())
|
||||
{
|
||||
handle(type, event.toString(), data.toString());
|
||||
event.delete(0, event.length());
|
||||
data.delete(0, event.length());
|
||||
}
|
||||
|
||||
if (line.startsWith("data: "))
|
||||
data.append(line.substring("data: ".length()));
|
||||
|
||||
if (line.startsWith("event: "))
|
||||
event.append(line.substring("event: ".length()));
|
||||
|
||||
/*
|
||||
* Note that I utterly ignore https://html.spec.whatwg.org
|
||||
* /multipage/server-sent-events.html#dispatchMessage.
|
||||
* That is because I am not a browser.
|
||||
*/
|
||||
}
|
||||
|
||||
public void
|
||||
connectionFailed(IOException eIo)
|
||||
{
|
||||
// sais pas dois-je faire..
|
||||
eIo.printStackTrace();
|
||||
}
|
||||
|
||||
public void
|
||||
requestFailed(int httpCode, Tree<String> json)
|
||||
{
|
||||
// mo shiranu
|
||||
System.err.println(httpCode + ", " + json.get("error").value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
TimelineWindowUpdater(JKomasto primaire)
|
||||
{
|
||||
this.primaire = primaire;
|
||||
this.api = primaire.getMastodonApi();
|
||||
|
||||
this.timelineUpdatees = new ArrayList<>();
|
||||
this.notificationUpdatees = new ArrayList<>();
|
||||
|
||||
loadNotificationSound();
|
||||
}
|
||||
|
||||
void
|
||||
loadNotificationSound()
|
||||
{
|
||||
URL url = getClass().getResource("KDE_Dialog_Appear.wav");
|
||||
try {
|
||||
Clip clip = AudioSystem.getClip();
|
||||
clip.open(AudioSystem.getAudioInputStream(url));
|
||||
notificationSound = clip;
|
||||
}
|
||||
catch (LineUnavailableException eLu) {
|
||||
assert false;
|
||||
}
|
||||
catch (UnsupportedAudioFileException eUa) {
|
||||
assert false;
|
||||
}
|
||||
catch (IOException eIo) {
|
||||
assert false;
|
||||
}
|
||||
catch (IllegalArgumentException eIa) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
275
WindowUpdater.java
Normal file
275
WindowUpdater.java
Normal file
@ -0,0 +1,275 @@
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import cafe.biskuteri.hinoki.Tree;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import java.net.URL;
|
||||
|
||||
class
|
||||
WindowUpdater {
|
||||
|
||||
private JKomasto
|
||||
primaire;
|
||||
|
||||
private MastodonApi
|
||||
api;
|
||||
|
||||
// - -%- -
|
||||
|
||||
private List<TimelineWindow>
|
||||
timelineWindows;
|
||||
|
||||
private List<NotificationsWindow>
|
||||
notificationWindows;
|
||||
|
||||
private Clip
|
||||
notificationSound;
|
||||
|
||||
private Connection
|
||||
publicConn,
|
||||
userConn;
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
public void
|
||||
add(TimelineWindow updatee)
|
||||
{
|
||||
if (timelineWindows.contains(updatee)) return;
|
||||
|
||||
timelineWindows.add(updatee);
|
||||
publicConn.reevaluate();
|
||||
userConn.reevaluate();
|
||||
}
|
||||
|
||||
public void
|
||||
add(NotificationsWindow updatee)
|
||||
{
|
||||
if (notificationWindows.contains(updatee)) return;
|
||||
|
||||
notificationWindows.add(updatee);
|
||||
userConn.reevaluate();
|
||||
}
|
||||
|
||||
public void
|
||||
remove(TimelineWindow updatee)
|
||||
{
|
||||
timelineWindows.remove(updatee);
|
||||
publicConn.reevaluate();
|
||||
userConn.reevaluate();
|
||||
}
|
||||
|
||||
public void
|
||||
remove(NotificationsWindow updatee)
|
||||
{
|
||||
notificationWindows.remove(updatee);
|
||||
userConn.reevaluate();
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
private class
|
||||
Connection
|
||||
implements Runnable, ServerSideEventsListener {
|
||||
|
||||
private TimelineType
|
||||
type;
|
||||
|
||||
// -=-
|
||||
|
||||
private Thread
|
||||
thread;
|
||||
|
||||
private StringBuilder
|
||||
event, data;
|
||||
|
||||
// -=%=-
|
||||
|
||||
public void
|
||||
restart()
|
||||
{
|
||||
if (thread != null) stop();
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void
|
||||
stop()
|
||||
{
|
||||
try {
|
||||
thread.interrupt();
|
||||
thread.join();
|
||||
thread = null;
|
||||
}
|
||||
catch (InterruptedException eIt) {
|
||||
assert false;
|
||||
// Who would do that to us..
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
reevaluate()
|
||||
{
|
||||
boolean hasUpdatee = false;
|
||||
|
||||
for (NotificationsWindow updatee: notificationWindows)
|
||||
if (responsibleFor(updatee)) hasUpdatee = true;
|
||||
|
||||
for (TimelineWindow updatee: timelineWindows)
|
||||
if (responsibleFor(updatee)) hasUpdatee = true;
|
||||
|
||||
if (!hasUpdatee && thread != null) stop();
|
||||
if (hasUpdatee && thread == null) restart();
|
||||
}
|
||||
|
||||
// -=-
|
||||
|
||||
private boolean
|
||||
responsibleFor(TimelineWindow updatee)
|
||||
{
|
||||
return type == updatee.getTimelineType();
|
||||
}
|
||||
|
||||
private boolean
|
||||
responsibleFor(NotificationsWindow updatee)
|
||||
{
|
||||
return type == TimelineType.HOME;
|
||||
}
|
||||
|
||||
public void
|
||||
run()
|
||||
{
|
||||
try {
|
||||
event = new StringBuilder();
|
||||
data = new StringBuilder();
|
||||
api.monitorTimeline(type, this);
|
||||
// monitorTimeline should not return
|
||||
// until the connection is closed.
|
||||
}
|
||||
catch (InterruptedException eIt) { }
|
||||
}
|
||||
|
||||
public void
|
||||
lineReceived(String line)
|
||||
{
|
||||
if (line.startsWith(":")) return;
|
||||
|
||||
if (line.isEmpty())
|
||||
{
|
||||
handle(event.toString(), data.toString());
|
||||
event.delete(0, event.length());
|
||||
data.delete(0, event.length());
|
||||
}
|
||||
|
||||
if (line.startsWith("data: "))
|
||||
data.append(line.substring("data: ".length()));
|
||||
|
||||
if (line.startsWith("event: "))
|
||||
event.append(line.substring("event: ".length()));
|
||||
|
||||
/*
|
||||
* Note that I ignore https://html.spec.whatwg.org
|
||||
* /multipage/server-sent-events.html#dispatchMessage.
|
||||
* That is because I am not a browser.
|
||||
*/
|
||||
}
|
||||
|
||||
private void
|
||||
handle(String event, String data)
|
||||
{
|
||||
assert !data.isEmpty();
|
||||
if (event.isEmpty()) return;
|
||||
|
||||
boolean newPost = event.equals("update");
|
||||
boolean newNotif = event.equals("notification");
|
||||
if (!(newPost || newNotif)) return;
|
||||
|
||||
if (newNotif)
|
||||
{
|
||||
notificationSound.setFramePosition(0);
|
||||
notificationSound.start();
|
||||
}
|
||||
|
||||
for (TimelineWindow updatee: timelineWindows)
|
||||
{
|
||||
if (!responsibleFor(updatee)) continue;
|
||||
updatee.refresh();
|
||||
/*
|
||||
* (悪) Note that we're in a separate thread,
|
||||
* and our windows aren't thread-safe. We could
|
||||
* probably make them a bit bananas asking
|
||||
* for a refresh while they're in the middle
|
||||
* of one. Could we add mutexes?
|
||||
*/
|
||||
}
|
||||
|
||||
for (NotificationsWindow updatee: notificationWindows)
|
||||
{
|
||||
if (!responsibleFor(updatee)) continue;
|
||||
updatee.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void
|
||||
connectionFailed(IOException eIo)
|
||||
{
|
||||
// sais pas dois-je faire..
|
||||
eIo.printStackTrace();
|
||||
}
|
||||
|
||||
public void
|
||||
requestFailed(int httpCode, Tree<String> json)
|
||||
{
|
||||
// mo shiranu
|
||||
System.err.println(httpCode + ", " + json.get("error").value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ---%-@-%---
|
||||
|
||||
WindowUpdater(JKomasto primaire)
|
||||
{
|
||||
this.primaire = primaire;
|
||||
this.api = primaire.getMastodonApi();
|
||||
|
||||
this.timelineWindows = new ArrayList<>();
|
||||
this.notificationWindows = new ArrayList<>();
|
||||
|
||||
publicConn = new Connection();
|
||||
publicConn.type = TimelineType.FEDERATED;
|
||||
|
||||
userConn = new Connection();
|
||||
userConn.type = TimelineType.HOME;
|
||||
|
||||
loadNotificationSound();
|
||||
}
|
||||
|
||||
void
|
||||
loadNotificationSound()
|
||||
{
|
||||
URL url = getClass().getResource("KDE_Dialog_Appear.wav");
|
||||
try {
|
||||
Clip clip = AudioSystem.getClip();
|
||||
clip.open(AudioSystem.getAudioInputStream(url));
|
||||
notificationSound = clip;
|
||||
}
|
||||
catch (LineUnavailableException eLu) {
|
||||
assert false;
|
||||
}
|
||||
catch (UnsupportedAudioFileException eUa) {
|
||||
assert false;
|
||||
}
|
||||
catch (IOException eIo) {
|
||||
assert false;
|
||||
}
|
||||
catch (IllegalArgumentException eIa) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user