added announcement reaction view

This commit is contained in:
nuclearfog 2023-12-01 23:47:42 +01:00
parent 725ceb6248
commit 3a95cacfa2
No known key found for this signature in database
GPG Key ID: 43E45B82006BC9D5
11 changed files with 247 additions and 11 deletions

View File

@ -7,7 +7,7 @@ import java.io.Serializable;
*
* @author nuclearfog
*/
public interface Reaction extends Serializable {
public interface Reaction extends Serializable, Comparable<Reaction> {
/**
* @return title, emoji unicode or custom emoji shortcode of the reaction
@ -28,4 +28,10 @@ public interface Reaction extends Serializable {
* @return true if selected by current user
*/
boolean isSelected();
@Override
default int compareTo(Reaction reaction) {
return Integer.compare(reaction.getCount(), getCount());
}
}

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import org.nuclearfog.twidda.model.Announcement;
import org.nuclearfog.twidda.model.Reaction;
import org.nuclearfog.twidda.model.lists.Announcements;
import org.nuclearfog.twidda.ui.adapter.recyclerview.holder.AnnouncementHolder;
import org.nuclearfog.twidda.ui.adapter.recyclerview.holder.OnHolderClickListener;
@ -49,10 +50,20 @@ public class AnnouncementAdapter extends Adapter<AnnouncementHolder> implements
@Override
public void onItemClick(int position, int type, int... extras) {
if (type == ANNOUNCEMENT_DISMISS) {
listener.onAnnouncementDismiss(items.get(position));
} else if (type == ANNOUNCEMENT_CLICK) {
listener.onAnnouncementClick(items.get(position));
switch(type) {
case ANNOUNCEMENT_DISMISS:
listener.onAnnouncementDismiss(items.get(position));
break;
case ANNOUNCEMENT_CLICK:
listener.onAnnouncementClick(items.get(position));
break;
case ANNOUNCEMENT_REACTION:
int reactionIndex = extras[0];
listener.onReactionClick(items.get(position).getReactions()[reactionIndex]);
break;
}
}
@ -125,5 +136,12 @@ public class AnnouncementAdapter extends Adapter<AnnouncementHolder> implements
* @param announcement clicked item
*/
void onAnnouncementDismiss(Announcement announcement);
/**
* called to select reaction
*
* @param reaction selected reaction
*/
void onReactionClick(Reaction reaction);
}
}

View File

@ -0,0 +1,83 @@
package org.nuclearfog.twidda.ui.adapter.recyclerview;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import org.nuclearfog.twidda.model.Reaction;
import org.nuclearfog.twidda.ui.adapter.recyclerview.holder.OnHolderClickListener;
import org.nuclearfog.twidda.ui.adapter.recyclerview.holder.ReactionHolder;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @author nuclearfog
*/
public class ReactionAdapter extends Adapter<ReactionHolder> implements OnHolderClickListener {
private OnReactionSelected listener;
private List<Reaction> items = new LinkedList<>();
/**
*
*/
public ReactionAdapter(OnReactionSelected listener) {
this.listener = listener;
}
@NonNull
@Override
public ReactionHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ReactionHolder(parent, this);
}
@Override
public void onBindViewHolder(@NonNull ReactionHolder holder, int position) {
holder.setContent(items.get(position));
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public void onItemClick(int position, int type, int... extras) {
if (type == ANNOUNCEMENT_REACTION) {
listener.onReactionClick(position);
}
}
@Override
public boolean onPlaceholderClick(int index) {
return false;
}
/**
* add adapter items
*/
public void setItems(Reaction[] reactions) {
items.clear();
Arrays.sort(reactions);
items.addAll(Arrays.asList(reactions));
notifyDataSetChanged();
}
/**
*
*/
public interface OnReactionSelected {
void onReactionClick(int index);
}
}

View File

@ -10,6 +10,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
@ -22,19 +23,22 @@ import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.backend.utils.Tagger;
import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.model.Announcement;
import org.nuclearfog.twidda.ui.adapter.recyclerview.ReactionAdapter;
import org.nuclearfog.twidda.ui.adapter.recyclerview.ReactionAdapter.OnReactionSelected;
/**
* Viewholder for {@link org.nuclearfog.twidda.ui.adapter.recyclerview.AnnouncementAdapter}
*
* @author nuclearfog
*/
public class AnnouncementHolder extends ViewHolder implements OnClickListener {
public class AnnouncementHolder extends ViewHolder implements OnClickListener, OnReactionSelected {
private TextView time, content;
private OnHolderClickListener listener;
private GlobalSettings settings;
private TextEmojiLoader emojiLoader;
private ReactionAdapter adapter;
private AsyncExecutor.AsyncCallback<TextEmojiLoader.Result> textResult = this::setTextEmojis;
private int iconSize;
@ -48,13 +52,17 @@ public class AnnouncementHolder extends ViewHolder implements OnClickListener {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_announcement, parent, false));
settings = GlobalSettings.get(parent.getContext());
emojiLoader = new TextEmojiLoader(parent.getContext());
adapter = new ReactionAdapter(this);
CardView card = (CardView) itemView;
ViewGroup container = itemView.findViewById(R.id.item_announcement_container);
View dismiss = itemView.findViewById(R.id.item_announcement_dismiss);
RecyclerView reactionList = itemView.findViewById(R.id.item_announcement_list_reactions);
time = itemView.findViewById(R.id.item_announcement_timestamp);
content = itemView.findViewById(R.id.item_announcement_content);
iconSize = parent.getResources().getDimensionPixelSize(R.dimen.item_announcement_icon_size);
reactionList.setLayoutManager(new LinearLayoutManager(parent.getContext(), LinearLayoutManager.HORIZONTAL, false));
reactionList.setAdapter(adapter);
card.setCardBackgroundColor(settings.getCardColor());
AppStyles.setTheme(container, Color.TRANSPARENT);
@ -76,6 +84,15 @@ public class AnnouncementHolder extends ViewHolder implements OnClickListener {
}
}
@Override
public void onReactionClick(int index) {
int position = getLayoutPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position, OnHolderClickListener.ANNOUNCEMENT_REACTION, index);
}
}
/**
*
*/
@ -88,6 +105,7 @@ public class AnnouncementHolder extends ViewHolder implements OnClickListener {
}
content.setText(textSpan);
time.setText(StringUtils.formatCreationTime(time.getResources(), announcement.getTimestamp()));
adapter.setItems(announcement.getReactions());
}
/**

View File

@ -61,6 +61,8 @@ public interface OnHolderClickListener {
int ANNOUNCEMENT_DISMISS = 29;
int ANNOUNCEMENT_REACTION = 30;
/**
* called when an item was clicked
*

View File

@ -0,0 +1,71 @@
package org.nuclearfog.twidda.ui.adapter.recyclerview.holder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.squareup.picasso.Picasso;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.image.PicassoBuilder;
import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.model.Reaction;
/**
* @author nuclearfog
*/
public class ReactionHolder extends ViewHolder implements OnClickListener {
private ImageView icon;
private TextView description;
private OnHolderClickListener listener;
private GlobalSettings settings;
private Picasso picasso;
public ReactionHolder(ViewGroup parent, OnHolderClickListener listener) {
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_reaction, parent, false));
icon = itemView.findViewById(R.id.item_reaction_icon);
description = itemView.findViewById(R.id.item_reaction_text);
picasso = PicassoBuilder.get(parent.getContext());
settings = GlobalSettings.get(parent.getContext());
this.listener = listener;
description.setTextColor(settings.getTextColor());
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.item_reaction_root) {
int position = getLayoutPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position, OnHolderClickListener.ANNOUNCEMENT_REACTION);
}
}
}
/**
*
*/
public void setContent(Reaction reaction) {
if (!reaction.getImageUrl().isEmpty() && settings.imagesEnabled()) {
icon.setVisibility(View.VISIBLE);
picasso.load(reaction.getImageUrl()).into(icon);
description.setText("");
} else {
icon.setVisibility(View.GONE);
icon.setImageResource(0);
description.setText(reaction.getName() + " ");
}
description.append(Integer.toString(reaction.getCount()));
}
}

View File

@ -14,6 +14,7 @@ import org.nuclearfog.twidda.backend.async.AnnouncementLoader;
import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.utils.ErrorUtils;
import org.nuclearfog.twidda.model.Announcement;
import org.nuclearfog.twidda.model.Reaction;
import org.nuclearfog.twidda.model.lists.Announcements;
import org.nuclearfog.twidda.ui.adapter.recyclerview.AnnouncementAdapter;
import org.nuclearfog.twidda.ui.adapter.recyclerview.AnnouncementAdapter.OnAnnouncementClickListener;
@ -123,6 +124,12 @@ public class AnnouncementFragment extends ListFragment implements OnAnnouncement
}
}
@Override
public void onReactionClick(Reaction reaction) {
// todo implement this
}
/**
*
*/

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/CardView">
@ -39,7 +39,7 @@
<TextView
android:id="@+id/item_announcement_content"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="15"
android:textSize="@dimen/item_announcement_textsize_content"
@ -50,8 +50,8 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/item_announcement_list_reactions"
android:layout_width="match_parent"
android:layout_height="@dimen/item_announcement_list_reaction_height"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/item_announcement_content"
app:layout_constraintEnd_toEndOf="parent" />

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_reaction_root"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="@dimen/item_reaction_margin_layout"
android:background="@drawable/button"
android:gravity="center">
<ImageView
android:id="@+id/item_reaction_icon"
android:layout_width="@dimen/item_reaction_size_icon"
android:layout_height="@dimen/item_reaction_size_icon"
android:layout_margin="@dimen/item_reaction_margin_layout"
android:contentDescription="@string/description_announcement_reaction" />
<TextView
android:id="@+id/item_reaction_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/item_reaction_size_text"
android:layout_margin="@dimen/item_reaction_margin_layout" />
</LinearLayout>

View File

@ -391,6 +391,11 @@
<!--dimens of item_media_field.xml-->
<dimen name="dialog_media_field_layout_margin">5dp</dimen>
<!--dimens of item_reaction.xml-->
<dimen name="item_reaction_size_icon">20dp</dimen>
<dimen name="item_reaction_size_text">14sp</dimen>
<dimen name="item_reaction_margin_layout">5dp</dimen>
<!--dimens of navigation_header-xml-->
<dimen name="navigation_header_layout_padding">10dp</dimen>
<dimen name="navigation_header_layout_margin">8dp</dimen>

View File

@ -329,6 +329,7 @@
<string name="status_media_preview_button">Video preview button</string>
<string name="poll_finished">Vote finished</string>
<string name="description_poll_vote_icon">voted</string>
<string name="description_announcement_reaction">reaction of an announcement</string>
<string name="description_attachment_icon">Status/Message attachment</string>
<string name="notification_status_poll">vote finished</string>
<string name="login_network_selector_label">select network</string>