mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 20:08:27 +00:00
Fix/video call rotation and avatars (#1548)
* Simplifying profile picture view We don't need the isLarge option as the component's size is always set. Using profilePictureView in the call screen. * Swapping avatars between user and contact's * Adding the user's avatar for when it needs to be displayed * Making sure we never invert the contact's landscape rotation * Update app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt Co-authored-by: Andrew <andrewgallasch@gmail.com> * Update app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt Co-authored-by: Andrew <andrewgallasch@gmail.com> * Update app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt Co-authored-by: Andrew <andrewgallasch@gmail.com> --------- Co-authored-by: Andrew <andrewgallasch@gmail.com>
This commit is contained in:
parent
3bac04c863
commit
01cd449794
@ -33,6 +33,8 @@ import network.loki.messenger.databinding.ActivityWebrtcBinding
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils
|
||||
import org.session.libsession.avatars.ProfileContactPhoto
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.truncateIdForDisplay
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
@ -200,6 +202,16 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
|
||||
clipFloatingInsets()
|
||||
|
||||
// set up the user avatar
|
||||
TextSecurePreferences.getLocalNumber(this)?.let{
|
||||
val username = TextSecurePreferences.getProfileName(this) ?: truncateIdForDisplay(it)
|
||||
binding.userAvatar.apply {
|
||||
publicKey = it
|
||||
displayName = username
|
||||
update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,8 +266,10 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
remoteRecipient.animate().cancel()
|
||||
remoteRecipient.animate().rotation(rotation).start()
|
||||
userAvatar.animate().cancel()
|
||||
userAvatar.animate().rotation(rotation).start()
|
||||
contactAvatar.animate().cancel()
|
||||
contactAvatar.animate().rotation(rotation).start()
|
||||
|
||||
speakerPhoneButton.animate().cancel()
|
||||
speakerPhoneButton.animate().rotation(rotation).start()
|
||||
@ -328,44 +342,20 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
launch {
|
||||
viewModel.recipient.collect { latestRecipient ->
|
||||
binding.contactAvatar.recycle()
|
||||
|
||||
if (latestRecipient.recipient != null) {
|
||||
val publicKey = latestRecipient.recipient.address.serialize()
|
||||
val displayName = getUserDisplayName(publicKey)
|
||||
supportActionBar?.title = displayName
|
||||
val signalProfilePicture = latestRecipient.recipient.contactPhoto
|
||||
val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject
|
||||
val sizeInPX =
|
||||
resources.getDimensionPixelSize(R.dimen.extra_large_profile_picture_size)
|
||||
binding.remoteRecipientName.text = displayName
|
||||
if (signalProfilePicture != null && avatar != "0" && avatar != "") {
|
||||
glide.clear(binding.remoteRecipient)
|
||||
glide.load(signalProfilePicture)
|
||||
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
|
||||
.circleCrop()
|
||||
.error(
|
||||
AvatarPlaceholderGenerator.generate(
|
||||
this@WebRtcCallActivity,
|
||||
sizeInPX,
|
||||
publicKey,
|
||||
displayName
|
||||
)
|
||||
)
|
||||
.into(binding.remoteRecipient)
|
||||
} else {
|
||||
glide.clear(binding.remoteRecipient)
|
||||
glide.load(
|
||||
AvatarPlaceholderGenerator.generate(
|
||||
this@WebRtcCallActivity,
|
||||
sizeInPX,
|
||||
publicKey,
|
||||
displayName
|
||||
)
|
||||
)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop()
|
||||
.into(binding.remoteRecipient)
|
||||
val contactPublicKey = latestRecipient.recipient.address.serialize()
|
||||
val contactDisplayName = getUserDisplayName(contactPublicKey)
|
||||
supportActionBar?.title = contactDisplayName
|
||||
binding.remoteRecipientName.text = contactDisplayName
|
||||
|
||||
// sort out the contact's avatar
|
||||
binding.contactAvatar.apply {
|
||||
publicKey = contactPublicKey
|
||||
displayName = contactDisplayName
|
||||
update()
|
||||
}
|
||||
} else {
|
||||
glide.clear(binding.remoteRecipient)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,22 +390,16 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
binding.floatingRenderer.removeAllViews()
|
||||
binding.fullscreenRenderer.removeAllViews()
|
||||
|
||||
// the floating video inset (empty or not) should be shown
|
||||
// the moment we have either of the video streams
|
||||
val showFloatingContainer = state.userVideoEnabled || state.remoteVideoEnabled
|
||||
binding.floatingRendererContainer.isVisible = showFloatingContainer
|
||||
binding.swapViewIcon.isVisible = showFloatingContainer
|
||||
|
||||
// handle fullscreen video window
|
||||
if(state.showFullscreenVideo()){
|
||||
viewModel.fullscreenRenderer?.let { surfaceView ->
|
||||
binding.fullscreenRenderer.addView(surfaceView)
|
||||
binding.fullscreenRenderer.isVisible = true
|
||||
binding.remoteRecipient.isVisible = false
|
||||
hideAvatar()
|
||||
}
|
||||
} else {
|
||||
binding.fullscreenRenderer.isVisible = false
|
||||
binding.remoteRecipient.isVisible = true
|
||||
showAvatar(state.swapped)
|
||||
}
|
||||
|
||||
// handle floating video window
|
||||
@ -429,6 +413,15 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
binding.floatingRenderer.isVisible = false
|
||||
}
|
||||
|
||||
// the floating video inset (empty or not) should be shown
|
||||
// the moment we have either of the video streams
|
||||
val showFloatingContainer = state.userVideoEnabled || state.remoteVideoEnabled
|
||||
binding.floatingRendererContainer.isVisible = showFloatingContainer
|
||||
binding.swapViewIcon.isVisible = showFloatingContainer
|
||||
|
||||
// make sure to default to the contact's avatar if the floating container is not visible
|
||||
if (!showFloatingContainer) showAvatar(false)
|
||||
|
||||
// handle buttons
|
||||
binding.enableCameraButton.isSelected = state.userVideoEnabled
|
||||
}
|
||||
@ -436,6 +429,20 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the avatar image.
|
||||
* If @showUserAvatar is true, the user's avatar is shown, otherwise the contact's avatar is shown.
|
||||
*/
|
||||
private fun showAvatar(showUserAvatar: Boolean) {
|
||||
binding.userAvatar.isVisible = showUserAvatar
|
||||
binding.contactAvatar.isVisible = !showUserAvatar
|
||||
}
|
||||
|
||||
private fun hideAvatar() {
|
||||
binding.userAvatar.isVisible = false
|
||||
binding.contactAvatar.isVisible = false
|
||||
}
|
||||
|
||||
private fun getUserDisplayName(publicKey: String): String {
|
||||
val contact =
|
||||
DatabaseComponent.get(this).sessionContactDatabase().getContactWithSessionID(publicKey)
|
||||
|
@ -33,7 +33,6 @@ class ProfilePictureView @JvmOverloads constructor(
|
||||
var displayName: String? = null
|
||||
var additionalPublicKey: String? = null
|
||||
var additionalDisplayName: String? = null
|
||||
var isLarge = false
|
||||
|
||||
private val profilePicturesCache = mutableMapOf<View, Recipient>()
|
||||
private val unknownRecipientDrawable by lazy { ResourceContactPhoto(R.drawable.ic_profile_default)
|
||||
@ -90,29 +89,25 @@ class ProfilePictureView @JvmOverloads constructor(
|
||||
fun update() {
|
||||
val publicKey = publicKey ?: return Log.w(TAG, "Could not find public key to update profile picture")
|
||||
val additionalPublicKey = additionalPublicKey
|
||||
// if we have a multi avatar setup
|
||||
if (additionalPublicKey != null) {
|
||||
setProfilePictureIfNeeded(binding.doubleModeImageView1, publicKey, displayName)
|
||||
setProfilePictureIfNeeded(binding.doubleModeImageView2, additionalPublicKey, additionalDisplayName)
|
||||
binding.doubleModeImageViewContainer.visibility = View.VISIBLE
|
||||
} else {
|
||||
|
||||
// clear single image
|
||||
glide.clear(binding.singleModeImageView)
|
||||
binding.singleModeImageView.visibility = View.INVISIBLE
|
||||
} else { // single image mode
|
||||
setProfilePictureIfNeeded(binding.singleModeImageView, publicKey, displayName)
|
||||
binding.singleModeImageView.visibility = View.VISIBLE
|
||||
|
||||
// clear multi image
|
||||
glide.clear(binding.doubleModeImageView1)
|
||||
glide.clear(binding.doubleModeImageView2)
|
||||
binding.doubleModeImageViewContainer.visibility = View.INVISIBLE
|
||||
}
|
||||
if (additionalPublicKey == null && !isLarge) {
|
||||
setProfilePictureIfNeeded(binding.singleModeImageView, publicKey, displayName)
|
||||
binding.singleModeImageView.visibility = View.VISIBLE
|
||||
} else {
|
||||
glide.clear(binding.singleModeImageView)
|
||||
binding.singleModeImageView.visibility = View.INVISIBLE
|
||||
}
|
||||
if (additionalPublicKey == null && isLarge) {
|
||||
setProfilePictureIfNeeded(binding.largeSingleModeImageView, publicKey, displayName)
|
||||
binding.largeSingleModeImageView.visibility = View.VISIBLE
|
||||
} else {
|
||||
glide.clear(binding.largeSingleModeImageView)
|
||||
binding.largeSingleModeImageView.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun setProfilePictureIfNeeded(imageView: ImageView, publicKey: String, displayName: String?) {
|
||||
|
@ -56,7 +56,6 @@ class UserDetailsBottomSheet: BottomSheetDialogFragment() {
|
||||
val threadRecipient = threadDb.getRecipientForThreadId(threadID) ?: return dismiss()
|
||||
with(binding) {
|
||||
profilePictureView.publicKey = publicKey
|
||||
profilePictureView.isLarge = true
|
||||
profilePictureView.update(recipient)
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameTextViewContainer.setOnClickListener {
|
||||
|
@ -123,7 +123,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
view.apply {
|
||||
publicKey = hexEncodedPublicKey
|
||||
displayName = getDisplayName()
|
||||
isLarge = true
|
||||
update()
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ import org.webrtc.SurfaceViewRenderer
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.ArrayDeque
|
||||
import java.util.UUID
|
||||
import kotlin.math.abs
|
||||
import org.thoughtcrime.securesms.webrtc.data.State as CallState
|
||||
|
||||
class CallManager(
|
||||
@ -718,7 +719,7 @@ class CallManager(
|
||||
|
||||
// apply the rotation to the streams
|
||||
peerConnection?.setDeviceRotation(rotation)
|
||||
remoteRotationSink?.rotation = rotation
|
||||
remoteRotationSink?.rotation = abs(rotation) // abs as we never need the remote video to be inverted
|
||||
}
|
||||
|
||||
fun handleWiredHeadsetChanged(present: Boolean) {
|
||||
|
@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
android:shape="oval">
|
||||
|
||||
<solid android:color="@color/profile_picture_background" />
|
||||
|
||||
<corners android:radius="40dp" />
|
||||
</shape>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid android:color="@color/profile_picture_background" />
|
||||
|
||||
<corners android:radius="23dp" />
|
||||
</shape>
|
@ -23,15 +23,27 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
</FrameLayout>
|
||||
<ImageView
|
||||
android:id="@+id/remote_recipient"
|
||||
|
||||
<org.thoughtcrime.securesms.components.ProfilePictureView
|
||||
android:id="@+id/userAvatar"
|
||||
app:layout_constraintStart_toStartOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintTop_toTopOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintBottom_toBottomOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintVertical_bias="0.4"
|
||||
android:layout_width="@dimen/extra_large_profile_picture_size"
|
||||
android:layout_height="@dimen/extra_large_profile_picture_size"/>
|
||||
android:layout_height="@dimen/extra_large_profile_picture_size"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ProfilePictureView
|
||||
android:id="@+id/contactAvatar"
|
||||
app:layout_constraintStart_toStartOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintEnd_toEndOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintTop_toTopOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintBottom_toBottomOf="@id/fullscreen_renderer_container"
|
||||
app:layout_constraintVertical_bias="0.4"
|
||||
android:layout_width="@dimen/extra_large_profile_picture_size"
|
||||
android:layout_height="@dimen/extra_large_profile_picture_size" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back_arrow"
|
||||
@ -71,9 +83,9 @@
|
||||
android:foregroundGravity="center"
|
||||
android:visibility="gone"
|
||||
app:SpinKit_Color="@color/core_white"
|
||||
app:layout_constraintEnd_toEndOf="@+id/remote_recipient"
|
||||
app:layout_constraintStart_toStartOf="@+id/remote_recipient"
|
||||
app:layout_constraintTop_toBottomOf="@id/remote_recipient"
|
||||
app:layout_constraintEnd_toEndOf="@+id/contactAvatar"
|
||||
app:layout_constraintStart_toStartOf="@+id/contactAvatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/contactAvatar"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
|
@ -27,17 +27,11 @@
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:scaleType="centerCrop"
|
||||
android:id="@+id/singleModeImageView"
|
||||
android:layout_width="@dimen/medium_profile_picture_size"
|
||||
android:layout_height="@dimen/medium_profile_picture_size"
|
||||
android:background="@drawable/profile_picture_view_medium_background" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/largeSingleModeImageView"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="@dimen/large_profile_picture_size"
|
||||
android:layout_height="@dimen/large_profile_picture_size"
|
||||
android:background="@drawable/profile_picture_view_large_background" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@drawable/profile_picture_view_background" />
|
||||
|
||||
</merge>
|
Loading…
x
Reference in New Issue
Block a user