diff --git a/app/build.gradle b/app/build.gradle
index 5892549a2..a6d041406 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -100,7 +100,7 @@ dependencies {
// https://github.com/tommybuonomo/dotsindicator/blob/master/LICENSE Apache v2.0
implementation("com.tbuonomo:dotsindicator:5.0")
- implementation platform('com.google.firebase:firebase-bom:30.3.2')
+ implementation platform('com.google.firebase:firebase-bom:32.2.3')
implementation 'com.google.firebase:firebase-messaging'
implementation 'org.linphone:linphone-sdk-android:5.3+'
diff --git a/app/src/main/java/org/linphone/ui/main/calls/fragment/StartCallFragment.kt b/app/src/main/java/org/linphone/ui/main/calls/fragment/StartCallFragment.kt
index 3b9f3bc8c..d99360c6e 100644
--- a/app/src/main/java/org/linphone/ui/main/calls/fragment/StartCallFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/calls/fragment/StartCallFragment.kt
@@ -43,6 +43,9 @@ import org.linphone.ui.main.contacts.viewmodel.ContactsListViewModel
import org.linphone.ui.main.fragment.GenericFragment
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.utils.DialogUtils
+import org.linphone.utils.hideKeyboard
+import org.linphone.utils.setKeyboardInsetListener
+import org.linphone.utils.showKeyboard
@UiThread
class StartCallFragment : GenericFragment() {
@@ -103,6 +106,10 @@ class StartCallFragment : GenericFragment() {
goBack()
}
+ binding.setHideNumpadClickListener {
+ viewModel.hideNumpad()
+ }
+
contactsAdapter = ContactsListAdapter(viewLifecycleOwner, disableLongClick = true)
binding.contactsList.setHasFixedSize(true)
binding.contactsList.adapter = contactsAdapter
@@ -140,6 +147,32 @@ class StartCallFragment : GenericFragment() {
contactsListViewModel.applyFilter(filter)
viewModel.applyFilter(filter)
}
+
+ viewModel.appendDigitToSearchBarEvent.observe(viewLifecycleOwner) {
+ it.consume { digit ->
+ val newValue = "${binding.searchBar.text}$digit"
+ binding.searchBar.setText(newValue)
+ binding.searchBar.setSelection(newValue.length)
+ }
+ }
+
+ viewModel.requestKeyboardVisibilityChangedEvent.observe(viewLifecycleOwner) {
+ it.consume { show ->
+ if (show) {
+ // To automatically open keyboard
+ binding.searchBar.showKeyboard(requireActivity().window)
+ } else {
+ binding.searchBar.requestFocus()
+ binding.searchBar.hideKeyboard()
+ }
+ }
+ }
+
+ binding.root.setKeyboardInsetListener { keyboardVisible ->
+ if (keyboardVisible) {
+ viewModel.isNumpadVisible.value = false
+ }
+ }
}
private fun startCall(model: ContactAvatarModel) {
diff --git a/app/src/main/java/org/linphone/ui/main/calls/model/NumpadModel.kt b/app/src/main/java/org/linphone/ui/main/calls/model/NumpadModel.kt
new file mode 100644
index 000000000..f39be1540
--- /dev/null
+++ b/app/src/main/java/org/linphone/ui/main/calls/model/NumpadModel.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of linphone-android
+ * (see https://www.linphone.org).
+ *
+ * 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 .
+ */
+package org.linphone.ui.main.calls.model
+
+import androidx.annotation.UiThread
+import org.linphone.core.tools.Log
+
+class NumpadModel @UiThread constructor(
+ private val onDigitClicked: (value: String) -> (Unit),
+ private val onCallClicked: () -> (Unit)
+) {
+ companion object {
+ private const val TAG = "[Numpad Model]"
+ }
+
+ @UiThread
+ fun onDigitClicked(value: String) {
+ Log.i("$TAG Clicked on digit [$value]")
+ onDigitClicked.invoke(value)
+ }
+
+ fun onDigitLongClicked(value: String): Boolean {
+ Log.i("$TAG Long clicked on digit [$value]")
+ onDigitClicked.invoke(value)
+ return true
+ }
+
+ @UiThread
+ fun onCallClicked() {
+ Log.i("$TAG Starting call")
+ onCallClicked.invoke()
+ }
+}
diff --git a/app/src/main/java/org/linphone/ui/main/calls/viewmodel/StartCallViewModel.kt b/app/src/main/java/org/linphone/ui/main/calls/viewmodel/StartCallViewModel.kt
index 6705a9033..67a34baa6 100644
--- a/app/src/main/java/org/linphone/ui/main/calls/viewmodel/StartCallViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/calls/viewmodel/StartCallViewModel.kt
@@ -33,6 +33,7 @@ import org.linphone.core.MagicSearch
import org.linphone.core.MagicSearchListenerStub
import org.linphone.core.SearchResult
import org.linphone.core.tools.Log
+import org.linphone.ui.main.calls.model.NumpadModel
import org.linphone.ui.main.calls.model.SuggestionModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.utils.Event
@@ -49,6 +50,18 @@ class StartCallViewModel @UiThread constructor() : ViewModel() {
val suggestionsList = MutableLiveData>()
+ val numpadModel: NumpadModel
+
+ val isNumpadVisible = MutableLiveData()
+
+ val appendDigitToSearchBarEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val requestKeyboardVisibilityChangedEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
val onSuggestionClickedEvent: MutableLiveData> by lazy {
MutableLiveData>()
}
@@ -81,6 +94,31 @@ class StartCallViewModel @UiThread constructor() : ViewModel() {
}
init {
+ isNumpadVisible.value = false
+ numpadModel = NumpadModel(
+ { digit ->
+ // onDigitClicked
+ appendDigitToSearchBarEvent.value = Event(digit)
+ // Don't do that, cursor will stay at start
+ // searchFilter.value = "${searchFilter.value.orEmpty()}$digit"
+ },
+ { // OnCallClicked
+ val suggestion = searchFilter.value.orEmpty()
+ if (suggestion.isNotEmpty()) {
+ Log.i("$TAG Using numpad dial button to call [$suggestion]")
+ coreContext.postOnCoreThread { core ->
+ val address = core.interpretUrl(suggestion, true)
+ if (address != null) {
+ Log.i("$TAG Calling [${address.asStringUriOnly()}]")
+ onSuggestionClickedEvent.postValue(Event(address))
+ } else {
+ Log.e("$TAG Failed to parse [$suggestion] as SIP address")
+ }
+ }
+ }
+ }
+ )
+
coreContext.postOnCoreThread { core ->
val defaultAccount = core.defaultAccount
limitSearchToLinphoneAccounts = defaultAccount?.isInSecureMode() ?: false
@@ -108,6 +146,17 @@ class StartCallViewModel @UiThread constructor() : ViewModel() {
searchFilter.value = ""
}
+ @UiThread
+ fun switchBetweenKeyboardAndNumpad() {
+ requestKeyboardVisibilityChangedEvent.value = Event(isNumpadVisible.value == true)
+ isNumpadVisible.value = isNumpadVisible.value == false
+ }
+
+ @UiThread
+ fun hideNumpad() {
+ isNumpadVisible.value = false
+ }
+
@WorkerThread
fun processMagicSearchResults(results: Array) {
Log.i("$TAG Processing [${results.size}] results")
diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt
index 053b13087..110544c37 100644
--- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt
+++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt
@@ -40,6 +40,7 @@ import androidx.core.view.doOnLayout
import androidx.databinding.BindingAdapter
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
+import androidx.lifecycle.LifecycleOwner
import coil.load
import coil.transform.CircleCropTransformation
import io.getstream.avatarview.AvatarView
@@ -120,7 +121,7 @@ fun View.setKeyboardInsetListener(lambda: (visible: Boolean) -> Unit) {
lambda(isKeyboardVisible)
} catch (ise: IllegalStateException) {
Log.e(
- "[Databinding Utils] Failed to called lambda after keyboard visibility changed: $ise"
+ "[Data Binding Utils] Failed to called lambda after keyboard visibility changed: $ise"
)
}
@@ -137,7 +138,7 @@ fun View.setKeyboardInsetListener(lambda: (visible: Boolean) -> Unit) {
lambda(isKeyboardVisible)
} catch (ise: IllegalStateException) {
Log.e(
- "[Databinding Utils] Failed to called lambda after keyboard visibility changed: $ise"
+ "[Data Binding Utils] Failed to called lambda after keyboard visibility changed: $ise"
)
}
}
@@ -284,3 +285,12 @@ fun setConstraintLayoutBottomMargin(view: View, margins: Float) {
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, m)
view.layoutParams = params
}
+
+@BindingAdapter("inflatedLifecycleOwner")
+fun setInflatedViewStubLifecycleOwner(view: View, enable: Boolean) {
+ val binding = DataBindingUtil.bind(view)
+ // This is a bit hacky...
+ if (view.context is LifecycleOwner) {
+ binding?.lifecycleOwner = view.context as? LifecycleOwner
+ }
+}
diff --git a/app/src/main/res/drawable/shape_circle_green_background.xml b/app/src/main/res/drawable/shape_circle_green_background.xml
new file mode 100644
index 000000000..d36f85dd7
--- /dev/null
+++ b/app/src/main/res/drawable/shape_circle_green_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_drawer_handle.xml b/app/src/main/res/drawable/shape_drawer_handle.xml
new file mode 100644
index 000000000..7946b3661
--- /dev/null
+++ b/app/src/main/res/drawable/shape_drawer_handle.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_numpad_background.xml b/app/src/main/res/drawable/shape_numpad_background.xml
new file mode 100644
index 000000000..334cf259c
--- /dev/null
+++ b/app/src/main/res/drawable/shape_numpad_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/calls_list_fragment.xml b/app/src/main/res/layout-land/calls_list_fragment.xml
index 659da509d..5b4e3a2c5 100644
--- a/app/src/main/res/layout-land/calls_list_fragment.xml
+++ b/app/src/main/res/layout-land/calls_list_fragment.xml
@@ -47,7 +47,7 @@
-
+
+
@@ -16,7 +19,7 @@
+ android:background="@color/gray_7">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/call_start_numpad.xml b/app/src/main/res/layout/call_start_numpad.xml
new file mode 100644
index 000000000..5c3eb9ada
--- /dev/null
+++ b/app/src/main/res/layout/call_start_numpad.xml
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/calls_list_fragment.xml b/app/src/main/res/layout/calls_list_fragment.xml
index 0a245880b..63dc048b6 100644
--- a/app/src/main/res/layout/calls_list_fragment.xml
+++ b/app/src/main/res/layout/calls_list_fragment.xml
@@ -47,7 +47,7 @@
#FFEACB
#FFB266
#22334D
+ #C0D1D9
#EEF7F8
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
index a2e74c5c8..612d669be 100644
--- a/app/src/main/res/values/dimen.xml
+++ b/app/src/main/res/values/dimen.xml
@@ -8,6 +8,8 @@
355dp
300dp
+ 24dp
+
45dp
50dp
100dp
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1b7939621..4ba503000 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -50,6 +50,14 @@
- @color/red_danger
- 8dp
+