Poll notifications (#1229)
* show poll notifications in the app * show poll notifications in the app * allow filtering poll notifications in the poll fragment * show poll notifications in system notifications
This commit is contained in:
parent
647238052b
commit
e735e4843e
44 changed files with 1076 additions and 318 deletions
|
|
@ -68,7 +68,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
|
||||
private static final int VIEW_TYPE_MENTION = 0;
|
||||
private static final int VIEW_TYPE_STATUS = 0;
|
||||
private static final int VIEW_TYPE_STATUS_NOTIFICATION = 1;
|
||||
private static final int VIEW_TYPE_FOLLOW = 2;
|
||||
private static final int VIEW_TYPE_PLACEHOLDER = 3;
|
||||
|
|
@ -77,6 +77,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private static final InputFilter[] COLLAPSE_INPUT_FILTER = new InputFilter[]{SmartLengthInputFilter.INSTANCE};
|
||||
private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0];
|
||||
|
||||
private String accountId;
|
||||
private StatusActionListener statusListener;
|
||||
private NotificationActionListener notificationActionListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
|
|
@ -84,10 +85,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private BidiFormatter bidiFormatter;
|
||||
private AdapterDataSource<NotificationViewData> dataSource;
|
||||
|
||||
public NotificationsAdapter(AdapterDataSource<NotificationViewData> dataSource,
|
||||
public NotificationsAdapter(String accountId,
|
||||
AdapterDataSource<NotificationViewData> dataSource,
|
||||
StatusActionListener statusListener,
|
||||
NotificationActionListener notificationActionListener) {
|
||||
super();
|
||||
|
||||
this.accountId = accountId;
|
||||
this.dataSource = dataSource;
|
||||
this.statusListener = statusListener;
|
||||
this.notificationActionListener = notificationActionListener;
|
||||
|
|
@ -101,7 +104,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_MENTION: {
|
||||
case VIEW_TYPE_STATUS: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_status, parent, false);
|
||||
return new StatusViewHolder(view, useAbsoluteTime);
|
||||
|
|
@ -159,17 +162,20 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
NotificationViewData.Concrete concreteNotificaton =
|
||||
(NotificationViewData.Concrete) notification;
|
||||
Notification.Type type = concreteNotificaton.getType();
|
||||
switch (type) {
|
||||
case MENTION: {
|
||||
switch (viewHolder.getItemViewType()) {
|
||||
case VIEW_TYPE_STATUS: {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
||||
holder.setupWithStatus(status,
|
||||
statusListener, mediaPreviewEnabled, payloadForHolder);
|
||||
if(concreteNotificaton.getType() == Notification.Type.POLL) {
|
||||
holder.setPollInfo(accountId.equals(concreteNotificaton.getAccount().getId()));
|
||||
} else {
|
||||
holder.hideStatusInfo();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FAVOURITE:
|
||||
case REBLOG: {
|
||||
case VIEW_TYPE_STATUS_NOTIFICATION: {
|
||||
StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder;
|
||||
StatusViewData.Concrete statusViewData = concreteNotificaton.getStatusViewData();
|
||||
if (payloadForHolder == null) {
|
||||
|
|
@ -200,7 +206,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case FOLLOW: {
|
||||
case VIEW_TYPE_FOLLOW: {
|
||||
if (payloadForHolder == null) {
|
||||
FollowViewHolder holder = (FollowViewHolder) viewHolder;
|
||||
holder.setMessage(concreteNotificaton.getAccount(), bidiFormatter);
|
||||
|
|
@ -225,8 +231,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
if (notification instanceof NotificationViewData.Concrete) {
|
||||
NotificationViewData.Concrete concrete = ((NotificationViewData.Concrete) notification);
|
||||
switch (concrete.getType()) {
|
||||
case MENTION: {
|
||||
return VIEW_TYPE_MENTION;
|
||||
case MENTION:
|
||||
case POLL: {
|
||||
return VIEW_TYPE_STATUS;
|
||||
}
|
||||
case FAVOURITE:
|
||||
case REBLOG: {
|
||||
|
|
|
|||
|
|
@ -815,13 +815,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
for(int i = 0; i < Status.MAX_POLL_OPTIONS; i++) {
|
||||
if(i < options.size()) {
|
||||
long percent = calculatePollPercent(options.get(i).getVotesCount(), poll.getVotesCount());
|
||||
int percent = options.get(i).getPercent(poll.getVotesCount());
|
||||
|
||||
String pollOptionText = pollResults[i].getContext().getString(R.string.poll_option_format, percent, options.get(i).getTitle());
|
||||
pollResults[i].setText(CustomEmojiHelper.emojifyText(HtmlUtils.fromHtml(pollOptionText), emojis, pollResults[i]));
|
||||
pollResults[i].setVisibility(View.VISIBLE);
|
||||
|
||||
int level = (int) percent * 100;
|
||||
int level = percent * 100;
|
||||
|
||||
pollResults[i].getBackground().setLevel(level);
|
||||
|
||||
|
|
@ -920,10 +920,4 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private static long calculatePollPercent(int votes, int totalVotes) {
|
||||
if(votes == 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.round(votes / (double) totalVotes * 100);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,18 +29,19 @@ import com.keylesspalace.tusky.viewdata.StatusViewData;
|
|||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import at.connyduck.sparkbutton.helpers.Utils;
|
||||
|
||||
public class StatusViewHolder extends StatusBaseViewHolder {
|
||||
private static final InputFilter[] COLLAPSE_INPUT_FILTER = new InputFilter[]{SmartLengthInputFilter.INSTANCE};
|
||||
private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0];
|
||||
|
||||
private TextView rebloggedBar;
|
||||
private TextView statusInfo;
|
||||
private ToggleButton contentCollapseButton;
|
||||
|
||||
StatusViewHolder(View itemView, boolean useAbsoluteTime) {
|
||||
super(itemView, useAbsoluteTime);
|
||||
rebloggedBar = itemView.findViewById(R.id.status_reblogged);
|
||||
statusInfo = itemView.findViewById(R.id.status_info);
|
||||
contentCollapseButton = itemView.findViewById(R.id.button_toggle_content);
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
@Override
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
if (status == null || payloads==null) {
|
||||
if (status == null || payloads == null) {
|
||||
if (status == null) {
|
||||
showContent(false);
|
||||
} else {
|
||||
|
|
@ -81,30 +82,39 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
||||
if (rebloggedByDisplayName == null) {
|
||||
hideRebloggedByDisplayName();
|
||||
hideStatusInfo();
|
||||
} else {
|
||||
setRebloggedByDisplayName(rebloggedByDisplayName);
|
||||
statusInfo.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition()));
|
||||
}
|
||||
|
||||
rebloggedBar.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition()));}
|
||||
}
|
||||
else{
|
||||
}
|
||||
} else {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRebloggedByDisplayName(final String name) {
|
||||
Context context = rebloggedBar.getContext();
|
||||
Context context = statusInfo.getContext();
|
||||
String boostedText = context.getString(R.string.status_boosted_format, name);
|
||||
rebloggedBar.setText(boostedText);
|
||||
rebloggedBar.setVisibility(View.VISIBLE);
|
||||
statusInfo.setText(boostedText);
|
||||
statusInfo.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void hideRebloggedByDisplayName() {
|
||||
if (rebloggedBar == null) {
|
||||
// don't use this on the same ViewHolder as setRebloggedByDisplayName, will cause recycling issues as paddings are changed
|
||||
void setPollInfo(final boolean ownPoll) {
|
||||
statusInfo.setText(ownPoll ? R.string.poll_ended_created : R.string.poll_ended_voted);
|
||||
statusInfo.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_poll_24dp, 0, 0, 0);
|
||||
statusInfo.setCompoundDrawablePadding(Utils.dpToPx(statusInfo.getContext(), 10));
|
||||
statusInfo.setPaddingRelative(Utils.dpToPx(statusInfo.getContext(), 28), 0, 0, 0);
|
||||
statusInfo.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
void hideStatusInfo() {
|
||||
if (statusInfo == null) {
|
||||
return;
|
||||
}
|
||||
rebloggedBar.setVisibility(View.GONE);
|
||||
statusInfo.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void setupCollapsedState(final StatusViewData.Concrete status, final StatusActionListener listener) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue