Dial pad: clean some code, remove useless method and allow cursor

This commit is contained in:
ganfra 2021-06-15 16:03:52 +02:00
parent 856481e6bc
commit 3a8a8d5b78
4 changed files with 123 additions and 105 deletions

View File

@ -61,6 +61,7 @@ class CallDialPadBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCa
arguments = Bundle().apply { arguments = Bundle().apply {
putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, showActions) putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, showActions)
putBoolean(DialPadFragment.EXTRA_ENABLE_OK, showActions) putBoolean(DialPadFragment.EXTRA_ENABLE_OK, showActions)
putBoolean(DialPadFragment.EXTRA_CURSOR_VISIBLE, false)
putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country) putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
} }
callback = DialPadFragmentCallbackWrapper(this@CallDialPadBottomSheet.callback) callback = DialPadFragmentCallbackWrapper(this@CallDialPadBottomSheet.callback)
@ -88,10 +89,6 @@ class CallDialPadBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCa
private inner class DialPadFragmentCallbackWrapper(val callback: DialPadFragment.Callback?): DialPadFragment.Callback { private inner class DialPadFragmentCallbackWrapper(val callback: DialPadFragment.Callback?): DialPadFragment.Callback {
override fun onDigitAppended(digit: String) {
callback?.onDigitAppended(digit)
}
override fun onOkClicked(formatted: String?, raw: String?) { override fun onOkClicked(formatted: String?, raw: String?) {
callback?.onOkClicked(formatted, raw) callback?.onOkClicked(formatted, raw)
dismiss() dismiss()

View File

@ -16,8 +16,18 @@
package im.vector.app.features.call.dialpad package im.vector.app.features.call.dialpad
import android.content.ClipboardManager
import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.os.Bundle import android.os.Bundle
import android.telephony.PhoneNumberFormattingTextWatcher
import android.telephony.PhoneNumberUtils
import android.text.Editable
import android.text.InputType
import android.text.TextUtils
import android.text.TextWatcher
import android.text.method.DialerKeyListener
import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -26,24 +36,20 @@ import androidx.core.widget.ImageViewCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.android.dialer.dialpadview.DialpadView import com.android.dialer.dialpadview.DialpadView
import com.android.dialer.dialpadview.DigitsEditText import com.android.dialer.dialpadview.DigitsEditText
import com.google.i18n.phonenumbers.AsYouTypeFormatter
import com.google.i18n.phonenumbers.PhoneNumberUtil
import im.vector.app.R import im.vector.app.R
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
class DialPadFragment : Fragment() { class DialPadFragment : Fragment(), TextWatcher {
var callback: Callback? = null var callback: Callback? = null
private var digits: DigitsEditText? = null private lateinit var digits: DigitsEditText
private var formatter: AsYouTypeFormatter? = null
private var input = ""
private var regionCode: String = DEFAULT_REGION_CODE private var regionCode: String = DEFAULT_REGION_CODE
private var formatAsYouType = true private var formatAsYouType = true
private var enableStar = true private var enableStar = true
private var enablePound = true private var enablePound = true
private var enablePlus = true private var enablePlus = true
private var cursorVisible = false private var cursorVisible = true
private var enableDelete = true private var enableDelete = true
private var enableFabOk = true private var enableFabOk = true
@ -55,70 +61,77 @@ class DialPadFragment : Fragment() {
val view = inflater.inflate(R.layout.dialpad_fragment, container, false) val view = inflater.inflate(R.layout.dialpad_fragment, container, false)
val dialpadView = view.findViewById<View>(R.id.dialpad_view) as DialpadView val dialpadView = view.findViewById<View>(R.id.dialpad_view) as DialpadView
dialpadView.findViewById<View>(R.id.dialpad_key_voicemail).isVisible = false dialpadView.findViewById<View>(R.id.dialpad_key_voicemail).isVisible = false
digits = dialpadView.digits as? DigitsEditText digits = dialpadView.digits as DigitsEditText
digits?.isCursorVisible = cursorVisible digits.isCursorVisible = cursorVisible
digits?.setTextColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_content_primary)) digits.inputType = InputType.TYPE_CLASS_PHONE
dialpadView.findViewById<View>(R.id.zero).setOnClickListener { append('0') } digits.keyListener = DialerKeyListener.getInstance()
if (enablePlus) { digits.setTextColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_content_primary))
dialpadView.findViewById<View>(R.id.zero).setOnLongClickListener { digits.addTextChangedListener(PhoneNumberFormattingTextWatcher(if (formatAsYouType) regionCode else ""))
append('+') digits.addTextChangedListener(this)
true dialpadView.findViewById<View>(R.id.zero).setOnClickListener { keyPressed(KeyEvent.KEYCODE_0, "0") }
} dialpadView.findViewById<View>(R.id.one).setOnClickListener { keyPressed(KeyEvent.KEYCODE_1,"1") }
} dialpadView.findViewById<View>(R.id.two).setOnClickListener { keyPressed(KeyEvent.KEYCODE_2,"2") }
dialpadView.findViewById<View>(R.id.one).setOnClickListener { append('1') } dialpadView.findViewById<View>(R.id.three).setOnClickListener { keyPressed(KeyEvent.KEYCODE_3,"3") }
dialpadView.findViewById<View>(R.id.two).setOnClickListener { append('2') } dialpadView.findViewById<View>(R.id.four).setOnClickListener { keyPressed(KeyEvent.KEYCODE_4,"4") }
dialpadView.findViewById<View>(R.id.three).setOnClickListener { append('3') } dialpadView.findViewById<View>(R.id.five).setOnClickListener { keyPressed(KeyEvent.KEYCODE_5,"5") }
dialpadView.findViewById<View>(R.id.four).setOnClickListener { append('4') } dialpadView.findViewById<View>(R.id.six).setOnClickListener { keyPressed(KeyEvent.KEYCODE_6,"6") }
dialpadView.findViewById<View>(R.id.four).setOnClickListener { append('4') } dialpadView.findViewById<View>(R.id.seven).setOnClickListener { keyPressed(KeyEvent.KEYCODE_7,"7") }
dialpadView.findViewById<View>(R.id.five).setOnClickListener { append('5') } dialpadView.findViewById<View>(R.id.eight).setOnClickListener { keyPressed(KeyEvent.KEYCODE_8,"8") }
dialpadView.findViewById<View>(R.id.six).setOnClickListener { append('6') } dialpadView.findViewById<View>(R.id.nine).setOnClickListener { keyPressed(KeyEvent.KEYCODE_9,"9") }
dialpadView.findViewById<View>(R.id.seven).setOnClickListener { append('7') }
dialpadView.findViewById<View>(R.id.eight).setOnClickListener { append('8') }
dialpadView.findViewById<View>(R.id.nine).setOnClickListener { append('9') }
if (enableStar) { if (enableStar) {
dialpadView.findViewById<View>(R.id.star).setOnClickListener { append('*') } dialpadView.findViewById<View>(R.id.star).setOnClickListener { keyPressed(KeyEvent.KEYCODE_STAR,"*") }
} else { } else {
dialpadView.findViewById<View>(R.id.star).isVisible = false dialpadView.findViewById<View>(R.id.star).isVisible = false
} }
if (enablePound) { if (enablePound) {
dialpadView.findViewById<View>(R.id.pound).setOnClickListener { append('#') } dialpadView.findViewById<View>(R.id.pound).setOnClickListener { keyPressed(KeyEvent.KEYCODE_POUND,"#") }
} else { } else {
dialpadView.findViewById<View>(R.id.pound).isVisible = false dialpadView.findViewById<View>(R.id.pound).isVisible = false
} }
if (enablePlus) {
dialpadView.findViewById<View>(R.id.zero).setOnLongClickListener {
keyPressed(KeyEvent.KEYCODE_PLUS, "+")
true
}
}
if (enableDelete) { if (enableDelete) {
dialpadView.deleteButton.setOnClickListener { poll() } dialpadView.deleteButton.setOnClickListener { keyPressed(KeyEvent.KEYCODE_DEL, null) }
dialpadView.deleteButton.setOnLongClickListener { dialpadView.deleteButton.setOnLongClickListener {
clear() clear()
true true
} }
val tintColor = ThemeUtils.getColor(requireContext(), im.vector.app.R.attr.vctr_content_secondary) val tintColor = ThemeUtils.getColor(requireContext(), R.attr.vctr_content_secondary)
ImageViewCompat.setImageTintList(dialpadView.deleteButton, ColorStateList.valueOf(tintColor)) ImageViewCompat.setImageTintList(dialpadView.deleteButton, ColorStateList.valueOf(tintColor))
} else { } else {
dialpadView.deleteButton.isVisible = false dialpadView.deleteButton.isVisible = false
} }
// if region code is null, no formatting is performed
formatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(if (formatAsYouType) regionCode else "")
val fabOk = view.findViewById<View>(R.id.fab_ok) val fabOk = view.findViewById<View>(R.id.fab_ok)
if (enableFabOk) { if (enableFabOk) {
fabOk.setOnClickListener { fabOk.setOnClickListener { onOkClicked() }
callback?.onOkClicked(digits?.text.toString(), input)
}
} else { } else {
fabOk.isVisible = false fabOk.isVisible = false
} }
digits?.setOnTextContextMenuClickListener {
val string = digits?.text.toString()
clear()
for (element in string) {
append(element)
}
}
return view return view
} }
private fun onOkClicked() {
val rawInput = getRawInput()
if (rawInput.isEmpty()) {
val clipboard = (requireContext().getSystemService(Context.CLIPBOARD_SERVICE)) as? ClipboardManager
val textToPaste = clipboard?.primaryClip?.getItemAt(0)?.text ?: return
val formatted = formatNumber(textToPaste.toString())
digits.setText(formatted)
digits.setSelection(digits.text!!.length)
} else {
val formatted = digits.text.toString()
callback?.onOkClicked(formatted, rawInput)
}
}
fun getRawInput(): String {
return PhoneNumberUtils.normalizeNumber(digits.text.toString())
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putString(EXTRA_REGION_CODE, regionCode) outState.putString(EXTRA_REGION_CODE, regionCode)
@ -145,40 +158,40 @@ class DialPadFragment : Fragment() {
} }
} }
private fun poll() { private fun keyPressed(keyCode: Int, digitString: String?) {
if (input.isNotEmpty()) { val event = KeyEvent(KeyEvent.ACTION_DOWN, keyCode)
input = input.substring(0, input.length - 1) // Disable cursor and enable it again after onKeyDown otherwise DigitsEditText force replacing cursor at the end
formatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(regionCode) digits.isCursorVisible = false
if (formatAsYouType) { digits.onKeyDown(keyCode, event)
digits?.setText("") digits.isCursorVisible = cursorVisible
for (c in input.toCharArray()) { digitString?.also {
digits?.setText(formatter?.inputDigit(c)) callback?.onDigitAppended(it)
}
} else {
digits?.setText(input)
}
} }
} }
private fun clear() { private fun clear() {
formatter?.clear() digits.setText("")
digits?.setText("")
input = ""
} }
private fun append(c: Char) { private fun formatNumber(dialString: String): String {
callback?.onDigitAppended(c.toString()) var number = PhoneNumberUtils.extractNetworkPortion(dialString)
input += c // Also retrieve the post dial portion of the provided data, so that the entire dial
if (formatAsYouType) { // string can be reconstituted later.
digits?.setText(formatter?.inputDigit(c)) val postDial = PhoneNumberUtils.extractPostDialPortion(dialString)
if (TextUtils.isEmpty(number)) {
return ""
}
number = PhoneNumberUtils.formatNumber(number, null, regionCode) ?: number
return if (TextUtils.isEmpty(postDial)) {
number
} else { } else {
digits?.setText(input) number + postDial
} }
} }
interface Callback { interface Callback {
fun onOkClicked(formatted: String?, raw: String?) = Unit
fun onDigitAppended(digit: String) = Unit fun onDigitAppended(digit: String) = Unit
fun onOkClicked(formatted: String?, raw: String?) = Unit
} }
companion object { companion object {
@ -193,4 +206,21 @@ class DialPadFragment : Fragment() {
private const val DEFAULT_REGION_CODE = "US" private const val DEFAULT_REGION_CODE = "US"
} }
// Text watcher
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
//Noop
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
//Noop
}
override fun afterTextChanged(s: Editable) {
if (s.isEmpty()) {
digits.clearFocus()
}
}
} }

View File

@ -79,24 +79,20 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
waitingView = views.waitingView.waitingView waitingView = views.waitingView.waitingView
callTransferViewModel.observeViewEvents { callTransferViewModel.observeViewEvents {
when (it) { when (it) {
is CallTransferViewEvents.Dismiss -> finish() is CallTransferViewEvents.Dismiss -> finish()
CallTransferViewEvents.Loading -> showWaitingView() CallTransferViewEvents.Loading -> showWaitingView()
is CallTransferViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure)) is CallTransferViewEvents.FailToTransfer -> showSnackbar(getString(R.string.call_transfer_failure))
} }
} }
sectionsPagerAdapter = CallTransferPagerAdapter(this).register() sectionsPagerAdapter = CallTransferPagerAdapter(this)
views.callTransferViewPager.adapter = sectionsPagerAdapter views.callTransferViewPager.adapter = sectionsPagerAdapter
sectionsPagerAdapter.onDialPadOkClicked = { phoneNumber ->
val action = CallTransferAction.ConnectWithPhoneNumber(views.callTransferConsultCheckBox.isChecked, phoneNumber)
callTransferViewModel.handle(action)
}
TabLayoutMediator(views.callTransferTabLayout, views.callTransferViewPager) { tab, position -> TabLayoutMediator(views.callTransferTabLayout, views.callTransferViewPager) { tab, position ->
when (position) { when (position) {
0 -> tab.text = getString(R.string.call_transfer_users_tab_title) CallTransferPagerAdapter.USER_LIST_INDEX -> tab.text = getString(R.string.call_transfer_users_tab_title)
1 -> tab.text = getString(R.string.call_dial_pad_title) CallTransferPagerAdapter.DIAL_PAD_INDEX -> tab.text = getString(R.string.call_dial_pad_title)
} }
}.attach() }.attach()
configureToolbar(views.callTransferToolbar) configureToolbar(views.callTransferToolbar)
@ -106,10 +102,17 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>(),
private fun setupConnectAction() { private fun setupConnectAction() {
views.callTransferConnectAction.debouncedClicks { views.callTransferConnectAction.debouncedClicks {
val selectedUser = sectionsPagerAdapter.userListFragment?.getCurrentState()?.getSelectedMatrixId()?.firstOrNull() when (views.callTransferTabLayout.selectedTabPosition) {
if (selectedUser != null) { CallTransferPagerAdapter.USER_LIST_INDEX -> {
val action = CallTransferAction.ConnectWithUserId(views.callTransferConsultCheckBox.isChecked, selectedUser) val selectedUser = sectionsPagerAdapter.userListFragment?.getCurrentState()?.getSelectedMatrixId()?.firstOrNull() ?: return@debouncedClicks
callTransferViewModel.handle(action) val action = CallTransferAction.ConnectWithUserId(views.callTransferConsultCheckBox.isChecked, selectedUser)
callTransferViewModel.handle(action)
}
CallTransferPagerAdapter.DIAL_PAD_INDEX -> {
val phoneNumber = sectionsPagerAdapter.dialPadFragment?.getRawInput() ?: return@debouncedClicks
val action = CallTransferAction.ConnectWithPhoneNumber(views.callTransferConsultCheckBox.isChecked, phoneNumber)
callTransferViewModel.handle(action)
}
} }
} }
} }

View File

@ -29,14 +29,17 @@ import im.vector.app.features.userdirectory.UserListFragmentArgs
class CallTransferPagerAdapter( class CallTransferPagerAdapter(
private val fragmentActivity: FragmentActivity private val fragmentActivity: FragmentActivity
) : FragmentStateAdapter(fragmentActivity), Restorable { ) : FragmentStateAdapter(fragmentActivity) {
companion object {
const val USER_LIST_INDEX = 0
const val DIAL_PAD_INDEX = 1
}
val userListFragment: UserListFragment? val userListFragment: UserListFragment?
get() = findFragmentAtPosition(0) as? UserListFragment get() = findFragmentAtPosition(USER_LIST_INDEX) as? UserListFragment
val dialPadFragment: DialPadFragment? val dialPadFragment: DialPadFragment?
get() = findFragmentAtPosition(1) as? DialPadFragment get() = findFragmentAtPosition(DIAL_PAD_INDEX) as? DialPadFragment
var onDialPadOkClicked: ((String) -> Unit)? = null
override fun getItemCount() = 2 override fun getItemCount() = 2
@ -57,10 +60,9 @@ class CallTransferPagerAdapter(
(fragment as DialPadFragment).apply { (fragment as DialPadFragment).apply {
arguments = Bundle().apply { arguments = Bundle().apply {
putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true) putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true) putBoolean(DialPadFragment.EXTRA_ENABLE_OK, false)
putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country) putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
} }
applyCallback()
} }
} }
return fragment return fragment
@ -70,19 +72,5 @@ class CallTransferPagerAdapter(
return fragmentActivity.supportFragmentManager.findFragmentByTag("f$position") return fragmentActivity.supportFragmentManager.findFragmentByTag("f$position")
} }
override fun onSaveInstanceState(outState: Bundle) = Unit
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
dialPadFragment?.applyCallback()
}
private fun DialPadFragment.applyCallback(): DialPadFragment {
callback = object : DialPadFragment.Callback {
override fun onOkClicked(formatted: String?, raw: String?) {
if (raw.isNullOrEmpty()) return
onDialPadOkClicked?.invoke(raw)
}
}
return this
}
} }