added bookmarks ,added custom emojis, gradle update

This commit is contained in:
nuclearfog 2023-02-12 10:15:30 +01:00
parent 46f1cc788b
commit 7f30465b18
No known key found for this signature in database
GPG Key ID: 03488A185C476379
25 changed files with 779 additions and 233 deletions

View File

@ -6,7 +6,7 @@ plugins {
android {
compileSdkVersion 33
buildToolsVersion '33.0.1'
buildToolsVersion '33.0.2'
namespace 'org.nuclearfog.twidda'
defaultConfig {

View File

@ -305,6 +305,15 @@ public interface Connection {
*/
List<Status> getUserFavorits(String name, long minId, long maxId) throws ConnectionException;
/**
* show statuses with bookmarks
*
* @param minId get statuses with ID above the min ID
* @param maxId get statuses with ID under the max ID
* @return list of statuses
*/
List<Status> getUserBookmarks(long minId, long maxId) throws ConnectionException;
/**
* return timeline from an user list
*
@ -361,22 +370,38 @@ public interface Connection {
/**
* remove repost
*
* @param id ID of the reposted status
* @param id status ID
* @return updated status
*/
Status removeRepost(long id) throws ConnectionException;
/**
* bookmark status
*
* @param id status ID
* @return updated status
*/
Status bookmarkStatus(long id) throws ConnectionException;
/**
* remove status from the bookmarks
*
* @param id status ID
* @return updated status
*/
Status removeBookmark(long id) throws ConnectionException;
/**
* mute a status from conversation
*
* @param id ID of the status
* @param id status ID
*/
void muteConversation(long id) throws ConnectionException;
/**
* unmute a status from conversation
*
* @param id ID of the status
* @param id status ID
*/
void unmuteConversation(long id) throws ConnectionException;

View File

@ -95,6 +95,7 @@ public class Mastodon implements Connection {
private static final String ENDPOINT_LOOKUP_USER = "/api/v1/accounts/lookup";
private static final String ENDPOINT_USERLIST = "/api/v1/lists/";
private static final String ENDPOINT_NOTIFICATION = "/api/v1/notifications";
private static final String ENDPOINT_BOOKMARKS = "/api/v1/bookmarks";
private static final String ENDPOINT_UPLOAD_MEDIA = "/api/v2/media";
private static final String ENDPOINT_MEDIA_STATUS = "/api/v1/media/";
private static final String ENDPOINT_UPDATE_CREDENTIALS = "/api/v1/accounts/update_credentials";
@ -454,6 +455,12 @@ public class Mastodon implements Connection {
}
@Override
public List<Status> getUserBookmarks(long minId, long maxId) throws MastodonException {
return getStatuses(ENDPOINT_BOOKMARKS, new ArrayList<>(), minId, maxId);
}
@Override
public List<Status> getUserlistStatuses(long id, long minId, long maxId) throws MastodonException {
return getStatuses(ENDPOINT_LIST_TIMELINE + id, new ArrayList<>(0), minId, maxId);
@ -508,6 +515,20 @@ public class Mastodon implements Connection {
}
@Override
public Status bookmarkStatus(long id) throws ConnectionException {
return postStatus(ENDPOINT_STATUS + id + "/bookmark", new ArrayList<>());
}
@Override
public Status removeBookmark(long id) throws ConnectionException {
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/unbookmark", new ArrayList<>());
status.removeBookmark();
return status;
}
@Override
public void muteConversation(long id) throws MastodonException {
createPost(ENDPOINT_MUTES + id + "/mute", new ArrayList<>());

View File

@ -85,8 +85,10 @@ public class MastodonException extends ConnectionException {
public int getErrorCode() {
switch (errorCode) {
case 404:
if (errorMessage.startsWith(MESSAGE_NOT_FOUND))
if (errorMessage.startsWith(MESSAGE_NOT_FOUND)) {
return RESOURCE_NOT_FOUND;
}
// fall through
case 401:
case 403:
@ -95,9 +97,6 @@ public class MastodonException extends ConnectionException {
case 429:
return RATE_LIMIT_EX;
case 422:
return INVALID_MEDIA;
case 503:
return SERVICE_UNAVAILABLE;

View File

@ -0,0 +1,51 @@
package org.nuclearfog.twidda.backend.api.mastodon.impl;
import org.json.JSONException;
import org.json.JSONObject;
import org.nuclearfog.twidda.model.Emoji;
/**
* Mastododn implementation of emoji
*
* @author nuclearfog
*/
public class CustomEmoji implements Emoji {
private String code;
private String url;
private String category;
private boolean visibleInPicker;
/**
* @param json CustomEmoji json format
*/
public CustomEmoji(JSONObject json) throws JSONException {
code = json.getString("shortcode");
url = json.getString("url");
category = json.optString("category", "");
visibleInPicker = json.optBoolean("visible_in_picker", true);
}
@Override
public String getCode() {
return code;
}
@Override
public String getUrl() {
return url;
}
@Override
public String getCategory() {
return category;
}
public boolean visible() {
return visibleInPicker;
}
}

View File

@ -9,6 +9,7 @@ import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.nuclearfog.twidda.backend.utils.StringTools;
import org.nuclearfog.twidda.model.Card;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Media;
import org.nuclearfog.twidda.model.Metrics;
@ -30,8 +31,14 @@ public class MastodonStatus implements Status {
private long replyUserId;
private long createdAt;
private int replyCount, favoriteCount, reblogCount;
private boolean favorited, reblogged, sensitive, muted;
private int replyCount;
private int favoriteCount;
private int reblogCount;
private boolean favorited;
private boolean reblogged;
private boolean bookmarked;
private boolean sensitive;
private boolean muted;
private String text;
private String mentions;
@ -43,6 +50,7 @@ public class MastodonStatus implements Status {
private Status embeddedStatus;
private Card[] cards = {};
private Media[] medias = {};
private Emoji[] emojis = {};
/**
* @param json Mastodon status json object
@ -55,6 +63,7 @@ public class MastodonStatus implements Status {
JSONObject pollJson = json.optJSONObject("poll");
JSONArray mentionsJson = json.optJSONArray("mentions");
JSONArray mediaArray = json.optJSONArray("media_attachments");
JSONArray emojiArray = json.optJSONArray("emojis");
String replyIdStr = json.optString("in_reply_to_id", "0");
String replyUserIdStr = json.optString("in_reply_to_account_id", "0");
String idStr = json.getString("id");
@ -69,6 +78,7 @@ public class MastodonStatus implements Status {
favorited = json.optBoolean("favourited", false);
reblogged = json.optBoolean("reblogged", false);
sensitive = json.optBoolean("sensitive", false);
bookmarked = json.optBoolean("bookmarked", false);
text = json.optString("content", "");
text = Jsoup.parse(text).text();
mentions = author.getScreenname() + ' ';
@ -89,7 +99,7 @@ public class MastodonStatus implements Status {
medias[i] = new MastodonMedia(mediaItem);
}
}
if (mentionsJson != null) {
if (mentionsJson != null && mentionsJson.length() > 0) {
StringBuilder mentionsBuilder = new StringBuilder(mentions);
for (int i = 0; i < mentionsJson.length(); i++) {
String mention = '@' + mentionsJson.getJSONObject(i).getString("acct");
@ -99,6 +109,13 @@ public class MastodonStatus implements Status {
}
mentions = mentionsBuilder.toString();
}
if (emojiArray != null && emojiArray.length() > 0) {
emojis = new Emoji[emojiArray.length()];
for ( int i = 0 ; i < emojis.length; i++) {
JSONObject emojiJson = emojiArray.getJSONObject(i);
emojis[i] = new CustomEmoji(emojiJson);
}
}
if (appJson != null) {
source = appJson.optString("name", "");
} else if (embeddedStatus != null) {
@ -176,7 +193,7 @@ public class MastodonStatus implements Status {
@Override
public long getConversationId() {
return 0; // todo add implementation
return replyId;
}
@ -211,6 +228,13 @@ public class MastodonStatus implements Status {
}
@NonNull
@Override
public Emoji[] getEmojis() {
return emojis;
}
@Override
public String getUserMentions() {
return mentions;
@ -235,6 +259,12 @@ public class MastodonStatus implements Status {
}
@Override
public boolean isBookmarked() {
return bookmarked;
}
@Override
public boolean isHidden() {
return muted;
@ -300,6 +330,9 @@ public class MastodonStatus implements Status {
* correct retweet count
*/
public void unreblog() {
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).unreblog();
}
if (reblogCount > 0) {
reblogCount--;
}
@ -310,9 +343,22 @@ public class MastodonStatus implements Status {
* correct favorite count
*/
public void unfavorite() {
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).unfavorite();
}
if (favoriteCount > 0) {
favoriteCount--;
}
favorited = false;
}
/**
* remove status bookmark
*/
public void removeBookmark() {
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).removeBookmark();
}
bookmarked = false;
}
}

View File

@ -9,6 +9,7 @@ import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.nuclearfog.twidda.backend.utils.StringTools;
import org.nuclearfog.twidda.model.Card;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Media;
import org.nuclearfog.twidda.model.Metrics;
@ -196,7 +197,6 @@ public class TweetV1 implements Status {
@Override
public long getConversationId() {
// note: does not show the root tweet of the conversation
return replyTweetId;
}
@ -233,6 +233,13 @@ public class TweetV1 implements Status {
}
@NonNull
@Override
public Emoji[] getEmojis() {
return new Emoji[0];
}
@Override
public String getUserMentions() {
return userMentions;
@ -257,6 +264,12 @@ public class TweetV1 implements Status {
}
@Override
public boolean isBookmarked() {
return false;
}
@Override
@Nullable
public Location getLocation() {

View File

@ -11,6 +11,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.nuclearfog.twidda.BuildConfig;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.twitter.Tokens;
import org.nuclearfog.twidda.backend.api.twitter.TwitterException;
import org.nuclearfog.twidda.backend.helper.Messages;
@ -577,6 +578,12 @@ public class TwitterV1 implements Connection {
}
@Override
public List<Status> getUserBookmarks(long minId, long maxId) throws ConnectionException {
throw new TwitterException("not implemented!");
}
@Override
public List<Status> getUserlistStatuses(long id, long minId, long maxId) throws TwitterException {
List<String> params = new ArrayList<>();
@ -651,6 +658,18 @@ public class TwitterV1 implements Connection {
}
@Override
public Status bookmarkStatus(long id) throws ConnectionException {
return null;
}
@Override
public Status removeBookmark(long id) throws ConnectionException {
return null;
}
@Override
public void muteConversation(long id) throws TwitterException {
}

View File

@ -12,6 +12,7 @@ import org.nuclearfog.twidda.backend.api.twitter.impl.v2.maps.PollV2Map;
import org.nuclearfog.twidda.backend.api.twitter.impl.v2.maps.UserV2Map;
import org.nuclearfog.twidda.backend.utils.StringTools;
import org.nuclearfog.twidda.model.Card;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Media;
import org.nuclearfog.twidda.model.Metrics;
@ -313,6 +314,13 @@ public class TweetV2 implements Status {
}
@NonNull
@Override
public Emoji[] getEmojis() {
return new Emoji[0];
}
@Override
public String getUserMentions() {
return mentions;
@ -337,6 +345,12 @@ public class TweetV2 implements Status {
}
@Override
public boolean isBookmarked() {
return false;
}
@Override
public boolean isHidden() {
return false;

View File

@ -62,11 +62,21 @@ public class StatusAction extends AsyncTask<Long, Status, Boolean> {
*/
public static final int UNHIDE = 8;
/**
* bookmark status
*/
public static final int BOOKMARK = 9;
/**
* remove bookmark from status
*/
public static final int UNBOOKMARK = 10;
/**
* delete status
* (delete operation, "status ID" required)
*/
public static final int DELETE = 9;
public static final int DELETE = 20;
private Connection connection;
private WeakReference<StatusActivity> weakRef;
@ -138,13 +148,25 @@ public class StatusAction extends AsyncTask<Long, Status, Boolean> {
case FAVORITE:
status = connection.favoriteStatus(ids[0]);
publishProgress(status);
db.saveToFavorites(status);
db.addToFavorits(status);
return true;
case UNFAVORITE:
status = connection.unfavoriteStatus(ids[0]);
publishProgress(status);
db.removeFavorite(status);
db.removeFromFavorite(status);
return true;
case BOOKMARK:
status = connection.bookmarkStatus(ids[0]);
publishProgress(status);
db.addToBookmarks(status);
return true;
case UNBOOKMARK:
status = connection.removeBookmark(ids[0]);
publishProgress(status);
db.removeFromBookmarks(status);
return true;
case HIDE:

View File

@ -64,6 +64,11 @@ public class StatusLoader extends AsyncTask<Long, Void, List<Status>> {
*/
public static final int PUBLIC = 9;
/**
* bookmark timeline
*/
public static final int BOOKMARKS = 10;
private WeakReference<StatusFragment> weakRef;
private Connection connection;
@ -104,32 +109,32 @@ public class StatusLoader extends AsyncTask<Long, Void, List<Status>> {
try {
switch (listType) {
case HOME:
if (sinceId == 0 && maxId == 0) {
if (sinceId == 0L && maxId == 0L) {
statuses = db.getHomeTimeline();
if (statuses.isEmpty()) {
statuses = connection.getHomeTimeline(sinceId, maxId);
db.saveHomeTimeline(statuses);
}
} else if (sinceId > 0) {
} else if (sinceId > 0L) {
statuses = connection.getHomeTimeline(sinceId, maxId);
db.saveHomeTimeline(statuses);
} else if (maxId > 1) {
} else if (maxId > 1L) {
statuses = connection.getHomeTimeline(sinceId, maxId);
}
break;
case USER:
if (id > 0) {
if (sinceId == 0 && maxId == 0) {
if (id > 0L) {
if (sinceId == 0L && maxId == 0L) {
statuses = db.getUserTimeline(id);
if (statuses.isEmpty()) {
statuses = connection.getUserTimeline(id, 0, maxId);
statuses = connection.getUserTimeline(id, 0L, maxId);
db.saveUserTimeline(statuses);
}
} else if (sinceId > 0) {
} else if (sinceId > 0L) {
statuses = connection.getUserTimeline(id, sinceId, maxId);
db.saveUserTimeline(statuses);
} else if (maxId > 1) {
} else if (maxId > 1L) {
statuses = connection.getUserTimeline(id, sinceId, maxId);
}
} else if (search != null) {
@ -138,18 +143,18 @@ public class StatusLoader extends AsyncTask<Long, Void, List<Status>> {
break;
case FAVORIT:
if (id > 0) {
if (sinceId == 0 && maxId == 0) {
if (id > 0L) {
if (sinceId == 0L && maxId == 0L) {
statuses = db.getUserFavorites(id);
if (statuses.isEmpty()) {
statuses = connection.getUserFavorits(id, 0, maxId);
statuses = connection.getUserFavorits(id, 0L, maxId);
db.saveFavoriteTimeline(statuses, id);
}
} else if (sinceId > 0) {
statuses = connection.getUserFavorits(id, 0, maxId);
} else if (sinceId > 0L) {
statuses = connection.getUserFavorits(id, 0L, maxId);
db.saveFavoriteTimeline(statuses, id);
pos = CLEAR_LIST; // set flag to clear previous data
} else if (maxId > 1) {
} else if (maxId > 1L) {
statuses = connection.getUserFavorits(id, sinceId, maxId);
}
} else if (search != null) {
@ -157,12 +162,29 @@ public class StatusLoader extends AsyncTask<Long, Void, List<Status>> {
}
break;
case BOOKMARKS:
if (id > 0L) {
if (sinceId == 0L && maxId == 0L) {
statuses = db.getUserBookmarks(id);
if (statuses.isEmpty()) {
statuses = connection.getUserBookmarks(0L, maxId);
db.saveBookmarkTimeline(statuses, id);
}
} else if (sinceId > 0L) {
statuses = connection.getUserBookmarks(sinceId, maxId);
db.saveBookmarkTimeline(statuses, id);
} else if (maxId > 1L) {
statuses = connection.getUserBookmarks(sinceId, maxId);
}
}
break;
case REPLIES_OFFLINE:
statuses = db.getReplies(id);
break;
case REPLIES:
if (sinceId == 0 && maxId == 0) {
if (sinceId == 0L && maxId == 0L) {
statuses = db.getReplies(id);
if (statuses.isEmpty()) {
statuses = connection.getStatusReplies(id, sinceId, maxId, search);
@ -170,12 +192,12 @@ public class StatusLoader extends AsyncTask<Long, Void, List<Status>> {
db.saveReplyTimeline(statuses);
}
}
} else if (sinceId > 0) {
} else if (sinceId > 0L) {
statuses = connection.getStatusReplies(id, sinceId, maxId, search);
if (!statuses.isEmpty() && db.containsStatus(id)) {
db.saveReplyTimeline(statuses);
}
} else if (maxId > 1) {
} else if (maxId > 1L) {
statuses = connection.getStatusReplies(id, sinceId, maxId, search);
}
break;

View File

@ -78,6 +78,7 @@ public class GlobalSettings {
private static final String FV_COLOR = "favorite_color";
private static final String FOLLOW_COLOR = "following_color";
private static final String F_REQ_COLOR = "following_pending_color";
private static final String BOOKMARK_COLOR = "bookmark_color";
private static final String INDEX_FONT = "index_font";
private static final String INDEX_SCALE = "index_scale";
private static final String LIST_SIZE = "preload";
@ -125,6 +126,7 @@ public class GlobalSettings {
private static final int DEFAULT_RT_ICON_COLOR = Color.GREEN;
private static final int DEFAULT_FV_ICON_COLOR = Color.YELLOW;
private static final int DEFAULT_FR_ICON_COLOR = Color.YELLOW;
private static final int DEFAULT_BOOKMARK_COLOR = Color.RED;
private static final int DEFAULT_FW_ICON_COLOR = Color.CYAN;
private static final long DEFAULT_LOCATION_ID = 1L;
private static final String DEFAULT_LOCATION_NAME = "Worldwide";
@ -156,6 +158,7 @@ public class GlobalSettings {
private int favorite_color;
private int request_color;
private int follow_color;
private int bookmark_color;
private int indexFont;
private int indexScale;
private int listSize;
@ -365,6 +368,27 @@ public class GlobalSettings {
return request_color;
}
/**
* get bookmark icon color
*
* @return icon color
*/
public int getBookmarkColor() {
return bookmark_color;
}
/**
* set bookmark icon color
*
* @param color icon color
*/
public void setbookmarkColor(int color) {
bookmark_color = color;
Editor edit = settings.edit();
edit.putInt(BOOKMARK_COLOR, color);
edit.apply();
}
/**
* set icon color of the follow button
*
@ -411,7 +435,7 @@ public class GlobalSettings {
popup_color, highlight_color,
card_color, icon_color,
retweet_color, favorite_color,
request_color, follow_color
request_color, follow_color, bookmark_color
};
}
@ -955,6 +979,7 @@ public class GlobalSettings {
retweet_color = settings.getInt(RT_COLOR, DEFAULT_RT_ICON_COLOR);
favorite_color = settings.getInt(FV_COLOR, DEFAULT_FV_ICON_COLOR);
request_color = settings.getInt(F_REQ_COLOR, DEFAULT_FR_ICON_COLOR);
bookmark_color = settings.getInt(BOOKMARK_COLOR, DEFAULT_BOOKMARK_COLOR);
follow_color = settings.getInt(FOLLOW_COLOR, DEFAULT_FW_ICON_COLOR);
indexFont = settings.getInt(INDEX_FONT, DEFAULT_FONT_INDEX);
indexScale = settings.getInt(INDEX_SCALE, DEFAULT_SCALE_INDEX);

View File

@ -4,6 +4,7 @@ import static android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE;
import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE;
import static org.nuclearfog.twidda.database.DatabaseAdapter.AccountTable;
import static org.nuclearfog.twidda.database.DatabaseAdapter.FavoriteTable;
import static org.nuclearfog.twidda.database.DatabaseAdapter.BookmarkTable;
import static org.nuclearfog.twidda.database.DatabaseAdapter.LocationTable;
import static org.nuclearfog.twidda.database.DatabaseAdapter.MediaTable;
import static org.nuclearfog.twidda.database.DatabaseAdapter.MessageTable;
@ -94,6 +95,11 @@ public class AppDatabase {
*/
public static final int HIDDEN_MASK = 1 << 9;
/**
* flag indicated that a status is bookmarked by the current user
*/
public static final int BOOKMARK_MASK = 1 << 10;
/**
* flag indicates that an user is verified
*/
@ -161,10 +167,22 @@ public class AppDatabase {
/**
* SQL query to get status favored by an user
*/
private static final String USERFAVORIT_QUERY = "SELECT * FROM(" + STATUS_SUBQUERY + ")"
private static final String USER_FAVORIT_QUERY = "SELECT * FROM(" + STATUS_SUBQUERY + ")"
+ " INNER JOIN " + FavoriteTable.NAME
+ " ON " + StatusTable.NAME + "." + StatusTable.ID + "=" + FavoriteTable.NAME + "." + FavoriteTable.STATUS_ID
+ " WHERE " + FavoriteTable.NAME + "." + FavoriteTable.FAVORITER_ID + "=?"
+ " WHERE " + FavoriteTable.NAME + "." + FavoriteTable.OWNER_ID + "=?"
+ " AND " + StatusRegisterTable.NAME + "." + StatusRegisterTable.OWNER + "=?"
+ " AND " + UserRegisterTable.NAME + "." + UserRegisterTable.OWNER + "=?"
+ " ORDER BY " + StatusTable.TIME + " DESC"
+ " LIMIT ?;";
/**
* SQL query to get status favored by an user
*/
private static final String USER_BOOKMARKS_QUERY = "SELECT * FROM(" + STATUS_SUBQUERY + ")"
+ " INNER JOIN " + BookmarkTable.NAME
+ " ON " + StatusTable.NAME + "." + StatusTable.ID + "=" + BookmarkTable.NAME + "." + BookmarkTable.STATUS_ID
+ " WHERE " + BookmarkTable.NAME + "." + BookmarkTable.OWNER_ID + "=?"
+ " AND " + StatusRegisterTable.NAME + "." + StatusRegisterTable.OWNER + "=?"
+ " AND " + UserRegisterTable.NAME + "." + UserRegisterTable.OWNER + "=?"
+ " ORDER BY " + StatusTable.TIME + " DESC"
@ -230,13 +248,29 @@ public class AppDatabase {
/**
* select all statuses from favorite table favored by given user
*/
private static final String FAVORITE_SELECT_OWNER = FavoriteTable.FAVORITER_ID + "=?";
private static final String FAVORITE_SELECT_OWNER = FavoriteTable.OWNER_ID + "=?";
/**
* select status entries from favorite table matching status ID
* this status can be favored by multiple users
*/
private static final String BOOKMARK_SELECT_STATUS = BookmarkTable.STATUS_ID + "=?";
/**
* select all statuses from favorite table favored by given user
*/
private static final String BOOKMARK_SELECT_OWNER = BookmarkTable.OWNER_ID + "=?";
/**
* select specific status from favorite table
*/
private static final String FAVORITE_SELECT = FAVORITE_SELECT_STATUS + " AND " + FAVORITE_SELECT_OWNER;
/**
* select specific status from favorite table
*/
private static final String BOOKMARK_SELECT = BOOKMARK_SELECT_STATUS + " AND " + BOOKMARK_SELECT_OWNER;
/**
* select message from message table with ID
*/
@ -263,7 +297,7 @@ public class AppDatabase {
private static final String USER_SELECT = UserTable.NAME + "." + UserTable.ID + "=?";
/**
* selection to get status register
* selection to get status flag register
*/
private static final String STATUS_REG_SELECT = StatusRegisterTable.ID + "=? AND " + StatusRegisterTable.OWNER + "=?";
@ -278,7 +312,7 @@ public class AppDatabase {
private static final String LOCATION_SELECT = LocationTable.ID + "=?";
/**
* selection to get user register
* selection to get user flag register
*/
private static final String USER_REG_SELECT = UserRegisterTable.ID + "=? AND " + UserRegisterTable.OWNER + "=?";
@ -288,12 +322,12 @@ public class AppDatabase {
private static final String ACCOUNT_SELECTION = AccountTable.ID + "=?";
/**
* column projection for user register
* column projection for user flag register
*/
private static final String[] USER_REG_COLUMN = {UserRegisterTable.REGISTER};
/**
* column projection for status register
* column projection for status flag register
*/
private static final String[] STATUS_REG_COLUMN = {StatusRegisterTable.REGISTER};
@ -383,19 +417,41 @@ public class AppDatabase {
/**
* save user favorite timeline
*
* @param fav status favored by user
* @param statuses status favored by user
* @param ownerId user ID
*/
public void saveFavoriteTimeline(List<Status> fav, long ownerId) {
public void saveFavoriteTimeline(List<Status> statuses, long ownerId) {
SQLiteDatabase db = getDbWrite();
removeFavorits(db, ownerId);
for (Status status : fav) {
// delete old favorits
String[] delArgs = {Long.toString(ownerId)};
db.delete(FavoriteTable.NAME, FAVORITE_SELECT_OWNER, delArgs);
// save new favorits
for (Status status : statuses) {
saveStatus(status, db, 0);
saveFavorite(status.getId(), ownerId, db);
}
commit(db);
}
/**
* save user bookmark timeline
*
* @param statuses bookmarked statuses
* @param ownerId id of the owner
*/
public void saveBookmarkTimeline(List<Status> statuses, long ownerId) {
SQLiteDatabase db = getDbWrite();
// delete old favorits
String[] delArgs = {Long.toString(ownerId)};
db.delete(BookmarkTable.NAME, BOOKMARK_SELECT_OWNER, delArgs);
// save new bookmarks
for (Status status : statuses) {
saveStatus(status, db, 0);
saveBookmark(status.getId(), ownerId, db);
}
commit(db);
}
/**
* store replies of a status
*
@ -433,7 +489,7 @@ public class AppDatabase {
*
* @param status favorited status
*/
public void saveToFavorites(Status status) {
public void addToFavorits(Status status) {
if (status.getEmbeddedStatus() != null)
status = status.getEmbeddedStatus();
SQLiteDatabase db = getDbWrite();
@ -442,6 +498,20 @@ public class AppDatabase {
commit(db);
}
/**
* store ID of a status to the current users bookmarks
*
* @param status favorited status
*/
public void addToBookmarks(Status status) {
if (status.getEmbeddedStatus() != null)
status = status.getEmbeddedStatus();
SQLiteDatabase db = getDbWrite();
saveStatus(status, db, 0);
saveBookmark(status.getId(), settings.getLogin().getId(), db);
commit(db);
}
/**
* save notifications to database
*/
@ -545,16 +615,8 @@ public class AppDatabase {
String[] args = {homeStr, homeStr, Integer.toString(settings.getListSize())};
SQLiteDatabase db = getDbRead();
List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(HOME_QUERY, args);
if (cursor.moveToFirst()) {
do {
Status status = getStatus(cursor, db);
result.add(status);
} while (cursor.moveToNext());
}
cursor.close();
return result;
return getStatuses(cursor, db);
}
/**
@ -568,16 +630,8 @@ public class AppDatabase {
String[] args = {homeStr, homeStr, Long.toString(userID), Integer.toString(settings.getListSize())};
SQLiteDatabase db = getDbRead();
List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(USER_STATUS_QUERY, args);
if (cursor.moveToFirst()) {
do {
Status status = getStatus(cursor, db);
result.add(status);
} while (cursor.moveToNext());
}
cursor.close();
return result;
return getStatuses(cursor, db);
}
/**
@ -591,16 +645,23 @@ public class AppDatabase {
String[] args = {Long.toString(ownerID), homeStr, homeStr, Integer.toString(settings.getListSize())};
SQLiteDatabase db = getDbRead();
List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(USERFAVORIT_QUERY, args);
if (cursor.moveToFirst()) {
do {
Status status = getStatus(cursor, db);
result.add(status);
} while (cursor.moveToNext());
Cursor cursor = db.rawQuery(USER_FAVORIT_QUERY, args);
return getStatuses(cursor, db);
}
cursor.close();
return result;
/**
* load status bookmarks
*
* @param ownerID user ID
* @return bookmark timeline
*/
public List<Status> getUserBookmarks(long ownerID) {
String homeStr = Long.toString(settings.getLogin().getId());
String[] args = {Long.toString(ownerID), homeStr, homeStr, Integer.toString(settings.getListSize())};
SQLiteDatabase db = getDbRead();
Cursor cursor = db.rawQuery(USER_BOOKMARKS_QUERY, args);
return getStatuses(cursor, db);
}
/**
@ -664,16 +725,8 @@ public class AppDatabase {
String[] args = {Long.toString(id), homeStr, homeStr, Integer.toString(settings.getListSize())};
SQLiteDatabase db = getDbRead();
List<Status> result = new LinkedList<>();
Cursor cursor = db.rawQuery(REPLY_QUERY, args);
if (cursor.moveToFirst()) {
do {
Status status = getStatus(cursor, db);
result.add(status);
} while (cursor.moveToNext());
}
cursor.close();
return result;
return getStatuses(cursor, db);
}
/**
@ -731,14 +784,14 @@ public class AppDatabase {
String[] args = {Long.toString(id), Long.toString(settings.getLogin().getId())};
SQLiteDatabase db = getDbWrite();
int register = getStatusRegister(db, id);
if (hide)
register |= HIDDEN_MASK;
else
register &= ~HIDDEN_MASK;
int flags = getStatusFlags(db, id);
if (hide) {
flags |= HIDDEN_MASK;
} else {
flags &= ~HIDDEN_MASK;
}
ContentValues values = new ContentValues(3);
values.put(StatusRegisterTable.REGISTER, register);
values.put(StatusRegisterTable.REGISTER, flags);
db.update(StatusRegisterTable.NAME, values, STATUS_REG_SELECT, args);
commit(db);
}
@ -763,22 +816,43 @@ public class AppDatabase {
*
* @param status status to remove from the favorites
*/
public void removeFavorite(Status status) {
public void removeFromFavorite(Status status) {
String[] delArgs = {Long.toString(status.getId()), Long.toString(settings.getLogin().getId())};
if (status.getEmbeddedStatus() != null) {
status = status.getEmbeddedStatus();
}
SQLiteDatabase db = getDbWrite();
// get status register
int register = getStatusRegister(db, status.getId());
register &= ~FAVORITE_MASK; // unset favorite flag
// get status flags
int flags = getStatusFlags(db, status.getId());
flags &= ~FAVORITE_MASK; // unset favorite flag
// update database
saveStatusRegister(db, status, register);
saveStatusFlags(db, status, flags);
db.delete(FavoriteTable.NAME, FAVORITE_SELECT, delArgs);
commit(db);
}
/**
* remove status from bookmarks
*
* @param status status to remove from the bookmarks
*/
public void removeFromBookmarks(Status status) {
String[] delArgs = {Long.toString(status.getId()), Long.toString(settings.getLogin().getId())};
if (status.getEmbeddedStatus() != null) {
status = status.getEmbeddedStatus();
}
SQLiteDatabase db = getDbWrite();
// get status flags
int flags = getStatusFlags(db, status.getId());
flags &= ~BOOKMARK_MASK; // unset bookmark flag
// update database
saveStatusFlags(db, status, flags);
db.delete(BookmarkTable.NAME, BOOKMARK_SELECT, delArgs);
commit(db);
}
/**
* Delete Direct Message
*
@ -927,13 +1001,13 @@ public class AppDatabase {
*/
public void muteUser(long id, boolean mute) {
SQLiteDatabase db = getDbWrite();
int register = getUserRegister(db, id);
int flags = getUserFlags(db, id);
if (mute) {
register |= EXCLUDE_MASK;
flags |= EXCLUDE_MASK;
} else {
register &= ~EXCLUDE_MASK;
flags &= ~EXCLUDE_MASK;
}
saveUserRegister(db, id, register);
saveUserFlags(db, id, flags);
commit(db);
}
@ -992,6 +1066,24 @@ public class AppDatabase {
return result;
}
/**
* create a list of statuses from a cursor
*
* @param cursor cursor with statuses
* @return status list
*/
private List<Status> getStatuses(Cursor cursor, SQLiteDatabase db) {
List<Status> result = new LinkedList<>();
if (cursor.moveToFirst()) {
do {
Status status = getStatus(cursor, db);
result.add(status);
} while (cursor.moveToNext());
}
cursor.close();
return result;
}
/**
* get status/message media
*
@ -1029,13 +1121,13 @@ public class AppDatabase {
}
/**
* get register of a status or zero if status not found
* get status flags or zero if status not found
*
* @param db database instance
* @param id ID of the status
* @return status register
* @return status flags
*/
private int getStatusRegister(SQLiteDatabase db, long id) {
private int getStatusFlags(SQLiteDatabase db, long id) {
String[] args = {Long.toString(id), Long.toString(settings.getLogin().getId())};
Cursor c = db.query(StatusRegisterTable.NAME, STATUS_REG_COLUMN, STATUS_REG_SELECT, args, null, null, null, SINGLE_ITEM);
@ -1053,7 +1145,7 @@ public class AppDatabase {
* @param userID ID of the user
* @return user flags
*/
private int getUserRegister(SQLiteDatabase db, long userID) {
private int getUserFlags(SQLiteDatabase db, long userID) {
String[] args = {Long.toString(userID), Long.toString(settings.getLogin().getId())};
Cursor c = db.query(UserRegisterTable.NAME, USER_REG_COLUMN, USER_REG_SELECT, args, null, null, null, SINGLE_ITEM);
@ -1072,24 +1164,27 @@ public class AppDatabase {
* @param mode SQLITE mode {@link SQLiteDatabase#CONFLICT_IGNORE,SQLiteDatabase#CONFLICT_REPLACE}
*/
private void saveUser(User user, SQLiteDatabase db, int mode) {
int register = getUserRegister(db, user.getId());
if (user.isVerified())
register |= VERIFIED_MASK;
else
register &= ~VERIFIED_MASK;
if (user.isProtected())
register |= LOCKED_MASK;
else
register &= ~LOCKED_MASK;
if (user.followRequested())
register |= FOLLOW_REQUEST_MASK;
else
register &= ~FOLLOW_REQUEST_MASK;
if (user.hasDefaultProfileImage())
register |= DEFAULT_IMAGE_MASK;
else
register &= ~DEFAULT_IMAGE_MASK;
int flags = getUserFlags(db, user.getId());
if (user.isVerified()) {
flags |= VERIFIED_MASK;
} else {
flags &= ~VERIFIED_MASK;
}
if (user.isProtected()) {
flags |= LOCKED_MASK;
} else {
flags &= ~LOCKED_MASK;
}
if (user.followRequested()) {
flags |= FOLLOW_REQUEST_MASK;
} else {
flags &= ~FOLLOW_REQUEST_MASK;
}
if (user.hasDefaultProfileImage()) {
flags |= DEFAULT_IMAGE_MASK;
} else {
flags &= ~DEFAULT_IMAGE_MASK;
}
ContentValues userColumn = new ContentValues(13);
userColumn.put(UserTable.ID, user.getId());
userColumn.put(UserTable.USERNAME, user.getUsername());
@ -1106,17 +1201,17 @@ public class AppDatabase {
userColumn.put(UserTable.FAVORITS, user.getFavoriteCount());
db.insertWithOnConflict(UserTable.NAME, "", userColumn, mode);
saveUserRegister(db, user.getId(), register);
saveUserFlags(db, user.getId(), flags);
}
/**
* save status into database
*
* @param status status information
* @param statusFlags predefined status status register or zero if there isn't one
* @param flags predefined status status flags or zero if there isn't one
* @param db SQLite database
*/
private void saveStatus(Status status, SQLiteDatabase db, int statusFlags) {
private void saveStatus(Status status, SQLiteDatabase db, int flags) {
User user = status.getAuthor();
Status rtStat = status.getEmbeddedStatus();
long rtId = -1L;
@ -1124,21 +1219,26 @@ public class AppDatabase {
saveStatus(rtStat, db, 0);
rtId = rtStat.getId();
}
statusFlags |= getStatusRegister(db, status.getId());
flags |= getStatusFlags(db, status.getId());
if (status.isFavorited()) {
statusFlags |= FAVORITE_MASK;
flags |= FAVORITE_MASK;
} else {
statusFlags &= ~FAVORITE_MASK;
flags &= ~FAVORITE_MASK;
}
if (status.isReposted()) {
statusFlags |= REPOST_MASK;
flags |= REPOST_MASK;
} else {
statusFlags &= ~REPOST_MASK;
flags &= ~REPOST_MASK;
}
if (status.isSensitive()) {
statusFlags |= MEDIA_SENS_MASK;
flags |= MEDIA_SENS_MASK;
} else {
statusFlags &= ~MEDIA_SENS_MASK;
flags &= ~MEDIA_SENS_MASK;
}
if (status.isBookmarked()) {
flags |= BOOKMARK_MASK;
} else {
flags &= ~BOOKMARK_MASK;
}
ContentValues statusUpdate = new ContentValues(15);
statusUpdate.put(StatusTable.ID, status.getId());
@ -1172,7 +1272,7 @@ public class AppDatabase {
}
db.insertWithOnConflict(StatusTable.NAME, "", statusUpdate, CONFLICT_REPLACE);
saveUser(user, db, CONFLICT_IGNORE);
saveStatusRegister(db, status, statusFlags);
saveStatusFlags(db, status, flags);
}
/**
@ -1213,13 +1313,13 @@ public class AppDatabase {
*
* @param db database instance
* @param status status
* @param register status register
* @param flags status flags
*/
private void saveStatusRegister(SQLiteDatabase db, Status status, int register) {
private void saveStatusFlags(SQLiteDatabase db, Status status, int flags) {
String[] args = {Long.toString(status.getId()), Long.toString(settings.getLogin().getId())};
ContentValues values = new ContentValues(4);
values.put(StatusRegisterTable.REGISTER, register);
values.put(StatusRegisterTable.REGISTER, flags);
values.put(StatusRegisterTable.REPOST_ID, status.getRepostId());
values.put(StatusRegisterTable.ID, status.getId());
values.put(StatusRegisterTable.OWNER, settings.getLogin().getId());
@ -1236,15 +1336,15 @@ public class AppDatabase {
*
* @param db database instance
* @param id User ID
* @param register status register
* @param flags status flags
*/
private void saveUserRegister(SQLiteDatabase db, long id, int register) {
private void saveUserFlags(SQLiteDatabase db, long id, int flags) {
String[] args = {Long.toString(id), Long.toString(settings.getLogin().getId())};
ContentValues values = new ContentValues(3);
values.put(UserRegisterTable.ID, id);
values.put(UserRegisterTable.OWNER, settings.getLogin().getId());
values.put(UserRegisterTable.REGISTER, register);
values.put(UserRegisterTable.REGISTER, flags);
int cnt = db.update(UserRegisterTable.NAME, values, USER_REG_SELECT, args);
if (cnt == 0) {
@ -1254,17 +1354,31 @@ public class AppDatabase {
}
/**
* Store status into favorite table of a user
* store status ID to the favorite table
*
* @param statusId ID of the favored status
* @param ownerId ID of the favorite list owner
* @param statusId ID of the status
* @param ownerId ID of the list owner
* @param db database instance
*/
private void saveFavorite(long statusId, long ownerId, SQLiteDatabase db) {
ContentValues favTable = new ContentValues(2);
favTable.put(FavoriteTable.STATUS_ID, statusId);
favTable.put(FavoriteTable.FAVORITER_ID, ownerId);
db.insertWithOnConflict(FavoriteTable.NAME, "", favTable, CONFLICT_REPLACE);
ContentValues column = new ContentValues(2);
column.put(FavoriteTable.STATUS_ID, statusId);
column.put(FavoriteTable.OWNER_ID, ownerId);
db.insertWithOnConflict(FavoriteTable.NAME, "", column, CONFLICT_REPLACE);
}
/**
* store status ID to the bookmark table
*
* @param statusId ID of the status
* @param ownerId ID of the list owner
* @param db database instance
*/
private void saveBookmark(long statusId, long ownerId, SQLiteDatabase db) {
ContentValues column = new ContentValues(2);
column.put(BookmarkTable.STATUS_ID, statusId);
column.put(BookmarkTable.OWNER_ID, ownerId);
db.insertWithOnConflict(BookmarkTable.NAME, "", column, CONFLICT_REPLACE);
}
/**
@ -1305,16 +1419,22 @@ public class AppDatabase {
String[] userIdArg = {Long.toString(status.getAuthor().getId())};
User user = status.getAuthor();
int register = getStatusRegister(db, status.getId());
if (status.isReposted())
register |= REPOST_MASK;
else
register &= ~REPOST_MASK;
if (status.isFavorited())
register |= FAVORITE_MASK;
else
register &= ~FAVORITE_MASK;
int flags = getStatusFlags(db, status.getId());
if (status.isReposted()) {
flags |= REPOST_MASK;
} else {
flags &= ~REPOST_MASK;
}
if (status.isFavorited()) {
flags |= FAVORITE_MASK;
} else {
flags &= ~FAVORITE_MASK;
}
if (status.isBookmarked()) {
flags |= BOOKMARK_MASK;
} else {
flags &= ~BOOKMARK_MASK;
}
ContentValues statusUpdate = new ContentValues(7);
statusUpdate.put(StatusTable.TEXT, status.getText());
statusUpdate.put(StatusTable.REPOST, status.getRepostCount());
@ -1337,18 +1457,7 @@ public class AppDatabase {
db.updateWithOnConflict(StatusTable.NAME, statusUpdate, STATUS_SELECT, statusIdArg, CONFLICT_REPLACE);
db.updateWithOnConflict(UserTable.NAME, userUpdate, USER_SELECT, userIdArg, CONFLICT_IGNORE);
saveStatusRegister(db, status, register);
}
/**
* remove user favorites from table
*
* @param db database instance
* @param userId ID of the favorite list owner
*/
private void removeFavorits(SQLiteDatabase db, long userId) {
String[] delArgs = {Long.toString(userId)};
db.delete(FavoriteTable.NAME, FAVORITE_SELECT_OWNER, delArgs);
saveStatusFlags(db, status, flags);
}
/**

View File

@ -75,13 +75,25 @@ public class DatabaseAdapter {
*/
private static final String TABLE_FAVORITES = "CREATE TABLE IF NOT EXISTS "
+ FavoriteTable.NAME + "("
+ FavoriteTable.FAVORITER_ID + " INTEGER,"
+ FavoriteTable.OWNER_ID + " INTEGER,"
+ FavoriteTable.STATUS_ID + " INTEGER,"
+ "FOREIGN KEY(" + FavoriteTable.FAVORITER_ID + ")"
+ "FOREIGN KEY(" + FavoriteTable.OWNER_ID + ")"
+ "REFERENCES " + UserTable.NAME + "(" + UserTable.ID + "),"
+ "FOREIGN KEY(" + FavoriteTable.STATUS_ID + ")"
+ "REFERENCES " + StatusTable.NAME + "(" + StatusTable.ID + "));";
/**
* SQL query to create a table for favorite list
*/
private static final String TABLE_BOOKMARKS = "CREATE TABLE IF NOT EXISTS "
+ BookmarkTable.NAME + "("
+ BookmarkTable.OWNER_ID + " INTEGER,"
+ BookmarkTable.STATUS_ID + " INTEGER,"
+ "FOREIGN KEY(" + BookmarkTable.OWNER_ID + ")"
+ "REFERENCES " + UserTable.NAME + "(" + UserTable.ID + "),"
+ "FOREIGN KEY(" + BookmarkTable.STATUS_ID + ")"
+ "REFERENCES " + StatusTable.NAME + "(" + StatusTable.ID + "));";
/**
* SQL query to create a table for trend information
*/
@ -320,6 +332,7 @@ public class DatabaseAdapter {
db.execSQL(TABLE_USER);
db.execSQL(TABLE_STATUS);
db.execSQL(TABLE_FAVORITES);
db.execSQL(TABLE_BOOKMARKS);
db.execSQL(TABLE_TRENDS);
db.execSQL(TABLE_MESSAGES);
db.execSQL(TABLE_ACCOUNTS);
@ -553,7 +566,27 @@ public class DatabaseAdapter {
/**
* ID of the user of this favored status
*/
String FAVORITER_ID = "ownerID";
String OWNER_ID = "ownerID";
}
/**
* status bookmark table
*/
public interface BookmarkTable {
/**
* table name
*/
String NAME = "bookmarks";
/**
* ID of the status
*/
String STATUS_ID = "tweetID";
/**
* ID of the user of this bookmarks
*/
String OWNER_ID = "ownerID";
}
/**

View File

@ -1,5 +1,6 @@
package org.nuclearfog.twidda.database.impl;
import static org.nuclearfog.twidda.database.AppDatabase.BOOKMARK_MASK;
import static org.nuclearfog.twidda.database.AppDatabase.FAVORITE_MASK;
import static org.nuclearfog.twidda.database.AppDatabase.HIDDEN_MASK;
import static org.nuclearfog.twidda.database.AppDatabase.MEDIA_SENS_MASK;
@ -15,6 +16,7 @@ import org.nuclearfog.twidda.database.DatabaseAdapter.StatusRegisterTable;
import org.nuclearfog.twidda.database.DatabaseAdapter.StatusTable;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Card;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.model.Media;
import org.nuclearfog.twidda.model.Metrics;
@ -46,6 +48,7 @@ public class StatusImpl implements Status {
private Status embedded;
private String[] mediaKeys = {};
private Media[] medias = {};
private Emoji[] emojis = {};
private User author;
private Location location;
private int repostCount;
@ -58,6 +61,7 @@ public class StatusImpl implements Status {
private String statusUrl;
private boolean reposted;
private boolean favorited;
private boolean bookmarked;
private boolean sensitive;
private boolean isHidden;
@ -90,6 +94,7 @@ public class StatusImpl implements Status {
reposted = (register & REPOST_MASK) != 0;
sensitive = (register & MEDIA_SENS_MASK) != 0;
isHidden = (register & HIDDEN_MASK) != 0;
bookmarked = (register & BOOKMARK_MASK) != 0;
if (mediaKeys != null && !mediaKeys.isEmpty()) {
this.mediaKeys = MEDIA_SEPARATOR.split(mediaKeys);
}
@ -188,6 +193,13 @@ public class StatusImpl implements Status {
}
@NonNull
@Override
public Emoji[] getEmojis() {
return emojis;
}
@Override
public String getUserMentions() {
return userMentions;
@ -212,6 +224,12 @@ public class StatusImpl implements Status {
}
@Override
public boolean isBookmarked() {
return bookmarked;
}
@Override
@Nullable
public Location getLocation() {

View File

@ -0,0 +1,30 @@
package org.nuclearfog.twidda.model;
/**
* Interface used for "custom emoji" implementation
*
* @author nuclearfog
*/
public interface Emoji {
/**
* short code of an emoji used by the server
*
* @return short code
*/
String getCode();
/**
* url of the emoji image
*
* @return url
*/
String getUrl();
/**
* category of the emoji
*
* @return category name
*/
String getCategory();
}

View File

@ -103,6 +103,11 @@ public interface Status extends Serializable, Comparable<Status> {
*/
boolean isFavorited();
/**
* @return true if status is bookmarked by the current user
*/
boolean isBookmarked();
/**
* @return true if status is hidden by current user
*/
@ -125,6 +130,13 @@ public interface Status extends Serializable, Comparable<Status> {
@NonNull
Media[] getMedia();
/**
*
* @return array of custom emojis
*/
@NonNull
Emoji[] getEmojis();
/**
* @return name of the location if attached
*/

View File

@ -85,7 +85,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
/**
* total count of all colors defined
*/
private static final int COLOR_COUNT = 10;
private static final int COLOR_COUNT = 11;
// app colors
private static final int COLOR_BACKGROUND = 0;
private static final int COLOR_TEXT = 1;
@ -97,6 +97,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
private static final int COLOR_FAVORITE = 7;
private static final int COLOR_FOLLOW_REQUEST = 8;
private static final int COLOR_FOLLOWING = 9;
private static final int COLOR_BOOKMARK = 10;
private GlobalSettings settings;
private Configuration configuration;
@ -159,6 +160,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
colorButtons[COLOR_FAVORITE] = findViewById(R.id.color_fav);
colorButtons[COLOR_FOLLOW_REQUEST] = findViewById(R.id.color_f_req);
colorButtons[COLOR_FOLLOWING] = findViewById(R.id.color_follow);
colorButtons[COLOR_BOOKMARK] = findViewById(R.id.color_bookmark);
proxyAddr = findViewById(R.id.edit_proxy_address);
proxyPort = findViewById(R.id.edit_proxy_port);
proxyUser = findViewById(R.id.edit_proxyuser);

View File

@ -51,6 +51,7 @@ import org.nuclearfog.tag.Tagger;
import org.nuclearfog.tag.Tagger.OnTagClickListener;
import org.nuclearfog.textviewtool.LinkAndScrollMovement;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.config.Configuration;
import org.nuclearfog.twidda.ui.adapter.PreviewAdapter;
import org.nuclearfog.twidda.ui.adapter.PreviewAdapter.OnCardClickListener;
import org.nuclearfog.twidda.backend.api.ConnectionException;
@ -144,7 +145,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
private MetricsDialog metricsDialog;
private TextView statusApi, createdAt, statusText, screenName, userName, locationName, sensitive_media;
private Button ansButton, rtwButton, favButton, replyName, coordinates, repostName;
private Button replyButton, repostButton, likeButton, replyName, locationButton, repostNameButton, bookmarkButton;
private ImageView profileImage;
private RecyclerView cardList;
private Toolbar toolbar;
@ -167,9 +168,10 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
setContentView(R.layout.page_status);
ViewGroup root = findViewById(R.id.page_status_root);
toolbar = findViewById(R.id.page_status_toolbar);
ansButton = findViewById(R.id.page_status_reply);
rtwButton = findViewById(R.id.page_status_repost);
favButton = findViewById(R.id.page_status_favorite);
replyButton = findViewById(R.id.page_status_reply);
repostButton = findViewById(R.id.page_status_repost);
likeButton = findViewById(R.id.page_status_favorite);
bookmarkButton = findViewById(R.id.page_status_bookmark);
userName = findViewById(R.id.page_status_username);
screenName = findViewById(R.id.page_status_screenname);
profileImage = findViewById(R.id.page_status_profile);
@ -178,13 +180,15 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
createdAt = findViewById(R.id.page_status_date);
statusApi = findViewById(R.id.page_status_api);
locationName = findViewById(R.id.page_status_location_name);
coordinates = findViewById(R.id.page_status_location_coordinates);
locationButton = findViewById(R.id.page_status_location_coordinates);
sensitive_media = findViewById(R.id.page_status_sensitive);
repostName = findViewById(R.id.page_status_reposter_reference);
repostNameButton = findViewById(R.id.page_status_reposter_reference);
cardList = findViewById(R.id.page_status_cards);
picasso = PicassoBuilder.get(this);
settings = GlobalSettings.getInstance(this);
clip = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
adapter = new PreviewAdapter(settings, picasso, this);
// get parameter
String replyUsername = "";
Object data = getIntent().getSerializableExtra(KEY_STATUS_DATA);
@ -202,35 +206,30 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
} else {
id = getIntent().getLongExtra(KEY_STATUS_ID, -1);
}
// create list fragment for status replies
// initialize status reply list
Bundle param = new Bundle();
param.putInt(KEY_STATUS_FRAGMENT_MODE, STATUS_FRAGMENT_REPLY);
param.putString(KEY_STATUS_FRAGMENT_SEARCH, replyUsername);
param.putLong(KEY_STATUS_FRAGMENT_ID, id);
// insert fragment into view
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.page_status_reply_fragment, StatusFragment.class, param);
fragmentTransaction.commit();
picasso = PicassoBuilder.get(this);
settings = GlobalSettings.getInstance(this);
adapter = new PreviewAdapter(settings, picasso, this);
ansButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.answer, 0, 0, 0);
rtwButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.repost, 0, 0, 0);
coordinates.setCompoundDrawablesWithIntrinsicBounds(R.drawable.location, 0, 0, 0);
replyButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.answer, 0, 0, 0);
repostButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.repost, 0, 0, 0);
locationButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.location, 0, 0, 0);
sensitive_media.setCompoundDrawablesWithIntrinsicBounds(R.drawable.sensitive, 0, 0, 0);
replyName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.back, 0, 0, 0);
repostName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.repost, 0, 0, 0);
repostNameButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.repost, 0, 0, 0);
bookmarkButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.bookmark, 0, 0, 0);
statusText.setMovementMethod(LinkAndScrollMovement.getInstance());
statusText.setLinkTextColor(settings.getHighlightColor());
cardList.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
cardList.setAdapter(adapter);
if (settings.likeEnabled()) {
favButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.like, 0, 0, 0);
likeButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.like, 0, 0, 0);
} else {
favButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.favorite, 0, 0, 0);
likeButton.setCompoundDrawablesWithIntrinsicBounds(R.drawable.favorite, 0, 0, 0);
}
toolbar.setTitle("");
setSupportActionBar(toolbar);
@ -239,17 +238,18 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
confirmDialog = new ConfirmDialog(this);
metricsDialog = new MetricsDialog(this);
confirmDialog.setConfirmListener(this);
repostName.setOnClickListener(this);
repostNameButton.setOnClickListener(this);
replyName.setOnClickListener(this);
ansButton.setOnClickListener(this);
rtwButton.setOnClickListener(this);
favButton.setOnClickListener(this);
replyButton.setOnClickListener(this);
repostButton.setOnClickListener(this);
likeButton.setOnClickListener(this);
profileImage.setOnClickListener(this);
coordinates.setOnClickListener(this);
rtwButton.setOnLongClickListener(this);
favButton.setOnLongClickListener(this);
repostName.setOnLongClickListener(this);
coordinates.setOnLongClickListener(this);
locationButton.setOnClickListener(this);
repostButton.setOnLongClickListener(this);
likeButton.setOnLongClickListener(this);
repostNameButton.setOnLongClickListener(this);
locationButton.setOnLongClickListener(this);
bookmarkButton.setOnLongClickListener(this);
}
@ -509,6 +509,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
intent.putExtra(KEY_STATUS_DATA, embeddedStatus);
startActivity(intent);
}
return true;
}
// copy status coordinates
else if (v.getId() == R.id.page_status_location_coordinates) {
@ -523,6 +524,18 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
clip.setPrimaryClip(linkClip);
Toast.makeText(getApplicationContext(), R.string.info_tweet_location_copied, LENGTH_SHORT).show();
}
return true;
}
// bookmark status
else if (v.getId() == R.id.page_status_bookmark) {
if (status.isBookmarked()) {
statusAsync = new StatusAction(this, StatusAction.UNBOOKMARK);
} else {
statusAsync = new StatusAction(this, StatusAction.BOOKMARK);
}
statusAsync.execute(status.getId());
Toast.makeText(getApplicationContext(), R.string.info_loading, LENGTH_SHORT).show();
return true;
}
}
return false;
@ -656,25 +669,30 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
public void setStatus(@NonNull Status status) {
this.status = status;
if (status.getEmbeddedStatus() != null) {
repostName.setVisibility(VISIBLE);
repostName.setText(status.getAuthor().getScreenname());
repostNameButton.setVisibility(VISIBLE);
repostNameButton.setText(status.getAuthor().getScreenname());
status = status.getEmbeddedStatus();
} else {
repostName.setVisibility(GONE);
repostNameButton.setVisibility(GONE);
}
User author = status.getAuthor();
Location location = status.getLocation();
invalidateOptionsMenu();
if (status.isReposted()) {
AppStyles.setDrawableColor(rtwButton, settings.getRepostIconColor());
AppStyles.setDrawableColor(repostButton, settings.getRepostIconColor());
} else {
AppStyles.setDrawableColor(rtwButton, settings.getIconColor());
AppStyles.setDrawableColor(repostButton, settings.getIconColor());
}
if (status.isFavorited()) {
AppStyles.setDrawableColor(favButton, settings.getFavoriteIconColor());
AppStyles.setDrawableColor(likeButton, settings.getFavoriteIconColor());
} else {
AppStyles.setDrawableColor(favButton, settings.getIconColor());
AppStyles.setDrawableColor(likeButton, settings.getIconColor());
}
if (status.isBookmarked()) {
AppStyles.setDrawableColor(bookmarkButton, settings.getBookmarkColor());
} else {
AppStyles.setDrawableColor(bookmarkButton, settings.getIconColor());
}
if (author.isVerified()) {
userName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.verify, 0, 0, 0);
@ -691,9 +709,9 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
userName.setText(author.getUsername());
screenName.setText(author.getScreenname());
createdAt.setText(SimpleDateFormat.getDateTimeInstance().format(status.getTimestamp()));
ansButton.setText(StringTools.NUMBER_FORMAT.format(status.getReplyCount()));
favButton.setText(StringTools.NUMBER_FORMAT.format(status.getFavoriteCount()));
rtwButton.setText(StringTools.NUMBER_FORMAT.format(status.getRepostCount()));
replyButton.setText(StringTools.NUMBER_FORMAT.format(status.getReplyCount()));
likeButton.setText(StringTools.NUMBER_FORMAT.format(status.getFavoriteCount()));
repostButton.setText(StringTools.NUMBER_FORMAT.format(status.getRepostCount()));
if (!status.getSource().isEmpty()) {
statusApi.setText(R.string.tweet_sent_from);
statusApi.append(status.getSource());
@ -737,19 +755,24 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
locationName.setVisibility(GONE);
}
if (!location.getCoordinates().isEmpty()) {
coordinates.setVisibility(VISIBLE);
coordinates.setText(location.getCoordinates());
locationButton.setVisibility(VISIBLE);
locationButton.setText(location.getCoordinates());
} else {
coordinates.setVisibility(GONE);
locationButton.setVisibility(GONE);
}
} else {
locationName.setVisibility(GONE);
coordinates.setVisibility(GONE);
locationButton.setVisibility(GONE);
}
if (rtwButton.getVisibility() != VISIBLE) {
rtwButton.setVisibility(VISIBLE);
favButton.setVisibility(VISIBLE);
ansButton.setVisibility(VISIBLE);
if (repostButton.getVisibility() != VISIBLE) {
if (settings.getLogin().getConfiguration() == Configuration.MASTODON) {
bookmarkButton.setVisibility(VISIBLE);
} else {
bookmarkButton.setVisibility(GONE);
}
repostButton.setVisibility(VISIBLE);
likeButton.setVisibility(VISIBLE);
replyButton.setVisibility(VISIBLE);
}
if ((status.getCards().length > 0 || status.getMedia().length > 0) || status.getPoll() != null) {
cardList.setVisibility(VISIBLE);
@ -791,6 +814,14 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
Toast.makeText(getApplicationContext(), R.string.info_tweet_unfavored, LENGTH_SHORT).show();
break;
case StatusAction.BOOKMARK:
Toast.makeText(getApplicationContext(), R.string.info_tweet_bookmarked, LENGTH_SHORT).show();
break;
case StatusAction.UNBOOKMARK:
Toast.makeText(getApplicationContext(), R.string.info_tweet_unbookmarked, LENGTH_SHORT).show();
break;
case StatusAction.HIDE:
hidden = true;
invalidateOptionsMenu();

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16sp"
android:height="16sp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14,2v17l-4,-4l-4,4V2c0,-0.553 0.585,-1.02 1,-1h6C13.689,0.98 14,1.447 14,2z" />
</vector>

View File

@ -160,7 +160,7 @@
android:text="@string/settings_follow_req_color"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/color_rt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/color_bookmark"
app:layout_constraintEnd_toStartOf="@id/color_follow"
style="@style/ColorButton" />
@ -172,10 +172,32 @@
android:text="@string/settings_follow_color"
app:layout_constraintStart_toEndOf="@id/color_f_req"
app:layout_constraintTop_toBottomOf="@id/color_fav"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@id/color_placeholder"
app:layout_constraintEnd_toEndOf="parent"
style="@style/ColorButton" />
<Button
android:id="@+id/color_bookmark"
android:layout_width="0dp"
android:layout_height="@dimen/settings_color_button_height"
android:layout_margin="@dimen/settings_color_button_margin"
android:text="@string/settings_bookmark_color"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/color_f_req"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/color_placeholder"
style="@style/ColorButton" />
<View
android:id="@+id/color_placeholder"
android:layout_width="0dp"
android:layout_height="@dimen/settings_color_button_height"
android:layout_margin="@dimen/settings_color_button_margin"
app:layout_constraintStart_toEndOf="@id/color_bookmark"
app:layout_constraintTop_toBottomOf="@id/color_follow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@ -247,7 +247,7 @@
android:layout_height="match_parent">
<Button
android:id="@+id/page_status_reply"
android:id="@+id/page_status_bookmark"
android:layout_width="0dp"
android:layout_height="@dimen/page_status_button_height"
android:visibility="invisible"
@ -258,10 +258,26 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/page_status_reply_fragment"
app:layout_constraintEnd_toStartOf="@id/page_status_repost"
app:layout_constraintEnd_toStartOf="@id/page_status_reply"
app:layout_constraintHorizontal_weight="1"
style="@style/FeedbackButton" />
<Button
android:id="@+id/page_status_reply"
android:layout_width="0dp"
android:layout_height="@dimen/page_status_button_height"
android:visibility="invisible"
android:paddingLeft="@dimen/page_status_button_padding"
android:paddingRight="@dimen/page_status_button_padding"
android:drawablePadding="@dimen/page_status_padding_drawable"
android:layout_margin="@dimen/page_status_button_margin"
app:layout_constraintStart_toEndOf="@id/page_status_bookmark"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/page_status_reply_fragment"
app:layout_constraintEnd_toStartOf="@id/page_status_repost"
app:layout_constraintHorizontal_weight="2"
style="@style/FeedbackButton" />
<Button
android:id="@+id/page_status_repost"
android:layout_width="0dp"
@ -275,7 +291,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/page_status_reply_fragment"
app:layout_constraintEnd_toStartOf="@id/page_status_favorite"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintHorizontal_weight="2"
style="@style/FeedbackButton" />
<Button
@ -291,7 +307,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/page_status_reply_fragment"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintHorizontal_weight="2"
style="@style/FeedbackButton" />
<androidx.fragment.app.FragmentContainerView

View File

@ -265,4 +265,7 @@
<string name="info_missing_host">bitte gültigen Hostnamen eingeben</string>
<string name="info_missing_api_keys">Bitte API-Schlüssel hinzufügen</string>
<string name="menu_show_local_timeline">zeige lokale Timeline</string>
<string name="info_tweet_bookmarked">Status zu Lesezeichen hinzugefügt</string>
<string name="info_tweet_unbookmarked">Status aus Lesezeichen entfernt</string>
<string name="settings_bookmark_color">Lesezeichen symbol</string>
</resources>

View File

@ -27,6 +27,8 @@
<string name="info_tweet_unfavored">Status removed from favorites</string>
<string name="info_tweet_liked">Status liked</string>
<string name="info_tweet_unliked">Status unliked</string>
<string name="info_tweet_bookmarked">Status added to bookmarks</string>
<string name="info_tweet_unbookmarked">Status removed from bookmarks</string>
<string name="info_reply_hidden">Reply is hidden</string>
<string name="info_reply_unhidden">Reply is visible</string>
<string name="info_user_muted">User muted</string>
@ -270,6 +272,7 @@
<string name="settings_rt_icon_color">Reposts</string>
<string name="settings_follow_req_color">Follow request</string>
<string name="settings_follow_color">Following icon</string>
<string name="settings_bookmark_color">Bookmark icon</string>
<string name="account_page" translatable="false">Accounts</string>
<string name="confirm_remove_account">remove account from list?</string>
<string name="dialog_confirm_warning">Warning</string>

View File

@ -1,5 +1,6 @@
#Sat Feb 11 13:53:51 CET 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME