added poll option emoji support, restructured adapter holder, code cleanup

This commit is contained in:
nuclearfog 2023-07-09 18:23:18 +02:00
parent 4f4fc191ae
commit a7a6a5cc2c
No known key found for this signature in database
GPG Key ID: 03488A185C476379
34 changed files with 246 additions and 79 deletions

View File

@ -0,0 +1,50 @@
package org.nuclearfog.twidda.backend.api.mastodon.impl;
import org.json.JSONException;
import org.json.JSONObject;
import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.model.User.Field;
/**
* User fields implementation of Mastodon
*
* @author nuclearfog
*/
public class MastodonField implements Field {
private static final long serialVersionUID = 2278113885084330065L;
private String key;
private String value;
private long timestamp = 0L;
/**
* @param json fields json
*/
public MastodonField(JSONObject json) throws JSONException {
key = json.getString("name");
value = json.getString("value");
String timeStr = json.getString("verified_at");
if (!timeStr.equals("null")) {
timestamp = StringUtils.getTime(timeStr, StringUtils.TIME_MASTODON);
}
}
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return value;
}
@Override
public long getTimestamp() {
return timestamp;
}
}

View File

@ -7,6 +7,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.nuclearfog.twidda.backend.utils.StringUtils; import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Poll; import org.nuclearfog.twidda.model.Poll;
/** /**
@ -25,15 +26,17 @@ public class MastodonPoll implements Poll {
private boolean multipleChoice; private boolean multipleChoice;
private int voteCount; private int voteCount;
private MastodonOption[] options; private MastodonOption[] options;
private Emoji[] emojis = {};
/** /**
* @param json Mastodon poll jswon format * @param json Mastodon poll jswon format
*/ */
public MastodonPoll(JSONObject json) throws JSONException { public MastodonPoll(JSONObject json) throws JSONException {
String idStr = json.getString("id"); JSONArray optionArray = json.getJSONArray("options");
JSONArray voteArray = json.optJSONArray("own_votes");
JSONArray emojiArray = json.optJSONArray("emojis");
String exTimeStr = json.getString("expires_at"); String exTimeStr = json.getString("expires_at");
JSONArray optionsJson = json.getJSONArray("options"); String idStr = json.getString("id");
JSONArray votesJson = json.optJSONArray("own_votes");
exTime = StringUtils.getTime(exTimeStr, StringUtils.TIME_MASTODON); exTime = StringUtils.getTime(exTimeStr, StringUtils.TIME_MASTODON);
expired = json.getBoolean("expired"); expired = json.getBoolean("expired");
voted = json.optBoolean("voted", false); voted = json.optBoolean("voted", false);
@ -41,20 +44,25 @@ public class MastodonPoll implements Poll {
if (!json.isNull("voters_count")) { if (!json.isNull("voters_count")) {
voteCount = json.getInt("voters_count"); voteCount = json.getInt("voters_count");
} }
options = new MastodonOption[optionArray.length()];
options = new MastodonOption[optionsJson.length()]; for (int i = 0; i < optionArray.length(); i++) {
for (int i = 0; i < optionsJson.length(); i++) { JSONObject option = optionArray.getJSONObject(i);
JSONObject option = optionsJson.getJSONObject(i);
options[i] = new MastodonOption(option); options[i] = new MastodonOption(option);
} }
if (votesJson != null) { if (voteArray != null) {
for (int i = 0; i < votesJson.length(); i++) { for (int i = 0; i < voteArray.length(); i++) {
int index = votesJson.getInt(i); int index = voteArray.getInt(i);
if (index >= 0 && index < options.length) { if (index >= 0 && index < options.length) {
options[index].setSelected(); options[index].setSelected();
} }
} }
} }
if (emojiArray != null && emojiArray.length() > 0) {
emojis = new Emoji[emojiArray.length()];
for (int i = 0; i < emojis.length; i++) {
emojis[i] = new MastodonEmoji(emojiArray.getJSONObject(i));
}
}
try { try {
id = Long.parseLong(idStr); id = Long.parseLong(idStr);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
@ -105,6 +113,12 @@ public class MastodonPoll implements Poll {
} }
@Override
public Emoji[] getEmojis() {
return emojis;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Poll && ((Poll) o).getId() == getId(); return o instanceof Poll && ((Poll) o).getId() == getId();

View File

@ -37,6 +37,7 @@ public class MastodonUser implements User {
private boolean locked; private boolean locked;
private boolean isCurrentUser; private boolean isCurrentUser;
private Emoji[] emojis = {}; private Emoji[] emojis = {};
private Field[] fields = {};
/** /**
* constructor used to create an user instance of the current user * constructor used to create an user instance of the current user
@ -56,6 +57,7 @@ public class MastodonUser implements User {
*/ */
public MastodonUser(JSONObject json, long currentUserId) throws JSONException { public MastodonUser(JSONObject json, long currentUserId) throws JSONException {
JSONArray emojiArray = json.optJSONArray("emojis"); JSONArray emojiArray = json.optJSONArray("emojis");
JSONArray fieldsArray = json.optJSONArray("fields");
String idStr = json.getString("id"); String idStr = json.getString("id");
String description = json.optString("note", ""); String description = json.optString("note", "");
String profileUrl = json.optString("avatar_static", ""); String profileUrl = json.optString("avatar_static", "");
@ -85,6 +87,13 @@ public class MastodonUser implements User {
emojis[i] = new MastodonEmoji(emojiJson); emojis[i] = new MastodonEmoji(emojiJson);
} }
} }
if (fieldsArray != null && fieldsArray.length() > 0) {
fields = new Field[fieldsArray.length()];
for (int i = 0; i < fields.length; i++) {
JSONObject fieldJson = fieldsArray.getJSONObject(i);
fields[i] = new MastodonField(fieldJson);
}
}
try { try {
id = Long.parseLong(idStr); id = Long.parseLong(idStr);
isCurrentUser = currentUserId == id; isCurrentUser = currentUserId == id;
@ -220,6 +229,12 @@ public class MastodonUser implements User {
} }
@Override
public Field[] getFields() {
return fields;
}
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof User)) if (!(obj instanceof User))

View File

@ -236,6 +236,12 @@ public class UserV1 implements User {
} }
@Override
public Field[] getFields() {
return new Field[0];
}
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof User)) if (!(obj instanceof User))

View File

@ -7,6 +7,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.nuclearfog.twidda.backend.utils.StringUtils; import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Poll; import org.nuclearfog.twidda.model.Poll;
/** /**
@ -98,6 +99,12 @@ public class PollV2 implements Poll {
} }
@Override
public Emoji[] getEmojis() {
return new Emoji[0];
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Poll && ((Poll) o).getId() == getId(); return o instanceof Poll && ((Poll) o).getId() == getId();

View File

@ -220,6 +220,12 @@ public class UserV2 implements User {
} }
@Override
public Field[] getFields() {
return new Field[0];
}
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof User)) if (!(obj instanceof User))

View File

@ -77,7 +77,7 @@ public class MediaStatus implements Serializable, Closeable {
/** /**
* create MediaStatus from an offline source * create MediaStatus from an offline source
* *
* @param uri path to the local file * @param uri path to the local file
* @throws FileNotFoundException if the file is invalid * @throws FileNotFoundException if the file is invalid
*/ */
public MediaStatus(Context context, Uri uri) throws FileNotFoundException { public MediaStatus(Context context, Uri uri) throws FileNotFoundException {

View File

@ -4,6 +4,7 @@ import android.content.ContentResolver;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.helper.MediaStatus; import org.nuclearfog.twidda.backend.helper.MediaStatus;
import java.io.Closeable; import java.io.Closeable;
@ -52,12 +53,14 @@ public class ProfileUpdate implements Closeable {
} }
/** /**
*
*/ */
public void setProfileImage(MediaStatus profileImage) { public void setProfileImage(MediaStatus profileImage) {
this.profileImage = profileImage; this.profileImage = profileImage;
} }
/** /**
*
*/ */
public void setBannerImage(MediaStatus bannerImage) { public void setBannerImage(MediaStatus bannerImage) {
this.bannerImage = bannerImage; this.bannerImage = bannerImage;

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.nuclearfog.twidda.database.DatabaseAdapter.PollTable; import org.nuclearfog.twidda.database.DatabaseAdapter.PollTable;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Poll; import org.nuclearfog.twidda.model.Poll;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -86,6 +87,12 @@ public class DatabasePoll implements Poll, PollTable {
} }
@Override
public Emoji[] getEmojis() {
return new Emoji[0];
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Poll && ((Poll) o).getId() == getId(); return o instanceof Poll && ((Poll) o).getId() == getId();

View File

@ -211,6 +211,12 @@ public class DatabaseUser implements User, UserTable, UserRegisterTable {
} }
@Override
public Field[] getFields() {
return new Field[0];// todo implement this
}
@Override @Override
public boolean equals(@Nullable Object obj) { public boolean equals(@Nullable Object obj) {
if (!(obj instanceof User)) if (!(obj instanceof User))

View File

@ -44,6 +44,10 @@ public interface Poll extends Serializable {
*/ */
Option[] getOptions(); Option[] getOptions();
/**
* @return emojis used in option titles
*/
Emoji[] getEmojis();
/** /**
* represents a vote option * represents a vote option

View File

@ -114,9 +114,41 @@ public interface User extends Serializable, Comparable<User> {
*/ */
Emoji[] getEmojis(); Emoji[] getEmojis();
/**
* @return fields set by user
*/
Field[] getFields();
@Override @Override
default int compareTo(User o) { default int compareTo(User o) {
return Long.compare(o.getId(), getId()); return Long.compare(o.getId(), getId());
} }
/**
* represents an user field.
*/
interface Field extends Serializable {
/**
* get the key of a given fields key-value pair.
*
* @return key string
*/
String getKey();
/**
* get the value associated with the name key.
*
* @return value string
*/
String getValue();
/**
* get the timestamp of the verification if any
*
* @return ISO 8601 Datetime or '0' if not defined
*/
long getTimestamp();
}
} }

View File

@ -213,8 +213,7 @@ public class ImageViewer extends MediaActivity implements AsyncCallback<ImageLoa
storeImage(cacheUri); storeImage(cacheUri);
return true; return true;
} }
} } else if (item.getItemId() == R.id.menu_image_add_description) {
else if (item.getItemId() == R.id.menu_image_add_description) {
descriptionDialog.show(); descriptionDialog.show();
return true; return true;
} }

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.adapter; package org.nuclearfog.twidda.ui.adapter;
import android.content.Context;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -8,7 +7,6 @@ import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.tag.Tagger.OnTagClickListener; import org.nuclearfog.tag.Tagger.OnTagClickListener;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.model.Message; import org.nuclearfog.twidda.model.Message;
import org.nuclearfog.twidda.model.lists.Messages; import org.nuclearfog.twidda.model.lists.Messages;
import org.nuclearfog.twidda.ui.adapter.holder.MessageHolder; import org.nuclearfog.twidda.ui.adapter.holder.MessageHolder;
@ -44,7 +42,6 @@ public class MessageAdapter extends Adapter<ViewHolder> implements OnItemClickLi
public static final int CLEAR_LIST = -1; public static final int CLEAR_LIST = -1;
private OnMessageClickListener itemClickListener; private OnMessageClickListener itemClickListener;
private TextEmojiLoader emojiLoader;
private Messages messages = new Messages(); private Messages messages = new Messages();
private int loadingIndex = NO_LOADING; private int loadingIndex = NO_LOADING;
@ -52,8 +49,7 @@ public class MessageAdapter extends Adapter<ViewHolder> implements OnItemClickLi
/** /**
* @param itemClickListener click listener * @param itemClickListener click listener
*/ */
public MessageAdapter(Context context, OnMessageClickListener itemClickListener) { public MessageAdapter(OnMessageClickListener itemClickListener) {
emojiLoader = new TextEmojiLoader(context);
this.itemClickListener = itemClickListener; this.itemClickListener = itemClickListener;
} }
@ -76,7 +72,7 @@ public class MessageAdapter extends Adapter<ViewHolder> implements OnItemClickLi
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_MESSAGE) { if (viewType == TYPE_MESSAGE) {
return new MessageHolder(parent, emojiLoader, this); return new MessageHolder(parent, this);
} else { } else {
return new PlaceHolder(parent, this, false); return new PlaceHolder(parent, this, false);
} }

View File

@ -1,13 +1,11 @@
package org.nuclearfog.twidda.ui.adapter; package org.nuclearfog.twidda.ui.adapter;
import android.content.Context;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.model.Notification; import org.nuclearfog.twidda.model.Notification;
import org.nuclearfog.twidda.model.User; import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.model.lists.Notifications; import org.nuclearfog.twidda.model.lists.Notifications;
@ -46,7 +44,6 @@ public class NotificationAdapter extends Adapter<ViewHolder> implements OnHolder
private static final int TYPE_USER = 2; private static final int TYPE_USER = 2;
private OnNotificationClickListener listener; private OnNotificationClickListener listener;
private TextEmojiLoader emojiLoader;
private Notifications notifications = new Notifications(); private Notifications notifications = new Notifications();
private int loadingIndex = NO_LOADING; private int loadingIndex = NO_LOADING;
@ -54,8 +51,7 @@ public class NotificationAdapter extends Adapter<ViewHolder> implements OnHolder
/** /**
* *
*/ */
public NotificationAdapter(Context context, OnNotificationClickListener listener) { public NotificationAdapter(OnNotificationClickListener listener) {
emojiLoader = new TextEmojiLoader(context);
this.listener = listener; this.listener = listener;
} }
@ -64,9 +60,9 @@ public class NotificationAdapter extends Adapter<ViewHolder> implements OnHolder
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_STATUS) { if (viewType == TYPE_STATUS) {
return new StatusHolder(parent, emojiLoader, this); return new StatusHolder(parent, this);
} else if (viewType == TYPE_USER) { } else if (viewType == TYPE_USER) {
return new UserHolder(parent, emojiLoader, this, false); return new UserHolder(parent, this, false);
} else { } else {
return new PlaceHolder(parent, this, false); return new PlaceHolder(parent, this, false);
} }

View File

@ -5,6 +5,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Poll; import org.nuclearfog.twidda.model.Poll;
import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener; import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener;
import org.nuclearfog.twidda.ui.adapter.holder.Optionholder; import org.nuclearfog.twidda.ui.adapter.holder.Optionholder;
@ -22,6 +23,7 @@ public class OptionsAdapter extends Adapter<Optionholder> implements OnHolderCli
private int totalVotes, limitVotes; private int totalVotes, limitVotes;
private Poll.Option[] options = {}; private Poll.Option[] options = {};
private Emoji[] emojis = {};
private Set<Integer> selection = new TreeSet<>(); private Set<Integer> selection = new TreeSet<>();
@ -34,7 +36,7 @@ public class OptionsAdapter extends Adapter<Optionholder> implements OnHolderCli
@Override @Override
public void onBindViewHolder(@NonNull Optionholder holder, int position) { public void onBindViewHolder(@NonNull Optionholder holder, int position) {
holder.setContent(options[position], selection.contains(position), totalVotes); holder.setContent(options[position], emojis, selection.contains(position), totalVotes);
} }
@ -70,6 +72,7 @@ public class OptionsAdapter extends Adapter<Optionholder> implements OnHolderCli
*/ */
public void addItems(Poll poll) { public void addItems(Poll poll) {
options = poll.getOptions(); options = poll.getOptions();
emojis = poll.getEmojis();
for (int i = 0; i < options.length; i++) { for (int i = 0; i < options.length; i++) {
Poll.Option option = options[i]; Poll.Option option = options[i];
if (option.isSelected()) { if (option.isSelected()) {
@ -84,7 +87,6 @@ public class OptionsAdapter extends Adapter<Optionholder> implements OnHolderCli
limitVotes = 1; limitVotes = 1;
} }
totalVotes = poll.voteCount(); totalVotes = poll.voteCount();
notifyDataSetChanged(); notifyDataSetChanged();
} }

View File

@ -1,13 +1,11 @@
package org.nuclearfog.twidda.ui.adapter; package org.nuclearfog.twidda.ui.adapter;
import android.content.Context;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.model.Status; import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.model.lists.Statuses; import org.nuclearfog.twidda.model.lists.Statuses;
import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener; import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener;
@ -48,7 +46,6 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
*/ */
public static final int CLEAR_LIST = -1; public static final int CLEAR_LIST = -1;
private TextEmojiLoader emojiLoader;
private StatusSelectListener listener; private StatusSelectListener listener;
private Statuses items; private Statuses items;
@ -57,8 +54,7 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
/** /**
* @param itemClickListener listener for item click * @param itemClickListener listener for item click
*/ */
public StatusAdapter(Context context, StatusSelectListener itemClickListener) { public StatusAdapter(StatusSelectListener itemClickListener) {
emojiLoader = new TextEmojiLoader(context);
loadingIndex = NO_LOADING; loadingIndex = NO_LOADING;
items = new Statuses(); items = new Statuses();
this.listener = itemClickListener; this.listener = itemClickListener;
@ -83,7 +79,7 @@ public class StatusAdapter extends Adapter<ViewHolder> implements OnHolderClickL
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_STATUS) { if (viewType == VIEW_STATUS) {
return new StatusHolder(parent, emojiLoader, this); return new StatusHolder(parent, this);
} else { } else {
return new PlaceHolder(parent, this, false); return new PlaceHolder(parent, this, false);
} }

View File

@ -1,13 +1,11 @@
package org.nuclearfog.twidda.ui.adapter; package org.nuclearfog.twidda.ui.adapter;
import android.content.Context;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.model.User; import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.model.lists.Users; import org.nuclearfog.twidda.model.lists.Users;
import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener; import org.nuclearfog.twidda.ui.adapter.holder.OnHolderClickListener;
@ -42,8 +40,6 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
*/ */
public static final int CLEAR_LIST = -1; public static final int CLEAR_LIST = -1;
private TextEmojiLoader emojiLoader;
private UserClickListener listener; private UserClickListener listener;
private boolean enableDelete; private boolean enableDelete;
@ -53,8 +49,7 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
/** /**
* @param listener item click listener * @param listener item click listener
*/ */
public UserAdapter(Context context, UserClickListener listener) { public UserAdapter(UserClickListener listener) {
emojiLoader = new TextEmojiLoader(context);
this.listener = listener; this.listener = listener;
} }
@ -77,7 +72,7 @@ public class UserAdapter extends Adapter<ViewHolder> implements OnHolderClickLis
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == ITEM_USER) { if (viewType == ITEM_USER) {
return new UserHolder(parent, emojiLoader, this, enableDelete); return new UserHolder(parent, this, enableDelete);
} else { } else {
return new PlaceHolder(parent, this, false); return new PlaceHolder(parent, this, false);
} }

View File

@ -1,13 +1,11 @@
package org.nuclearfog.twidda.ui.adapter; package org.nuclearfog.twidda.ui.adapter;
import android.content.Context;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.model.User; import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.model.UserList; import org.nuclearfog.twidda.model.UserList;
import org.nuclearfog.twidda.model.lists.UserLists; import org.nuclearfog.twidda.model.lists.UserLists;
@ -48,7 +46,6 @@ public class UserlistAdapter extends Adapter<ViewHolder> implements OnHolderClic
*/ */
private ListClickListener listener; private ListClickListener listener;
private TextEmojiLoader emojiLoader;
private UserLists userlists = new UserLists(); private UserLists userlists = new UserLists();
private int loadingIndex = NO_LOADING; private int loadingIndex = NO_LOADING;
@ -56,9 +53,8 @@ public class UserlistAdapter extends Adapter<ViewHolder> implements OnHolderClic
/** /**
* @param listener item click listener * @param listener item click listener
*/ */
public UserlistAdapter(Context context, ListClickListener listener) { public UserlistAdapter(ListClickListener listener) {
this.listener = listener; this.listener = listener;
emojiLoader = new TextEmojiLoader(context);
} }
@ -80,7 +76,7 @@ public class UserlistAdapter extends Adapter<ViewHolder> implements OnHolderClic
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == ITEM_LIST) { if (viewType == ITEM_LIST) {
return new UserlistHolder(parent, emojiLoader, this); return new UserlistHolder(parent, this);
} else { } else {
return new PlaceHolder(parent, this, false); return new PlaceHolder(parent, this, false);
} }

View File

@ -69,13 +69,15 @@ public class MessageHolder extends ViewHolder implements OnClickListener, OnTagC
private long tagId; private long tagId;
/**
public MessageHolder(ViewGroup parent, TextEmojiLoader emojiLoader, OnItemClickListener listener) { *
*/
public MessageHolder(ViewGroup parent, OnItemClickListener listener) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message, parent, false)); super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message, parent, false));
settings = GlobalSettings.get(parent.getContext()); settings = GlobalSettings.get(parent.getContext());
picasso = PicassoBuilder.get(parent.getContext()); picasso = PicassoBuilder.get(parent.getContext());
emojiLoader = new TextEmojiLoader(parent.getContext());
this.listener = listener; this.listener = listener;
this.emojiLoader = emojiLoader;
CardView background = (CardView) itemView; CardView background = (CardView) itemView;
ViewGroup container = itemView.findViewById(R.id.item_message_container); ViewGroup container = itemView.findViewById(R.id.item_message_container);

View File

@ -1,5 +1,7 @@
package org.nuclearfog.twidda.ui.adapter.holder; package org.nuclearfog.twidda.ui.adapter.holder;
import android.text.Spannable;
import android.text.SpannableString;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
@ -8,13 +10,20 @@ import android.widget.ImageView;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.nuclearfog.twidda.R; import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader.EmojiParam;
import org.nuclearfog.twidda.backend.async.TextEmojiLoader.EmojiResult;
import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.EmojiUtils;
import org.nuclearfog.twidda.backend.utils.StringUtils; import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.config.GlobalSettings; import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.model.Emoji;
import org.nuclearfog.twidda.model.Poll.Option; import org.nuclearfog.twidda.model.Poll.Option;
/** /**
@ -22,21 +31,25 @@ import org.nuclearfog.twidda.model.Poll.Option;
* *
* @author nuclearfog * @author nuclearfog
*/ */
public class Optionholder extends ViewHolder implements OnClickListener { public class Optionholder extends ViewHolder implements OnClickListener, AsyncCallback<EmojiResult> {
private SeekBar voteProgress; private SeekBar voteProgress;
private TextView optionName, optionVotes; private TextView optionName, optionVotes;
private ImageView checkIcon; private ImageView checkIcon;
private OnHolderClickListener listener; private OnHolderClickListener listener;
private TextEmojiLoader emojiLoader;
private GlobalSettings settings; private GlobalSettings settings;
private long tagId;
/** /**
* *
*/ */
public Optionholder(ViewGroup parent, OnHolderClickListener listener) { public Optionholder(ViewGroup parent, OnHolderClickListener listener) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false)); super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false));
settings = GlobalSettings.get(parent.getContext()); settings = GlobalSettings.get(parent.getContext());
emojiLoader = new TextEmojiLoader(parent.getContext());
this.listener = listener; this.listener = listener;
optionName = itemView.findViewById(R.id.item_option_name); optionName = itemView.findViewById(R.id.item_option_name);
@ -66,6 +79,15 @@ public class Optionholder extends ViewHolder implements OnClickListener {
} }
} }
@Override
public void onResult(@NonNull EmojiResult result) {
if (result.images != null && result.id == tagId) {
Spannable spannable = EmojiUtils.addEmojis(optionName.getContext(), result.spannable, result.images);
optionName.setText(spannable);
}
}
/** /**
* set viewholder content * set viewholder content
* *
@ -73,16 +95,24 @@ public class Optionholder extends ViewHolder implements OnClickListener {
* @param selected true if option is selected * @param selected true if option is selected
* @param totalCount total vote count * @param totalCount total vote count
*/ */
public void setContent(Option option, boolean selected, int totalCount) { public void setContent(Option option, Emoji[] emojis, boolean selected, int totalCount) {
voteProgress.setMax(Math.max(totalCount, 1));
AppStyles.setDrawableColor(checkIcon, settings.getIconColor());
voteProgress.setProgress(option.getVotes());
optionVotes.setText(StringUtils.NUMBER_FORMAT.format(option.getVotes()));
if (emojis.length > 0 && settings.imagesEnabled()) {
tagId = option.getTitle().hashCode();
SpannableString optionSpan = new SpannableString(option.getTitle());
EmojiParam param = new EmojiParam(tagId, emojis, optionSpan, optionName.getResources().getDimensionPixelSize(R.dimen.item_option_emoji_size));
optionName.setText(EmojiUtils.removeTags(optionSpan));
emojiLoader.execute(param, this);
} else {
optionName.setText(option.getTitle());
}
if (option.isSelected() | selected) { if (option.isSelected() | selected) {
checkIcon.setImageResource(R.drawable.check); checkIcon.setImageResource(R.drawable.check);
} else { } else {
checkIcon.setImageResource(R.drawable.circle); checkIcon.setImageResource(R.drawable.circle);
} }
voteProgress.setMax(Math.max(totalCount, 1));
AppStyles.setDrawableColor(checkIcon, settings.getIconColor());
optionName.setText(option.getTitle());
voteProgress.setProgress(option.getVotes());
optionVotes.setText(StringUtils.NUMBER_FORMAT.format(option.getVotes()));
} }
} }

View File

@ -72,13 +72,15 @@ public class StatusHolder extends ViewHolder implements OnClickListener, OnMedia
private long tagId = 0L; private long tagId = 0L;
/**
public StatusHolder(ViewGroup parent, TextEmojiLoader emojiLoader, OnHolderClickListener listener) { *
*/
public StatusHolder(ViewGroup parent, OnHolderClickListener listener) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_status, parent, false)); super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_status, parent, false));
settings = GlobalSettings.get(parent.getContext()); settings = GlobalSettings.get(parent.getContext());
picasso = PicassoBuilder.get(parent.getContext()); picasso = PicassoBuilder.get(parent.getContext());
emojiLoader = new TextEmojiLoader(parent.getContext());
this.listener = listener; this.listener = listener;
this.emojiLoader = emojiLoader;
CardView cardLayout = (CardView) itemView; CardView cardLayout = (CardView) itemView;
ViewGroup container = itemView.findViewById(R.id.item_status_container); ViewGroup container = itemView.findViewById(R.id.item_status_container);

View File

@ -63,13 +63,15 @@ public class UserHolder extends ViewHolder implements OnClickListener, AsyncCall
private long tagId = 0L; private long tagId = 0L;
/**
public UserHolder(ViewGroup parent, TextEmojiLoader emojiLoader, OnHolderClickListener listener, boolean enableDelete) { * @param enableRemoveButton true to enable remove button
*/
public UserHolder(ViewGroup parent, OnHolderClickListener listener, boolean enableRemoveButton) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false)); super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false));
this.settings = GlobalSettings.get(parent.getContext()); settings = GlobalSettings.get(parent.getContext());
this.picasso = PicassoBuilder.get(parent.getContext()); picasso = PicassoBuilder.get(parent.getContext());
emojiLoader = new TextEmojiLoader(parent.getContext());
this.listener = listener; this.listener = listener;
this.emojiLoader = emojiLoader;
CardView background = (CardView) itemView; CardView background = (CardView) itemView;
ViewGroup container = itemView.findViewById(R.id.item_user_container); ViewGroup container = itemView.findViewById(R.id.item_user_container);
@ -87,7 +89,7 @@ public class UserHolder extends ViewHolder implements OnClickListener, AsyncCall
AppStyles.setTheme(container, Color.TRANSPARENT); AppStyles.setTheme(container, Color.TRANSPARENT);
background.setCardBackgroundColor(settings.getCardColor()); background.setCardBackgroundColor(settings.getCardColor());
if (enableDelete) { if (enableRemoveButton) {
delete.setVisibility(View.VISIBLE); delete.setVisibility(View.VISIBLE);
} else { } else {
delete.setVisibility(View.GONE); delete.setVisibility(View.GONE);

View File

@ -62,13 +62,13 @@ public class UserlistHolder extends ViewHolder implements OnClickListener {
private long tagId; private long tagId;
/** /**
* @param parent Parent view from adapter *
*/ */
public UserlistHolder(ViewGroup parent, TextEmojiLoader emojiLoader, OnHolderClickListener listener) { public UserlistHolder(ViewGroup parent, OnHolderClickListener listener) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false)); super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false));
settings = GlobalSettings.get(parent.getContext()); settings = GlobalSettings.get(parent.getContext());
picasso = PicassoBuilder.get(parent.getContext()); picasso = PicassoBuilder.get(parent.getContext());
this.emojiLoader = emojiLoader; emojiLoader = new TextEmojiLoader(parent.getContext());
this.listener = listener; this.listener = listener;
CardView background = (CardView) itemView; CardView background = (CardView) itemView;

View File

@ -53,7 +53,7 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
confirmDialog = new ConfirmDialog(requireActivity(), this); confirmDialog = new ConfirmDialog(requireActivity(), this);
adapter = new MessageAdapter(requireContext(), this); adapter = new MessageAdapter(this);
messageLoader = new MessageLoader(requireContext()); messageLoader = new MessageLoader(requireContext());
setAdapter(adapter); setAdapter(adapter);

View File

@ -64,7 +64,7 @@ public class NotificationFragment extends ListFragment implements OnNotification
confirmDialog = new ConfirmDialog(requireActivity(), this); confirmDialog = new ConfirmDialog(requireActivity(), this);
notificationLoader = new NotificationLoader(requireContext()); notificationLoader = new NotificationLoader(requireContext());
notificationAction = new NotificationAction(requireContext()); notificationAction = new NotificationAction(requireContext());
adapter = new NotificationAdapter(requireContext(), this); adapter = new NotificationAdapter(this);
setAdapter(adapter); setAdapter(adapter);
if (savedInstanceState != null) { if (savedInstanceState != null) {

View File

@ -127,7 +127,7 @@ public class StatusFragment extends ListFragment implements StatusSelectListener
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
statusLoader = new StatusLoader(requireContext()); statusLoader = new StatusLoader(requireContext());
adapter = new StatusAdapter(requireContext(), this); adapter = new StatusAdapter(this);
setAdapter(adapter); setAdapter(adapter);
Bundle param = getArguments(); Bundle param = getArguments();

View File

@ -168,7 +168,7 @@ public class UserFragment extends ListFragment implements UserClickListener, OnC
userLoader = new UsersLoader(requireContext()); userLoader = new UsersLoader(requireContext());
userlistManager = new UserlistManager(requireContext()); userlistManager = new UserlistManager(requireContext());
confirmDialog = new ConfirmDialog(requireActivity(), this); confirmDialog = new ConfirmDialog(requireActivity(), this);
adapter = new UserAdapter(requireContext(), this); adapter = new UserAdapter(this);
setAdapter(adapter); setAdapter(adapter);
Bundle param = getArguments(); Bundle param = getArguments();

View File

@ -79,7 +79,7 @@ public class UserListFragment extends ListFragment implements ListClickListener,
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
userlistLoader = new UserlistLoader(requireContext()); userlistLoader = new UserlistLoader(requireContext());
adapter = new UserlistAdapter(requireContext(), this); adapter = new UserlistAdapter(this);
setAdapter(adapter); setAdapter(adapter);
Bundle param = getArguments(); Bundle param = getArguments();

View File

@ -11,7 +11,7 @@
android:text="@string/dialog_description_title" android:text="@string/dialog_description_title"
android:lines="1" android:lines="1"
android:textSize="@dimen/dialog_description_textsize_title" android:textSize="@dimen/dialog_description_textsize_title"
android:layout_margin="@dimen/dialog_description_layout_margin"/> android:layout_margin="@dimen/dialog_description_layout_margin" />
<EditText <EditText
android:id="@+id/dialog_description_input" android:id="@+id/dialog_description_input"

View File

@ -9,6 +9,6 @@
<WebView <WebView
android:id="@+id/dialog_license_view" android:id="@+id/dialog_license_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent" />
</LinearLayout> </LinearLayout>

View File

@ -9,5 +9,5 @@
<item <item
android:id="@+id/menu_image_add_description" android:id="@+id/menu_image_add_description"
android:title="@string/menu_media_add_description" android:title="@string/menu_media_add_description"
android:visible="false"/> android:visible="false" />
</menu> </menu>

View File

@ -4,10 +4,10 @@
<item <item
android:id="@+id/menu_video_link" android:id="@+id/menu_video_link"
android:title="@string/button_share" android:title="@string/button_share"
android:visible="true"/> android:visible="true" />
<item <item
android:id="@+id/menu_video_add_description" android:id="@+id/menu_video_add_description"
android:title="@string/menu_media_add_description" android:title="@string/menu_media_add_description"
android:visible="false"/> android:visible="false" />
</menu> </menu>

View File

@ -289,6 +289,7 @@
<dimen name="item_option_text_size">13sp</dimen> <dimen name="item_option_text_size">13sp</dimen>
<dimen name="item_option_layout_padding">5dp</dimen> <dimen name="item_option_layout_padding">5dp</dimen>
<dimen name="item_option_button_margin">10dp</dimen> <dimen name="item_option_button_margin">10dp</dimen>
<dimen name="item_option_emoji_size">13sp</dimen>
<!--dimens of item_option_edit.xml --> <!--dimens of item_option_edit.xml -->
<dimen name="item_option_edit_layout_padding">3dp</dimen> <dimen name="item_option_edit_layout_padding">3dp</dimen>