Add the join / return button to call log items.

This commit is contained in:
Alex Hart 2023-04-04 13:13:49 -03:00
parent 9d575650d1
commit c254b08e33
7 changed files with 138 additions and 18 deletions

View file

@ -153,13 +153,12 @@ class CallLogAdapter(
val event = model.call.call.event
val direction = model.call.call.direction
val type = model.call.call.type
binding.callRecipientAvatar.setAvatar(GlideApp.with(binding.callRecipientAvatar), model.call.peer, true)
binding.callRecipientBadge.setBadgeFromRecipient(model.call.peer)
binding.callRecipientName.text = model.call.peer.getDisplayName(context)
presentCallInfo(event, direction, model.call.date)
presentCallType(type, model.call.peer)
presentCallType(model)
}
private fun presentCallInfo(event: CallTable.Event, direction: CallTable.Direction, date: Long) {
@ -190,24 +189,47 @@ class CallLogAdapter(
binding.callInfo.setTextColor(color)
}
private fun presentCallType(callType: CallTable.Type, peer: Recipient) {
when (callType) {
private fun presentCallType(model: CallModel) {
when (model.call.call.type) {
CallTable.Type.AUDIO_CALL -> {
binding.callType.setImageResource(R.drawable.symbol_phone_24)
binding.callType.setOnClickListener { onStartAudioCallClicked(peer) }
binding.callType.setOnClickListener { onStartAudioCallClicked(model.call.peer) }
binding.callType.visible = true
binding.groupCallButton.visible = false
}
CallTable.Type.VIDEO_CALL -> {
binding.callType.setImageResource(R.drawable.symbol_video_24)
binding.callType.setOnClickListener { onStartVideoCallClicked(peer) }
binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer) }
binding.callType.visible = true
binding.groupCallButton.visible = false
}
CallTable.Type.GROUP_CALL, CallTable.Type.AD_HOC_CALL -> {
// TODO [alex] -- Group call button
binding.callType.setImageResource(R.drawable.symbol_video_24)
binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer) }
binding.groupCallButton.setOnClickListener { onStartVideoCallClicked(model.call.peer) }
when (model.call.groupCallState) {
CallLogRow.GroupCallState.NONE, CallLogRow.GroupCallState.FULL -> {
binding.callType.visible = true
binding.groupCallButton.visible = false
}
CallLogRow.GroupCallState.ACTIVE, CallLogRow.GroupCallState.LOCAL_USER_JOINED -> {
binding.callType.visible = false
binding.groupCallButton.visible = true
binding.groupCallButton.setText(
if (model.call.groupCallState == CallLogRow.GroupCallState.LOCAL_USER_JOINED) {
R.string.CallLogAdapter__return
} else {
R.string.CallLogAdapter__join
}
)
}
}
}
}
binding.callType.visible = true
}
@DrawableRes

View file

@ -26,16 +26,11 @@ class CallLogRepository : CallLogPagedDataSource.CallRepository {
refresh()
}
val messageObserver = DatabaseObserver.MessageObserver {
refresh()
}
ApplicationDependencies.getDatabaseObserver().registerConversationListObserver(databaseObserver)
ApplicationDependencies.getDatabaseObserver().registerMessageUpdateObserver(messageObserver)
ApplicationDependencies.getDatabaseObserver().registerCallUpdateObserver(databaseObserver)
emitter.setCancellable {
ApplicationDependencies.getDatabaseObserver().unregisterObserver(databaseObserver)
ApplicationDependencies.getDatabaseObserver().unregisterObserver(messageObserver)
}
}
}

View file

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.calls.log
import org.thoughtcrime.securesms.database.CallTable
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails
import org.thoughtcrime.securesms.recipients.Recipient
/**
@ -17,6 +18,7 @@ sealed class CallLogRow {
val call: CallTable.Call,
val peer: Recipient,
val date: Long,
val groupCallState: GroupCallState,
override val id: Id = Id.Call(call.callId)
) : CallLogRow()
@ -36,4 +38,48 @@ sealed class CallLogRow {
object ClearFilter : Id()
object CreateCallLink : Id()
}
enum class GroupCallState {
/**
* No group call available.
*/
NONE,
/**
* Active, but the local user is not in the call.
*/
ACTIVE,
/**
* Active and the local user is in the call
*/
LOCAL_USER_JOINED,
/**
* Active but the call is full.
*/
FULL;
companion object {
fun fromDetails(groupCallUpdateDetails: GroupCallUpdateDetails?): GroupCallState {
if (groupCallUpdateDetails == null) {
return NONE
}
if (groupCallUpdateDetails.isCallFull) {
return FULL
}
if (groupCallUpdateDetails.inCallUuidsList.contains(Recipient.self().requireServiceId().uuid().toString())) {
return LOCAL_USER_JOINED
}
return if (groupCallUpdateDetails.inCallUuidsCount > 0) {
ACTIVE
} else {
NONE
}
}
}
}
}

View file

@ -15,6 +15,7 @@ import org.signal.core.util.readToSingleLong
import org.signal.core.util.readToSingleObject
import org.signal.core.util.requireLong
import org.signal.core.util.requireObject
import org.signal.core.util.requireString
import org.signal.core.util.select
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
@ -22,6 +23,7 @@ import org.signal.ringrtc.CallId
import org.signal.ringrtc.CallManager.RingUpdate
import org.thoughtcrime.securesms.calls.log.CallLogFilter
import org.thoughtcrime.securesms.calls.log.CallLogRow
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.CallSyncEventJob
@ -93,6 +95,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
}
ApplicationDependencies.getMessageNotifier().updateNotification(context)
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
Log.i(TAG, "Inserted call: $callId type: $type direction: $direction event:$event")
}
@ -117,6 +120,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
SignalDatabase.messages.updateCallLog(call.messageId!!, call.messageType)
ApplicationDependencies.getMessageNotifier().updateNotification(context)
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
call
@ -205,6 +209,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
CallSyncEventJob.enqueueDeleteSyncEvents(toSync)
ApplicationDependencies.getDeletedCallEventManager().scheduleIfNecessary()
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
// region Group / Ad-Hoc Calling
@ -228,6 +233,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
}
ApplicationDependencies.getMessageNotifier().updateNotification(context)
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
Log.d(TAG, "Marked group call event for deletion: ${call.callId}")
}
@ -275,6 +281,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
.run()
ApplicationDependencies.getMessageNotifier().updateNotification(context)
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
Log.d(TAG, "Transitioned group call ${call.callId} from ${call.event} to $newEvent")
}
@ -316,6 +323,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
)
.run()
}
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
fun insertOrUpdateGroupCallFromExternalEvent(
@ -434,6 +443,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
} else {
Log.d(TAG, "Skipping call event processing for null era id.")
}
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
/**
@ -445,7 +456,9 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
peekJoinedUuids: Collection<UUID>,
isCallFull: Boolean
): Boolean {
return SignalDatabase.messages.updatePreviousGroupCall(threadId, peekGroupCallEraId, peekJoinedUuids, isCallFull)
val sameEraId = SignalDatabase.messages.updatePreviousGroupCall(threadId, peekGroupCallEraId, peekJoinedUuids, isCallFull)
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
return sameEraId
}
fun insertOrUpdateGroupCallFromRingState(
@ -545,6 +558,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
createEventFromRingState(ringId, groupRecipientId, ringerRecipient, event, dateReceived)
}
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
private fun updateEventFromRingState(
@ -634,6 +649,8 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
SignalDatabase.messages.updateCallTimestamps(call.messageId, timestamp)
}
}
ApplicationDependencies.getDatabaseObserver().notifyCallUpdateObservers()
}
private fun setMessageId(callId: Long, messageId: MessageId) {
@ -723,7 +740,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
//language=sql
val statement = """
SELECT
${if (isCount) "COUNT(*)," else "$TABLE_NAME.*, ${MessageTable.DATE_RECEIVED},"}
${if (isCount) "COUNT(*)," else "$TABLE_NAME.*, ${MessageTable.DATE_RECEIVED}, ${MessageTable.BODY},"}
LOWER(
COALESCE(
NULLIF(${RecipientTable.TABLE_NAME}.${RecipientTable.SYSTEM_JOINED_NAME}, ''),
@ -756,10 +773,13 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl
val call = Call.deserialize(it)
val recipient = Recipient.resolved(call.peer)
val date = it.requireLong(MessageTable.DATE_RECEIVED)
val groupCallDetails = GroupCallUpdateDetailsUtil.parse(it.requireString(MessageTable.BODY))
CallLogRow.Call(
call = call,
peer = recipient,
date = date
date = date,
groupCallState = CallLogRow.GroupCallState.fromDetails(groupCallDetails)
)
}
}

View file

@ -45,6 +45,8 @@ public class DatabaseObserver {
private static final String KEY_SCHEDULED_MESSAGES = "ScheduledMessages";
private static final String KEY_CONVERSATION_DELETES = "ConversationDeletes";
private static final String KEY_CALL_UPDATES = "CallUpdates";
private final Application application;
private final Executor executor;
@ -64,6 +66,8 @@ public class DatabaseObserver {
private final Set<Observer> notificationProfileObservers;
private final Map<RecipientId, Set<Observer>> storyObservers;
private final Set<Observer> callUpdateObservers;
public DatabaseObserver(Application application) {
this.application = application;
this.executor = new SerialExecutor(SignalExecutors.BOUNDED);
@ -82,6 +86,7 @@ public class DatabaseObserver {
this.notificationProfileObservers = new HashSet<>();
this.storyObservers = new HashMap<>();
this.scheduledMessageObservers = new HashMap<>();
this.callUpdateObservers = new HashSet<>();
}
public void registerConversationListObserver(@NonNull Observer listener) {
@ -177,6 +182,10 @@ public class DatabaseObserver {
});
}
public void registerCallUpdateObserver(@NonNull Observer observer) {
executor.execute(() -> callUpdateObservers.add(observer));
}
public void unregisterObserver(@NonNull Observer listener) {
executor.execute(() -> {
conversationListObservers.remove(listener);
@ -191,6 +200,7 @@ public class DatabaseObserver {
unregisterMapped(storyObservers, listener);
unregisterMapped(scheduledMessageObservers, listener);
unregisterMapped(conversationDeleteObservers, listener);
callUpdateObservers.remove(listener);
});
}
@ -328,6 +338,10 @@ public class DatabaseObserver {
});
}
public void notifyCallUpdateObservers() {
runPostSuccessfulTransaction(KEY_CALL_UPDATES, () -> notifySet(callUpdateObservers));
}
private void runPostSuccessfulTransaction(@NonNull String dedupeKey, @NonNull Runnable runnable) {
SignalDatabase.runPostSuccessfulTransaction(dedupeKey, () -> {
executor.execute(runnable);

View file

@ -126,4 +126,23 @@
app:tint="@color/signal_colorOnSurface"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/group_call_button"
style="@style/Signal.Widget.Button.Small.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/signal_colorPrimary"
android:textColor="@color/signal_colorOnPrimary"
android:visibility="gone"
app:icon="@drawable/symbol_video_fill_24"
app:iconPadding="4dp"
app:iconSize="20dp"
app:iconTint="@color/signal_colorOnPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp"
tools:text="Return"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -5775,6 +5775,10 @@
<string name="CallLogAdapter__outgoing">Outgoing</string>
<!-- Displayed for missed calls -->
<string name="CallLogAdapter__missed">Missed</string>
<!-- Displayed on Group Call button if user is not in the call -->
<string name="CallLogAdapter__join">Join</string>
<!-- Displayed on Group Call button if user is in the call -->
<string name="CallLogAdapter__return">Return</string>
<!-- Call Log context menu -->
<!-- Displayed as a context menu item to start a video call -->