update fork #128

Manually merged
tristan merged 181 commits from mirror/monocles_chat_clean:master into master 2026-01-23 14:02:38 +01:00
2 changed files with 55 additions and 18 deletions
Showing only changes of commit 71e4370acd - Show all commits

Show expandable posts in Microblog stream

Arne 2026-01-09 13:53:52 +01:00

View file

@ -3,13 +3,12 @@ package eu.siacs.conversations.ui.adapter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ItemPostBinding; import eu.siacs.conversations.databinding.ItemPostBinding;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
@ -24,6 +23,7 @@ public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.PostViewHold
private final List<Post> posts; private final List<Post> posts;
private final XmppActivity mActivity; private final XmppActivity mActivity;
private final Set<Post> expandedPosts = new HashSet<>();
public PostsAdapter(XmppActivity activity, List<Post> posts) { public PostsAdapter(XmppActivity activity, List<Post> posts) {
this.mActivity = activity; this.mActivity = activity;
@ -56,41 +56,60 @@ public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.PostViewHold
} }
void bind(Post post) { void bind(Post post) {
final boolean isExpanded = expandedPosts.contains(post);
binding.postContentSummary.setVisibility(isExpanded ? View.GONE : View.VISIBLE);
binding.postContentFull.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
binding.postContentSummary.setText(post.getContent());
binding.postContentFull.setText(post.getContent());
itemView.setOnClickListener(v -> {
if (expandedPosts.contains(post)) {
expandedPosts.remove(post);
} else {
expandedPosts.add(post);
}
notifyItemChanged(getAdapterPosition());
});
if (post.getAuthor() != null) { if (post.getAuthor() != null) {
final Jid authorJid = post.getAuthor(); final Jid authorJid = post.getAuthor();
final View.OnClickListener contactClickListener = v -> {
Account account = AccountUtils.getFirstEnabled(mActivity.xmppConnectionService.getAccounts());
if (account != null) {
if (authorJid.asBareJid().equals(account.getJid().asBareJid())) {
mActivity.switchToContactDetails(account.getSelfContact());
} else {
Contact contact = account.getRoster().getContact(authorJid);
if (contact != null) {
mActivity.switchToContactDetails(contact);
}
}
}
};
binding.postAuthorAvatar.setOnClickListener(contactClickListener);
binding.postAuthorName.setOnClickListener(contactClickListener);
if (mActivity.xmppConnectionService != null) { if (mActivity.xmppConnectionService != null) {
Account account = AccountUtils.getFirstEnabled(mActivity.xmppConnectionService.getAccounts()); Account account = AccountUtils.getFirstEnabled(mActivity.xmppConnectionService.getAccounts());
if (account != null) { if (account != null) {
if (authorJid.asBareJid().equals(account.getJid().asBareJid())) { if (authorJid.asBareJid().equals(account.getJid().asBareJid())) {
binding.postAuthorName.setText(account.getDisplayName()); binding.postAuthorName.setText(account.getDisplayName());
AvatarWorkerTask.loadAvatar(account, binding.postAuthorAvatar, R.dimen.bubble_avatar_size); AvatarWorkerTask.loadAvatar(account, binding.postAuthorAvatar, R.dimen.bubble_avatar_size);
final Contact self = account.getSelfContact();
binding.postAuthorAvatar.setOnClickListener(v -> mActivity.switchToContactDetails(self));
binding.postAuthorName.setOnClickListener(v -> mActivity.switchToContactDetails(self));
} else { } else {
Contact contact = account.getRoster().getContact(authorJid); Contact contact = account.getRoster().getContact(authorJid);
if (contact != null) { if (contact != null) {
binding.postAuthorName.setText(contact.getDisplayName()); binding.postAuthorName.setText(contact.getDisplayName());
AvatarWorkerTask.loadAvatar(contact, binding.postAuthorAvatar, R.dimen.bubble_avatar_size); AvatarWorkerTask.loadAvatar(contact, binding.postAuthorAvatar, R.dimen.bubble_avatar_size);
binding.postAuthorAvatar.setOnClickListener(v -> mActivity.switchToContactDetails(contact));
binding.postAuthorName.setOnClickListener(v -> mActivity.switchToContactDetails(contact));
} else { } else {
binding.postAuthorName.setText(authorJid.asBareJid().toString()); binding.postAuthorName.setText(authorJid.asBareJid().toString());
binding.postAuthorAvatar.setImageResource(R.drawable.ic_person_24dp); binding.postAuthorAvatar.setImageResource(R.drawable.ic_person_24dp);
binding.postAuthorAvatar.setOnClickListener(null);
binding.postAuthorName.setOnClickListener(null);
} }
} }
} else { } else {
binding.postAuthorName.setText(authorJid.asBareJid().toString()); binding.postAuthorName.setText(authorJid.asBareJid().toString());
binding.postAuthorAvatar.setImageResource(R.drawable.ic_person_24dp); binding.postAuthorAvatar.setImageResource(R.drawable.ic_person_24dp);
binding.postAuthorAvatar.setOnClickListener(null);
binding.postAuthorName.setOnClickListener(null);
} }
} else { } else {
binding.postAuthorName.setText(authorJid.asBareJid().toString()); binding.postAuthorName.setText(authorJid.asBareJid().toString());
binding.postAuthorAvatar.setOnClickListener(null);
binding.postAuthorName.setOnClickListener(null);
} }
} else { } else {
binding.postAuthorName.setText(null); binding.postAuthorName.setText(null);
@ -99,7 +118,6 @@ public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.PostViewHold
binding.postAuthorName.setOnClickListener(null); binding.postAuthorName.setOnClickListener(null);
} }
binding.postTitle.setText(post.getTitle()); binding.postTitle.setText(post.getTitle());
binding.postContent.setText(post.getContent());
if (post.getPublished() != null) { if (post.getPublished() != null) {
binding.postTimestamp.setText(DateFormat.getDateTimeInstance().format(post.getPublished())); binding.postTimestamp.setText(DateFormat.getDateTimeInstance().format(post.getPublished()));
} else { } else {

View file

@ -23,23 +23,26 @@
<TextView <TextView
android:id="@+id/post_author_name" android:id="@+id/post_author_name"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" android:textAppearance="@style/TextAppearance.AppCompat.Body2"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/post_author_avatar" app:layout_constraintStart_toEndOf="@+id/post_author_avatar"
app:layout_constraintTop_toTopOf="@+id/post_author_avatar" app:layout_constraintTop_toTopOf="@+id/post_author_avatar"
tools:text="John Doe" /> tools:text="John Doe" />
<TextView <TextView
android:id="@+id/post_timestamp" android:id="@+id/post_timestamp"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp" android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/post_author_avatar" app:layout_constraintStart_toEndOf="@+id/post_author_avatar"
app:layout_constraintTop_toBottomOf="@+id/post_author_name" app:layout_constraintTop_toBottomOf="@+id/post_author_name"
tools:text="2 hours ago" /> tools:text="2 hours ago" />
@ -50,16 +53,32 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Title" android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/post_author_avatar" app:layout_constraintTop_toBottomOf="@+id/post_author_avatar"
tools:text="This is a post title" /> tools:text="This is a post title" />
<TextView <TextView
android:id="@+id/post_content" android:id="@+id/post_content_summary"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/post_title"
tools:text="This is the content of the post. It can be a long text spanning multiple lines." />
<TextView
android:id="@+id/post_content_full"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:autoLink="web"
android:textIsSelectable="true"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/post_title" app:layout_constraintTop_toBottomOf="@+id/post_title"