Implement user selection view

This commit is contained in:
Niels Andriesse 2019-10-10 13:53:02 +11:00
parent 25bd1073b0
commit 9207e479a6
9 changed files with 186 additions and 7 deletions

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.loki.UserSelectionViewCell
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="52dp"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical">
<RelativeLayout
android:layout_width="36dp"
android:layout_height="38dp"
android:layout_marginTop="1dp">
<!-- The frame layout below is a workaround for an avatar image view bug -->
<FrameLayout
android:id="@+id/profilePictureImageViewContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/profilePictureImageView"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginBottom="2dp" />
</FrameLayout>
<ImageView
android:id="@+id/moderatorIconImageView"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginEnd="1.5dp"
android:src="@drawable/icon_crown"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
</RelativeLayout>
<TextView
android:id="@+id/displayNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
style="@style/Signal.Text.Body"
android:ellipsize="end" />
</org.thoughtcrime.securesms.loki.UserSelectionViewCell>

View file

@ -71,17 +71,26 @@
android:inflatedId="@+id/attachment_editor" android:inflatedId="@+id/attachment_editor"
android:layout="@layout/conversation_activity_attachment_editor_stub" /> android:layout="@layout/conversation_activity_attachment_editor_stub" />
<FrameLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clipChildren="false" android:orientation="vertical">
android:clipToPadding="false">
<include layout="@layout/conversation_input_panel" /> <include layout="@layout/view_user_selection" />
<include layout="@layout/conversation_search_nav" /> <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false">
</FrameLayout> <include layout="@layout/conversation_input_panel" />
<include layout="@layout/conversation_search_nav" />
</FrameLayout>
</LinearLayout>
<Button <Button
android:id="@+id/register_button" android:id="@+id/register_button"

View file

@ -101,6 +101,7 @@
tools:visibility="invisible" tools:visibility="invisible"
tools:hint="Send TextSecure message" > tools:hint="Send TextSecure message" >
<requestFocus /> <requestFocus />
</org.thoughtcrime.securesms.components.ComposeText> </org.thoughtcrime.securesms.components.ComposeText>
<FrameLayout <FrameLayout

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.loki.UserSelectionView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/userSelectionView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:paddingTop="6dp" />

View file

@ -19,6 +19,7 @@ import android.view.ViewOutlineProvider;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable; import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
@ -123,6 +124,10 @@ public class AvatarImageView extends AppCompatImageView {
setImageDrawable(image); setImageDrawable(image);
} }
public void update(String hexEncodedPublicKey) {
this.recipient = Recipient.from(getContext(), Address.fromSerialized(hexEncodedPublicKey), false);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) { public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
this.recipient = recipient; this.recipient = recipient;
/* /*

View file

@ -158,6 +158,8 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate; import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
import org.thoughtcrime.securesms.loki.LokiAPIUtilities; import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate; import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.UserSelectionView;
import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.mms.AttachmentManager;
@ -225,6 +227,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.loki.api.LokiAPI;
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
import org.whispersystems.signalservice.loki.utilities.Analytics; import org.whispersystems.signalservice.loki.utilities.Analytics;
@ -396,6 +399,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}); });
LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, this); LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, this);
UserSelectionView userSelectionView = findViewById(R.id.userSelectionView);
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this);
userSelectionView.setHasGroupContext(true);
userSelectionView.setUsers(LokiAPI.Companion.getUserIDs("", threadId, userDatabase));
if (this.recipient.isGroupRecipient()) { if (this.recipient.isGroupRecipient()) {
if (this.recipient.getName().equals("Loki Public Chat")) { if (this.recipient.getName().equals("Loki Public Chat")) {

View file

@ -214,7 +214,7 @@ public class ConversationItem extends LinearLayout
this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile); this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
this.alertView = findViewById(R.id.indicators_parent); this.alertView = findViewById(R.id.indicators_parent);
this.contactPhoto = findViewById(R.id.contact_photo); this.contactPhoto = findViewById(R.id.contact_photo);
this.moderatorIconImageView = findViewById(R.id.moderator_icon_image_view); this.moderatorIconImageView = findViewById(R.id.moderator_icon_image_view);
this.contactPhotoHolder = findViewById(R.id.contact_photo_container); this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
this.bodyBubble = findViewById(R.id.body_bubble); this.bodyBubble = findViewById(R.id.body_bubble);
this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub)); this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub));

View file

@ -0,0 +1,52 @@
package org.thoughtcrime.securesms.loki
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import nl.komponents.kovenant.combine.Tuple2
class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) {
var users = listOf<Tuple2<String, String>>()
set(newValue) { field = newValue; userSelectionViewAdapter.users = newValue }
var hasGroupContext = false
private val userSelectionViewAdapter by lazy { Adapter(context) }
private class Adapter(private val context: Context) : BaseAdapter() {
var users = listOf<Tuple2<String, String>>()
set(newValue) { field = newValue; notifyDataSetChanged() }
var hasGroupContext = false
override fun getCount(): Int {
return users.count()
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Tuple2<String, String> {
return users[position]
}
override fun getView(position: Int, cellToBeReused: View?, parent: ViewGroup): View {
val cell = cellToBeReused as UserSelectionViewCell? ?: UserSelectionViewCell.inflate(LayoutInflater.from(context), parent)
val user = getItem(position)
cell.user = user
cell.hasGroupContext = hasGroupContext
return cell
}
}
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null)
init {
adapter = userSelectionViewAdapter
userSelectionViewAdapter.users = users
}
}

View file

@ -0,0 +1,48 @@
package org.thoughtcrime.securesms.loki
import android.content.Context
import android.graphics.Outline
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.cell_user_selection_view.view.*
import network.loki.messenger.R
import nl.komponents.kovenant.combine.Tuple2
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
class UserSelectionViewCell(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
var user = Tuple2("", "")
set(newValue) { field = newValue; update() }
var hasGroupContext = false
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null)
companion object {
fun inflate(layoutInflater: LayoutInflater, parent: ViewGroup): UserSelectionViewCell {
return layoutInflater.inflate(R.layout.cell_user_selection_view, parent, false) as UserSelectionViewCell
}
}
override fun onFinishInflate() {
super.onFinishInflate()
profilePictureImageViewContainer.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setOval(0, 0, view.width, view.height)
}
}
profilePictureImageViewContainer.clipToOutline = true
}
private fun update() {
displayNameTextView.text = user.second
profilePictureImageView.update(user.first)
val isUserModerator = LokiGroupChatAPI.isUserModerator(user.first, LokiGroupChatAPI.publicChatServerID, LokiGroupChatAPI.publicChatServer)
moderatorIconImageView.visibility = if (isUserModerator && hasGroupContext) View.VISIBLE else View.GONE
}
}