mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-25 14:40:41 +01:00
Replace Fresco with Coil
Fresco is replaced with Coil everywhere to make it possible to set 'minSdkVersion' to 23. But Coil is not used directly to avoid splintering the dependency everywhere in the code. Coil is wrapped by extension functions for 'ImageView'. Some shared functionality is moved from 'DisplayUtils' into the 'ImageViewExtensions'. The exisiting initialization of Coil has also be changed. The usage of the self initialized OKHttp client is removed. If this one is added the caching of the http client is used by Coil additionally to memory and disk cache. Resolves: #2227, #2376 Signed-off-by: Tim Krüger <t@timkrueger.me>
This commit is contained in:
parent
537f375f86
commit
49da463971
@ -245,15 +245,8 @@ dependencies {
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'com.github.wooplr:Spotlight:1.3'
|
||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
implementation('com.github.nextcloud-deps:ChatKit:0.3.0-1', {
|
||||
exclude group: 'com.facebook.fresco'
|
||||
})
|
||||
implementation 'com.github.nextcloud-deps:ChatKit:0.3.1'
|
||||
|
||||
implementation 'com.github.nextcloud-deps.fresco:fresco:v111'
|
||||
implementation 'com.github.nextcloud-deps.fresco:animated-webp:v111'
|
||||
implementation 'com.github.nextcloud-deps.fresco:webpsupport:v111'
|
||||
implementation 'com.github.nextcloud-deps.fresco:animated-gif:v111'
|
||||
implementation 'com.github.nextcloud-deps.fresco:imagepipeline-okhttp3:v111'
|
||||
implementation 'joda-time:joda-time:2.12.2'
|
||||
implementation "io.coil-kt:coil:${coilKtVersion}"
|
||||
implementation "io.coil-kt:coil-gif:${coilKtVersion}"
|
||||
|
@ -149,7 +149,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import autodagger.AutoInjector;
|
||||
@ -540,20 +539,16 @@ public class CallActivity extends CallBaseActivity {
|
||||
private void updateAudioOutputButton(WebRtcAudioManager.AudioDevice activeAudioDevice) {
|
||||
switch (activeAudioDevice) {
|
||||
case BLUETOOTH:
|
||||
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_bluetooth_audio_24));
|
||||
binding.audioOutputButton.setImageResource ( R.drawable.ic_baseline_bluetooth_audio_24);
|
||||
break;
|
||||
case SPEAKER_PHONE:
|
||||
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_volume_up_white_24dp));
|
||||
binding.audioOutputButton.setImageResource(R.drawable.ic_volume_up_white_24dp);
|
||||
break;
|
||||
case EARPIECE:
|
||||
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_phone_in_talk_24));
|
||||
binding.audioOutputButton.setImageResource(R.drawable.ic_baseline_phone_in_talk_24);
|
||||
break;
|
||||
case WIRED_HEADSET:
|
||||
binding.audioOutputButton.getHierarchy().setPlaceholderImage(
|
||||
AppCompatResources.getDrawable(context, R.drawable.ic_baseline_headset_mic_24));
|
||||
binding.audioOutputButton.setImageResource(R.drawable.ic_baseline_headset_mic_24);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Icon for audio output not available");
|
||||
@ -795,7 +790,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
onCameraClick();
|
||||
}
|
||||
} else {
|
||||
binding.cameraButton.getHierarchy().setPlaceholderImage(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.cameraButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.cameraButton.setAlpha(0.7f);
|
||||
binding.switchSelfVideoButton.setVisibility(View.GONE);
|
||||
}
|
||||
@ -806,7 +801,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
onMicrophoneClick();
|
||||
}
|
||||
} else {
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
|
||||
}
|
||||
|
||||
if (!isConnectionEstablished()) {
|
||||
@ -917,7 +912,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
|
||||
if (!canPublishAudioStream) {
|
||||
microphoneOn = false;
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
|
||||
toggleMedia(false, false);
|
||||
}
|
||||
|
||||
@ -961,12 +956,12 @@ public class CallActivity extends CallBaseActivity {
|
||||
microphoneOn = !microphoneOn;
|
||||
|
||||
if (microphoneOn) {
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_white_24px);
|
||||
updatePictureInPictureActions(R.drawable.ic_mic_white_24px,
|
||||
getResources().getString(R.string.nc_pip_microphone_mute),
|
||||
MICROPHONE_PIP_REQUEST_MUTE);
|
||||
} else {
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
|
||||
updatePictureInPictureActions(R.drawable.ic_mic_off_white_24px,
|
||||
getResources().getString(R.string.nc_pip_microphone_unmute),
|
||||
MICROPHONE_PIP_REQUEST_UNMUTE);
|
||||
@ -974,7 +969,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
|
||||
toggleMedia(microphoneOn, false);
|
||||
} else {
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_white_24px);
|
||||
pulseAnimation.start();
|
||||
toggleMedia(true, false);
|
||||
}
|
||||
@ -997,7 +992,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
|
||||
if (!canPublishVideoStream) {
|
||||
videoOn = false;
|
||||
binding.cameraButton.getHierarchy().setPlaceholderImage(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.cameraButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.switchSelfVideoButton.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
@ -1006,12 +1001,12 @@ public class CallActivity extends CallBaseActivity {
|
||||
videoOn = !videoOn;
|
||||
|
||||
if (videoOn) {
|
||||
binding.cameraButton.getHierarchy().setPlaceholderImage(R.drawable.ic_videocam_white_24px);
|
||||
binding.cameraButton.setImageResource(R.drawable.ic_videocam_white_24px);
|
||||
if (cameraEnumerator.getDeviceNames().length > 1) {
|
||||
binding.switchSelfVideoButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
binding.cameraButton.getHierarchy().setPlaceholderImage(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.cameraButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
|
||||
binding.switchSelfVideoButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@ -2675,7 +2670,7 @@ public class CallActivity extends CallBaseActivity {
|
||||
v.onTouchEvent(event);
|
||||
if (event.getAction() == MotionEvent.ACTION_UP && isPushToTalkActive) {
|
||||
isPushToTalkActive = false;
|
||||
binding.microphoneButton.getHierarchy().setPlaceholderImage(R.drawable.ic_mic_off_white_24px);
|
||||
binding.microphoneButton.setImageResource(R.drawable.ic_mic_off_white_24px);
|
||||
pulseAnimation.stop();
|
||||
toggleMedia(false, false);
|
||||
animateCallControls(false, 5000);
|
||||
|
@ -28,8 +28,6 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.media.AudioAttributes
|
||||
import android.media.MediaPlayer
|
||||
import android.os.Build
|
||||
@ -41,24 +39,18 @@ import android.view.View
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import autodagger.AutoInjector
|
||||
import com.facebook.common.executors.UiThreadImmediateExecutorService
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.datasource.DataSource
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.CallNotificationActivityBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
import com.nextcloud.talk.models.json.participants.ParticipantsOverall
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
|
||||
import com.nextcloud.talk.utils.NotificationUtils
|
||||
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
|
||||
@ -75,6 +67,7 @@ import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.synthetic.main.call_item.*
|
||||
import okhttp3.Cache
|
||||
import org.parceler.Parcels
|
||||
import java.io.IOException
|
||||
@ -356,7 +349,7 @@ class CallNotificationActivity : CallBaseActivity() {
|
||||
private fun setUpAfterConversationIsKnown() {
|
||||
binding!!.conversationNameTextView.text = currentConversation!!.displayName
|
||||
if (currentConversation!!.type === Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
||||
setAvatarForOneToOneCall()
|
||||
avatarImageView.loadAvatar(userBeingCalled!!, currentConversation!!.name!!)
|
||||
} else {
|
||||
binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group)
|
||||
}
|
||||
@ -364,34 +357,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
||||
showAnswerControls()
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun setAvatarForOneToOneCall() {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
userBeingCalled!!.baseUrl,
|
||||
currentConversation!!.name,
|
||||
true
|
||||
)
|
||||
)
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
binding!!.avatarImageView.hierarchy.setImage(
|
||||
BitmapDrawable(resources, bitmap), 100f,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage?>>) {
|
||||
Log.e(TAG, "failed to load avatar")
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
)
|
||||
}
|
||||
|
||||
private fun endMediaNotifications() {
|
||||
if (mediaPlayer != null) {
|
||||
if (mediaPlayer!!.isPlaying) {
|
||||
|
@ -12,12 +12,9 @@ import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.activities.CallActivity;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
|
||||
import org.webrtc.MediaStream;
|
||||
import org.webrtc.MediaStreamTrack;
|
||||
@ -109,7 +106,7 @@ public class ParticipantsAdapter extends BaseAdapter {
|
||||
convertView.setLayoutParams(layoutParams);
|
||||
|
||||
TextView nickTextView = convertView.findViewById(R.id.peer_nick_text_view);
|
||||
SimpleDraweeView imageView = convertView.findViewById(R.id.avatarImageView);
|
||||
ImageView imageView = convertView.findViewById(R.id.avatarImageView);
|
||||
|
||||
MediaStream mediaStream = participantDisplayItem.getMediaStream();
|
||||
if (hasVideoStream(participantDisplayItem, mediaStream)) {
|
||||
@ -128,13 +125,7 @@ public class ParticipantsAdapter extends BaseAdapter {
|
||||
nickTextView.setVisibility(View.VISIBLE);
|
||||
nickTextView.setText(participantDisplayItem.getNick());
|
||||
}
|
||||
|
||||
imageView.setController(null);
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(imageView.getController())
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(participantDisplayItem.getUrlForAvatar()))
|
||||
.build();
|
||||
imageView.setController(draweeController);
|
||||
ImageViewExtensionsKt.loadAvatarWithUrl(imageView,null, participantDisplayItem.getUrlForAvatar());
|
||||
}
|
||||
|
||||
ImageView audioOffView = convertView.findViewById(R.id.remote_audio_off);
|
||||
|
@ -34,7 +34,7 @@ class ReactionsAdapter(
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReactionsViewHolder {
|
||||
val itemBinding = ReactionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return ReactionsViewHolder(itemBinding, user?.baseUrl)
|
||||
return ReactionsViewHolder(itemBinding, user)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ReactionsViewHolder, position: Int) {
|
||||
|
@ -22,18 +22,17 @@ package com.nextcloud.talk.adapters
|
||||
|
||||
import android.text.TextUtils
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.ReactionItemBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.extensions.loadGuestAvatar
|
||||
import com.nextcloud.talk.models.json.reactions.ReactionVoter
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
|
||||
class ReactionsViewHolder(
|
||||
private val binding: ReactionItemBinding,
|
||||
private val baseUrl: String?
|
||||
private val user: User?
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(reactionItem: ReactionItem, clickListener: ReactionItemClickListener) {
|
||||
@ -41,7 +40,7 @@ class ReactionsViewHolder(
|
||||
binding.reaction.text = reactionItem.reaction
|
||||
binding.name.text = reactionItem.reactionVoter.actorDisplayName
|
||||
|
||||
if (baseUrl != null && baseUrl.isNotEmpty()) {
|
||||
if (user != null && user.baseUrl?.isNotEmpty() == true) {
|
||||
loadAvatar(reactionItem)
|
||||
}
|
||||
}
|
||||
@ -52,35 +51,13 @@ class ReactionsViewHolder(
|
||||
if (!TextUtils.isEmpty(reactionItem.reactionVoter.actorDisplayName)) {
|
||||
displayName = reactionItem.reactionVoter.actorDisplayName!!
|
||||
}
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.avatar.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForGuestAvatar(
|
||||
baseUrl,
|
||||
displayName,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
binding.avatar.controller = draweeController
|
||||
binding.avatar.loadGuestAvatar(user!!.baseUrl!!, displayName!!, false)
|
||||
} else if (reactionItem.reactionVoter.actorType == ReactionVoter.ReactionActorType.USERS) {
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.avatar.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
baseUrl,
|
||||
reactionItem.reactionVoter.actorId,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
binding.avatar.controller = draweeController
|
||||
binding.avatar.loadAvatar(
|
||||
user!!,
|
||||
reactionItem.reactionVoter.actorId!!,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,15 +27,12 @@ import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.databinding.AccountItemBinding;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
@ -108,7 +105,6 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
|
||||
|
||||
@Override
|
||||
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
|
||||
holder.binding.userIcon.setController(null);
|
||||
|
||||
if (adapter.hasFilter()) {
|
||||
FlexibleUtils.highlightText(
|
||||
@ -129,24 +125,10 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
|
||||
}
|
||||
}
|
||||
|
||||
holder.binding.userIcon.getHierarchy().setPlaceholderImage(R.drawable.account_circle_48dp);
|
||||
holder.binding.userIcon.getHierarchy().setFailureImage(R.drawable.account_circle_48dp);
|
||||
|
||||
if (user != null && user.getBaseUrl() != null &&
|
||||
user.getBaseUrl().startsWith("http://") ||
|
||||
user.getBaseUrl().startsWith("https://")) {
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.userIcon.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.getBaseUrl(),
|
||||
participant.getCalculatedActorId(),
|
||||
true)))
|
||||
.build();
|
||||
holder.binding.userIcon.setController(draweeController);
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.userIcon, user, participant.getCalculatedActorId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,16 +29,13 @@ import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.databinding.RvItemContactBinding;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
@ -110,7 +107,6 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Override
|
||||
public void bindViewHolder(FlexibleAdapter adapter, ContactItemViewHolder holder, int position, List payloads) {
|
||||
holder.binding.avatarDraweeView.setController(null);
|
||||
|
||||
if (participant.getSelected()) {
|
||||
viewThemeUtils.platform.colorImageView(holder.binding.checkedImageView);
|
||||
@ -121,18 +117,18 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
|
||||
|
||||
if (!isOnline) {
|
||||
holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.medium_emphasis_text,
|
||||
null)
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.medium_emphasis_text,
|
||||
null)
|
||||
);
|
||||
holder.binding.avatarDraweeView.setAlpha(0.38f);
|
||||
holder.binding.avatarView.setAlpha(0.38f);
|
||||
} else {
|
||||
holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.high_emphasis_text,
|
||||
null)
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.high_emphasis_text,
|
||||
null)
|
||||
);
|
||||
holder.binding.avatarDraweeView.setAlpha(1.0f);
|
||||
holder.binding.avatarView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
holder.binding.nameText.setText(participant.getDisplayName());
|
||||
@ -179,38 +175,29 @@ public class ContactItem extends AbstractFlexibleItem<ContactItem.ContactItemVie
|
||||
.getResources().getString(R.string.nc_guest);
|
||||
}
|
||||
|
||||
setUserStyleAvatar(holder,
|
||||
ApiUtils.getUrlForGuestAvatar(user.getBaseUrl(), displayName, false));
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, user, displayName, true);
|
||||
} else if (participant.getCalculatedActorType() == Participant.ActorType.USERS ||
|
||||
PARTICIPANT_SOURCE_USERS.equals(participant.getSource())) {
|
||||
setUserStyleAvatar(holder,
|
||||
ApiUtils.getUrlForAvatar(user.getBaseUrl(),
|
||||
participant.getCalculatedActorId(),
|
||||
false));
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, user, participant.getCalculatedActorId(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUserStyleAvatar(ContactItemViewHolder holder, String avatarUrl) {
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.avatarDraweeView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl))
|
||||
.build();
|
||||
holder.binding.avatarDraweeView.setController(draweeController);
|
||||
}
|
||||
|
||||
private void setGenericAvatar(
|
||||
ContactItemViewHolder holder,
|
||||
int roundPlaceholderDrawable,
|
||||
int fallbackImageResource) {
|
||||
Object avatar;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.avatarDraweeView.getHierarchy().setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(holder.binding.avatarDraweeView,
|
||||
roundPlaceholderDrawable)));
|
||||
avatar = viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.avatarView,
|
||||
roundPlaceholderDrawable
|
||||
);
|
||||
|
||||
} else {
|
||||
holder.binding.avatarDraweeView.setImageResource(fallbackImageResource);
|
||||
avatar = fallbackImageResource;
|
||||
}
|
||||
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, avatar);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,27 +29,26 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.adapters.items.ConversationItem.ConversationItemViewHolder
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.RvItemConversationWithLastMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.extensions.loadGroupCallAvatar
|
||||
import com.nextcloud.talk.extensions.loadPublicCallAvatar
|
||||
import com.nextcloud.talk.extensions.loadSystemAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType
|
||||
import com.nextcloud.talk.ui.StatusDrawable
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
@ -113,7 +112,6 @@ class ConversationItem(
|
||||
payloads: List<Any>
|
||||
) {
|
||||
val appContext = sharedApplication!!.applicationContext
|
||||
holder.binding.dialogAvatar.controller = null
|
||||
holder.binding.dialogName.setTextColor(
|
||||
ResourcesCompat.getColor(
|
||||
context.resources,
|
||||
@ -130,40 +128,7 @@ class ConversationItem(
|
||||
holder.binding.dialogName.text = model.displayName
|
||||
}
|
||||
if (model.unreadMessages > 0) {
|
||||
holder.binding.dialogName.setTypeface(holder.binding.dialogName.typeface, Typeface.BOLD)
|
||||
holder.binding.dialogLastMessage.setTypeface(holder.binding.dialogLastMessage.typeface, Typeface.BOLD)
|
||||
holder.binding.dialogUnreadBubble.visibility = View.VISIBLE
|
||||
if (model.unreadMessages < 1000) {
|
||||
holder.binding.dialogUnreadBubble.text = model.unreadMessages.toLong().toString()
|
||||
} else {
|
||||
holder.binding.dialogUnreadBubble.setText(R.string.tooManyUnreadMessages)
|
||||
}
|
||||
val lightBubbleFillColor = ColorStateList.valueOf(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.conversation_unread_bubble
|
||||
)
|
||||
)
|
||||
val lightBubbleTextColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.conversation_unread_bubble_text
|
||||
)
|
||||
if (model.type === ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
} else if (model.unreadMention) {
|
||||
if (hasSpreedFeatureCapability(user, "direct-mention-flag")) {
|
||||
if (model.unreadMentionDirect!!) {
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
} else {
|
||||
viewThemeUtils.material.colorChipOutlined(holder.binding.dialogUnreadBubble, 6.0f)
|
||||
}
|
||||
} else {
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
}
|
||||
} else {
|
||||
holder.binding.dialogUnreadBubble.chipBackgroundColor = lightBubbleFillColor
|
||||
holder.binding.dialogUnreadBubble.setTextColor(lightBubbleTextColor)
|
||||
}
|
||||
showUnreadMessages(holder)
|
||||
} else {
|
||||
holder.binding.dialogName.setTypeface(null, Typeface.NORMAL)
|
||||
holder.binding.dialogDate.setTypeface(null, Typeface.NORMAL)
|
||||
@ -175,13 +140,13 @@ class ConversationItem(
|
||||
} else {
|
||||
holder.binding.favoriteConversationImageView.visibility = View.GONE
|
||||
}
|
||||
if (model != null && ConversationType.ROOM_SYSTEM !== model.type) {
|
||||
if (ConversationType.ROOM_SYSTEM !== model.type) {
|
||||
val size = DisplayUtils.convertDpToPixel(STATUS_SIZE_IN_DP, appContext)
|
||||
holder.binding.userStatusImage.visibility = View.VISIBLE
|
||||
holder.binding.userStatusImage.setImageDrawable(
|
||||
StatusDrawable(
|
||||
model.status,
|
||||
model.status,
|
||||
model.statusIcon,
|
||||
size,
|
||||
context.resources.getColor(R.color.bg_default),
|
||||
appContext
|
||||
@ -190,10 +155,77 @@ class ConversationItem(
|
||||
} else {
|
||||
holder.binding.userStatusImage.visibility = View.GONE
|
||||
}
|
||||
setLastMessage(holder, appContext)
|
||||
showAvatar(holder)
|
||||
}
|
||||
|
||||
private fun showAvatar(holder: ConversationItemViewHolder) {
|
||||
holder.binding.dialogAvatar.visibility = View.VISIBLE
|
||||
var shouldLoadAvatar = shouldLoadAvatar(holder)
|
||||
if (ConversationType.ROOM_SYSTEM == model.type) {
|
||||
holder.binding.dialogAvatar.loadSystemAvatar()
|
||||
shouldLoadAvatar = false
|
||||
}
|
||||
if (shouldLoadAvatar) {
|
||||
when (model.type) {
|
||||
ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(model.name)) {
|
||||
holder.binding.dialogAvatar.loadAvatar(user, model.name!!)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.visibility = View.GONE
|
||||
}
|
||||
ConversationType.ROOM_GROUP_CALL ->
|
||||
holder.binding.dialogAvatar.loadGroupCallAvatar(viewThemeUtils)
|
||||
ConversationType.ROOM_PUBLIC_CALL ->
|
||||
holder.binding.dialogAvatar.loadPublicCallAvatar(viewThemeUtils)
|
||||
else -> holder.binding.dialogAvatar.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldLoadAvatar(
|
||||
holder: ConversationItemViewHolder
|
||||
): Boolean {
|
||||
var objectType: String?
|
||||
var returnValue = true
|
||||
if (!TextUtils.isEmpty(model.objectType.also { objectType = it })) {
|
||||
when (objectType) {
|
||||
"share:password" -> {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_circular_lock
|
||||
)
|
||||
)
|
||||
returnValue = false
|
||||
}
|
||||
"file" -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.dialogAvatar.loadAvatar(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.dialogAvatar,
|
||||
R.drawable.ic_avatar_document
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.loadAvatar(
|
||||
R.drawable.ic_circular_document
|
||||
)
|
||||
}
|
||||
returnValue = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnValue
|
||||
}
|
||||
|
||||
private fun setLastMessage(
|
||||
holder: ConversationItemViewHolder,
|
||||
appContext: Context
|
||||
) {
|
||||
if (model.lastMessage != null) {
|
||||
holder.binding.dialogDate.visibility = View.VISIBLE
|
||||
holder.binding.dialogDate.text = DateUtils.getRelativeTimeSpanString(
|
||||
model.lastActivity * 1000L,
|
||||
model.lastActivity * MILLIES,
|
||||
System.currentTimeMillis(),
|
||||
0,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||
@ -204,30 +236,13 @@ class ConversationItem(
|
||||
holder.binding.dialogLastMessage.text = model.lastMessage!!.text
|
||||
} else {
|
||||
model.lastMessage!!.activeUser = user
|
||||
val text: String
|
||||
if (model.lastMessage!!.getCalculateMessageType() === ChatMessage.MessageType.REGULAR_TEXT_MESSAGE) {
|
||||
if (model.lastMessage!!.actorId == user.userId) {
|
||||
text = String.format(
|
||||
appContext.getString(R.string.nc_formatted_message_you),
|
||||
model.lastMessage!!.lastMessageDisplayText
|
||||
)
|
||||
} else {
|
||||
val authorDisplayName =
|
||||
if (!TextUtils.isEmpty(model.lastMessage!!.actorDisplayName)) {
|
||||
model.lastMessage!!.actorDisplayName
|
||||
} else if ("guests" == model.lastMessage!!.actorType) {
|
||||
appContext.getString(R.string.nc_guest)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
text = String.format(
|
||||
appContext.getString(R.string.nc_formatted_message),
|
||||
authorDisplayName,
|
||||
model.lastMessage!!.lastMessageDisplayText
|
||||
)
|
||||
}
|
||||
|
||||
val text = if (model.lastMessage!!.getCalculateMessageType() === ChatMessage.MessageType
|
||||
.REGULAR_TEXT_MESSAGE
|
||||
) {
|
||||
calculateRegularLastMessageText(appContext)
|
||||
} else {
|
||||
text = model.lastMessage!!.lastMessageDisplayText
|
||||
model.lastMessage!!.lastMessageDisplayText
|
||||
}
|
||||
holder.binding.dialogLastMessage.text = text
|
||||
}
|
||||
@ -235,105 +250,68 @@ class ConversationItem(
|
||||
holder.binding.dialogDate.visibility = View.GONE
|
||||
holder.binding.dialogLastMessage.setText(R.string.nc_no_messages_yet)
|
||||
}
|
||||
holder.binding.dialogAvatar.visibility = View.VISIBLE
|
||||
var shouldLoadAvatar = true
|
||||
var objectType: String?
|
||||
if (!TextUtils.isEmpty(model.objectType.also { objectType = it })) {
|
||||
when (objectType) {
|
||||
"share:password" -> {
|
||||
shouldLoadAvatar = false
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
context,
|
||||
R.drawable.ic_circular_lock
|
||||
)
|
||||
}
|
||||
|
||||
private fun calculateRegularLastMessageText(appContext: Context): String {
|
||||
return if (model.lastMessage!!.actorId == user.userId) {
|
||||
String.format(
|
||||
appContext.getString(R.string.nc_formatted_message_you),
|
||||
model.lastMessage!!.lastMessageDisplayText
|
||||
)
|
||||
} else {
|
||||
val authorDisplayName =
|
||||
if (!TextUtils.isEmpty(model.lastMessage!!.actorDisplayName)) {
|
||||
model.lastMessage!!.actorDisplayName
|
||||
} else if ("guests" == model.lastMessage!!.actorType) {
|
||||
appContext.getString(R.string.nc_guest)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
String.format(
|
||||
appContext.getString(R.string.nc_formatted_message),
|
||||
authorDisplayName,
|
||||
model.lastMessage!!.lastMessageDisplayText
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnreadMessages(holder: ConversationItemViewHolder) {
|
||||
holder.binding.dialogName.setTypeface(holder.binding.dialogName.typeface, Typeface.BOLD)
|
||||
holder.binding.dialogLastMessage.setTypeface(holder.binding.dialogLastMessage.typeface, Typeface.BOLD)
|
||||
holder.binding.dialogUnreadBubble.visibility = View.VISIBLE
|
||||
if (model.unreadMessages < UNREAD_MESSAGES_TRESHOLD) {
|
||||
holder.binding.dialogUnreadBubble.text = model.unreadMessages.toLong().toString()
|
||||
} else {
|
||||
holder.binding.dialogUnreadBubble.setText(R.string.tooManyUnreadMessages)
|
||||
}
|
||||
val lightBubbleFillColor = ColorStateList.valueOf(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.conversation_unread_bubble
|
||||
)
|
||||
)
|
||||
val lightBubbleTextColor = ContextCompat.getColor(
|
||||
context,
|
||||
R.color.conversation_unread_bubble_text
|
||||
)
|
||||
if (model.type === ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
} else if (model.unreadMention) {
|
||||
if (hasSpreedFeatureCapability(user, "direct-mention-flag")) {
|
||||
if (model.unreadMentionDirect!!) {
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
} else {
|
||||
viewThemeUtils.material.colorChipOutlined(
|
||||
holder.binding.dialogUnreadBubble,
|
||||
UNREAD_BUBBLE_STROKE_WIDTH
|
||||
)
|
||||
}
|
||||
"file" -> {
|
||||
shouldLoadAvatar = false
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.dialogAvatar,
|
||||
R.drawable.ic_avatar_document
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_circular_document)
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
if (ConversationType.ROOM_SYSTEM == model.type) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
holder.binding.dialogAvatar.hierarchy.setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(layerDrawable)
|
||||
)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.hierarchy.setPlaceholderImage(R.mipmap.ic_launcher)
|
||||
}
|
||||
shouldLoadAvatar = false
|
||||
}
|
||||
if (shouldLoadAvatar) {
|
||||
when (model.type) {
|
||||
ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(model.name)) {
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.dialogAvatar.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
model.name,
|
||||
true
|
||||
),
|
||||
user
|
||||
)
|
||||
)
|
||||
.build()
|
||||
holder.binding.dialogAvatar.controller = draweeController
|
||||
} else {
|
||||
holder.binding.dialogAvatar.visibility = View.GONE
|
||||
}
|
||||
ConversationType.ROOM_GROUP_CALL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.dialogAvatar,
|
||||
R.drawable.ic_avatar_group
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_circular_group)
|
||||
)
|
||||
}
|
||||
ConversationType.ROOM_PUBLIC_CALL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.dialogAvatar,
|
||||
R.drawable.ic_avatar_link
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
holder.binding.dialogAvatar.setImageDrawable(
|
||||
ContextCompat.getDrawable(context, R.drawable.ic_circular_link)
|
||||
)
|
||||
}
|
||||
else -> holder.binding.dialogAvatar.visibility = View.GONE
|
||||
viewThemeUtils.material.colorChipBackground(holder.binding.dialogUnreadBubble)
|
||||
}
|
||||
} else {
|
||||
holder.binding.dialogUnreadBubble.chipBackgroundColor = lightBubbleFillColor
|
||||
holder.binding.dialogUnreadBubble.setTextColor(lightBubbleTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,6 +341,9 @@ class ConversationItem(
|
||||
|
||||
companion object {
|
||||
const val VIEW_TYPE = R.layout.rv_item_conversation_with_last_message
|
||||
private const val MILLIES = 1000L
|
||||
private const val STATUS_SIZE_IN_DP = 9f
|
||||
private const val UNREAD_BUBBLE_STROKE_WIDTH = 6.0f
|
||||
private const val UNREAD_MESSAGES_TRESHOLD = 1000
|
||||
}
|
||||
}
|
||||
|
@ -29,15 +29,13 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.models.json.mention.Mention;
|
||||
import com.nextcloud.talk.models.json.status.StatusType;
|
||||
import com.nextcloud.talk.ui.StatusDrawable;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -151,34 +149,22 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<ParticipantIte
|
||||
|
||||
if (SOURCE_CALLS.equals(source)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.avatarDraweeView.getHierarchy().setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(holder.binding.avatarDraweeView,
|
||||
R.drawable.ic_avatar_group)));
|
||||
ImageViewExtensionsKt.loadAvatar(
|
||||
holder.binding.avatarView,
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(
|
||||
holder.binding.avatarView,
|
||||
R.drawable.ic_avatar_group
|
||||
)
|
||||
);
|
||||
} else {
|
||||
holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_group);
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, R.drawable.ic_circular_group);
|
||||
}
|
||||
} else {
|
||||
String avatarId = objectId;
|
||||
String avatarUrl = ApiUtils.getUrlForAvatar(currentUser.getBaseUrl(),
|
||||
avatarId, true);
|
||||
|
||||
if (SOURCE_GUESTS.equals(source)) {
|
||||
avatarId = displayName;
|
||||
avatarUrl = ApiUtils.getUrlForGuestAvatar(
|
||||
currentUser.getBaseUrl(),
|
||||
avatarId,
|
||||
false);
|
||||
}
|
||||
|
||||
holder.binding.avatarDraweeView.setController(null);
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.avatarDraweeView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl))
|
||||
.build();
|
||||
holder.binding.avatarDraweeView.setController(draweeController);
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, currentUser, avatarId, true);
|
||||
}
|
||||
|
||||
drawStatus(holder);
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Álvaro Brey
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2022 Álvaro Brey
|
||||
* Copyright (C) 2022 Nextcloud GmbH
|
||||
*
|
||||
@ -27,9 +29,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.RvItemSearchMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadThumbnail
|
||||
import com.nextcloud.talk.models.domain.SearchMessageEntry
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFilterable
|
||||
@ -72,7 +74,7 @@ data class MessageResultItem constructor(
|
||||
) {
|
||||
holder.binding.conversationTitle.text = messageEntry.title
|
||||
bindMessageExcerpt(holder)
|
||||
loadImage(holder)
|
||||
messageEntry.thumbnailURL?.let { holder.binding.thumbnail.loadThumbnail(it, currentUser) }
|
||||
}
|
||||
|
||||
private fun bindMessageExcerpt(holder: ViewHolder) {
|
||||
@ -83,17 +85,6 @@ data class MessageResultItem constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadImage(holder: ViewHolder) {
|
||||
DisplayUtils.loadAvatarPlaceholder(holder.binding.thumbnail)
|
||||
if (messageEntry.thumbnailURL != null) {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
messageEntry.thumbnailURL,
|
||||
currentUser
|
||||
)
|
||||
DisplayUtils.loadImage(holder.binding.thumbnail, imageRequest)
|
||||
}
|
||||
}
|
||||
|
||||
override fun filter(constraint: String?): Boolean = true
|
||||
|
||||
override fun getItemViewType(): Int {
|
||||
|
@ -27,23 +27,20 @@ package com.nextcloud.talk.adapters.items;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.databinding.RvItemConversationInfoParticipantBinding;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
import com.nextcloud.talk.models.json.participants.Participant.InCallFlags;
|
||||
import com.nextcloud.talk.models.json.status.StatusType;
|
||||
import com.nextcloud.talk.ui.StatusDrawable;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -111,24 +108,22 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
|
||||
@Override
|
||||
public void bindViewHolder(FlexibleAdapter adapter, ParticipantItemViewHolder holder, int position, List payloads) {
|
||||
|
||||
holder.binding.avatarDraweeView.setController(null);
|
||||
|
||||
drawStatus(holder);
|
||||
|
||||
if (!isOnline) {
|
||||
holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.medium_emphasis_text,
|
||||
null)
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.medium_emphasis_text,
|
||||
null)
|
||||
);
|
||||
holder.binding.avatarDraweeView.setAlpha(0.38f);
|
||||
holder.binding.avatarView.setAlpha(0.38f);
|
||||
} else {
|
||||
holder.binding.nameText.setTextColor(ResourcesCompat.getColor(
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.high_emphasis_text,
|
||||
null)
|
||||
holder.binding.nameText.getContext().getResources(),
|
||||
R.color.high_emphasis_text,
|
||||
null)
|
||||
);
|
||||
holder.binding.avatarDraweeView.setAlpha(1.0f);
|
||||
holder.binding.avatarView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
holder.binding.nameText.setText(participant.getDisplayName());
|
||||
@ -152,23 +147,9 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
|
||||
"groups".equals(participant.getSource()) ||
|
||||
participant.getCalculatedActorType() == Participant.ActorType.CIRCLES ||
|
||||
"circles".equals(participant.getSource())) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.avatarDraweeView.getHierarchy().setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(holder.binding.avatarDraweeView,
|
||||
R.drawable.ic_avatar_group)));
|
||||
} else {
|
||||
holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_group);
|
||||
}
|
||||
ImageViewExtensionsKt.loadGroupCallAvatar(holder.binding.avatarView, viewThemeUtils);
|
||||
} else if (participant.getCalculatedActorType() == Participant.ActorType.EMAILS) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
holder.binding.avatarDraweeView.getHierarchy().setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(holder.binding.avatarDraweeView,
|
||||
R.drawable.ic_avatar_mail)));
|
||||
} else {
|
||||
holder.binding.avatarDraweeView.setImageResource(R.drawable.ic_circular_mail);
|
||||
}
|
||||
ImageViewExtensionsKt.loadMailAvatar(holder.binding.avatarView, viewThemeUtils);
|
||||
} else if (participant.getCalculatedActorType() == Participant.ActorType.GUESTS ||
|
||||
participant.getType() == Participant.ParticipantType.GUEST ||
|
||||
participant.getType() == Participant.ParticipantType.GUEST_MODERATOR) {
|
||||
@ -180,25 +161,11 @@ public class ParticipantItem extends AbstractFlexibleItem<ParticipantItem.Partic
|
||||
displayName = participant.getDisplayName();
|
||||
}
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.avatarDraweeView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForGuestAvatar(user.getBaseUrl(),
|
||||
displayName, false)))
|
||||
.build();
|
||||
holder.binding.avatarDraweeView.setController(draweeController);
|
||||
ImageViewExtensionsKt.loadGuestAvatar(holder.binding.avatarView, user, displayName, false);
|
||||
|
||||
} else if (participant.getCalculatedActorType() == Participant.ActorType.USERS ||
|
||||
participant.getSource().equals("users")) {
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.binding.avatarDraweeView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(user.getBaseUrl(),
|
||||
participant.getCalculatedActorId(), false)))
|
||||
.build();
|
||||
holder.binding.avatarDraweeView.setController(draweeController);
|
||||
ImageViewExtensionsKt.loadAvatar(holder.binding.avatarView, user, participant.getCalculatedActorId(), true);
|
||||
}
|
||||
|
||||
Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
|
||||
|
@ -24,25 +24,21 @@ package com.nextcloud.talk.adapters.messages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import autodagger.AutoInjector
|
||||
import coil.load
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingLinkPreviewMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadBotsAvatar
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.stfalcon.chatkit.messages.MessageHolders
|
||||
import javax.inject.Inject
|
||||
@ -143,26 +139,9 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : M
|
||||
if (message.actorType == "guests") {
|
||||
// do nothing, avatar is set
|
||||
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
} else {
|
||||
binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
|
||||
}
|
||||
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
ResourcesCompat.getColor(context.resources, R.color.black, null)
|
||||
)
|
||||
binding.messageUserAvatar.visibility = View.VISIBLE
|
||||
binding.messageUserAvatar.setImageDrawable(drawable)
|
||||
binding.messageUserAvatar.loadBotsAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ package com.nextcloud.talk.adapters.messages
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
@ -40,18 +38,17 @@ import android.view.View
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import autodagger.AutoInjector
|
||||
import coil.load
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingLocationMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadBotsAvatar
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.UriUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.stfalcon.chatkit.messages.MessageHolders
|
||||
@ -136,22 +133,9 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : Mess
|
||||
if (message.actorType == "guests") {
|
||||
// do nothing, avatar is set
|
||||
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_background)
|
||||
layers[1] = AppCompatResources.getDrawable(context!!, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
context!!.resources.getColor(R.color.black)
|
||||
)
|
||||
binding.messageUserAvatar.visibility = View.VISIBLE
|
||||
binding.messageUserAvatar.setImageDrawable(drawable)
|
||||
binding.messageUserAvatar.loadBotsAvatar()
|
||||
}
|
||||
} else {
|
||||
if (message.isOneToOneConversation) {
|
||||
|
@ -22,27 +22,23 @@ package com.nextcloud.talk.adapters.messages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import autodagger.AutoInjector
|
||||
import coil.load
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingPollMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadBotsAvatar
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.polls.ui.PollMainDialogFragment
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.stfalcon.chatkit.messages.MessageHolders
|
||||
import javax.inject.Inject
|
||||
@ -170,26 +166,9 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : MessageH
|
||||
if (message.actorType == "guests") {
|
||||
// do nothing, avatar is set
|
||||
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
} else {
|
||||
binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
|
||||
}
|
||||
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
ResourcesCompat.getColor(context.resources, R.color.black, null)
|
||||
)
|
||||
binding.messageUserAvatar.visibility = View.VISIBLE
|
||||
binding.messageUserAvatar.setImageDrawable(drawable)
|
||||
binding.messageUserAvatar.loadBotsAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021-2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -23,9 +23,9 @@
|
||||
package com.nextcloud.talk.adapters.messages;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingPreviewMessageBinding;
|
||||
@ -74,7 +74,7 @@ public class IncomingPreviewMessageViewHolder extends PreviewMessageViewHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDraweeView getPreviewContactPhoto() {
|
||||
public ImageView getPreviewContactPhoto() {
|
||||
return binding.contactPhoto;
|
||||
}
|
||||
|
||||
|
@ -26,24 +26,21 @@ package com.nextcloud.talk.adapters.messages
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.TextUtils
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import autodagger.AutoInjector
|
||||
import coil.load
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingTextMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadBotsAvatar
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
@ -179,28 +176,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : MessageHolde
|
||||
if (message.actorType == "guests") {
|
||||
// do nothing, avatar is set
|
||||
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||
if (context != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
} else {
|
||||
binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
|
||||
}
|
||||
}
|
||||
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
ResourcesCompat.getColor(context!!.resources, R.color.black, null)
|
||||
)
|
||||
binding.messageUserAvatar.visibility = View.VISIBLE
|
||||
binding.messageUserAvatar.setImageDrawable(drawable)
|
||||
binding.messageUserAvatar.loadBotsAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,6 @@ package com.nextcloud.talk.adapters.messages
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
@ -46,10 +43,10 @@ import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.databinding.ItemCustomIncomingVoiceMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.stfalcon.chatkit.messages.MessageHolders
|
||||
import java.util.concurrent.ExecutionException
|
||||
@ -245,15 +242,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
|
||||
if (message.actorType == "guests") {
|
||||
// do nothing, avatar is set
|
||||
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.messageUserAvatar.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
} else {
|
||||
binding.messageUserAvatar.setImageResource(R.mipmap.ic_launcher)
|
||||
}
|
||||
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||
} else if (message.actorType == "bots") {
|
||||
val drawable = TextDrawable.builder()
|
||||
.beginConfig()
|
||||
|
@ -25,14 +25,12 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import coil.load
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.databinding.ReferenceInsideMessageBinding
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.models.json.opengraph.OpenGraphOverall
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
@ -92,12 +90,7 @@ class LinkPreview {
|
||||
val referenceThumbUrl = reference.openGraphObject?.thumb
|
||||
if (!referenceThumbUrl.isNullOrEmpty()) {
|
||||
binding.referenceThumbImage.visibility = View.VISIBLE
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(referenceThumbUrl))
|
||||
.build()
|
||||
binding.referenceThumbImage.controller =
|
||||
draweeController
|
||||
binding.referenceThumbImage.load(referenceThumbUrl)
|
||||
} else {
|
||||
binding.referenceThumbImage.visibility = View.GONE
|
||||
}
|
||||
|
@ -23,9 +23,9 @@
|
||||
package com.nextcloud.talk.adapters.messages;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.databinding.ItemCustomOutcomingPreviewMessageBinding;
|
||||
@ -75,7 +75,7 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDraweeView getPreviewContactPhoto() {
|
||||
public ImageView getPreviewContactPhoto() {
|
||||
return binding.contactPhoto;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021-2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
@ -30,7 +30,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.util.Base64
|
||||
@ -38,13 +37,13 @@ import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.ProgressBar
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
import autodagger.AutoInjector
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
@ -53,6 +52,7 @@ import com.nextcloud.talk.components.filebrowser.models.BrowserFile
|
||||
import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding
|
||||
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
||||
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
@ -92,6 +92,8 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
lateinit var commonMessageInterface: CommonMessageInterface
|
||||
var previewMessageInterface: PreviewMessageInterface? = null
|
||||
|
||||
private var placeholder: Drawable? = null
|
||||
|
||||
init {
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
}
|
||||
@ -118,13 +120,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
}
|
||||
}
|
||||
if (ACTOR_TYPE_BOTS == message.actorType && ACTOR_ID_CHANGELOG == message.actorId) {
|
||||
if (context != null) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
userAvatar.hierarchy.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
}
|
||||
userAvatar.loadChangelogBotAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,11 +146,10 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
}
|
||||
if (message.selectedIndividualHashMap!!.containsKey(KEY_CONTACT_PHOTO)) {
|
||||
image = previewContactPhoto
|
||||
val drawable = getDrawableFromContactDetails(
|
||||
placeholder = getDrawableFromContactDetails(
|
||||
context,
|
||||
message.selectedIndividualHashMap!![KEY_CONTACT_PHOTO]
|
||||
)
|
||||
image.hierarchy.setPlaceholderImage(drawable)
|
||||
} else if (message.selectedIndividualHashMap!!.containsKey(KEY_MIMETYPE)) {
|
||||
val mimetype = message.selectedIndividualHashMap!![KEY_MIMETYPE]
|
||||
val drawableResourceId = getDrawableResourceIdForMimeType(mimetype)
|
||||
@ -170,7 +165,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
}
|
||||
image.hierarchy.setPlaceholderImage(drawable)
|
||||
placeholder = drawable
|
||||
} else {
|
||||
fetchFileInformation(
|
||||
"/" + message.selectedIndividualHashMap!![KEY_PATH],
|
||||
@ -208,13 +203,13 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
DisplayUtils.setClickableString("Tenor", "https://tenor.com", messageText)
|
||||
} else {
|
||||
if (message.messageType == ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE.name) {
|
||||
(clickView as SimpleDraweeView?)?.setOnClickListener {
|
||||
clickView!!.setOnClickListener {
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(message.imageUrl))
|
||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context!!.startActivity(browserIntent)
|
||||
}
|
||||
} else {
|
||||
(clickView as SimpleDraweeView?)?.setOnClickListener(null)
|
||||
clickView!!.setOnClickListener(null)
|
||||
}
|
||||
messageText.text = ""
|
||||
}
|
||||
@ -238,6 +233,10 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
commonMessageInterface.onClickReaction(chatMessage, emoji)
|
||||
}
|
||||
|
||||
override fun getPayloadForImageLoader(message: ChatMessage?): Any? {
|
||||
return placeholder
|
||||
}
|
||||
|
||||
private fun getDrawableFromContactDetails(context: Context?, base64: String?): Drawable? {
|
||||
var drawable: Drawable? = null
|
||||
if (base64 != "") {
|
||||
@ -300,8 +299,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
if (browserFileList.isNotEmpty()) {
|
||||
Handler(context!!.mainLooper).post {
|
||||
val resourceId = getDrawableResourceIdForMimeType(browserFileList[0].mimeType)
|
||||
val drawable = ContextCompat.getDrawable(context!!, resourceId)
|
||||
image.hierarchy.setPlaceholderImage(drawable)
|
||||
placeholder = ContextCompat.getDrawable(context!!, resourceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,7 +322,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
|
||||
abstract val messageText: EmojiTextView
|
||||
abstract val previewContainer: View
|
||||
abstract val previewContactContainer: MaterialCardView
|
||||
abstract val previewContactPhoto: SimpleDraweeView
|
||||
abstract val previewContactPhoto: ImageView
|
||||
abstract val previewContactName: EmojiTextView
|
||||
abstract val previewContactProgressBar: ProgressBar?
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
@ -46,9 +48,7 @@ import coil.decode.GifDecoder
|
||||
import coil.decode.ImageDecoderDecoder
|
||||
import coil.decode.SvgDecoder
|
||||
import coil.memory.MemoryCache
|
||||
import com.facebook.cache.disk.DiskCacheConfig
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
||||
import coil.util.DebugLogger
|
||||
import com.nextcloud.talk.BuildConfig
|
||||
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils
|
||||
import com.nextcloud.talk.dagger.modules.BusModule
|
||||
@ -66,7 +66,6 @@ import com.nextcloud.talk.utils.ClosedInterfaceImpl
|
||||
import com.nextcloud.talk.utils.DeviceUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.NotificationUtils
|
||||
import com.nextcloud.talk.utils.OkHttpNetworkFetcherWithCache
|
||||
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule
|
||||
import com.nextcloud.talk.utils.database.user.UserModule
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
@ -174,18 +173,6 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
setAppTheme(appPreferences.theme)
|
||||
super.onCreate()
|
||||
|
||||
val imagePipelineConfig = ImagePipelineConfig.newBuilder(this)
|
||||
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
|
||||
.setMainDiskCacheConfig(
|
||||
DiskCacheConfig.newBuilder(this)
|
||||
.setMaxCacheSize(0)
|
||||
.setMaxCacheSizeOnLowDiskSpace(0)
|
||||
.setMaxCacheSizeOnVeryLowDiskSpace(0)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
||||
Fresco.initialize(this, imagePipelineConfig)
|
||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||
|
||||
ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync()
|
||||
@ -240,7 +227,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
}
|
||||
|
||||
private fun buildDefaultImageLoader(): ImageLoader {
|
||||
return ImageLoader.Builder(applicationContext)
|
||||
val imageLoaderBuilder = ImageLoader.Builder(applicationContext)
|
||||
.memoryCache {
|
||||
// Use 50% of the application's available memory.
|
||||
MemoryCache.Builder(applicationContext).maxSizePercent(FIFTY_PERCENT).build()
|
||||
@ -254,8 +241,12 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
}
|
||||
add(SvgDecoder.Factory())
|
||||
}
|
||||
.okHttpClient(okHttpClient)
|
||||
.build()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
imageLoaderBuilder.logger(DebugLogger())
|
||||
}
|
||||
|
||||
return imageLoaderBuilder.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -27,7 +27,7 @@ import android.text.Editable;
|
||||
import android.text.Spanned;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.facebook.widget.text.span.BetterImageSpan;
|
||||
import third.parties.fresco.BetterImageSpan;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.models.json.mention.Mention;
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @author Marcel Hibbe
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021-2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2021-2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
|
||||
@ -37,8 +37,9 @@ import android.content.pm.PackageManager
|
||||
import android.content.res.AssetFileDescriptor
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.MediaPlayer
|
||||
import android.media.MediaRecorder
|
||||
import android.net.Uri
|
||||
@ -78,7 +79,7 @@ import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.content.PermissionChecker
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
@ -90,15 +91,13 @@ import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import autodagger.AutoInjector
|
||||
import coil.imageLoader
|
||||
import coil.load
|
||||
import coil.request.ImageRequest
|
||||
import coil.target.Target
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.facebook.common.executors.UiThreadImmediateExecutorService
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.datasource.DataSource
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nextcloud.talk.BuildConfig
|
||||
@ -134,6 +133,7 @@ import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.ControllerChatBinding
|
||||
import com.nextcloud.talk.events.UserMentionClickEvent
|
||||
import com.nextcloud.talk.events.WebSocketCommunicationEvent
|
||||
import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
|
||||
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
|
||||
import com.nextcloud.talk.jobs.ShareOperationWorker
|
||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
|
||||
@ -165,7 +165,6 @@ import com.nextcloud.talk.utils.ConductorRemapping
|
||||
import com.nextcloud.talk.utils.ConductorRemapping.remapChatController
|
||||
import com.nextcloud.talk.utils.ContactUtils
|
||||
import com.nextcloud.talk.utils.DateUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.FileUtils
|
||||
import com.nextcloud.talk.utils.ImageEmojiEditText
|
||||
import com.nextcloud.talk.utils.MagicCharPolicy
|
||||
@ -462,42 +461,48 @@ class ChatController(args: Bundle) :
|
||||
|
||||
private fun loadAvatarForStatusBar() {
|
||||
if (isOneToOneConversation() && activity != null) {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
conversationUser?.baseUrl,
|
||||
currentConversation?.name,
|
||||
true
|
||||
),
|
||||
conversationUser!!
|
||||
|
||||
val url = ApiUtils.getUrlForAvatar(
|
||||
conversationUser!!.baseUrl,
|
||||
currentConversation!!.name,
|
||||
true
|
||||
)
|
||||
val target = object : Target {
|
||||
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
private fun setIcon(drawable: Drawable?) {
|
||||
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (actionBar != null && bitmap != null && resources != null) {
|
||||
val avatarSize = (actionBar?.height!! / TOOLBAR_AVATAR_RATIO).roundToInt()
|
||||
if (avatarSize > 0) {
|
||||
val bitmapResized = Bitmap.createScaledBitmap(bitmap, avatarSize, avatarSize, false)
|
||||
actionBar?.let {
|
||||
val avatarSize = (it.height / TOOLBAR_AVATAR_RATIO).roundToInt()
|
||||
|
||||
val roundedBitmapDrawable =
|
||||
RoundedBitmapDrawableFactory.create(resources!!, bitmapResized)
|
||||
roundedBitmapDrawable.isCircular = true
|
||||
roundedBitmapDrawable.setAntiAlias(true)
|
||||
actionBar?.setIcon(roundedBitmapDrawable)
|
||||
} else {
|
||||
Log.d(TAG, "loadAvatarForStatusBar avatarSize <= 0")
|
||||
}
|
||||
if (drawable != null && avatarSize > 0) {
|
||||
val bitmap = drawable.toBitmap(avatarSize, avatarSize)
|
||||
it.setIcon(BitmapDrawable(resources, bitmap))
|
||||
} else {
|
||||
Log.d(TAG, "loadAvatarForStatusBar avatarSize <= 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
|
||||
// unused atm
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
override fun onStart(placeholder: Drawable?) {
|
||||
this.setIcon(placeholder)
|
||||
}
|
||||
|
||||
override fun onSuccess(result: Drawable) {
|
||||
this.setIcon(result)
|
||||
}
|
||||
}
|
||||
|
||||
val credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token)
|
||||
|
||||
context.imageLoader.enqueue(
|
||||
ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.addHeader("Authorization", credentials)
|
||||
.placeholder(R.drawable.ic_user)
|
||||
.transformations(CircleCropTransformation())
|
||||
.crossfade(true)
|
||||
.target(target)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -617,14 +622,8 @@ class ChatController(args: Bundle) :
|
||||
adapter = TalkMessagesListAdapter(
|
||||
senderId,
|
||||
messageHolders,
|
||||
ImageLoader { imageView, url, payload ->
|
||||
val draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser))
|
||||
.setControllerListener(DisplayUtils.getImageControllerListener(imageView))
|
||||
.setOldController(imageView.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.build()
|
||||
imageView.controller = draweeController
|
||||
ImageLoader { imageView, url, _ ->
|
||||
imageView.loadAvatarOrImagePreview(url!!, conversationUser, placeholder = payload as? Drawable)
|
||||
},
|
||||
this
|
||||
)
|
||||
|
@ -28,9 +28,6 @@ package com.nextcloud.talk.controllers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.text.TextUtils
|
||||
@ -42,7 +39,6 @@ import android.view.View.VISIBLE
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
@ -53,7 +49,6 @@ import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
||||
import com.afollestad.materialdialogs.datetime.dateTimePicker
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.adapters.items.ParticipantItem
|
||||
@ -67,6 +62,10 @@ import com.nextcloud.talk.conversation.info.GuestAccessHelper
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
|
||||
import com.nextcloud.talk.events.EventStatus
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.extensions.loadSystemAvatar
|
||||
import com.nextcloud.talk.extensions.loadGroupCallAvatar
|
||||
import com.nextcloud.talk.extensions.loadPublicCallAvatar
|
||||
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
@ -83,7 +82,6 @@ import com.nextcloud.talk.shareditems.activities.SharedItemsActivity
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DateConstants
|
||||
import com.nextcloud.talk.utils.DateUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
|
||||
import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
|
||||
@ -778,54 +776,16 @@ class ConversationInfoController(args: Bundle) :
|
||||
private fun loadConversationAvatar() {
|
||||
when (conversation!!.type) {
|
||||
Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(conversation!!.name)) {
|
||||
val draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.avatarImage.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
conversationUser!!.baseUrl,
|
||||
conversation!!.name,
|
||||
true
|
||||
),
|
||||
conversationUser
|
||||
)
|
||||
)
|
||||
.build()
|
||||
binding.avatarImage.controller = draweeController
|
||||
conversation!!.name?.let { binding.avatarImage.loadAvatar(conversationUser!!, it) }
|
||||
}
|
||||
Conversation.ConversationType.ROOM_GROUP_CALL -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(binding.avatarImage, R.drawable.ic_avatar_group)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
R.drawable.ic_circular_group
|
||||
)
|
||||
}
|
||||
binding.avatarImage.loadGroupCallAvatar(viewThemeUtils)
|
||||
}
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(binding.avatarImage, R.drawable.ic_avatar_link)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
R.drawable.ic_circular_link
|
||||
)
|
||||
}
|
||||
binding.avatarImage.loadPublicCallAvatar(viewThemeUtils)
|
||||
}
|
||||
Conversation.ConversationType.ROOM_SYSTEM -> {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
binding.avatarImage.loadSystemAvatar()
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
@ -31,7 +31,7 @@ import android.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -49,8 +49,6 @@ import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.core.view.MenuItemCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -58,15 +56,13 @@ import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import autodagger.AutoInjector
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.target.Target
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
|
||||
import com.facebook.common.executors.UiThreadImmediateExecutorService
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.datasource.DataSource
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nextcloud.talk.R
|
||||
@ -104,7 +100,6 @@ import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.ClosedInterfaceImpl
|
||||
import com.nextcloud.talk.utils.ConductorRemapping.remapChatController
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.FileUtils
|
||||
import com.nextcloud.talk.utils.Mimetype
|
||||
import com.nextcloud.talk.utils.ParticipantPermissions
|
||||
@ -211,78 +206,56 @@ class ConversationsListController(bundle: Bundle) :
|
||||
prepareViews()
|
||||
}
|
||||
|
||||
private fun loadUserAvatar(button: MaterialButton) {
|
||||
if (activity != null) {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
currentUser!!.baseUrl,
|
||||
currentUser!!.userId,
|
||||
true
|
||||
),
|
||||
currentUser
|
||||
)
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (bitmap != null && resources != null) {
|
||||
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
|
||||
resources!!,
|
||||
bitmap
|
||||
)
|
||||
roundedBitmapDrawable.isCircular = true
|
||||
roundedBitmapDrawable.setAntiAlias(true)
|
||||
button.icon = roundedBitmapDrawable
|
||||
}
|
||||
}
|
||||
private fun loadUserAvatar(
|
||||
target: Target
|
||||
) {
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage?>>) {
|
||||
if (resources != null) {
|
||||
button.icon = ResourcesCompat.getDrawable(resources!!, R.drawable.ic_user, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
if (activity != null) {
|
||||
val url = ApiUtils.getUrlForAvatar(
|
||||
currentUser!!.baseUrl,
|
||||
currentUser!!.userId,
|
||||
true
|
||||
)
|
||||
|
||||
val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
|
||||
|
||||
context.imageLoader.enqueue(
|
||||
ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.addHeader("Authorization", credentials)
|
||||
.placeholder(R.drawable.ic_user)
|
||||
.transformations(CircleCropTransformation())
|
||||
.crossfade(true)
|
||||
.target(target)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadUserAvatar(menuItem: MenuItem) {
|
||||
if (activity != null) {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
currentUser!!.baseUrl,
|
||||
currentUser!!.userId,
|
||||
true
|
||||
),
|
||||
currentUser
|
||||
)
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (bitmap != null && resources != null) {
|
||||
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
|
||||
resources!!,
|
||||
bitmap
|
||||
)
|
||||
roundedBitmapDrawable.isCircular = true
|
||||
roundedBitmapDrawable.setAntiAlias(true)
|
||||
menuItem.icon = roundedBitmapDrawable
|
||||
}
|
||||
}
|
||||
private fun loadUserAvatar(button: MaterialButton) {
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage?>>) {
|
||||
if (resources != null) {
|
||||
menuItem.icon = ResourcesCompat.getDrawable(resources!!, R.drawable.ic_user, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
)
|
||||
val target = object : Target {
|
||||
override fun onStart(placeholder: Drawable?) {
|
||||
button.icon = placeholder
|
||||
}
|
||||
override fun onSuccess(result: Drawable) {
|
||||
button.icon = result
|
||||
}
|
||||
}
|
||||
|
||||
loadUserAvatar(target)
|
||||
}
|
||||
|
||||
private fun loadUserAvatar(menuItem: MenuItem) {
|
||||
val target = object : Target {
|
||||
override fun onStart(placeholder: Drawable?) {
|
||||
menuItem.icon = placeholder
|
||||
}
|
||||
override fun onSuccess(result: Drawable) {
|
||||
menuItem.icon = result
|
||||
}
|
||||
}
|
||||
loadUserAvatar(target)
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
|
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2022 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package com.nextcloud.talk.extensions
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import coil.annotation.ExperimentalCoilApi
|
||||
import coil.imageLoader
|
||||
import coil.load
|
||||
import coil.request.ImageRequest
|
||||
import coil.request.SuccessResult
|
||||
import coil.result
|
||||
import coil.transform.CircleCropTransformation
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.amulyakhare.textdrawable.TextDrawable
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
|
||||
private const val ROUNDING_PIXEL = 16f
|
||||
private const val TAG = "ImageViewExtensions"
|
||||
|
||||
fun ImageView.loadAvatar(
|
||||
user: User,
|
||||
avatar: String,
|
||||
requestBigSize: Boolean = true
|
||||
): io.reactivex.disposables
|
||||
.Disposable {
|
||||
|
||||
val imageRequestUri = ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
avatar,
|
||||
requestBigSize
|
||||
)
|
||||
|
||||
return loadAvatarInternal(user, imageRequestUri, false)
|
||||
}
|
||||
|
||||
fun ImageView.replaceAvatar(
|
||||
user: User,
|
||||
avatar: String,
|
||||
requestBigSize: Boolean = true
|
||||
): io.reactivex.disposables
|
||||
.Disposable {
|
||||
|
||||
val imageRequestUri = ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
avatar,
|
||||
requestBigSize
|
||||
)
|
||||
|
||||
return loadAvatarInternal(user, imageRequestUri, true)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
private fun ImageView.loadAvatarInternal(
|
||||
user: User?,
|
||||
url: String,
|
||||
replace: Boolean
|
||||
): io.reactivex.disposables
|
||||
.Disposable {
|
||||
|
||||
if (replace && this.result is SuccessResult) {
|
||||
val result = this.result as SuccessResult
|
||||
val memoryCacheKey = result.memoryCacheKey
|
||||
val memoryCache = context.imageLoader.memoryCache
|
||||
memoryCacheKey?.let { memoryCache?.remove(it) }
|
||||
|
||||
val diskCacheKey = result.diskCacheKey
|
||||
val diskCache = context.imageLoader.diskCache
|
||||
diskCacheKey?.let { diskCache?.remove(it) }
|
||||
}
|
||||
|
||||
return DisposableWrapper(
|
||||
load(url) {
|
||||
user?.let {
|
||||
addHeader(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(user.username, user.token)
|
||||
)
|
||||
}
|
||||
transformations(CircleCropTransformation())
|
||||
placeholder(R.drawable.account_circle_96dp)
|
||||
listener(onError = { _, result ->
|
||||
Log.w(TAG, "Can't load avatar with URL: $url", result.throwable)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Use function loadAvatar", level = DeprecationLevel.WARNING)
|
||||
fun ImageView.loadAvatarWithUrl(user: User? = null, url: String): io.reactivex.disposables.Disposable {
|
||||
return loadAvatarInternal(user, url, false)
|
||||
}
|
||||
|
||||
fun ImageView.loadThumbnail(url: String, user: User): io.reactivex.disposables.Disposable {
|
||||
val requestBuilder = ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.crossfade(true)
|
||||
.target(this)
|
||||
.transformations(CircleCropTransformation())
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
requestBuilder.placeholder(LayerDrawable(layers))
|
||||
} else {
|
||||
requestBuilder.placeholder(R.mipmap.ic_launcher)
|
||||
}
|
||||
|
||||
if (url.startsWith(user.baseUrl!!) &&
|
||||
(url.contains("index.php/core/preview?fileId=") || url.contains("/avatar/"))
|
||||
) {
|
||||
requestBuilder.addHeader(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(user.username, user.token)
|
||||
)
|
||||
}
|
||||
|
||||
return DisposableWrapper(context.imageLoader.enqueue(requestBuilder.build()))
|
||||
}
|
||||
|
||||
fun ImageView.loadImage(url: String, user: User, placeholder: Drawable? = null): io.reactivex.disposables.Disposable {
|
||||
|
||||
val requestBuilder = ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.crossfade(true)
|
||||
.target(this)
|
||||
.placeholder(placeholder)
|
||||
.error(placeholder)
|
||||
.transformations(RoundedCornersTransformation(ROUNDING_PIXEL, ROUNDING_PIXEL, ROUNDING_PIXEL, ROUNDING_PIXEL))
|
||||
|
||||
if (url.startsWith(user.baseUrl!!) &&
|
||||
(url.contains("index.php/core/preview?fileId=") || url.contains("/avatar/"))
|
||||
) {
|
||||
requestBuilder.addHeader(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(user.username, user.token)
|
||||
)
|
||||
}
|
||||
|
||||
return DisposableWrapper(context.imageLoader.enqueue(requestBuilder.build()))
|
||||
}
|
||||
|
||||
fun ImageView.loadAvatarOrImagePreview(url: String, user: User, placeholder: Drawable? = null): io.reactivex
|
||||
.disposables.Disposable {
|
||||
return if (url.contains("/avatar/")) {
|
||||
loadAvatarInternal(user, url, false)
|
||||
} else {
|
||||
loadImage(url, user, placeholder)
|
||||
}
|
||||
}
|
||||
|
||||
fun ImageView.loadAvatar(any: Any?): io.reactivex.disposables.Disposable {
|
||||
return DisposableWrapper(
|
||||
load(any) {
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun ImageView.loadSystemAvatar(): io.reactivex.disposables.Disposable {
|
||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
layerDrawable
|
||||
} else {
|
||||
R.mipmap.ic_launcher
|
||||
}
|
||||
|
||||
return DisposableWrapper(
|
||||
load(data) {
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun ImageView.loadChangelogBotAvatar(): io.reactivex.disposables.Disposable {
|
||||
return loadSystemAvatar()
|
||||
}
|
||||
|
||||
fun ImageView.loadBotsAvatar(): io.reactivex.disposables.Disposable {
|
||||
return loadAvatar(
|
||||
TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(
|
||||
">",
|
||||
ResourcesCompat.getColor(context.resources, R.color.black, null)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun ImageView.loadGroupCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||
|
||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_group) as Any
|
||||
} else {
|
||||
R.drawable.ic_circular_group
|
||||
}
|
||||
return loadAvatar(data)
|
||||
}
|
||||
|
||||
fun ImageView.loadPublicCallAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_link) as Any
|
||||
} else {
|
||||
R.drawable.ic_circular_link
|
||||
}
|
||||
return loadAvatar(data)
|
||||
}
|
||||
|
||||
fun ImageView.loadMailAvatar(viewThemeUtils: ViewThemeUtils): io.reactivex.disposables.Disposable {
|
||||
val data: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
viewThemeUtils.talk.themePlaceholderAvatar(this, R.drawable.ic_avatar_mail) as Any
|
||||
} else {
|
||||
R.drawable.ic_circular_mail
|
||||
}
|
||||
return loadAvatar(data)
|
||||
}
|
||||
|
||||
fun ImageView.loadGuestAvatar(user: User, name: String, big: Boolean): io.reactivex.disposables.Disposable {
|
||||
return loadGuestAvatar(user.baseUrl!!, name, big)
|
||||
}
|
||||
|
||||
fun ImageView.loadGuestAvatar(baseUrl: String, name: String, big: Boolean): io.reactivex.disposables.Disposable {
|
||||
val imageRequestUri = ApiUtils.getUrlForGuestAvatar(
|
||||
baseUrl,
|
||||
name,
|
||||
big
|
||||
)
|
||||
return DisposableWrapper(
|
||||
load(imageRequestUri) {
|
||||
transformations(CircleCropTransformation())
|
||||
listener(onError = { _, result ->
|
||||
Log.w(TAG, "Can't load guest avatar with URL: $imageRequestUri", result.throwable)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private class DisposableWrapper(private val disposable: coil.request.Disposable) : io.reactivex.disposables
|
||||
.Disposable {
|
||||
|
||||
override fun dispose() {
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
override fun isDisposed(): Boolean {
|
||||
return disposable.isDisposed
|
||||
}
|
||||
}
|
@ -526,7 +526,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
||||
notificationUser.id,
|
||||
false
|
||||
) else ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.name, false)
|
||||
person.setIcon(loadAvatarSync(avatarUrl))
|
||||
person.setIcon(loadAvatarSync(avatarUrl, context!!))
|
||||
}
|
||||
notificationBuilder.setStyle(getStyle(person.build(), style))
|
||||
}
|
||||
|
@ -22,16 +22,15 @@ package com.nextcloud.talk.polls.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.TextUtils
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import android.widget.ImageView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.PollResultVoterItemBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.extensions.loadGuestAvatar
|
||||
import com.nextcloud.talk.polls.model.PollDetails
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
|
||||
class PollResultVoterViewHolder(
|
||||
private val user: User,
|
||||
@ -46,45 +45,19 @@ class PollResultVoterViewHolder(
|
||||
binding.root.setOnClickListener { clickListener.onClick() }
|
||||
|
||||
binding.pollVoterName.text = item.details.actorDisplayName
|
||||
binding.pollVoterAvatar.controller = getAvatarDraweeController(item.details)
|
||||
loadAvatar(item.details, binding.pollVoterAvatar)
|
||||
viewThemeUtils.dialog.colorDialogSupportingText(binding.pollVoterName)
|
||||
}
|
||||
|
||||
private fun getAvatarDraweeController(pollDetail: PollDetails): DraweeController? {
|
||||
var draweeController: DraweeController? = null
|
||||
private fun loadAvatar(pollDetail: PollDetails, avatar: ImageView) {
|
||||
if (pollDetail.actorType == "guests") {
|
||||
var displayName = NextcloudTalkApplication.sharedApplication?.resources?.getString(R.string.nc_guest)
|
||||
if (!TextUtils.isEmpty(pollDetail.actorDisplayName)) {
|
||||
displayName = pollDetail.actorDisplayName!!
|
||||
}
|
||||
draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForGuestAvatar(
|
||||
user.baseUrl,
|
||||
displayName,
|
||||
false
|
||||
),
|
||||
user
|
||||
)
|
||||
)
|
||||
.build()
|
||||
avatar.loadGuestAvatar(user, displayName!!, false)
|
||||
} else if (pollDetail.actorType == "users") {
|
||||
draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
pollDetail.actorId,
|
||||
false
|
||||
),
|
||||
user
|
||||
)
|
||||
)
|
||||
.build()
|
||||
avatar.loadAvatar(user, pollDetail.actorId!!, false)
|
||||
}
|
||||
return draweeController
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Marcel Hibbe
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -22,20 +24,16 @@ package com.nextcloud.talk.polls.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.TextUtils
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.generic.RoundingParams
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.PollResultVotersOverviewItemBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.extensions.loadGuestAvatar
|
||||
import com.nextcloud.talk.polls.model.PollDetails
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
|
||||
class PollResultVotersOverviewViewHolder(
|
||||
private val user: User,
|
||||
@ -61,24 +59,14 @@ class PollResultVotersOverviewViewHolder(
|
||||
|
||||
for (i in 0 until avatarsToDisplay) {
|
||||
val pollDetails = item.detailsList[i]
|
||||
val avatar = SimpleDraweeView(binding.root.context)
|
||||
val avatar = ImageView(binding.root.context)
|
||||
|
||||
layoutParams.marginStart = i * AVATAR_OFFSET
|
||||
avatar.layoutParams = layoutParams
|
||||
|
||||
avatar.translationZ = i.toFloat() * -1
|
||||
|
||||
val roundingParams = RoundingParams.fromCornersRadius(AVATAR_RADIUS)
|
||||
roundingParams.roundAsCircle = true
|
||||
roundingParams.borderColor = ResourcesCompat.getColor(
|
||||
itemView.context.resources!!,
|
||||
R.color.vote_dialog_background,
|
||||
null
|
||||
)
|
||||
roundingParams.borderWidth = DisplayUtils.convertDpToPixel(2.0f, itemView.context)
|
||||
|
||||
avatar.hierarchy.roundingParams = roundingParams
|
||||
avatar.controller = getAvatarDraweeController(pollDetails)
|
||||
loadAvatar(pollDetails, avatar)
|
||||
|
||||
binding.votersAvatarsOverviewWrapper.addView(avatar)
|
||||
|
||||
@ -92,47 +80,20 @@ class PollResultVotersOverviewViewHolder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvatarDraweeController(pollDetail: PollDetails): DraweeController? {
|
||||
var draweeController: DraweeController? = null
|
||||
private fun loadAvatar(pollDetail: PollDetails, avatar: ImageView) {
|
||||
if (pollDetail.actorType == "guests") {
|
||||
var displayName = NextcloudTalkApplication.sharedApplication?.resources?.getString(R.string.nc_guest)
|
||||
if (!TextUtils.isEmpty(pollDetail.actorDisplayName)) {
|
||||
displayName = pollDetail.actorDisplayName!!
|
||||
}
|
||||
draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForGuestAvatar(
|
||||
user.baseUrl,
|
||||
displayName,
|
||||
false
|
||||
),
|
||||
user
|
||||
)
|
||||
)
|
||||
.build()
|
||||
avatar.loadGuestAvatar(user, displayName!!, false)
|
||||
} else if (pollDetail.actorType == "users") {
|
||||
draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
pollDetail.actorId,
|
||||
false
|
||||
),
|
||||
user
|
||||
)
|
||||
)
|
||||
.build()
|
||||
avatar.loadAvatar(user, pollDetail.actorId!!, false)
|
||||
}
|
||||
return draweeController
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val AVATAR_SIZE = 60
|
||||
const val AVATAR_RADIUS = 5f
|
||||
const val MAX_AVATARS = 10
|
||||
const val AVATAR_OFFSET = AVATAR_SIZE - 20
|
||||
const val DOTS_OFFSET = 70
|
||||
|
@ -162,7 +162,7 @@ class DirectReplyReceiver : BroadcastReceiver() {
|
||||
val avatarUrl = ApiUtils.getUrlForAvatar(currentUser.baseUrl, currentUser.userId, false)
|
||||
val me = Person.Builder()
|
||||
.setName(currentUser.displayName)
|
||||
.setIcon(NotificationUtils.loadAvatarSync(avatarUrl))
|
||||
.setIcon(NotificationUtils.loadAvatarSync(avatarUrl, context))
|
||||
.build()
|
||||
val message = NotificationCompat.MessagingStyle.Message(reply, System.currentTimeMillis(), me)
|
||||
previousStyle?.addMessage(message)
|
||||
|
@ -22,20 +22,18 @@ package com.nextcloud.talk.remotefilebrowser.adapters
|
||||
|
||||
import android.text.format.Formatter
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import autodagger.AutoInjector
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.RvItemBrowserFileBinding
|
||||
import com.nextcloud.talk.extensions.loadImage
|
||||
import com.nextcloud.talk.remotefilebrowser.SelectionInterface
|
||||
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DateUtils.getLocalDateTimeStringFromTimestamp
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.Mimetype.FOLDER
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
@ -48,7 +46,7 @@ class RemoteFileBrowserItemsListViewHolder(
|
||||
onItemClicked: (Int) -> Unit
|
||||
) : RemoteFileBrowserItemsViewHolder(binding, mimeTypeSelectionFilter, currentUser, selectionInterface) {
|
||||
|
||||
override val fileIcon: SimpleDraweeView
|
||||
override val fileIcon: ImageView
|
||||
get() = binding.fileIcon
|
||||
|
||||
private var selectable: Boolean = true
|
||||
@ -68,7 +66,6 @@ class RemoteFileBrowserItemsListViewHolder(
|
||||
override fun onBind(item: RemoteFileBrowserItem) {
|
||||
super.onBind(item)
|
||||
|
||||
binding.fileIcon.controller = null
|
||||
if (!item.isAllowedToReShare || item.isEncrypted) {
|
||||
binding.root.isEnabled = false
|
||||
binding.root.alpha = DISABLED_ALPHA
|
||||
@ -95,11 +92,7 @@ class RemoteFileBrowserItemsListViewHolder(
|
||||
calculateClickability(item, selectable)
|
||||
setSelectability()
|
||||
|
||||
binding.fileIcon
|
||||
.hierarchy
|
||||
.setPlaceholderImage(
|
||||
viewThemeUtils.talk.getPlaceholderImage(binding.root.context, item.mimeType)
|
||||
)
|
||||
val placeholder = viewThemeUtils.talk.getPlaceholderImage(binding.root.context, item.mimeType)
|
||||
|
||||
if (item.hasPreview) {
|
||||
val path = ApiUtils.getUrlForFilePreviewWithRemotePath(
|
||||
@ -108,12 +101,10 @@ class RemoteFileBrowserItemsListViewHolder(
|
||||
binding.fileIcon.context.resources.getDimensionPixelSize(R.dimen.small_item_height)
|
||||
)
|
||||
if (path.isNotEmpty()) {
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(path))
|
||||
.build()
|
||||
binding.fileIcon.controller = draweeController
|
||||
binding.fileIcon.loadImage(path, currentUser, placeholder)
|
||||
}
|
||||
} else {
|
||||
binding.fileIcon.setImageDrawable(placeholder)
|
||||
}
|
||||
|
||||
binding.filenameTextView.text = item.displayName
|
||||
|
@ -20,11 +20,9 @@
|
||||
|
||||
package com.nextcloud.talk.remotefilebrowser.adapters
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat
|
||||
import android.widget.ImageView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.remotefilebrowser.SelectionInterface
|
||||
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
|
||||
@ -37,17 +35,9 @@ abstract class RemoteFileBrowserItemsViewHolder(
|
||||
val selectionInterface: SelectionInterface,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
abstract val fileIcon: SimpleDraweeView
|
||||
abstract val fileIcon: ImageView
|
||||
|
||||
open fun onBind(item: RemoteFileBrowserItem) {
|
||||
fileIcon.hierarchy.setPlaceholderImage(staticImage(item.mimeType, fileIcon))
|
||||
}
|
||||
|
||||
private fun staticImage(
|
||||
mimeType: String?,
|
||||
image: SimpleDraweeView
|
||||
): Drawable {
|
||||
val drawableResourceId = DrawableUtils.getDrawableResourceIdForMimeType(mimeType)
|
||||
return ContextCompat.getDrawable(image.context, drawableResourceId)!!
|
||||
fileIcon.setImageResource(DrawableUtils.getDrawableResourceIdForMimeType(item.mimeType))
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,8 @@
|
||||
package com.nextcloud.talk.shareditems.adapters
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.SharedItemGridBinding
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
@ -35,7 +35,7 @@ class SharedItemsGridViewHolder(
|
||||
viewThemeUtils: ViewThemeUtils
|
||||
) : SharedItemsViewHolder(binding, user, viewThemeUtils) {
|
||||
|
||||
override val image: SimpleDraweeView
|
||||
override val image: ImageView
|
||||
get() = binding.image
|
||||
override val clickTarget: View
|
||||
get() = binding.image
|
||||
|
@ -26,9 +26,10 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.format.Formatter
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import coil.load
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.SharedItemListBinding
|
||||
@ -46,7 +47,7 @@ class SharedItemsListViewHolder(
|
||||
viewThemeUtils: ViewThemeUtils
|
||||
) : SharedItemsViewHolder(binding, user, viewThemeUtils) {
|
||||
|
||||
override val image: SimpleDraweeView
|
||||
override val image: ImageView
|
||||
get() = binding.fileImage
|
||||
override val clickTarget: View
|
||||
get() = binding.fileItem
|
||||
@ -75,7 +76,7 @@ class SharedItemsListViewHolder(
|
||||
binding.separator1.visibility = View.GONE
|
||||
binding.fileDate.text = item.dateTime
|
||||
binding.actor.text = item.actorName
|
||||
image.hierarchy.setPlaceholderImage(R.drawable.ic_baseline_bar_chart_24)
|
||||
image.load(R.drawable.ic_baseline_bar_chart_24)
|
||||
image.setColorFilter(
|
||||
ContextCompat.getColor(image.context, R.color.high_emphasis_menu_icon),
|
||||
android.graphics.PorterDuff.Mode.SRC_IN
|
||||
@ -93,7 +94,7 @@ class SharedItemsListViewHolder(
|
||||
binding.separator1.visibility = View.GONE
|
||||
binding.fileDate.text = item.dateTime
|
||||
binding.actor.text = item.actorName
|
||||
image.hierarchy.setPlaceholderImage(R.drawable.ic_baseline_location_on_24)
|
||||
image.load(R.drawable.ic_baseline_location_on_24)
|
||||
image.setColorFilter(
|
||||
ContextCompat.getColor(image.context, R.color.high_emphasis_menu_icon),
|
||||
android.graphics.PorterDuff.Mode.SRC_IN
|
||||
@ -114,7 +115,7 @@ class SharedItemsListViewHolder(
|
||||
binding.separator1.visibility = View.GONE
|
||||
binding.fileDate.text = item.dateTime
|
||||
binding.actor.text = item.actorName
|
||||
image.hierarchy.setPlaceholderImage(R.drawable.ic_mimetype_file)
|
||||
image.load(R.drawable.ic_mimetype_file)
|
||||
image.setColorFilter(
|
||||
ContextCompat.getColor(image.context, R.color.high_emphasis_menu_icon),
|
||||
android.graphics.PorterDuff.Mode.SRC_IN
|
||||
@ -129,7 +130,7 @@ class SharedItemsListViewHolder(
|
||||
binding.separator1.visibility = View.GONE
|
||||
binding.fileDate.text = item.dateTime
|
||||
binding.actor.text = item.actorName
|
||||
image.hierarchy.setPlaceholderImage(R.drawable.ic_baseline_deck_24)
|
||||
image.load(R.drawable.ic_baseline_deck_24)
|
||||
image.setColorFilter(
|
||||
ContextCompat.getColor(image.context, R.color.high_emphasis_menu_icon),
|
||||
android.graphics.PorterDuff.Mode.SRC_IN
|
||||
|
@ -23,29 +23,20 @@
|
||||
package com.nextcloud.talk.shareditems.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.controller.BaseControllerListener
|
||||
import com.facebook.drawee.controller.ControllerListener
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.facebook.imagepipeline.common.RotationOptions
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.extensions.loadImage
|
||||
import com.nextcloud.talk.shareditems.model.SharedDeckCardItem
|
||||
import com.nextcloud.talk.shareditems.model.SharedFileItem
|
||||
import com.nextcloud.talk.shareditems.model.SharedItem
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.shareditems.model.SharedLocationItem
|
||||
import com.nextcloud.talk.shareditems.model.SharedOtherItem
|
||||
import com.nextcloud.talk.shareditems.model.SharedPollItem
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.FileViewerUtils
|
||||
|
||||
abstract class SharedItemsViewHolder(
|
||||
@ -58,21 +49,21 @@ abstract class SharedItemsViewHolder(
|
||||
private val TAG = SharedItemsViewHolder::class.simpleName
|
||||
}
|
||||
|
||||
abstract val image: SimpleDraweeView
|
||||
abstract val image: ImageView
|
||||
abstract val clickTarget: View
|
||||
abstract val progressBar: ProgressBar
|
||||
|
||||
private val authHeader = mapOf(
|
||||
Pair(
|
||||
"Authorization",
|
||||
ApiUtils.getCredentials(user.username, user.token)
|
||||
)
|
||||
)
|
||||
|
||||
open fun onBind(item: SharedFileItem) {
|
||||
image.hierarchy.setPlaceholderImage(viewThemeUtils.talk.getPlaceholderImage(image.context, item.mimeType))
|
||||
|
||||
val placeholder = viewThemeUtils.talk.getPlaceholderImage(image.context, item.mimeType)
|
||||
if (item.previewAvailable) {
|
||||
image.controller = configurePreview(item)
|
||||
image.loadImage(
|
||||
item.previewLink,
|
||||
user,
|
||||
placeholder
|
||||
)
|
||||
} else {
|
||||
image.setImageDrawable(placeholder)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -105,28 +96,6 @@ abstract class SharedItemsViewHolder(
|
||||
)
|
||||
}
|
||||
|
||||
private fun configurePreview(item: SharedFileItem): DraweeController {
|
||||
val imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(item.previewLink))
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.setRotationOptions(RotationOptions.autoRotate())
|
||||
.disableDiskCache()
|
||||
.setHeaders(authHeader)
|
||||
.build()
|
||||
|
||||
val listener: ControllerListener<ImageInfo?> = object : BaseControllerListener<ImageInfo?>() {
|
||||
override fun onFailure(id: String, e: Throwable) {
|
||||
Log.w(TAG, "Failed to load image. A static mimetype image will be used", e)
|
||||
}
|
||||
}
|
||||
|
||||
return Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(image.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(imageRequest)
|
||||
.setControllerListener(listener)
|
||||
.build()
|
||||
}
|
||||
|
||||
open fun onBind(item: SharedPollItem, showPoll: (item: SharedItem, context: Context) -> Unit) {}
|
||||
|
||||
open fun onBind(item: SharedLocationItem) {}
|
||||
|
@ -33,8 +33,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.nextcloud.talk.activities.MainActivity;
|
||||
import com.nextcloud.talk.adapters.items.AdvancedUserItem;
|
||||
@ -42,6 +40,7 @@ import com.nextcloud.talk.api.NcApi;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.databinding.DialogChooseAccountBinding;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
import com.nextcloud.talk.models.json.status.Status;
|
||||
import com.nextcloud.talk.models.json.status.StatusOverall;
|
||||
@ -132,22 +131,10 @@ public class ChooseAccountDialogFragment extends DialogFragment {
|
||||
if (user.getBaseUrl() != null &&
|
||||
(user.getBaseUrl().startsWith("http://") || user.getBaseUrl().startsWith("https://"))) {
|
||||
binding.currentAccount.userIcon.setVisibility(View.VISIBLE);
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding.currentAccount.userIcon.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.getBaseUrl(),
|
||||
user.getUserId(),
|
||||
false)))
|
||||
.build();
|
||||
binding.currentAccount.userIcon.setController(draweeController);
|
||||
|
||||
ImageViewExtensionsKt.loadAvatar(binding.currentAccount.userIcon, user, user.getUserId(), true);
|
||||
} else {
|
||||
binding.currentAccount.userIcon.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
loadCurrentStatus(user);
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import autodagger.AutoInjector
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.adapters.items.AdvancedUserItem
|
||||
@ -42,11 +40,10 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.DialogChooseAccountShareToBinding
|
||||
import com.nextcloud.talk.extensions.loadAvatar
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import java.net.CookieManager
|
||||
@ -97,21 +94,7 @@ class ChooseAccountShareToDialogFragment : DialogFragment() {
|
||||
if (user.baseUrl != null &&
|
||||
(user.baseUrl!!.startsWith("http://") || user.baseUrl!!.startsWith("https://"))
|
||||
) {
|
||||
binding!!.currentAccount.userIcon.visibility = View.VISIBLE
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding!!.currentAccount.userIcon.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
user.userId,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
binding!!.currentAccount.userIcon.controller = draweeController
|
||||
binding!!.currentAccount.userIcon.loadAvatar(user, user.userId!!)
|
||||
} else {
|
||||
binding!!.currentAccount.userIcon.visibility = View.INVISIBLE
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* @author Tim Krüger
|
||||
* Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
@ -33,11 +35,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
@ -51,36 +49,19 @@ import android.text.style.AbsoluteSizeSpan;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.controller.ControllerListener;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.common.RotationOptions;
|
||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
|
||||
import com.facebook.imagepipeline.postprocessors.RoundPostprocessor;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.facebook.widget.text.span.BetterImageSpan;
|
||||
import com.google.android.material.chip.ChipDrawable;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.data.user.model.User;
|
||||
import com.nextcloud.talk.events.UserMentionClickEvent;
|
||||
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.utils.text.Spans;
|
||||
|
||||
@ -91,8 +72,6 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -109,6 +88,11 @@ import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
import coil.Coil;
|
||||
import coil.request.ImageRequest;
|
||||
import coil.target.Target;
|
||||
import coil.transform.CircleCropTransformation;
|
||||
import third.parties.fresco.BetterImageSpan;
|
||||
|
||||
import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id;
|
||||
import static com.nextcloud.talk.utils.FileSortOrder.sort_big_to_small_id;
|
||||
@ -119,8 +103,6 @@ import static com.nextcloud.talk.utils.FileSortOrder.sort_z_to_a_id;
|
||||
|
||||
public class DisplayUtils {
|
||||
|
||||
private static final String TAG = "DisplayUtils";
|
||||
|
||||
private static final int INDEX_LUMINATION = 2;
|
||||
private static final double MAX_LIGHTNESS = 0.92;
|
||||
|
||||
@ -154,33 +136,6 @@ public class DisplayUtils {
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
|
||||
private static void updateViewSize(@Nullable ImageInfo imageInfo, SimpleDraweeView draweeView) {
|
||||
if (imageInfo != null && draweeView.getId() != R.id.messageUserAvatar) {
|
||||
int maxSize = draweeView.getContext().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size);
|
||||
draweeView.getLayoutParams().width = imageInfo.getWidth() > maxSize ? maxSize : imageInfo.getWidth();
|
||||
draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
|
||||
draweeView.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable getRoundedDrawable(Drawable drawable) {
|
||||
Bitmap bitmap = getBitmap(drawable);
|
||||
new RoundAsCirclePostprocessor(true).process(bitmap);
|
||||
return new BitmapDrawable(bitmap);
|
||||
}
|
||||
|
||||
public static Bitmap getRoundedBitmapFromVectorDrawableResource(Resources resources, int resource) {
|
||||
VectorDrawable vectorDrawable = (VectorDrawable) ResourcesCompat.getDrawable(resources, resource, null);
|
||||
Bitmap bitmap = getBitmap(vectorDrawable);
|
||||
new RoundPostprocessor(true).process(bitmap);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Drawable getRoundedBitmapDrawableFromVectorDrawableResource(Resources resources, int resource) {
|
||||
return new BitmapDrawable(getRoundedBitmapFromVectorDrawableResource(resources, resource));
|
||||
}
|
||||
|
||||
public static Bitmap getBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
|
||||
drawable.getIntrinsicHeight(),
|
||||
@ -191,60 +146,6 @@ public class DisplayUtils {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static ImageRequest getImageRequestForUrl(String url) {
|
||||
return getImageRequestForUrl(url, (User) null);
|
||||
}
|
||||
|
||||
public static ImageRequest getImageRequestForUrl(String url, @Nullable User user) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
if (user != null &&
|
||||
url.startsWith(user.getBaseUrl()) &&
|
||||
(url.contains("index.php/core/preview?fileId=") || url.contains("/avatar/"))) {
|
||||
headers.put("Authorization", ApiUtils.getCredentials(user.getUsername(), user.getToken()));
|
||||
}
|
||||
|
||||
return ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.setRotationOptions(RotationOptions.autoRotate())
|
||||
.disableDiskCache()
|
||||
.setHeaders(headers)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ControllerListener getImageControllerListener(SimpleDraweeView draweeView) {
|
||||
return new ControllerListener() {
|
||||
@Override
|
||||
public void onSubmit(String id, Object callerContext) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinalImageSet(String id, @Nullable Object imageInfo, @Nullable Animatable animatable) {
|
||||
updateViewSize((ImageInfo) imageInfo, draweeView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIntermediateImageSet(String id, @Nullable Object imageInfo) {
|
||||
updateViewSize((ImageInfo) imageInfo, draweeView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIntermediateImageFailed(String id, Throwable throwable) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String id, Throwable throwable) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(String id) {
|
||||
// unused atm
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static float convertDpToPixel(float dp, Context context) {
|
||||
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
|
||||
context.getResources().getDisplayMetrics()) + 0.5f);
|
||||
@ -335,33 +236,37 @@ public class DisplayUtils {
|
||||
conversationUser.getBaseUrl(),
|
||||
String.valueOf(label), true);
|
||||
}
|
||||
ImageRequest imageRequest = getImageRequestForUrl(url);
|
||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(
|
||||
imageRequest,
|
||||
context);
|
||||
|
||||
dataSource.subscribe(
|
||||
new BaseBitmapDataSubscriber() {
|
||||
ImageRequest imageRequest = new ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.crossfade(true)
|
||||
.transformations(new CircleCropTransformation())
|
||||
.target(new Target() {
|
||||
@Override
|
||||
protected void onNewResultImpl(Bitmap bitmap) {
|
||||
if (bitmap != null) {
|
||||
chip.setChipIcon(getRoundedDrawable(new BitmapDrawable(bitmap)));
|
||||
public void onStart(@Nullable Drawable drawable) {
|
||||
|
||||
// A hack to refresh the chip icon
|
||||
if (emojiEditText != null) {
|
||||
emojiEditText.post(() -> emojiEditText.setTextKeepState(
|
||||
emojiEditText.getText(),
|
||||
TextView.BufferType.SPANNABLE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@Nullable Drawable drawable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@NonNull Drawable drawable) {
|
||||
chip.setChipIcon(drawable);
|
||||
|
||||
// A hack to refresh the chip icon
|
||||
if (emojiEditText != null) {
|
||||
emojiEditText.post(() -> emojiEditText.setTextKeepState(
|
||||
emojiEditText.getText(),
|
||||
TextView.BufferType.SPANNABLE));
|
||||
}
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
@Override
|
||||
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance());
|
||||
Coil.imageLoader(context).enqueue(imageRequest);
|
||||
}
|
||||
|
||||
return chip;
|
||||
@ -575,7 +480,7 @@ public class DisplayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadAvatarImage(User user, SimpleDraweeView avatarImageView, boolean deleteCache) {
|
||||
public static void loadAvatarImage(User user, ImageView avatarImageView, boolean deleteCache) {
|
||||
String avatarId;
|
||||
if (!TextUtils.isEmpty(user.getUserId())) {
|
||||
avatarId = user.getUserId();
|
||||
@ -583,50 +488,13 @@ public class DisplayUtils {
|
||||
avatarId = user.getUsername();
|
||||
}
|
||||
|
||||
String avatarString = ApiUtils.getUrlForAvatar(user.getBaseUrl(), avatarId, true);
|
||||
|
||||
// clear cache
|
||||
if (deleteCache) {
|
||||
Uri avatarUri = Uri.parse(avatarString);
|
||||
|
||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
imagePipeline.evictFromMemoryCache(avatarUri);
|
||||
imagePipeline.evictFromDiskCache(avatarUri);
|
||||
imagePipeline.evictFromCache(avatarUri);
|
||||
}
|
||||
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(avatarImageView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(avatarString))
|
||||
.build();
|
||||
avatarImageView.setController(draweeController);
|
||||
}
|
||||
|
||||
public static void loadAvatarPlaceholder(final SimpleDraweeView targetView) {
|
||||
final Context context = targetView.getContext();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Drawable[] layers = new Drawable[2];
|
||||
layers[0] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_background);
|
||||
layers[1] = ContextCompat.getDrawable(context, R.drawable.ic_launcher_foreground);
|
||||
LayerDrawable layerDrawable = new LayerDrawable(layers);
|
||||
|
||||
targetView.getHierarchy().setPlaceholderImage(
|
||||
DisplayUtils.getRoundedDrawable(layerDrawable));
|
||||
ImageViewExtensionsKt.replaceAvatar(avatarImageView, user, avatarId, true);
|
||||
} else {
|
||||
targetView.getHierarchy().setPlaceholderImage(R.mipmap.ic_launcher);
|
||||
ImageViewExtensionsKt.loadAvatar(avatarImageView, user, avatarId, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadImage(final SimpleDraweeView targetView, final ImageRequest imageRequest) {
|
||||
final DraweeController newController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(targetView.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(imageRequest)
|
||||
.build();
|
||||
targetView.setController(newController);
|
||||
}
|
||||
|
||||
public static @StringRes
|
||||
int getSortOrderStringId(FileSortOrder sortOrder) {
|
||||
switch (sortOrder.getName()) {
|
||||
@ -649,7 +517,7 @@ public class DisplayUtils {
|
||||
/**
|
||||
* calculates the relative time string based on the given modification timestamp.
|
||||
*
|
||||
* @param context the app's context
|
||||
* @param context the app's context
|
||||
* @param modificationTimestamp the UNIX timestamp of the file modification time in milliseconds.
|
||||
* @return a relative time string
|
||||
*/
|
||||
|
@ -22,7 +22,7 @@
|
||||
package com.nextcloud.talk.utils
|
||||
|
||||
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
|
||||
import third_parties.daveKoeller.AlphanumComparator
|
||||
import third.parties.daveKoeller.AlphanumComparator
|
||||
import java.util.Collections
|
||||
|
||||
class FileSortOrderByName internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) {
|
||||
@ -40,7 +40,8 @@ class FileSortOrderByName internal constructor(name: String, ascending: Boolean)
|
||||
* Comparator for RemoteFileBrowserItems, sorts by name.
|
||||
*/
|
||||
class RemoteFileBrowserItemNameComparator(private val multiplier: Int) : Comparator<RemoteFileBrowserItem> {
|
||||
private val alphanumComparator = AlphanumComparator<RemoteFileBrowserItem>()
|
||||
private val alphanumComparator =
|
||||
AlphanumComparator<RemoteFileBrowserItem>()
|
||||
|
||||
override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int {
|
||||
return if (!left.isFile && !right.isFile) {
|
||||
|
@ -28,6 +28,7 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
@ -36,7 +37,6 @@ import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.FullScreenImageActivity
|
||||
import com.nextcloud.talk.activities.FullScreenMediaActivity
|
||||
@ -412,7 +412,7 @@ class FileViewerUtils(private val context: Context, private val user: User) {
|
||||
data class ProgressUi(
|
||||
val progressBar: ProgressBar?,
|
||||
val messageText: EmojiTextView?,
|
||||
val previewImage: SimpleDraweeView
|
||||
val previewImage: ImageView
|
||||
)
|
||||
|
||||
data class FileInfo(
|
||||
|
@ -27,18 +27,19 @@ import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.media.AudioAttributes
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import coil.executeBlocking
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.datasource.DataSources
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.image.CloseableBitmap
|
||||
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor
|
||||
import com.nextcloud.talk.BuildConfig
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
@ -50,6 +51,8 @@ import java.io.IOException
|
||||
@Suppress("TooManyFunctions")
|
||||
object NotificationUtils {
|
||||
|
||||
const val TAG = "NotificationUtils"
|
||||
|
||||
enum class NotificationChannels {
|
||||
NOTIFICATION_CHANNEL_MESSAGES_V4,
|
||||
NOTIFICATION_CHANNEL_CALLS_V4,
|
||||
@ -320,28 +323,31 @@ object NotificationUtils {
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Load user avatar synchronously.
|
||||
* Inspired by:
|
||||
* https://frescolib.org/docs/using-image-pipeline.html
|
||||
* https://github.com/facebook/fresco/issues/830
|
||||
* https://localcoder.org/using-facebooks-fresco-to-load-a-bitmap
|
||||
*/
|
||||
fun loadAvatarSync(avatarUrl: String): IconCompat? {
|
||||
// TODO - how to handle errors here?
|
||||
fun loadAvatarSync(avatarUrl: String, context: Context): IconCompat? {
|
||||
var avatarIcon: IconCompat? = null
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl)
|
||||
val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, null)
|
||||
val closeableImageRef = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>?
|
||||
val bitmap = closeableImageRef?.get()?.underlyingBitmap
|
||||
if (bitmap != null) {
|
||||
// According to Fresco documentation a copy of the bitmap should be made before closing the references.
|
||||
// However, it seems to work without making a copy... ;-)
|
||||
RoundAsCirclePostprocessor(true).process(bitmap)
|
||||
avatarIcon = IconCompat.createWithBitmap(bitmap)
|
||||
}
|
||||
CloseableReference.closeSafely(closeableImageRef)
|
||||
dataSource.close()
|
||||
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(avatarUrl)
|
||||
.transformations(CircleCropTransformation())
|
||||
.placeholder(R.drawable.account_circle_96dp)
|
||||
.placeholder(R.drawable.account_circle_96dp)
|
||||
.target(
|
||||
onSuccess = { result ->
|
||||
val bitmap = (result as BitmapDrawable).bitmap
|
||||
avatarIcon = IconCompat.createWithBitmap(bitmap)
|
||||
},
|
||||
onError = { error ->
|
||||
error?.let {
|
||||
val bitmap = (error as BitmapDrawable).bitmap
|
||||
avatarIcon = IconCompat.createWithBitmap(bitmap)
|
||||
}
|
||||
Log.w(TAG, "Can't load avatar for URL: $avatarUrl")
|
||||
}
|
||||
)
|
||||
.build()
|
||||
|
||||
context.imageLoader.executeBlocking(request)
|
||||
|
||||
return avatarIcon
|
||||
}
|
||||
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.utils;
|
||||
|
||||
import com.facebook.imagepipeline.backends.okhttp3.OkHttpNetworkFetcher;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class OkHttpNetworkFetcherWithCache extends OkHttpNetworkFetcher {
|
||||
public OkHttpNetworkFetcherWithCache(OkHttpClient okHttpClient) {
|
||||
super(okHttpClient);
|
||||
}
|
||||
|
||||
public OkHttpNetworkFetcherWithCache(Call.Factory callFactory, Executor cancellationExecutor) {
|
||||
super(callFactory, cancellationExecutor);
|
||||
}
|
||||
|
||||
public OkHttpNetworkFetcherWithCache(Call.Factory callFactory, Executor cancellationExecutor, boolean disableOkHttpCache) {
|
||||
super(callFactory, cancellationExecutor, true);
|
||||
}
|
||||
}
|
@ -22,9 +22,10 @@ package com.nextcloud.talk.utils.text;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.facebook.widget.text.span.BetterImageSpan;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import third.parties.fresco.BetterImageSpan;
|
||||
|
||||
public class Spans {
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package third_parties.daveKoeller;
|
||||
package third.parties.daveKoeller;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
138
app/src/main/java/third/parties/fresco/BetterImageSpan.kt
Normal file
138
app/src/main/java/third/parties/fresco/BetterImageSpan.kt
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package third.parties.fresco
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Paint.FontMetricsInt
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.style.ReplacementSpan
|
||||
import androidx.annotation.IntDef
|
||||
|
||||
/**
|
||||
* A better implementation of image spans that also supports centering images against the text.
|
||||
*
|
||||
* In order to migrate from ImageSpan, replace `new ImageSpan(drawable, alignment)` with
|
||||
* `new BetterImageSpan(drawable, BetterImageSpan.normalizeAlignment(alignment))`.
|
||||
*
|
||||
* There are 2 main differences between BetterImageSpan and ImageSpan:
|
||||
* 1. Pass in ALIGN_CENTER to center images against the text.
|
||||
* 2. ALIGN_BOTTOM no longer unnecessarily increases the size of the text:
|
||||
* DynamicDrawableSpan (ImageSpan's parent) adjusts sizes as if alignment was ALIGN_BASELINE
|
||||
* which can lead to unnecessary whitespace.
|
||||
*/
|
||||
open class BetterImageSpan @JvmOverloads constructor(
|
||||
val drawable: Drawable,
|
||||
@param:BetterImageSpanAlignment private val mAlignment: Int = ALIGN_BASELINE
|
||||
) : ReplacementSpan() {
|
||||
@IntDef(*[ALIGN_BASELINE, ALIGN_BOTTOM, ALIGN_CENTER])
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class BetterImageSpanAlignment
|
||||
|
||||
private var mWidth = 0
|
||||
private var mHeight = 0
|
||||
private var mBounds: Rect? = null
|
||||
private val mFontMetricsInt = FontMetricsInt()
|
||||
|
||||
init {
|
||||
updateBounds()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of the image span and increases the height if font metrics are available.
|
||||
*/
|
||||
override fun getSize(
|
||||
paint: Paint,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
end: Int,
|
||||
fontMetrics: FontMetricsInt?
|
||||
): Int {
|
||||
updateBounds()
|
||||
if (fontMetrics == null) {
|
||||
return mWidth
|
||||
}
|
||||
val offsetAbove = getOffsetAboveBaseline(fontMetrics)
|
||||
val offsetBelow = mHeight + offsetAbove
|
||||
if (offsetAbove < fontMetrics.ascent) {
|
||||
fontMetrics.ascent = offsetAbove
|
||||
}
|
||||
if (offsetAbove < fontMetrics.top) {
|
||||
fontMetrics.top = offsetAbove
|
||||
}
|
||||
if (offsetBelow > fontMetrics.descent) {
|
||||
fontMetrics.descent = offsetBelow
|
||||
}
|
||||
if (offsetBelow > fontMetrics.bottom) {
|
||||
fontMetrics.bottom = offsetBelow
|
||||
}
|
||||
return mWidth
|
||||
}
|
||||
|
||||
override fun draw(
|
||||
canvas: Canvas,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
end: Int,
|
||||
x: Float,
|
||||
top: Int,
|
||||
y: Int,
|
||||
bottom: Int,
|
||||
paint: Paint
|
||||
) {
|
||||
paint.getFontMetricsInt(mFontMetricsInt)
|
||||
val iconTop = y + getOffsetAboveBaseline(mFontMetricsInt)
|
||||
canvas.translate(x, iconTop.toFloat())
|
||||
drawable.draw(canvas)
|
||||
canvas.translate(-x, -iconTop.toFloat())
|
||||
}
|
||||
|
||||
private fun updateBounds() {
|
||||
mBounds = drawable.bounds
|
||||
mWidth = mBounds!!.width()
|
||||
mHeight = mBounds!!.height()
|
||||
}
|
||||
|
||||
private fun getOffsetAboveBaseline(fm: FontMetricsInt): Int {
|
||||
return when (mAlignment) {
|
||||
ALIGN_BOTTOM -> fm.descent - mHeight
|
||||
ALIGN_CENTER -> {
|
||||
val textHeight = fm.descent - fm.ascent
|
||||
val offset = (textHeight - mHeight) / 2
|
||||
fm.ascent + offset
|
||||
}
|
||||
ALIGN_BASELINE -> -mHeight
|
||||
else -> -mHeight
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ALIGN_BOTTOM = 0
|
||||
const val ALIGN_BASELINE = 1
|
||||
const val ALIGN_CENTER = 2
|
||||
}
|
||||
}
|
5
app/src/main/res/drawable/shape_oval.xml
Normal file
5
app/src/main/res/drawable/shape_oval.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#000000" />
|
||||
</shape>
|
@ -21,7 +21,6 @@
|
||||
-->
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
@ -44,7 +43,7 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/user_icon"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
@ -54,10 +53,7 @@
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:src="@drawable/account_circle_48dp"
|
||||
fresco:placeholderImage="@drawable/account_circle_48dp"
|
||||
fresco:failureImage="@drawable/account_circle_48dp"
|
||||
app:roundAsCircle="true"/>
|
||||
android:src="@drawable/account_circle_48dp" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
@ -113,7 +113,8 @@
|
||||
android:transitionName="userAvatar.transitionTag"
|
||||
app:cornerRadius="@dimen/button_corner_radius"
|
||||
app:iconSize="@dimen/avatar_size_app_bar"
|
||||
tools:visibility="gone" />
|
||||
app:iconTint="@null"
|
||||
tools:icon="@drawable/ic_user" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
~ Nextcloud Talk application
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
~ @author Marcel Hibbe
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2021 Marcel Hibbe <dev@mhibbe.de>
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
@ -69,14 +71,14 @@
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/switchSelfVideoButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:placeholderImage="@drawable/ic_switch_video_white_24px"
|
||||
app:roundAsCircle="true" />
|
||||
app:srcCompat="@drawable/ic_switch_video_white_24px"
|
||||
android:contentDescription="@string/nc_call_button_content_description_switch_to_self_vide"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/selfVideoViewProgressBar"
|
||||
@ -144,6 +146,7 @@
|
||||
android:id="@+id/callControls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/call_controls_height"
|
||||
android:paddingHorizontal="@dimen/call_controls_padding_horizontal"
|
||||
android:layout_alignBottom="@id/linearWrapperLayout"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@android:color/transparent"
|
||||
@ -151,94 +154,98 @@
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="5">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/pictureInPictureButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:elevation="10dp"
|
||||
app:backgroundImage="@color/call_buttons_background"
|
||||
app:placeholderImage="@drawable/ic_baseline_picture_in_picture_alt_24"
|
||||
app:roundAsCircle="true"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginHorizontal="@dimen/call_controls_margin_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/call_buttons_background"
|
||||
app:srcCompat="@drawable/ic_baseline_picture_in_picture_alt_24"
|
||||
android:contentDescription="@string/nc_call_button_content_description_pip" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/audioOutputButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
app:backgroundImage="@color/call_buttons_background"
|
||||
app:placeholderImage="@drawable/ic_volume_mute_white_24dp"
|
||||
app:roundAsCircle="true"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginHorizontal="@dimen/call_controls_margin_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/call_buttons_background"
|
||||
app:srcCompat="@drawable/ic_volume_mute_white_24dp"
|
||||
android:contentDescription="@string/nc_call_button_content_description_audio_output" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/cameraButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginHorizontal="@dimen/call_controls_margin_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:alpha="0.7"
|
||||
app:backgroundImage="@color/call_buttons_background"
|
||||
app:placeholderImage="@drawable/ic_videocam_white_24px"
|
||||
app:roundAsCircle="true"
|
||||
android:layout_weight="1"/>
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/call_buttons_background"
|
||||
app:srcCompat="@drawable/ic_videocam_white_24px"
|
||||
android:contentDescription="@string/nc_call_button_content_description_camera" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/microphoneButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginHorizontal="@dimen/call_controls_margin_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:alpha="0.7"
|
||||
app:backgroundImage="@color/call_buttons_background"
|
||||
app:placeholderImage="@drawable/ic_mic_off_white_24px"
|
||||
app:roundAsCircle="true"
|
||||
android:layout_weight="1"/>
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/call_buttons_background"
|
||||
app:srcCompat="@drawable/ic_mic_off_white_24px"
|
||||
android:contentDescription="@string/nc_call_button_content_description_microphone" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/hangupButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
app:backgroundImage="@color/nc_darkRed"
|
||||
app:placeholderImage="@drawable/ic_call_end_white_24px"
|
||||
app:roundAsCircle="true"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_marginHorizontal="@dimen/call_controls_margin_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/nc_darkRed"
|
||||
app:srcCompat="@drawable/ic_call_end_white_24px"
|
||||
android:contentDescription="@string/nc_call_button_content_description_hangup" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/pipGroupCallOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/black"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pipCallConversationNameTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-30dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="-30dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:textAlignment="center"
|
||||
android:maxLines="3"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="3"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
tools:text="our group call" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
app:backgroundImage="@drawable/ic_circular_group"
|
||||
app:roundAsCircle="true" />
|
||||
app:srcCompat="@drawable/ic_circular_group"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -31,12 +31,12 @@
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatarImageView"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_centerInParent="true"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar"/>
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/surface_view"
|
||||
|
@ -3,6 +3,8 @@
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Andy Scherzinger
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
@ -36,36 +38,37 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/callAnswerVoiceOnlyView"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="24dp"
|
||||
android:visibility="gone"
|
||||
app:backgroundImage="@color/nc_darkGreen"
|
||||
app:placeholderImage="@drawable/ic_call_white_24dp"
|
||||
app:roundAsCircle="true"
|
||||
tools:visibility="visible" />
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/nc_darkGreen"
|
||||
android:src="@drawable/ic_call_white_24dp"
|
||||
android:contentDescription="@string/nc_call_button_content_description_answer_voice_only" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/hangupButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="24dp"
|
||||
app:backgroundImage="@color/nc_darkRed"
|
||||
app:placeholderImage="@drawable/ic_call_end_white_24px"
|
||||
app:roundAsCircle="true" />
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/nc_darkRed"
|
||||
android:src="@drawable/ic_call_end_white_24px"
|
||||
android:contentDescription="@string/nc_call_button_content_description_hangup" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageButton
|
||||
android:id="@+id/callAnswerCameraView"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="24dp"
|
||||
android:background="@drawable/shape_oval"
|
||||
android:backgroundTint="@color/nc_darkGreen"
|
||||
android:src="@drawable/ic_videocam_white_24px"
|
||||
android:visibility="gone"
|
||||
app:backgroundImage="@color/nc_darkGreen"
|
||||
app:placeholderImage="@drawable/ic_videocam_white_24px"
|
||||
app:roundAsCircle="true"
|
||||
tools:visibility="visible" />
|
||||
tools:visibility="visible"
|
||||
android:contentDescription="@string/nc_call_button_content_description_answer_video_call" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
@ -111,11 +114,11 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatarImageView"
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
android:layout_centerInParent="true"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -77,13 +77,13 @@
|
||||
android:layout_marginTop="@dimen/margin_between_elements"
|
||||
tools:text="Jane Doe" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatar_image"
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
android:layout_centerHorizontal="true"
|
||||
apc:roundAsCircle="true"
|
||||
tools:background="@color/hwSecurityRed" />
|
||||
tools:background="@color/hwSecurityRed"
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
</RelativeLayout>
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
@ -19,7 +19,6 @@
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -31,7 +30,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatar_image"
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
@ -39,9 +38,7 @@
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:src="@drawable/account_circle_96dp"
|
||||
android:transitionName="userAvatar.transitionTag"
|
||||
app:roundAsCircle="true"
|
||||
fresco:failureImage="@drawable/account_circle_96dp"
|
||||
fresco:placeholderImage="@drawable/account_circle_96dp" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/userinfo_fullName"
|
||||
|
@ -25,7 +25,6 @@
|
||||
<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:apc="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:background="@color/white"
|
||||
android:id="@+id/settings_screen"
|
||||
@ -119,16 +118,14 @@
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatar_image"
|
||||
android:layout_width="@dimen/avatar_size_big"
|
||||
android:layout_height="@dimen/avatar_size_big"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:src="@drawable/account_circle_96dp"
|
||||
android:transitionName="userAvatar.transitionTag"
|
||||
apc:roundAsCircle="true"
|
||||
fresco:failureImage="@drawable/account_circle_96dp"
|
||||
fresco:placeholderImage="@drawable/account_circle_96dp" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.yarolegovich.mp.MaterialStandardPreference
|
||||
android:id="@+id/settings_remove_account"
|
||||
|
@ -21,7 +21,6 @@
|
||||
-->
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
@ -45,7 +44,7 @@
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/user_icon"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
@ -55,10 +54,7 @@
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:src="@drawable/account_circle_48dp"
|
||||
fresco:placeholderImage="@drawable/account_circle_48dp"
|
||||
fresco:failureImage="@drawable/account_circle_48dp"
|
||||
app:roundAsCircle="true"/>
|
||||
android:src="@drawable/account_circle_48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ticker"
|
||||
|
@ -32,13 +32,13 @@
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@id/bubble"
|
||||
|
@ -31,13 +31,13 @@
|
||||
android:layout_marginEnd="@dimen/standard_margin"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@id/bubble"
|
||||
|
@ -28,13 +28,13 @@
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@id/bubble"
|
||||
|
@ -32,13 +32,13 @@
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:layout_width="wrap_content"
|
||||
@ -64,14 +64,13 @@
|
||||
app:layout_wrapBefore="true"
|
||||
tools:visibility="gone">
|
||||
|
||||
<!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/image"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitStart"
|
||||
app:roundedCornerRadius="6dp"
|
||||
tools:src="@drawable/ic_call_black_24dp" />
|
||||
tools:src="@drawable/ic_call_black_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
@ -105,14 +104,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true">
|
||||
|
||||
<!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/contact_photo"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:scaleType="fitStart"
|
||||
app:roundAsCircle="true"
|
||||
tools:src="@drawable/ic_call_black_24dp" />
|
||||
tools:src="@drawable/ic_call_black_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/contact_progress_bar"
|
||||
|
@ -30,13 +30,13 @@
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@id/bubble"
|
||||
|
@ -32,13 +32,13 @@
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="2dp">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/messageUserAvatar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
android:id="@id/bubble"
|
||||
|
@ -55,14 +55,13 @@
|
||||
app:layout_flexGrow="1"
|
||||
app:layout_wrapBefore="true">
|
||||
|
||||
<!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/image"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:scaleType="fitEnd"
|
||||
app:roundedCornerRadius="6dp"
|
||||
tools:src="@drawable/ic_call_black_24dp" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitStart"
|
||||
tools:src="@drawable/ic_call_black_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
@ -95,14 +94,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:adjustViewBounds="true">
|
||||
|
||||
<!-- SimpleDraweeView does not support wrap_content for layout_width or layout_height attributes! -->
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/contact_photo"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:scaleType="fitStart"
|
||||
app:roundAsCircle="true"
|
||||
tools:src="@drawable/ic_call_black_24dp" />
|
||||
tools:src="@drawable/ic_call_black_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/contact_progress_bar"
|
||||
|
@ -19,20 +19,19 @@
|
||||
-->
|
||||
|
||||
<LinearLayout 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"
|
||||
android:paddingBottom="4dp"
|
||||
tools:background="@color/white">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/poll_voter_avatar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_gravity="center"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/poll_voter_name"
|
||||
|
@ -19,19 +19,18 @@
|
||||
-->
|
||||
|
||||
<LinearLayout 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="@dimen/item_height"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="@dimen/avatar_size"
|
||||
android:layout_height="@dimen/avatar_size"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_margin="@dimen/standard_margin"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
|
@ -19,7 +19,6 @@
|
||||
-->
|
||||
|
||||
<RelativeLayout 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:id="@+id/referenceWrapper"
|
||||
android:layout_width="match_parent"
|
||||
@ -32,64 +31,64 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@color/low_emphasis_text"
|
||||
tools:layout_height="100dp"/>
|
||||
tools:layout_height="100dp" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/referenceName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:maxLines="2"
|
||||
android:textAlignment="viewStart"
|
||||
android:textIsSelectable="false"
|
||||
android:layout_marginStart="10dp"
|
||||
android:visibility="gone"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:text="Name of Website"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/referenceDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/referenceName"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:maxLines="2"
|
||||
android:textAlignment="viewStart"
|
||||
android:textIsSelectable="false"
|
||||
android:layout_marginStart="10dp"
|
||||
android:visibility="gone"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
tools:text="Description of Website"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/referenceLink"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/referenceDescription"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textAlignment="viewStart"
|
||||
android:textIsSelectable="false"
|
||||
android:layout_marginStart="10dp"
|
||||
android:textColor="@color/medium_emphasis_text"
|
||||
android:singleLine="true"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:lines="1"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/medium_emphasis_text"
|
||||
android:textIsSelectable="false"
|
||||
android:visibility="gone"
|
||||
tools:text="http://nextcloud.com"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/referenceThumbImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:layout_below="@id/referenceLink"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:visibility="gone"
|
||||
app:roundedCornerRadius="6dp"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible"
|
||||
tools:ignore="ContentDescription" />
|
||||
</RelativeLayout>
|
@ -93,13 +93,12 @@
|
||||
android:textSize="@dimen/two_line_primary_text_size"
|
||||
tools:text="filename.md" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/file_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/standard_margin"
|
||||
app:actualImageScaleType="fitCenter"
|
||||
app:placeholderImageScaleType="fitCenter" />
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -48,19 +48,19 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@id/checkedImageView"
|
||||
android:layout_toEndOf="@id/avatar_drawee_view"
|
||||
android:layout_toEndOf="@id/avatar_view"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/ListItem"
|
||||
tools:text="Jane Doe" />
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/avatar_drawee_view"
|
||||
<ImageView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="@dimen/avatar_size"
|
||||
android:layout_height="@dimen/avatar_size"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/standard_margin"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@string/avatar" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -29,7 +29,7 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.elyeproj.loaderviewlibrary.LoaderTextView
|
||||
android:id="@+id/simple_drawee_view"
|
||||
android:id="@+id/loader_text_view"
|
||||
android:layout_width="@dimen/avatar_size"
|
||||
android:layout_height="@dimen/avatar_size"
|
||||
android:layout_centerVertical="true"
|
||||
@ -42,7 +42,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/simple_drawee_view"
|
||||
android:layout_toEndOf="@id/loader_text_view"
|
||||
app:custom_color="@color/nc_shimmer_default_color" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -26,15 +26,14 @@
|
||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/avatar_drawee_view"
|
||||
<ImageView
|
||||
android:id="@+id/avatar_view"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:layout_marginStart="@dimen/standard_margin"
|
||||
android:contentDescription="@null"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:roundAsCircle="true" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.vanniktech.emoji.EmojiEditText
|
||||
android:id="@+id/participant_status_emoji"
|
||||
@ -54,8 +53,8 @@
|
||||
android:layout_height="18dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:contentDescription="@string/nc_account_chooser_active_user"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/avatar_drawee_view"
|
||||
app:layout_constraintEnd_toEndOf="@+id/avatar_drawee_view"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/avatar_view"
|
||||
app:layout_constraintEnd_toEndOf="@+id/avatar_view"
|
||||
tools:src="@drawable/emoji_one_category_smileysandpeople"/>
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
@ -68,8 +67,8 @@
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="@color/conversation_item_header"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar_drawee_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/avatar_drawee_view"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar_view"
|
||||
app:layout_constraintTop_toTopOf="@+id/avatar_view"
|
||||
tools:text="Jane Doe" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
|
@ -3,6 +3,8 @@
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Andy Scherzinger
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
@ -38,12 +40,11 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="@dimen/double_margin_between_elements">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@id/dialogAvatar"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:contentDescription="@null"
|
||||
app:roundAsCircle="true" />
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/favoriteConversationImageView"
|
||||
|
@ -41,8 +41,7 @@
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:roundAsCircle="true" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
|
@ -3,6 +3,8 @@
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Andy Scherzinger
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
@ -35,14 +37,13 @@
|
||||
android:layout_margin="@dimen/double_margin_between_elements"
|
||||
tools:background="@color/white">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/small_item_height"
|
||||
android:layout_height="@dimen/small_item_height"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:roundAsCircle="true" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/conversation_title"
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@ -40,14 +40,12 @@
|
||||
app:layout_flexGrow="1"
|
||||
app:layout_wrapBefore="true">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="4dp"
|
||||
app:placeholderImageScaleType="fitCenter"
|
||||
fresco:actualImageScaleType="centerCrop"
|
||||
fresco:roundedCornerRadius="4dp" />
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
|
@ -39,17 +39,14 @@
|
||||
app:layout_flexGrow="1"
|
||||
app:layout_wrapBefore="true">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
xmlns:fresco="http://schemas.android.com/apk/res-auto"
|
||||
<ImageView
|
||||
android:id="@+id/file_image"
|
||||
android:layout_width="@dimen/mediatab_file_icon_size"
|
||||
android:layout_height="@dimen/mediatab_file_icon_size"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:placeholderImageScaleType="fitCenter"
|
||||
fresco:actualImageScaleType="centerCrop"
|
||||
fresco:roundedCornerRadius="4dp"
|
||||
tools:src="@drawable/ic_call_black_24dp"/>
|
||||
tools:src="@drawable/ic_call_black_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
|
@ -2,6 +2,8 @@
|
||||
~ Nextcloud Talk application
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
@ -67,6 +69,8 @@
|
||||
<dimen name="call_self_video_short_side_length">80dp</dimen>
|
||||
<dimen name="call_grid_item_min_height">180dp</dimen>
|
||||
<dimen name="call_controls_height">110dp</dimen>
|
||||
<dimen name="call_controls_padding_horizontal">10dp</dimen>
|
||||
<dimen name="call_controls_margin_horizontal">10dp</dimen>
|
||||
<dimen name="call_participant_progress_bar_size">48dp</dimen>
|
||||
<dimen name="call_self_participant_progress_bar_size">48dp</dimen>
|
||||
<dimen name="zero">0dp</dimen>
|
||||
|
@ -4,6 +4,8 @@
|
||||
~ @author Mario Danic
|
||||
~ @author Andy Scherzinger
|
||||
~ @author Marcel Hibbe
|
||||
~ @author Tim Krüger
|
||||
~ Copyright (C) 2022 Tim Krüger <t@timkrueger.me>
|
||||
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
~ Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
@ -211,6 +213,14 @@
|
||||
<string name="nc_call_state_with_phone">%1$s with phone</string>
|
||||
<string name="nc_call_state_with_video">%1$s with video</string>
|
||||
<string name="nc_missed_call">You missed a call from %s</string>
|
||||
<string name="nc_call_button_content_description_pip">Open picture in picture mode</string>
|
||||
<string name="nc_call_button_content_description_audio_output">Change audio output</string>
|
||||
<string name="nc_call_button_content_description_camera">Toggle camera</string>
|
||||
<string name="nc_call_button_content_description_microphone">Toggle microphone</string>
|
||||
<string name="nc_call_button_content_description_hangup">Hangup</string>
|
||||
<string name="nc_call_button_content_description_answer_voice_only">Answer as voice call only</string>
|
||||
<string name="nc_call_button_content_description_answer_video_call">Answer as video call</string>
|
||||
<string name="nc_call_button_content_description_switch_to_self_vide">Switch to self video</string>
|
||||
|
||||
<!-- Picture in Picture -->
|
||||
<string name="nc_pip_microphone_mute">Mute microphone</string>
|
||||
|
Loading…
Reference in New Issue
Block a user