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:
Konrad Pozniak 2019-05-02 19:44:35 +02:00 committed by GitHub
commit e735e4843e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1076 additions and 318 deletions

View file

@ -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: {

View file

@ -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);
}
}

View file

@ -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) {