Added in-call numpad

This commit is contained in:
Sylvain Berfini 2023-09-22 18:08:13 +02:00
parent 913e7cdb02
commit ee8779cc00
16 changed files with 337 additions and 28 deletions

View file

@ -46,6 +46,8 @@ import org.linphone.ui.call.viewmodel.SharedCallViewModel
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
import org.linphone.utils.addCharacterAtPosition
import org.linphone.utils.removeCharacterAtPosition
@UiThread
class ActiveCallFragment : GenericCallFragment() {
@ -117,9 +119,13 @@ class ActiveCallFragment : GenericCallFragment() {
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = callViewModel
binding.callsViewModel = callsViewModel
binding.numpadModel = callViewModel.numpadModel
val bottomSheetBehavior = BottomSheetBehavior.from(binding.bottomBar.root)
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
val actionsBottomSheetBehavior = BottomSheetBehavior.from(binding.bottomBar.root)
actionsBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
val numpadBottomSheetBehavior = BottomSheetBehavior.from(binding.callNumpad.root)
numpadBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
binding.setNewCallClickListener {
val action = ActiveCallFragmentDirections.actionActiveCallFragmentToNewCallFragment()
@ -185,16 +191,35 @@ class ActiveCallFragment : GenericCallFragment() {
callViewModel.toggleExtraActionsBottomSheetEvent.observe(viewLifecycleOwner) {
it.consume {
val state = bottomSheetBehavior.state
val state = actionsBottomSheetBehavior.state
if (state == BottomSheetBehavior.STATE_COLLAPSED) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
actionsBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
} else if (state == BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
actionsBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
callViewModel.showNumpadBottomSheetEvent.observe(viewLifecycleOwner) {
it.consume {
actionsBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
numpadBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
callViewModel.removedCharacterAtCurrentPositionEvent.observe(viewLifecycleOwner) {
it.consume {
binding.callNumpad.digitsHistory.removeCharacterAtPosition()
}
}
callViewModel.appendDigitToSearchBarEvent.observe(viewLifecycleOwner) {
it.consume { digit ->
binding.callNumpad.digitsHistory.addCharacterAtPosition(digit)
}
}
actionsBottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_COLLAPSED, BottomSheetBehavior.STATE_HIDDEN -> {

View file

@ -37,6 +37,7 @@ import org.linphone.core.MediaEncryption
import org.linphone.core.tools.Log
import org.linphone.ui.call.model.AudioDeviceModel
import org.linphone.ui.main.contacts.model.ContactAvatarModel
import org.linphone.ui.main.history.model.NumpadModel
import org.linphone.utils.AppUtils
import org.linphone.utils.AudioRouteUtils
import org.linphone.utils.Event
@ -100,6 +101,20 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
MutableLiveData<Event<Boolean>>()
}
val showNumpadBottomSheetEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
val numpadModel: NumpadModel
val appendDigitToSearchBarEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
val removedCharacterAtCurrentPositionEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
private lateinit var call: Call
private val callListener = object : CallListenerStub() {
@ -158,6 +173,21 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
showSwitchCamera.postValue(coreContext.showSwitchCameraButton())
}
numpadModel = NumpadModel(
{ digit -> // onDigitClicked
appendDigitToSearchBarEvent.value = Event(digit)
coreContext.postOnCoreThread {
Log.i("$TAG Sending DTMF [${digit.first()}]")
call.sendDtmf(digit.first())
}
},
{ // OnBackspaceClicked
removedCharacterAtCurrentPositionEvent.value = Event(true)
},
{ // OnCallClicked
}
)
}
@UiThread
@ -323,6 +353,11 @@ class CurrentCallViewModel @UiThread constructor() : ViewModel() {
toggleExtraActionsBottomSheetEvent.value = Event(true)
}
@UiThread
fun showNumpad() {
showNumpadBottomSheetEvent.value = Event(true)
}
@WorkerThread
private fun showZrtpSasDialog(authToken: String) {
val toRead: String

View file

@ -44,7 +44,9 @@ import org.linphone.ui.main.history.viewmodel.StartCallViewModel
import org.linphone.ui.main.model.isInSecureMode
import org.linphone.utils.DialogUtils
import org.linphone.utils.RecyclerViewHeaderDecoration
import org.linphone.utils.addCharacterAtPosition
import org.linphone.utils.hideKeyboard
import org.linphone.utils.removeCharacterAtPosition
import org.linphone.utils.setKeyboardInsetListener
import org.linphone.utils.showKeyboard
@ -140,24 +142,13 @@ class StartCallFragment : GenericFragment() {
viewModel.removedCharacterAtCurrentPositionEvent.observe(viewLifecycleOwner) {
it.consume {
val selectionStart = binding.searchBar.selectionStart
val selectionEnd = binding.searchBar.selectionEnd
if (selectionStart > 0) {
binding.searchBar.text =
binding.searchBar.text?.delete(
selectionStart - 1,
selectionEnd
)
binding.searchBar.setSelection(selectionStart - 1)
}
binding.searchBar.removeCharacterAtPosition()
}
}
viewModel.appendDigitToSearchBarEvent.observe(viewLifecycleOwner) {
it.consume { digit ->
val newValue = "${binding.searchBar.text}$digit"
binding.searchBar.setText(newValue)
binding.searchBar.setSelection(newValue.length)
binding.searchBar.addCharacterAtPosition(digit)
}
}

View file

@ -20,9 +20,10 @@
package org.linphone.ui.main.history.model
import androidx.annotation.UiThread
import androidx.lifecycle.MutableLiveData
import org.linphone.core.tools.Log
class NumpadModel @UiThread constructor(
open class NumpadModel @UiThread constructor(
private val onDigitClicked: (value: String) -> (Unit),
private val onBackspaceClicked: () -> (Unit),
private val onCallClicked: () -> (Unit)
@ -31,6 +32,8 @@ class NumpadModel @UiThread constructor(
private const val TAG = "[Numpad Model]"
}
val digits = MutableLiveData<String>()
@UiThread
fun onDigitClicked(value: String) {
Log.i("$TAG Clicked on digit [$value]")

View file

@ -113,6 +113,27 @@ fun View.hideKeyboard() {
imm.hideSoftInputFromWindow(this.windowToken, 0)
}
@UiThread
fun AppCompatEditText.removeCharacterAtPosition() {
val start = selectionStart
val end = selectionEnd
if (start > 0) {
text =
text?.delete(
start - 1,
end
)
setSelection(start - 1)
}
}
@UiThread
fun AppCompatEditText.addCharacterAtPosition(character: String) {
val newValue = "${text}$character"
setText(newValue)
setSelection(newValue.length)
}
@UiThread
fun View.setKeyboardInsetListener(lambda: (visible: Boolean) -> Unit) {
doOnLayout {

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:topRightRadius="20dp" android:topLeftRadius="20dp" />
<solid android:color="@color/gray_900"/>
</shape>

View file

@ -25,7 +25,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/call_all_actions_menu_height"
android:background="@color/grey_900"
android:background="@color/gray_900"
app:behavior_hideable="false"
app:behavior_peekHeight="@dimen/call_main_actions_menu_height"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
@ -103,6 +103,7 @@
<ImageView
android:id="@+id/dialer"
android:onClick="@{() -> viewModel.showNumpad()}"
android:layout_width="0dp"
android:layout_height="@dimen/call_button_size"
android:layout_marginTop="@dimen/call_extra_button_top_margin"
@ -196,6 +197,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/in_call_extra_action_label_style"
android:id="@+id/dialer_label"
android:onClick="@{() -> viewModel.showNumpad()}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="15dp"

View file

@ -20,6 +20,9 @@
<variable
name="callsViewModel"
type="org.linphone.ui.call.viewmodel.CallsViewModel" />
<variable
name="numpadModel"
type="org.linphone.ui.main.history.model.NumpadModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
@ -30,7 +33,7 @@
android:id="@+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_900">
android:background="@color/gray_900">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/hinge_top"
@ -223,6 +226,12 @@
bind:newCallClickListener="@{newCallClickListener}"
bind:callsListClickListener="@{callsListClickListener}"/>
<include
android:id="@+id/call_numpad"
android:visibility="@{viewModel.fullScreenMode || viewModel.pipMode ? View.INVISIBLE : View.VISIBLE}"
layout="@layout/call_numpad"
bind:model="@{numpadModel}"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -25,7 +25,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/call_all_actions_menu_height"
android:background="@color/grey_900"
android:background="@color/gray_900"
app:behavior_hideable="false"
app:behavior_peekHeight="@dimen/call_main_actions_menu_height"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
@ -103,6 +103,7 @@
<ImageView
android:id="@+id/dialer"
android:onClick="@{() -> viewModel.showNumpad()}"
android:layout_width="0dp"
android:layout_height="@dimen/call_button_size"
android:layout_marginTop="@dimen/call_extra_button_top_margin"
@ -193,6 +194,7 @@
<androidx.appcompat.widget.AppCompatTextView
style="@style/in_call_extra_action_label_style"
android:id="@+id/dialer_label"
android:onClick="@{() -> viewModel.showNumpad()}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/call_action_show_dialer"

View file

@ -12,7 +12,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/grey_900"
android:background="@color/gray_900"
android:paddingTop="15dp"
android:paddingBottom="15dp">

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_900">
android:background="@color/gray_900">
<ImageView
android:id="@+id/call_direction_icon"

View file

@ -16,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/call_main_actions_menu_height"
android:paddingBottom="5dp"
android:background="@color/grey_900">
android:background="@color/gray_900">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:onClick="@{() -> viewModel.toggleExpandActionsMenu()}"

View file

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="handleClickedListener"
type="View.OnClickListener" />
<variable
name="model"
type="org.linphone.ui.main.history.model.NumpadModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_numpad_call_background"
android:clickable="true"
android:focusable="true"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/handle"
android:onClick="@{handleClickedListener}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="11dp"
android:src="@drawable/shape_drawer_handle"
app:tint="@color/gray_500"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatEditText
style="@style/default_text_style_300"
android:id="@+id/digits_history"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:textColor="@color/white"
android:textSize="30sp"
android:text="@{model.digits, default=`0123456789`}"
android:background="@color/transparent_color"
android:gravity="center"
android:maxLines="1"
android:ellipsize="start"
app:layout_constraintTop_toTopOf="@id/backspace"
app:layout_constraintBottom_toBottomOf="@id/backspace"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/backspace"/>
<ImageView
android:id="@+id/backspace"
android:onClick="@{() -> model.onBackspaceClicked()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="30dp"
android:src="@drawable/backspace_fill"
android:padding="20dp"
android:elevation="3dp"
app:tint="@color/white"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toEndOf="@id/digits_history"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="14dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/backspace"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="20dp"
app:flow_horizontalStyle="spread"
app:flow_wrapMode="aligned"
app:flow_verticalGap="10dp"
app:flow_maxElementsWrap="3"
app:constraint_referenced_ids="digit_1, digit_2, digit_3, digit_4, digit_5, digit_6, digit_7, digit_8, digit_9, digit_star, digit_0, digit_sharp" />
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`1`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`2`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`3`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`4`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="4"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`5`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`6`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="6"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`7`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="7"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`8`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="8"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`9`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="9"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`*`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`0`)}"
android:onLongClick="@{() -> model.onDigitLongClicked(`+`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView
android:onClick="@{() -> model.onDigitClicked(`#`)}"
style="@style/call_numpad_digits_style"
android:id="@+id/digit_sharp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#"
app:layout_constraintTop_toBottomOf="@id/handle"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -13,7 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_900">
android:background="@color/gray_900">
<ImageView
android:id="@+id/call_direction_icon"

View file

@ -26,7 +26,7 @@
<color name="gray_400">#949494</color>
<color name="gray_500">#4E4E4E</color>
<color name="gray_600">#2E3030</color>
<color name="grey_900">#070707</color>
<color name="gray_900">#070707</color>
<color name="red_danger_200">#F5CCBE</color>
<color name="red_danger_500">#DD5F5F</color>

View file

@ -119,6 +119,14 @@
<item name="android:elevation">3dp</item>
<item name="android:background">@drawable/circle_white_button_background</item>
</style>
<style name="call_numpad_digits_style">
<item name="android:fontFamily">@font/noto_sans</item>
<item name="android:textColor">@color/white</item>
<item name="android:textSize">32sp</item>
<item name="android:gravity">center</item>
<item name="android:elevation">3dp</item>
<item name="android:background">@drawable/in_call_button_background</item>
</style>
<style name="in_call_extra_action_label_style">
<item name="android:fontFamily">@font/noto_sans</item>
<item name="android:textSize">14sp</item>