talk-android/app/src/main/java/com/nextcloud/talk/call/CallParticipantModel.java
Daniel Calviño Sánchez 92d655080d
Add "reaction" event to CallParticipantModel observer
The CallParticipantModel observer now also emits one-time events that
are not reflected in the model state.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2023-05-04 15:15:36 +02:00

188 lines
6.0 KiB
Java

/*
* Nextcloud Talk application
*
* @author Daniel Calviño Sánchez
* Copyright (C) 2022 Daniel Calviño Sánchez <danxuliu@gmail.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.call;
import android.os.Handler;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import java.util.Objects;
/**
* Read-only data model for (remote) call participants.
*
* If the hand was never raised null is returned by "getRaisedHand()". Otherwise a RaisedHand object is returned with
* the current state (raised or not) and the timestamp when the raised hand state last changed.
*
* The received audio and video are available only if the participant is sending them and also has them enabled.
* Before a connection is established it is not known whether audio and video are available or not, so null is returned
* in that case (therefore it should not be autoboxed to a plain boolean without checking that).
*
* Audio and video in screen shares, on the other hand, are always seen as available.
*
* Clients of the model can observe it with CallParticipantModel.Observer to be notified when any value changes.
* Getters called after receiving a notification are guaranteed to provide at least the value that triggered the
* notification, but it may return even a more up to date one (so getting the value again on the following
* notification may return the same value as before).
*
* Besides onChange(), which notifies about changes in the model values, CallParticipantModel.Observer provides
* additional methods to be notified about one-time events that are not reflected in the model values, like reactions.
*/
public class CallParticipantModel {
public interface Observer {
void onChange();
void onReaction(String reaction);
}
protected class Data<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
if (Objects.equals(this.value, value)) {
return;
}
this.value = value;
callParticipantModelNotifier.notifyChange();
}
}
protected final CallParticipantModelNotifier callParticipantModelNotifier = new CallParticipantModelNotifier();
protected final String sessionId;
protected Data<String> userId;
protected Data<String> nick;
protected Data<Boolean> internal;
protected Data<RaisedHand> raisedHand;
protected Data<PeerConnection.IceConnectionState> iceConnectionState;
protected Data<MediaStream> mediaStream;
protected Data<Boolean> audioAvailable;
protected Data<Boolean> videoAvailable;
protected Data<PeerConnection.IceConnectionState> screenIceConnectionState;
protected Data<MediaStream> screenMediaStream;
public CallParticipantModel(String sessionId) {
this.sessionId = sessionId;
this.userId = new Data<>();
this.nick = new Data<>();
this.internal = new Data<>();
this.raisedHand = new Data<>();
this.iceConnectionState = new Data<>();
this.mediaStream = new Data<>();
this.audioAvailable = new Data<>();
this.videoAvailable = new Data<>();
this.screenIceConnectionState = new Data<>();
this.screenMediaStream = new Data<>();
}
public String getSessionId() {
return sessionId;
}
public String getUserId() {
return userId.getValue();
}
public String getNick() {
return nick.getValue();
}
public Boolean isInternal() {
return internal.getValue();
}
public RaisedHand getRaisedHand() {
return raisedHand.getValue();
}
public PeerConnection.IceConnectionState getIceConnectionState() {
return iceConnectionState.getValue();
}
public MediaStream getMediaStream() {
return mediaStream.getValue();
}
public Boolean isAudioAvailable() {
return audioAvailable.getValue();
}
public Boolean isVideoAvailable() {
return videoAvailable.getValue();
}
public PeerConnection.IceConnectionState getScreenIceConnectionState() {
return screenIceConnectionState.getValue();
}
public MediaStream getScreenMediaStream() {
return screenMediaStream.getValue();
}
/**
* Adds an Observer to be notified when any value changes.
*
* @param observer the Observer
* @see CallParticipantModel#addObserver(Observer, Handler)
*/
public void addObserver(Observer observer) {
addObserver(observer, null);
}
/**
* Adds an observer to be notified when any value changes.
*
* The observer will be notified on the thread associated to the given handler. If no handler is given the
* observer will be immediately notified on the same thread that changed the value; the observer will be
* immediately notified too if the thread of the handler is the same thread that changed the value.
*
* An observer is expected to be added only once. If the same observer is added again it will be notified just
* once on the thread of the last handler.
*
* @param observer the Observer
* @param handler a Handler for the thread to be notified on
*/
public void addObserver(Observer observer, Handler handler) {
callParticipantModelNotifier.addObserver(observer, handler);
}
public void removeObserver(Observer observer) {
callParticipantModelNotifier.removeObserver(observer);
}
}