Add news tab, which shows status updates from mastodon
This commit is contained in:
parent
80e577db7c
commit
6ee666a0b1
|
@ -44,6 +44,7 @@ import ctbrec.sites.fc2live.Fc2Live;
|
|||
import ctbrec.sites.jasmin.LiveJasmin;
|
||||
import ctbrec.sites.mfc.MyFreeCams;
|
||||
import ctbrec.sites.streamate.Streamate;
|
||||
import ctbrec.ui.news.NewsTab;
|
||||
import ctbrec.ui.settings.SettingsTab;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.HostServices;
|
||||
|
@ -141,6 +142,7 @@ public class CamrecApplication extends Application {
|
|||
rootPane.getTabs().add(recordingsTab);
|
||||
settingsTab = new SettingsTab(sites, recorder);
|
||||
rootPane.getTabs().add(settingsTab);
|
||||
rootPane.getTabs().add(new NewsTab());
|
||||
rootPane.getTabs().add(new DonateTabFx());
|
||||
|
||||
switchToStartTab();
|
||||
|
@ -368,11 +370,11 @@ public class CamrecApplication extends Application {
|
|||
updateCheck.start();
|
||||
}
|
||||
|
||||
private Version getVersion() throws IOException {
|
||||
public static Version getVersion() throws IOException {
|
||||
if (Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||
return Version.of("0.0.0-DEV");
|
||||
} else {
|
||||
try (InputStream is = getClass().getClassLoader().getResourceAsStream("version")) {
|
||||
try (InputStream is = CamrecApplication.class.getClassLoader().getResourceAsStream("version")) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
String versionString = reader.readLine();
|
||||
Version version = Version.of(versionString);
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
package ctbrec.ui.news;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.squareup.moshi.Json;
|
||||
|
||||
public class Account {
|
||||
|
||||
@Json(name = "emojis")
|
||||
private List<Object> emojis = null;
|
||||
@Json(name = "note")
|
||||
private String note;
|
||||
@Json(name = "bot")
|
||||
private Boolean bot;
|
||||
@Json(name = "created_at")
|
||||
private String createdAt;
|
||||
@Json(name = "avatar")
|
||||
private String avatar;
|
||||
@Json(name = "display_name")
|
||||
private String displayName;
|
||||
@Json(name = "header_static")
|
||||
private String headerStatic;
|
||||
@Json(name = "url")
|
||||
private String url;
|
||||
@Json(name = "following_count")
|
||||
private Integer followingCount;
|
||||
@Json(name = "statuses_count")
|
||||
private Integer statusesCount;
|
||||
@Json(name = "followers_count")
|
||||
private Integer followersCount;
|
||||
@Json(name = "header")
|
||||
private String header;
|
||||
@Json(name = "id")
|
||||
private String id;
|
||||
@Json(name = "locked")
|
||||
private Boolean locked;
|
||||
@Json(name = "avatar_static")
|
||||
private String avatarStatic;
|
||||
@Json(name = "fields")
|
||||
private List<Object> fields = null;
|
||||
@Json(name = "acct")
|
||||
private String acct;
|
||||
@Json(name = "username")
|
||||
private String username;
|
||||
|
||||
public List<Object> getEmojis() {
|
||||
return emojis;
|
||||
}
|
||||
|
||||
public void setEmojis(List<Object> emojis) {
|
||||
this.emojis = emojis;
|
||||
}
|
||||
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
|
||||
public void setNote(String note) {
|
||||
this.note = note;
|
||||
}
|
||||
|
||||
public Boolean getBot() {
|
||||
return bot;
|
||||
}
|
||||
|
||||
public void setBot(Boolean bot) {
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(String createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getHeaderStatic() {
|
||||
return headerStatic;
|
||||
}
|
||||
|
||||
public void setHeaderStatic(String headerStatic) {
|
||||
this.headerStatic = headerStatic;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Integer getFollowingCount() {
|
||||
return followingCount;
|
||||
}
|
||||
|
||||
public void setFollowingCount(Integer followingCount) {
|
||||
this.followingCount = followingCount;
|
||||
}
|
||||
|
||||
public Integer getStatusesCount() {
|
||||
return statusesCount;
|
||||
}
|
||||
|
||||
public void setStatusesCount(Integer statusesCount) {
|
||||
this.statusesCount = statusesCount;
|
||||
}
|
||||
|
||||
public Integer getFollowersCount() {
|
||||
return followersCount;
|
||||
}
|
||||
|
||||
public void setFollowersCount(Integer followersCount) {
|
||||
this.followersCount = followersCount;
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setHeader(String header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Boolean getLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public void setLocked(Boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
public String getAvatarStatic() {
|
||||
return avatarStatic;
|
||||
}
|
||||
|
||||
public void setAvatarStatic(String avatarStatic) {
|
||||
this.avatarStatic = avatarStatic;
|
||||
}
|
||||
|
||||
public List<Object> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<Object> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public String getAcct() {
|
||||
return acct;
|
||||
}
|
||||
|
||||
public void setAcct(String acct) {
|
||||
this.acct = acct;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ctbrec.ui.news;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import ctbrec.ui.TabSelectionListener;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import javafx.application.Platform;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.layout.VBox;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class NewsTab extends Tab implements TabSelectionListener {
|
||||
private static final String ACCESS_TOKEN = "a2804d73a89951a22e0f8483a6fcec8943afd88b7ba17c459c095aa9e6f94fd0";
|
||||
private static final String URL = "https://mastodon.cloud/api/v1/timelines/home";
|
||||
|
||||
private VBox layout = new VBox();
|
||||
|
||||
public NewsTab() {
|
||||
setText("News");
|
||||
layout.setMaxWidth(800);
|
||||
layout.setAlignment(Pos.CENTER);
|
||||
setContent(new ScrollPane(layout));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Request request = new Request.Builder()
|
||||
.url(URL)
|
||||
.header("Authorization", "Bearer " + ACCESS_TOKEN)
|
||||
.header("User-Agent", "ctbrec " + CamrecApplication.getVersion().toString())
|
||||
.build();
|
||||
try(Response response = CamrecApplication.httpClient.execute(request)) {
|
||||
if(response.isSuccessful()) {
|
||||
String body = response.body().string();
|
||||
if(body.startsWith("[")) {
|
||||
Moshi moshi = new Moshi.Builder().build();
|
||||
JsonAdapter<Status[]> statusListAdapter = moshi.adapter(Status[].class);
|
||||
Status[] statusArray = statusListAdapter.fromJson(body);
|
||||
Platform.runLater(() -> {
|
||||
layout.getChildren().clear();
|
||||
for (Status status : statusArray) {
|
||||
StatusPane stp = new StatusPane(status);
|
||||
layout.getChildren().add(stp);
|
||||
VBox.setMargin(stp, new Insets(10));
|
||||
}
|
||||
});
|
||||
} else if(body.startsWith("{")) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if(json.has("error")) {
|
||||
throw new IOException("Request not successful: " + json.getString("error"));
|
||||
} else {
|
||||
throw new IOException("Unexpected response: " + body);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unexpected response: " + body);
|
||||
}
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Dialogs.showError("News", "Couldn't load news from mastodon", e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deselected() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
package ctbrec.ui.news;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import com.squareup.moshi.Json;
|
||||
|
||||
public class Status {
|
||||
|
||||
@Json(name = "pinned")
|
||||
private Boolean pinned;
|
||||
@Json(name = "in_reply_to_id")
|
||||
private Object inReplyToId;
|
||||
@Json(name = "favourites_count")
|
||||
private Integer favouritesCount;
|
||||
@Json(name = "media_attachments")
|
||||
private List<Object> mediaAttachments = null;
|
||||
@Json(name = "created_at")
|
||||
private String createdAt;
|
||||
@Json(name = "replies_count")
|
||||
private Integer repliesCount;
|
||||
@Json(name = "language")
|
||||
private String language;
|
||||
@Json(name = "in_reply_to_account_id")
|
||||
private Object inReplyToAccountId;
|
||||
@Json(name = "content")
|
||||
private String content;
|
||||
@Json(name = "reblog")
|
||||
private Object reblog;
|
||||
@Json(name = "spoiler_text")
|
||||
private String spoilerText;
|
||||
@Json(name = "id")
|
||||
private String id;
|
||||
@Json(name = "reblogged")
|
||||
private Boolean reblogged;
|
||||
@Json(name = "muted")
|
||||
private Boolean muted;
|
||||
@Json(name = "emojis")
|
||||
private List<Object> emojis = null;
|
||||
@Json(name = "reblogs_count")
|
||||
private Integer reblogsCount;
|
||||
@Json(name = "visibility")
|
||||
private String visibility;
|
||||
@Json(name = "sensitive")
|
||||
private Boolean sensitive;
|
||||
@Json(name = "uri")
|
||||
private String uri;
|
||||
@Json(name = "url")
|
||||
private String url;
|
||||
@Json(name = "tags")
|
||||
private List<Object> tags = null;
|
||||
@Json(name = "application")
|
||||
private Object application;
|
||||
@Json(name = "favourited")
|
||||
private Boolean favourited;
|
||||
@Json(name = "mentions")
|
||||
private List<Object> mentions = null;
|
||||
@Json(name = "account")
|
||||
private Account account;
|
||||
@Json(name = "card")
|
||||
private Object card;
|
||||
|
||||
public Boolean getPinned() {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
public void setPinned(Boolean pinned) {
|
||||
this.pinned = pinned;
|
||||
}
|
||||
|
||||
public Object getInReplyToId() {
|
||||
return inReplyToId;
|
||||
}
|
||||
|
||||
public void setInReplyToId(Object inReplyToId) {
|
||||
this.inReplyToId = inReplyToId;
|
||||
}
|
||||
|
||||
public Integer getFavouritesCount() {
|
||||
return favouritesCount;
|
||||
}
|
||||
|
||||
public void setFavouritesCount(Integer favouritesCount) {
|
||||
this.favouritesCount = favouritesCount;
|
||||
}
|
||||
|
||||
public List<Object> getMediaAttachments() {
|
||||
return mediaAttachments;
|
||||
}
|
||||
|
||||
public void setMediaAttachments(List<Object> mediaAttachments) {
|
||||
this.mediaAttachments = mediaAttachments;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(String createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public Integer getRepliesCount() {
|
||||
return repliesCount;
|
||||
}
|
||||
|
||||
public void setRepliesCount(Integer repliesCount) {
|
||||
this.repliesCount = repliesCount;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
public Object getInReplyToAccountId() {
|
||||
return inReplyToAccountId;
|
||||
}
|
||||
|
||||
public void setInReplyToAccountId(Object inReplyToAccountId) {
|
||||
this.inReplyToAccountId = inReplyToAccountId;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Object getReblog() {
|
||||
return reblog;
|
||||
}
|
||||
|
||||
public void setReblog(Object reblog) {
|
||||
this.reblog = reblog;
|
||||
}
|
||||
|
||||
public String getSpoilerText() {
|
||||
return spoilerText;
|
||||
}
|
||||
|
||||
public void setSpoilerText(String spoilerText) {
|
||||
this.spoilerText = spoilerText;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Boolean getReblogged() {
|
||||
return reblogged;
|
||||
}
|
||||
|
||||
public void setReblogged(Boolean reblogged) {
|
||||
this.reblogged = reblogged;
|
||||
}
|
||||
|
||||
public Boolean getMuted() {
|
||||
return muted;
|
||||
}
|
||||
|
||||
public void setMuted(Boolean muted) {
|
||||
this.muted = muted;
|
||||
}
|
||||
|
||||
public List<Object> getEmojis() {
|
||||
return emojis;
|
||||
}
|
||||
|
||||
public void setEmojis(List<Object> emojis) {
|
||||
this.emojis = emojis;
|
||||
}
|
||||
|
||||
public Integer getReblogsCount() {
|
||||
return reblogsCount;
|
||||
}
|
||||
|
||||
public void setReblogsCount(Integer reblogsCount) {
|
||||
this.reblogsCount = reblogsCount;
|
||||
}
|
||||
|
||||
public String getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
public void setVisibility(String visibility) {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Boolean getSensitive() {
|
||||
return sensitive;
|
||||
}
|
||||
|
||||
public void setSensitive(Boolean sensitive) {
|
||||
this.sensitive = sensitive;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public List<Object> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<Object> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public Object getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public void setApplication(Object application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
public Boolean getFavourited() {
|
||||
return favourited;
|
||||
}
|
||||
|
||||
public void setFavourited(Boolean favourited) {
|
||||
this.favourited = favourited;
|
||||
}
|
||||
|
||||
public List<Object> getMentions() {
|
||||
return mentions;
|
||||
}
|
||||
|
||||
public void setMentions(List<Object> mentions) {
|
||||
this.mentions = mentions;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public Object getCard() {
|
||||
return card;
|
||||
}
|
||||
|
||||
public void setCard(Object card) {
|
||||
this.card = card;
|
||||
}
|
||||
|
||||
public ZonedDateTime getCreationTime() {
|
||||
String timestamp = getCreatedAt();
|
||||
Instant instant = Instant.parse(timestamp);
|
||||
ZonedDateTime time = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
return time;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package ctbrec.ui.news;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
|
||||
import ctbrec.io.HtmlParser;
|
||||
import ctbrec.ui.DesktopIntegration;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
public class StatusPane extends StackPane {
|
||||
|
||||
public StatusPane(Status status) {
|
||||
String text = HtmlParser.getText("<div>" + status.getContent() + "</div>", "div");
|
||||
TextArea content = new TextArea(text);
|
||||
content.setMaxHeight(130);
|
||||
content.setEditable(false);
|
||||
content.setWrapText(true);
|
||||
getChildren().add(content);
|
||||
|
||||
ZonedDateTime createdAt = status.getCreationTime();
|
||||
String creationTime = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT).format(createdAt);
|
||||
Label time = new Label(creationTime);
|
||||
getChildren().add(time);
|
||||
StackPane.setMargin(time, new Insets(5));
|
||||
StackPane.setAlignment(time, Pos.BOTTOM_LEFT);
|
||||
|
||||
Button reply = new Button("Reply");
|
||||
reply.setOnAction((evt) -> DesktopIntegration.open(status.getUrl()));
|
||||
getChildren().add(reply);
|
||||
StackPane.setMargin(reply, new Insets(5));
|
||||
StackPane.setAlignment(reply, Pos.BOTTOM_RIGHT);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue