convert ParticipantsAdapter to kt

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2025-05-05 10:16:26 +02:00
parent b85016ad13
commit 7df19b7623
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
2 changed files with 129 additions and 142 deletions

View File

@ -303,7 +303,7 @@ class CallActivity : CallBaseActivity() {
private var handler: Handler? = null private var handler: Handler? = null
private var currentCallStatus: CallStatus? = null private var currentCallStatus: CallStatus? = null
private var mediaPlayer: MediaPlayer? = null private var mediaPlayer: MediaPlayer? = null
private var participantDisplayItems: MutableMap<String, ParticipantDisplayItem?>? = null private var participantDisplayItems: MutableMap<String, ParticipantDisplayItem>? = null
private var participantsAdapter: ParticipantsAdapter? = null private var participantsAdapter: ParticipantsAdapter? = null
private var binding: CallActivityBinding? = null private var binding: CallActivityBinding? = null
private var audioOutputDialog: AudioOutputDialog? = null private var audioOutputDialog: AudioOutputDialog? = null
@ -994,7 +994,7 @@ class CallActivity : CallBaseActivity() {
} }
participantsAdapter = ParticipantsAdapter( participantsAdapter = ParticipantsAdapter(
this, this,
participantDisplayItems, participantDisplayItems!!.toMap(),
binding!!.conversationRelativeLayout, binding!!.conversationRelativeLayout,
binding!!.callInfosLinearLayout, binding!!.callInfosLinearLayout,
columns, columns,

View File

@ -5,213 +5,200 @@
* SPDX-FileCopyrightText: 2022 Daniel Calviño Sánchez <danxuliu@gmail.com> * SPDX-FileCopyrightText: 2022 Daniel Calviño Sánchez <danxuliu@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later * SPDX-License-Identifier: GPL-3.0-or-later
*/ */
package com.nextcloud.talk.adapters; package com.nextcloud.talk.adapters
import android.content.Context; import android.content.Context
import android.util.Log; import android.util.Log
import android.view.LayoutInflater; import android.view.LayoutInflater
import android.view.View; import android.view.View
import android.view.ViewGroup; import android.view.ViewGroup
import android.widget.BaseAdapter; import android.widget.BaseAdapter
import android.widget.ImageView; import android.widget.ImageView
import android.widget.LinearLayout; import android.widget.LinearLayout
import android.widget.ProgressBar; import android.widget.ProgressBar
import android.widget.RelativeLayout; import android.widget.RelativeLayout
import android.widget.TextView; import android.widget.TextView
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.extensions.loadAvatarWithUrl
import com.nextcloud.talk.extensions.loadFirstLetterAvatar
import com.nextcloud.talk.models.json.participants.Participant
import org.webrtc.MediaStream
import org.webrtc.MediaStreamTrack
import org.webrtc.RendererCommon
import org.webrtc.SurfaceViewRenderer
import kotlin.math.ceil
import com.nextcloud.talk.R; class ParticipantsAdapter(
import com.nextcloud.talk.activities.CallActivity; private val mContext: Context,
import com.nextcloud.talk.extensions.ImageViewExtensionsKt; participantDisplayItems: Map<String?, ParticipantDisplayItem>,
import com.nextcloud.talk.models.json.participants.Participant; private val gridViewWrapper: RelativeLayout,
private val callInfosLinearLayout: LinearLayout,
private val columns: Int,
private val isVoiceOnlyCall: Boolean
) : BaseAdapter() {
private val participantDisplayItemObserver = ParticipantDisplayItem.Observer { this.notifyDataSetChanged() }
import org.webrtc.MediaStream; private val participantDisplayItems = ArrayList<ParticipantDisplayItem>()
import org.webrtc.MediaStreamTrack;
import org.webrtc.RendererCommon;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoTrack;
import java.util.ArrayList; init {
import java.util.Map; this.participantDisplayItems.addAll(participantDisplayItems.values)
public class ParticipantsAdapter extends BaseAdapter { for (participantDisplayItem in this.participantDisplayItems) {
participantDisplayItem.addObserver(participantDisplayItemObserver)
private static final String TAG = "ParticipantsAdapter";
private final ParticipantDisplayItem.Observer participantDisplayItemObserver = this::notifyDataSetChanged;
private final Context mContext;
private final ArrayList<ParticipantDisplayItem> participantDisplayItems;
private final RelativeLayout gridViewWrapper;
private final LinearLayout callInfosLinearLayout;
private final int columns;
private final boolean isVoiceOnlyCall;
public ParticipantsAdapter(Context mContext,
Map<String, ParticipantDisplayItem> participantDisplayItems,
RelativeLayout gridViewWrapper,
LinearLayout callInfosLinearLayout,
int columns,
boolean isVoiceOnlyCall) {
this.mContext = mContext;
this.gridViewWrapper = gridViewWrapper;
this.callInfosLinearLayout = callInfosLinearLayout;
this.columns = columns;
this.isVoiceOnlyCall = isVoiceOnlyCall;
this.participantDisplayItems = new ArrayList<>();
this.participantDisplayItems.addAll(participantDisplayItems.values());
for (ParticipantDisplayItem participantDisplayItem : this.participantDisplayItems) {
participantDisplayItem.addObserver(participantDisplayItemObserver);
} }
} }
public void destroy() { fun destroy() {
for (ParticipantDisplayItem participantDisplayItem : participantDisplayItems) { for (participantDisplayItem in participantDisplayItems) {
participantDisplayItem.removeObserver(participantDisplayItemObserver); participantDisplayItem.removeObserver(participantDisplayItemObserver)
} }
} }
@Override override fun getCount(): Int {
public int getCount() { return participantDisplayItems.size
return participantDisplayItems.size();
} }
@Override override fun getItem(position: Int): ParticipantDisplayItem {
public ParticipantDisplayItem getItem(int position) { return participantDisplayItems[position]
return participantDisplayItems.get(position);
} }
@Override override fun getItemId(position: Int): Long {
public long getItemId(int position) { return 0
return 0;
} }
@Override @Suppress("Detekt.LongMethod", "Detekt.TooGenericExceptionCaught")
public View getView(int position, View convertView, ViewGroup parent) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
ParticipantDisplayItem participantDisplayItem = getItem(position); var convertView = convertView
val participantDisplayItem = getItem(position)
SurfaceViewRenderer surfaceViewRenderer; val surfaceViewRenderer: SurfaceViewRenderer
if (convertView == null) { if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.call_item, parent, false); convertView = LayoutInflater.from(mContext).inflate(R.layout.call_item, parent, false)
convertView.setVisibility(View.VISIBLE); convertView.visibility = View.VISIBLE
surfaceViewRenderer = convertView.findViewById(R.id.surface_view); surfaceViewRenderer = convertView.findViewById(R.id.surface_view)
try { try {
Log.d(TAG, "hasSurface: " + participantDisplayItem.getRootEglBase().hasSurface()); Log.d(TAG, "hasSurface: " + participantDisplayItem.rootEglBase.hasSurface())
surfaceViewRenderer.setMirror(false); surfaceViewRenderer.setMirror(false)
surfaceViewRenderer.init(participantDisplayItem.getRootEglBase().getEglBaseContext(), null); surfaceViewRenderer.init(participantDisplayItem.rootEglBase.eglBaseContext, null)
surfaceViewRenderer.setZOrderMediaOverlay(false); surfaceViewRenderer.setZOrderMediaOverlay(false)
// disabled because it causes some devices to crash // disabled because it causes some devices to crash
surfaceViewRenderer.setEnableHardwareScaler(false); surfaceViewRenderer.setEnableHardwareScaler(false)
surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); surfaceViewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
} catch (Exception e) { } catch (e: Exception) {
Log.e(TAG, "error while initializing surfaceViewRenderer", e); Log.e(TAG, "error while initializing surfaceViewRenderer", e)
} }
} else { } else {
surfaceViewRenderer = convertView.findViewById(R.id.surface_view); surfaceViewRenderer = convertView.findViewById(R.id.surface_view)
} }
ProgressBar progressBar = convertView.findViewById(R.id.participant_progress_bar); val progressBar = convertView!!.findViewById<ProgressBar>(R.id.participant_progress_bar)
if (!participantDisplayItem.isConnected()) { if (!participantDisplayItem.isConnected) {
progressBar.setVisibility(View.VISIBLE); progressBar.visibility = View.VISIBLE
} else { } else {
progressBar.setVisibility(View.GONE); progressBar.visibility = View.GONE
} }
ViewGroup.LayoutParams layoutParams = convertView.getLayoutParams(); val layoutParams = convertView.layoutParams
layoutParams.height = scaleGridViewItemHeight(); layoutParams.height = scaleGridViewItemHeight()
convertView.setLayoutParams(layoutParams); convertView.layoutParams = layoutParams
TextView nickTextView = convertView.findViewById(R.id.peer_nick_text_view); val nickTextView = convertView.findViewById<TextView>(R.id.peer_nick_text_view)
ImageView imageView = convertView.findViewById(R.id.avatarImageView); val imageView = convertView.findViewById<ImageView>(R.id.avatarImageView)
MediaStream mediaStream = participantDisplayItem.getMediaStream(); val mediaStream = participantDisplayItem.mediaStream
if (hasVideoStream(participantDisplayItem, mediaStream)) { if (hasVideoStream(participantDisplayItem, mediaStream)) {
VideoTrack videoTrack = mediaStream.videoTracks.get(0); val videoTrack = mediaStream.videoTracks[0]
videoTrack.addSink(surfaceViewRenderer); videoTrack.addSink(surfaceViewRenderer)
imageView.setVisibility(View.INVISIBLE); imageView.visibility = View.INVISIBLE
surfaceViewRenderer.setVisibility(View.VISIBLE); surfaceViewRenderer.visibility = View.VISIBLE
nickTextView.setVisibility(View.GONE); nickTextView.visibility = View.GONE
} else { } else {
imageView.setVisibility(View.VISIBLE); imageView.visibility = View.VISIBLE
surfaceViewRenderer.setVisibility(View.INVISIBLE); surfaceViewRenderer.visibility = View.INVISIBLE
if (((CallActivity) mContext).isInPipMode) { if ((mContext as CallActivity).isInPipMode) {
nickTextView.setVisibility(View.GONE); nickTextView.visibility = View.GONE
} else { } else {
nickTextView.setVisibility(View.VISIBLE); nickTextView.visibility = View.VISIBLE
nickTextView.setText(participantDisplayItem.getNick()); nickTextView.text = participantDisplayItem.nick
} }
if (participantDisplayItem.getActorType() == Participant.ActorType.GUESTS || if (participantDisplayItem.actorType == Participant.ActorType.GUESTS ||
participantDisplayItem.getActorType() == Participant.ActorType.EMAILS) { participantDisplayItem.actorType == Participant.ActorType.EMAILS
ImageViewExtensionsKt.loadFirstLetterAvatar( ) {
imageView, imageView
String.valueOf(participantDisplayItem.getNick()) .loadFirstLetterAvatar(
); participantDisplayItem.nick.toString()
)
} else { } else {
ImageViewExtensionsKt.loadAvatarWithUrl(imageView,null, participantDisplayItem.getUrlForAvatar()); imageView.loadAvatarWithUrl(null, participantDisplayItem.urlForAvatar)
} }
} }
ImageView audioOffView = convertView.findViewById(R.id.remote_audio_off); val audioOffView = convertView.findViewById<ImageView>(R.id.remote_audio_off)
if (!participantDisplayItem.isAudioEnabled()) { if (!participantDisplayItem.isAudioEnabled) {
audioOffView.setVisibility(View.VISIBLE); audioOffView.visibility = View.VISIBLE
} else { } else {
audioOffView.setVisibility(View.GONE); audioOffView.visibility = View.GONE
} }
ImageView raisedHandView = convertView.findViewById(R.id.raised_hand); val raisedHandView = convertView.findViewById<ImageView>(R.id.raised_hand)
if (participantDisplayItem.getRaisedHand() != null && participantDisplayItem.getRaisedHand().getState()) { if (participantDisplayItem.raisedHand != null && participantDisplayItem.raisedHand.state) {
raisedHandView.setVisibility(View.VISIBLE); raisedHandView.visibility = View.VISIBLE
} else { } else {
raisedHandView.setVisibility(View.GONE); raisedHandView.visibility = View.GONE
} }
return convertView; return convertView
} }
private boolean hasVideoStream(ParticipantDisplayItem participantDisplayItem, MediaStream mediaStream) { @Suppress("ReturnCount")
if (!participantDisplayItem.isStreamEnabled()) { private fun hasVideoStream(participantDisplayItem: ParticipantDisplayItem, mediaStream: MediaStream?): Boolean {
return false; if (!participantDisplayItem.isStreamEnabled) {
return false
} }
if (mediaStream == null || mediaStream.videoTracks == null) { if (mediaStream?.videoTracks == null) {
return false; return false
} }
for (VideoTrack t : mediaStream.videoTracks) { for (t in mediaStream.videoTracks) {
if (MediaStreamTrack.State.LIVE == t.state()) { if (MediaStreamTrack.State.LIVE == t.state()) {
return true; return true
} }
} }
return false; return false
} }
private int scaleGridViewItemHeight() { private fun scaleGridViewItemHeight(): Int {
int headerHeight = 0; var headerHeight = 0
int callControlsHeight = 0; var callControlsHeight = 0
if (callInfosLinearLayout.getVisibility() == View.VISIBLE && isVoiceOnlyCall) { if (callInfosLinearLayout.visibility == View.VISIBLE && isVoiceOnlyCall) {
headerHeight = callInfosLinearLayout.getHeight(); headerHeight = callInfosLinearLayout.height
} }
if (isVoiceOnlyCall) { if (isVoiceOnlyCall) {
callControlsHeight = Math.round(mContext.getResources().getDimension(R.dimen.call_controls_height)); callControlsHeight = Math.round(mContext.resources.getDimension(R.dimen.call_controls_height))
} }
int itemHeight = (gridViewWrapper.getHeight() - headerHeight - callControlsHeight) / getRowsCount(getCount()); var itemHeight = (gridViewWrapper.height - headerHeight - callControlsHeight) / getRowsCount(count)
int itemMinHeight = Math.round(mContext.getResources().getDimension(R.dimen.call_grid_item_min_height)); val itemMinHeight = Math.round(mContext.resources.getDimension(R.dimen.call_grid_item_min_height))
if (itemHeight < itemMinHeight) { if (itemHeight < itemMinHeight) {
itemHeight = itemMinHeight; itemHeight = itemMinHeight
} }
return itemHeight; return itemHeight
} }
private int getRowsCount(int items) { private fun getRowsCount(items: Int): Int {
int rows = (int) Math.ceil((double) items / (double) columns); var rows = ceil(items.toDouble() / columns.toDouble()).toInt()
if (rows == 0) { if (rows == 0) {
rows = 1; rows = 1
} }
return rows; return rows
}
companion object {
private const val TAG = "ParticipantsAdapter"
} }
} }