This commit is contained in:
Sylvain Berfini 2023-08-03 11:15:18 +02:00
parent bd51fe383b
commit 5dfd04ad70
11 changed files with 88 additions and 52 deletions

View file

@ -19,6 +19,7 @@
<activity <activity
android:name=".ui.MainActivity" android:name=".ui.MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true" android:exported="true"
android:label="@string/app_name"> android:label="@string/app_name">

View file

@ -24,6 +24,8 @@ import androidx.lifecycle.ViewModel
import org.linphone.utils.Event import org.linphone.utils.Event
open class TopBarViewModel : ViewModel() { open class TopBarViewModel : ViewModel() {
val title = MutableLiveData<String>()
val searchBarVisible = MutableLiveData<Boolean>() val searchBarVisible = MutableLiveData<Boolean>()
val searchFilter = MutableLiveData<String>() val searchFilter = MutableLiveData<String>()

View file

@ -35,6 +35,7 @@ import org.linphone.databinding.ContactsFragmentBinding
import org.linphone.ui.MainActivity import org.linphone.ui.MainActivity
import org.linphone.ui.contacts.viewmodel.ContactsListViewModel import org.linphone.ui.contacts.viewmodel.ContactsListViewModel
import org.linphone.utils.hideKeyboard import org.linphone.utils.hideKeyboard
import org.linphone.utils.setKeyboardInsetListener
import org.linphone.utils.showKeyboard import org.linphone.utils.showKeyboard
class ContactsFragment : Fragment() { class ContactsFragment : Fragment() {
@ -67,6 +68,11 @@ class ContactsFragment : Fragment() {
binding.lifecycleOwner = viewLifecycleOwner binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = listViewModel binding.viewModel = listViewModel
binding.root.setKeyboardInsetListener { keyboardVisible ->
// val portraitOrientation = resources.configuration.orientation != Configuration.ORIENTATION_LANDSCAPE
listViewModel.bottomNavBarVisible.value = !keyboardVisible
}
// postponeEnterTransition() // postponeEnterTransition()
binding.setOnNewContactClicked { binding.setOnNewContactClicked {
@ -92,8 +98,8 @@ class ContactsFragment : Fragment() {
} }
listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) { listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) {
it.consume { take -> it.consume { show ->
if (take) { if (show) {
// To automatically open keyboard // To automatically open keyboard
binding.topBar.search.showKeyboard(requireActivity().window) binding.topBar.search.showKeyboard(requireActivity().window)
} else { } else {

View file

@ -19,6 +19,14 @@
*/ */
package org.linphone.ui.contacts.viewmodel package org.linphone.ui.contacts.viewmodel
import androidx.lifecycle.MutableLiveData
import org.linphone.ui.TopBarViewModel import org.linphone.ui.TopBarViewModel
class ContactsListViewModel : TopBarViewModel() class ContactsListViewModel : TopBarViewModel() {
val bottomNavBarVisible = MutableLiveData<Boolean>()
init {
title.value = "Contacts"
bottomNavBarVisible.value = true
}
}

View file

@ -38,6 +38,8 @@ import org.linphone.R
import org.linphone.databinding.ConversationsFragmentBinding import org.linphone.databinding.ConversationsFragmentBinding
import org.linphone.ui.conversations.adapter.ConversationsListAdapter import org.linphone.ui.conversations.adapter.ConversationsListAdapter
import org.linphone.ui.conversations.viewmodel.ConversationsListViewModel import org.linphone.ui.conversations.viewmodel.ConversationsListViewModel
import org.linphone.utils.hideKeyboard
import org.linphone.utils.showKeyboard
class ConversationsFragment : Fragment() { class ConversationsFragment : Fragment() {
private lateinit var binding: ConversationsFragmentBinding private lateinit var binding: ConversationsFragmentBinding
@ -144,6 +146,17 @@ class ConversationsFragment : Fragment() {
} }
} }
listViewModel.focusSearchBarEvent.observe(viewLifecycleOwner) {
it.consume { show ->
if (show) {
// To automatically open keyboard
binding.topBar.search.showKeyboard(requireActivity().window)
} else {
binding.topBar.search.hideKeyboard()
}
}
}
binding.setOnNewConversationClicked { binding.setOnNewConversationClicked {
if (findNavController().currentDestination?.id == R.id.conversationsFragment) { if (findNavController().currentDestination?.id == R.id.conversationsFragment) {
val action = ConversationsFragmentDirections.actionConversationsFragmentToNewConversationFragment() val action = ConversationsFragmentDirections.actionConversationsFragmentToNewConversationFragment()

View file

@ -20,7 +20,6 @@
package org.linphone.ui.conversations.viewmodel package org.linphone.ui.conversations.viewmodel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import java.util.ArrayList import java.util.ArrayList
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.contacts.ContactsListener import org.linphone.contacts.ContactsListener
@ -29,11 +28,12 @@ import org.linphone.core.ChatRoom
import org.linphone.core.Core import org.linphone.core.Core
import org.linphone.core.CoreListenerStub import org.linphone.core.CoreListenerStub
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.ui.TopBarViewModel
import org.linphone.ui.conversations.data.ChatRoomData import org.linphone.ui.conversations.data.ChatRoomData
import org.linphone.utils.Event import org.linphone.utils.Event
import org.linphone.utils.LinphoneUtils import org.linphone.utils.LinphoneUtils
class ConversationsListViewModel : ViewModel() { class ConversationsListViewModel : TopBarViewModel() {
val chatRoomsList = MutableLiveData<ArrayList<ChatRoomData>>() val chatRoomsList = MutableLiveData<ArrayList<ChatRoomData>>()
val notifyItemChangedEvent = MutableLiveData<Event<Int>>() val notifyItemChangedEvent = MutableLiveData<Event<Int>>()
@ -101,6 +101,8 @@ class ConversationsListViewModel : ViewModel() {
coreContext.postOnCoreThread { core -> coreContext.postOnCoreThread { core ->
updateChatRoomsList() updateChatRoomsList()
} }
title.value = "Conversations"
} }
override fun onCleared() { override fun onCleared() {

View file

@ -20,12 +20,15 @@
package org.linphone.utils package org.linphone.utils
import android.content.Context import android.content.Context
import android.view.View
import android.view.Window import android.view.Window
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnLayout
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
import coil.load import coil.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
@ -49,6 +52,29 @@ fun TextInputLayout.hideKeyboard() {
imm.hideSoftInputFromWindow(this.windowToken, 0) imm.hideSoftInputFromWindow(this.windowToken, 0)
} }
fun View.setKeyboardInsetListener(lambda: (visible: Boolean) -> Unit) {
doOnLayout {
var isKeyboardVisible = ViewCompat.getRootWindowInsets(this)?.isVisible(
WindowInsetsCompat.Type.ime()
) == true
lambda(isKeyboardVisible)
// See https://issuetracker.google.com/issues/281942480
ViewCompat.setOnApplyWindowInsetsListener(
rootView
) { view, insets ->
val keyboardVisibilityChanged = ViewCompat.getRootWindowInsets(view)
?.isVisible(WindowInsetsCompat.Type.ime()) == true
if (keyboardVisibilityChanged != isKeyboardVisible) {
isKeyboardVisible = keyboardVisibilityChanged
lambda(isKeyboardVisible)
}
ViewCompat.onApplyWindowInsets(view, insets)
}
}
}
@BindingAdapter("android:src") @BindingAdapter("android:src")
fun ImageView.setSourceImageResource(resource: Int) { fun ImageView.setSourceImageResource(resource: Int) {
this.setImageResource(resource) this.setImageResource(resource)

View file

@ -12,6 +12,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:transitionName="bottom_nav_bar" android:transitionName="bottom_nav_bar"
android:id="@+id/bottom_nav_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">

View file

@ -28,7 +28,7 @@
android:id="@+id/top_bar" android:id="@+id/top_bar"
bind:viewModel="@{viewModel}" bind:viewModel="@{viewModel}"
bind:onAvatarClickListener="@{onAvatarClickListener}" bind:onAvatarClickListener="@{onAvatarClickListener}"
layout="@layout/main_fragment_top_bar" /> layout="@layout/top_search_bar" />
<ImageView <ImageView
android:id="@+id/background" android:id="@+id/background"
@ -66,8 +66,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/no_contacts_image" /> app:layout_constraintTop_toBottomOf="@id/no_contacts_image" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/contactsList"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/background"
app:layout_constraintBottom_toTopOf="@id/bottom_nav_bar" />
<include <include
bind:onConversationsClicked="@{onConversationsClicked}" bind:onConversationsClicked="@{onConversationsClicked}"
android:visibility="@{viewModel.bottomNavBarVisible ? View.VISIBLE : View.GONE}"
android:id="@+id/bottom_nav_bar" android:id="@+id/bottom_nav_bar"
layout="@layout/bottom_nav_bar_contacts" layout="@layout/bottom_nav_bar_contacts"
android:layout_width="0dp" android:layout_width="0dp"

View file

@ -21,56 +21,21 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/primary_color"> android:background="@color/primary_color">
<TextView <include
android:id="@+id/title" android:id="@+id/top_bar"
android:layout_width="wrap_content" bind:viewModel="@{viewModel}"
android:layout_height="wrap_content" layout="@layout/top_search_bar" />
android:text="Conversations"
android:textSize="20sp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:layout_margin="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/menu"
android:layout_marginStart="22dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/title"
app:layout_constraintBottom_toBottomOf="@id/title"/>
<ImageView <ImageView
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginTop="10dp" android:layout_marginTop="17dp"
android:src="@drawable/shape_white_background" android:src="@drawable/shape_white_background"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" app:layout_constraintTop_toBottomOf="@id/top_bar"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
<EditText
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:padding="10dp"
android:drawableStart="@drawable/search"
android:drawablePadding="10dp"
android:background="@drawable/shape_search_round_background"
android:hint="Rechercher un contact, une conversation..."
android:textSize="14sp"
android:inputType="textPersonName|textNoSuggestions"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
<TextView <TextView
android:id="@+id/sort_by_label" android:id="@+id/sort_by_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -79,7 +44,7 @@
android:text="Trier par" android:text="Trier par"
android:textSize="12sp" android:textSize="12sp"
android:textColor="@color/gray_5" android:textColor="@color/gray_5"
app:layout_constraintStart_toStartOf="@id/search_bar" app:layout_constraintStart_toStartOf="@id/top_bar"
app:layout_constraintTop_toTopOf="@id/sort_by" app:layout_constraintTop_toTopOf="@id/sort_by"
app:layout_constraintBottom_toBottomOf="@id/sort_by"/> app:layout_constraintBottom_toBottomOf="@id/sort_by"/>
@ -94,7 +59,7 @@
android:textColor="@color/blue_filter" android:textColor="@color/blue_filter"
android:drawablePadding="5dp" android:drawablePadding="5dp"
app:layout_constraintStart_toEndOf="@id/sort_by_label" app:layout_constraintStart_toEndOf="@id/sort_by_label"
app:layout_constraintTop_toBottomOf="@id/search_bar" app:layout_constraintTop_toBottomOf="@id/top_bar"
app:drawableEndCompat="@drawable/spinner" /> app:drawableEndCompat="@drawable/spinner" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View file

@ -56,7 +56,7 @@
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:layout_marginEnd="10dp" android:layout_marginEnd="10dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:text="Contacts" android:text="@{viewModel.title, default=`Title`}"
android:textColor="#FFFFFF" android:textColor="#FFFFFF"
android:textSize="20sp" android:textSize="20sp"
android:textStyle="bold" android:textStyle="bold"
@ -98,8 +98,7 @@
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textColorHint="@color/gray_6" android:textColorHint="@color/gray_6"
android:hint="Search contacts" app:hintEnabled="false"
app:hintEnabled="@{viewModel.searchFilter.length() == 0}"
app:hintAnimationEnabled="false" app:hintAnimationEnabled="false"
app:hintTextColor="@color/gray_6" app:hintTextColor="@color/gray_6"
app:boxStrokeWidth="0dp" app:boxStrokeWidth="0dp"