diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt index b422d49b9..3b8fb4a6e 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt @@ -35,8 +35,11 @@ import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.core.Account import org.linphone.core.Call +import org.linphone.core.ChatMessage +import org.linphone.core.ChatRoom import org.linphone.core.Core import org.linphone.core.CoreListenerStub +import org.linphone.core.GlobalState import org.linphone.core.RegistrationState import org.linphone.core.VFS import org.linphone.core.tools.Log @@ -59,6 +62,8 @@ class MainViewModel @UiThread constructor() : ViewModel() { val showAlert = MutableLiveData() + val maxAlertLevel = MutableLiveData() + val alertLabel = MutableLiveData() val alertIcon = MutableLiveData() @@ -104,11 +109,21 @@ class MainViewModel @UiThread constructor() : ViewModel() { private var firstAccountRegistered: Boolean = false private val coreListener = object : CoreListenerStub() { + @WorkerThread + override fun onGlobalStateChanged(core: Core, state: GlobalState?, message: String) { + Log.i("$TAG Core's global state is now [${core.globalState}]") + if (core.globalState == GlobalState.On) { + computeNonDefaultAccountNotificationsCount() + } + } + @WorkerThread override fun onLastCallEnded(core: Core) { Log.i("$TAG Last call ended, removing in-call 'alert'") removeAlert(SINGLE_CALL) atLeastOneCall.postValue(false) + + computeNonDefaultAccountNotificationsCount() } @WorkerThread @@ -125,6 +140,7 @@ class MainViewModel @UiThread constructor() : ViewModel() { state: Call.State?, message: String ) { + Log.i("$TAG A call's state changed, updating alerts if needed") if ( core.callsNb > 1 && ( LinphoneUtils.isCallEnding(call.state) || @@ -141,6 +157,16 @@ class MainViewModel @UiThread constructor() : ViewModel() { } } + @WorkerThread + override fun onMessagesReceived( + core: Core, + chatRoom: ChatRoom, + messages: Array + ) { + Log.i("$TAG Message(s) received, updating notifications count if needed") + computeNonDefaultAccountNotificationsCount() + } + @WorkerThread override fun onNetworkReachable(core: Core, reachable: Boolean) { Log.i("$TAG Network is ${if (reachable) "reachable" else "not reachable"}") @@ -213,9 +239,7 @@ class MainViewModel @UiThread constructor() : ViewModel() { core.refreshRegisters() } - removeAlert(NON_DEFAULT_ACCOUNT_NOTIFICATIONS) - - // TODO FIXME: compute other accounts notifications count + computeNonDefaultAccountNotificationsCount() } @WorkerThread @@ -234,6 +258,7 @@ class MainViewModel @UiThread constructor() : ViewModel() { init { defaultAccountRegistrationFailed = false showAlert.value = false + maxAlertLevel.value = NONE coreContext.postOnCoreThread { core -> accountsFound = core.accountList.size @@ -311,6 +336,28 @@ class MainViewModel @UiThread constructor() : ViewModel() { } } + @WorkerThread + private fun computeNonDefaultAccountNotificationsCount() { + var count = 0 + for (account in coreContext.core.accountList) { + if (account == coreContext.core.defaultAccount) continue + count += account.unreadChatMessageCount + account.missedCallsCount + } + + if (count > 0) { + val label = AppUtils.getStringWithPlural( + R.plurals.pending_notification_for_other_accounts, + count, + count.toString() + ) + addAlert(NON_DEFAULT_ACCOUNT_NOTIFICATIONS, label, forceUpdate = true) + Log.i("$TAG Found [$count] pending notifications for other account(s)") + } else { + Log.i("$TAG No pending notification found for other account(s), clearing alert") + removeAlert(NON_DEFAULT_ACCOUNT_NOTIFICATIONS) + } + } + @WorkerThread private fun updateCallAlert() { val core = coreContext.core @@ -347,13 +394,18 @@ class MainViewModel @UiThread constructor() : ViewModel() { } @WorkerThread - private fun addAlert(type: Int, label: String) { + private fun addAlert(type: Int, label: String, forceUpdate: Boolean = false) { val found = alertsList.find { it.first == type } - if (found == null) { + if (found == null || forceUpdate) { cancelAlertJob() + if (found != null) { + alertsList.remove(found) + } + val alert = Pair(type, label) + Log.i("$TAG Adding alert with type [$type]") alertsList.add(alert) updateDisplayedAlert() } else { @@ -368,6 +420,7 @@ class MainViewModel @UiThread constructor() : ViewModel() { } if (found != null) { cancelAlertJob() + Log.i("$TAG Removing alert with type [$type]") alertsList.remove(found) updateDisplayedAlert() } else { @@ -397,10 +450,12 @@ class MainViewModel @UiThread constructor() : ViewModel() { Log.i("$TAG No alert to display") showAlert.postValue(false) changeSystemTopBarColorEvent.postValue(Event(NONE)) + maxAlertLevel.postValue(NONE) } else { val type = maxedPriorityAlert.first val label = maxedPriorityAlert.second Log.i("$TAG Max priority alert right now is [$type]") + maxAlertLevel.postValue(type) when (type) { NON_DEFAULT_ACCOUNT_NOTIFICATIONS, NON_DEFAULT_ACCOUNT_NOT_CONNECTED -> { alertIcon.postValue(R.drawable.bell_simple) @@ -414,14 +469,20 @@ class MainViewModel @UiThread constructor() : ViewModel() { } alertLabel.postValue(label) - coreContext.postOnMainThread { - val delayMs = if (type == SINGLE_CALL) 1000L else 0L - alertJob = viewModelScope.launch { - withContext(Dispatchers.IO) { - delay(delayMs) - withContext(Dispatchers.Main) { - showAlert.value = true - changeSystemTopBarColorEvent.value = Event(type) + if (showAlert.value == true) { + Log.i("$TAG Alert top-bar is already visible, updating color if needed") + changeSystemTopBarColorEvent.postValue(Event(type)) + } else { + Log.i("$TAG Alert top-bar is currently invisible, starting job to display it") + coreContext.postOnMainThread { + val delayMs = if (type == SINGLE_CALL) 1000L else 0L + alertJob = viewModelScope.launch { + withContext(Dispatchers.IO) { + delay(delayMs) + withContext(Dispatchers.Main) { + showAlert.value = true + changeSystemTopBarColorEvent.value = Event(type) + } } } } diff --git a/app/src/main/res/layout/assistant_landing_fragment.xml b/app/src/main/res/layout/assistant_landing_fragment.xml index d43fd73dc..9fdedc43d 100644 --- a/app/src/main/res/layout/assistant_landing_fragment.xml +++ b/app/src/main/res/layout/assistant_landing_fragment.xml @@ -36,8 +36,8 @@ android:layout_height="wrap_content"> @@ -113,7 +113,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginTop="16dp" - android:text="@{@string/password + `*`, default=@string/password}" + android:text="@{@string/password + `*`, default=`Password*`}" app:layout_constraintWidth_max="@dimen/text_input_max_width" app:layout_constraintTop_toBottomOf="@id/sip_identity" app:layout_constraintStart_toStartOf="@id/password"/> @@ -139,8 +139,8 @@ app:layout_constraintEnd_toEndOf="parent"/> @@ -102,7 +102,7 @@ android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:layout_marginTop="16dp" - android:text="@{@string/password + `*`}" + android:text="@string/password" app:layout_constraintTop_toBottomOf="@id/username" app:layout_constraintStart_toStartOf="@id/password"/> @@ -148,7 +148,7 @@ android:layout_marginTop="18dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" - android:text="@{@string/sip_address_domain + `*`}" + android:text="@{@string/sip_address_domain + `*`, default=`Domain*`}" app:layout_constraintTop_toBottomOf="@id/password" app:layout_constraintStart_toStartOf="@id/domain"/> @@ -212,7 +212,7 @@ android:layout_marginTop="18dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" - android:text="@{@string/assistant_sip_account_transport_protocol + `*`}" + android:text="@string/assistant_sip_account_transport_protocol" app:layout_constraintTop_toBottomOf="@id/display_name" app:layout_constraintStart_toStartOf="@id/transport"/> diff --git a/app/src/main/res/layout/main_activity_notification_top_bar.xml b/app/src/main/res/layout/main_activity_notification_top_bar.xml index bdb3776c8..eb5e44a4f 100644 --- a/app/src/main/res/layout/main_activity_notification_top_bar.xml +++ b/app/src/main/res/layout/main_activity_notification_top_bar.xml @@ -13,7 +13,7 @@ Les participants selectionnés apparaîtront ici Compte(s) non connecté(s) + + %s notification en attente + %s notifications en attente + Vous n\'êtes pas connecté à internet Opération en cours, merci de patienter… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index facbea1cc..2a26d1a64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -663,6 +663,10 @@ Selected participants will appear here Account(s) connection error + + %s notification for other account(s) + %s notifications for other account(s) + You aren\'t connected to internet Operation in progress, please wait