Add ability to share profile by QR code
This commit is contained in:
parent
5b278f704c
commit
e8d084b855
|
@ -39,7 +39,7 @@ We do not forget all translators, for their work of translating Element into man
|
||||||
|
|
||||||
Feel free to add your name below, when you contribute to the project!
|
Feel free to add your name below, when you contribute to the project!
|
||||||
|
|
||||||
Name | Matrix ID | GitHub
|
Name | Matrix ID | GitHub
|
||||||
--------|---------------------|--------------------------------------
|
----------|-----------------------------|--------------------------------------
|
||||||
gjpower | @gjpower:matrix.org | [gjpower](https://github.com/gjpower)
|
gjpower | @gjpower:matrix.org | [gjpower](https://github.com/gjpower)
|
||||||
|
TR_SLimey | @tr_slimey:an-atom-in.space | [TR-SLimey](https://github.com/TR-SLimey)
|
||||||
|
|
|
@ -2,7 +2,7 @@ Changes in Element 1.0.11 (2020-XX-XX)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
Features ✨:
|
Features ✨:
|
||||||
-
|
- Create DMs with users by scanning their QR code (#2025)
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- New room creation tile with quick action (#2346)
|
- New room creation tile with quick action (#2346)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
|
@ -37,6 +38,8 @@ import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.SimpleFragmentActivity
|
import im.vector.app.core.platform.SimpleFragmentActivity
|
||||||
import im.vector.app.core.platform.WaitingViewData
|
import im.vector.app.core.platform.WaitingViewData
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH
|
import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH
|
||||||
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
|
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS
|
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS
|
||||||
import im.vector.app.core.utils.allGranted
|
import im.vector.app.core.utils.allGranted
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
|
@ -72,35 +75,45 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
toolbar.visibility = View.GONE
|
toolbar.visibility = View.GONE
|
||||||
sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java)
|
||||||
sharedActionViewModel
|
if (intent?.getBooleanExtra(BY_QR_CODE, false)!!) {
|
||||||
.observe()
|
if (isFirstCreation()) { openAddByQrCode() }
|
||||||
.subscribe { sharedAction ->
|
} else {
|
||||||
when (sharedAction) {
|
sharedActionViewModel
|
||||||
UserDirectorySharedAction.OpenUsersDirectory ->
|
.observe()
|
||||||
addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java)
|
.subscribe { sharedAction ->
|
||||||
UserDirectorySharedAction.Close -> finish()
|
when (sharedAction) {
|
||||||
UserDirectorySharedAction.GoBack -> onBackPressed()
|
UserDirectorySharedAction.OpenUsersDirectory ->
|
||||||
is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction)
|
addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java)
|
||||||
UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook()
|
UserDirectorySharedAction.Close -> finish()
|
||||||
}.exhaustive
|
UserDirectorySharedAction.GoBack -> onBackPressed()
|
||||||
}
|
is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction)
|
||||||
.disposeOnDestroy()
|
UserDirectorySharedAction.OpenPhoneBook -> openPhoneBook()
|
||||||
if (isFirstCreation()) {
|
}.exhaustive
|
||||||
addFragment(
|
}
|
||||||
R.id.container,
|
.disposeOnDestroy()
|
||||||
KnownUsersFragment::class.java,
|
if (isFirstCreation()) {
|
||||||
KnownUsersFragmentArgs(
|
addFragment(
|
||||||
title = getString(R.string.fab_menu_create_chat),
|
R.id.container,
|
||||||
menuResId = R.menu.vector_create_direct_room,
|
KnownUsersFragment::class.java,
|
||||||
isCreatingRoom = true
|
KnownUsersFragmentArgs(
|
||||||
)
|
title = getString(R.string.fab_menu_create_chat),
|
||||||
)
|
menuResId = R.menu.vector_create_direct_room,
|
||||||
|
isCreatingRoom = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) {
|
viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) {
|
||||||
renderCreateAndInviteState(it)
|
renderCreateAndInviteState(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openAddByQrCode() {
|
||||||
|
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA, 0)) {
|
||||||
|
addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun openPhoneBook() {
|
private fun openPhoneBook() {
|
||||||
// Check permission first
|
// Check permission first
|
||||||
if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH,
|
if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH,
|
||||||
|
@ -116,6 +129,13 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
||||||
if (allGranted(grantResults)) {
|
if (allGranted(grantResults)) {
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
|
if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
|
||||||
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) }
|
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) }
|
||||||
|
} else if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) {
|
||||||
|
addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show()
|
||||||
|
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && intent?.getBooleanExtra(BY_QR_CODE, false)!!) {
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,8 +198,12 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getIntent(context: Context): Intent {
|
private const val BY_QR_CODE = "BY_QR_CODE"
|
||||||
return Intent(context, CreateDirectRoomActivity::class.java)
|
|
||||||
|
fun getIntent(context: Context, byQrCode: Boolean = false): Intent {
|
||||||
|
return Intent(context, CreateDirectRoomActivity::class.java).apply {
|
||||||
|
putExtra(BY_QR_CODE, byQrCode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.createdirect
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.airbnb.mvrx.activityViewModel
|
||||||
|
import com.google.zxing.Result
|
||||||
|
import com.google.zxing.ResultMetadataType
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.features.userdirectory.PendingInvitee
|
||||||
|
import kotlinx.android.synthetic.main.fragment_qr_code_scanner.*
|
||||||
|
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||||
|
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||||
|
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||||
|
import org.matrix.android.sdk.api.session.user.model.User
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler {
|
||||||
|
|
||||||
|
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_qr_code_scanner
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
// Register ourselves as a handler for scan results.
|
||||||
|
scannerView.setResultHandler(null)
|
||||||
|
// Start camera on resume
|
||||||
|
scannerView.startCamera()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
// Stop camera on pause
|
||||||
|
scannerView.stopCamera()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from https://github.com/markusfisch/BinaryEye/blob/
|
||||||
|
// 9d57889b810dcaa1a91d7278fc45c262afba1284/app/src/main/kotlin/de/markusfisch/android/binaryeye/activity/CameraActivity.kt#L434
|
||||||
|
private fun getRawBytes(result: Result): ByteArray? {
|
||||||
|
val metadata = result.resultMetadata ?: return null
|
||||||
|
val segments = metadata[ResultMetadataType.BYTE_SEGMENTS] ?: return null
|
||||||
|
var bytes = ByteArray(0)
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
for (seg in segments as Iterable<ByteArray>) {
|
||||||
|
bytes += seg
|
||||||
|
}
|
||||||
|
// byte segments can never be shorter than the text.
|
||||||
|
// Zxing cuts off content prefixes like "WIFI:"
|
||||||
|
return if (bytes.size >= result.text.length) bytes else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addByQrCode(value: String) {
|
||||||
|
val mxid = (PermalinkParser.parse(value) as? PermalinkData.UserLink)?.userId
|
||||||
|
|
||||||
|
if (mxid === null) {
|
||||||
|
Toast.makeText(requireContext(), R.string.invalid_qr_code_uri, Toast.LENGTH_SHORT).show()
|
||||||
|
requireActivity().finish()
|
||||||
|
} else {
|
||||||
|
val existingDm = viewModel.session.getExistingDirectRoomWithUser(mxid)
|
||||||
|
|
||||||
|
if (existingDm === null) {
|
||||||
|
// The following assumes MXIDs are case insensitive
|
||||||
|
if (mxid.equals(other = viewModel.session.myUserId, ignoreCase = true)) {
|
||||||
|
Toast.makeText(requireContext(), R.string.cannot_dm_self, Toast.LENGTH_SHORT).show()
|
||||||
|
requireActivity().finish()
|
||||||
|
} else {
|
||||||
|
// Try to get user from known users and fall back to creating a User object from MXID
|
||||||
|
val qrInvitee = if (viewModel.session.getUser(mxid) != null) viewModel.session.getUser(mxid)!! else User(mxid, null, null)
|
||||||
|
|
||||||
|
viewModel.handle(
|
||||||
|
CreateDirectRoomAction.CreateRoomAndInviteSelectedUsers(setOf(PendingInvitee.UserPendingInvitee(qrInvitee)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigator.openRoom(requireContext(), existingDm, null, false)
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleResult(result: Result?) {
|
||||||
|
if (result === null) {
|
||||||
|
Toast.makeText(requireContext(), R.string.qr_code_not_scanned, Toast.LENGTH_SHORT).show()
|
||||||
|
requireActivity().finish()
|
||||||
|
} else {
|
||||||
|
val rawBytes = getRawBytes(result)
|
||||||
|
val rawBytesStr = rawBytes?.toString(Charsets.ISO_8859_1)
|
||||||
|
val value = rawBytesStr ?: result.text
|
||||||
|
addByQrCode(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ import org.matrix.android.sdk.rx.rx
|
||||||
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||||
initialState: CreateDirectRoomViewState,
|
initialState: CreateDirectRoomViewState,
|
||||||
private val rawService: RawService,
|
private val rawService: RawService,
|
||||||
private val session: Session)
|
val session: Session)
|
||||||
: VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, CreateDirectRoomViewEvents>(initialState) {
|
: VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, CreateDirectRoomViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
|
|
|
@ -22,7 +22,7 @@ import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.app.features.home.room.list.widget.FabMenuView
|
import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_room_filter_footer)
|
@EpoxyModelClass(layout = R.layout.item_room_filter_footer)
|
||||||
abstract class FilteredRoomFooterItem : VectorEpoxyModel<FilteredRoomFooterItem.Holder>() {
|
abstract class FilteredRoomFooterItem : VectorEpoxyModel<FilteredRoomFooterItem.Holder>() {
|
||||||
|
@ -46,7 +46,7 @@ abstract class FilteredRoomFooterItem : VectorEpoxyModel<FilteredRoomFooterItem.
|
||||||
val openRoomDirectory by bind<Button>(R.id.roomFilterFooterOpenRoomDirectory)
|
val openRoomDirectory by bind<Button>(R.id.roomFilterFooterOpenRoomDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FilteredRoomFooterItemListener : FabMenuView.Listener {
|
interface FilteredRoomFooterItemListener : NotifsFabMenuView.Listener {
|
||||||
fun createRoom(initialName: String)
|
fun createRoom(initialName: String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.list.widget.FabMenuView
|
import im.vector.app.features.home.room.list.widget.DmsFabMenuView
|
||||||
|
import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||||
|
@ -66,8 +67,7 @@ class RoomListFragment @Inject constructor(
|
||||||
val roomListViewModelFactory: RoomListViewModel.Factory,
|
val roomListViewModelFactory: RoomListViewModel.Factory,
|
||||||
private val notificationDrawerManager: NotificationDrawerManager,
|
private val notificationDrawerManager: NotificationDrawerManager,
|
||||||
private val sharedViewPool: RecyclerView.RecycledViewPool
|
private val sharedViewPool: RecyclerView.RecycledViewPool
|
||||||
|
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, DmsFabMenuView.Listener, NotifsFabMenuView.Listener {
|
||||||
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
|
|
||||||
|
|
||||||
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
||||||
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
|
@ -111,6 +111,7 @@ class RoomListFragment @Inject constructor(
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createDmFabMenu.listener = this
|
||||||
createChatFabMenu.listener = this
|
createChatFabMenu.listener = this
|
||||||
|
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
|
@ -129,6 +130,7 @@ class RoomListFragment @Inject constructor(
|
||||||
roomListView.cleanup()
|
roomListView.cleanup()
|
||||||
roomController.listener = null
|
roomController.listener = null
|
||||||
stateRestorer.clear()
|
stateRestorer.clear()
|
||||||
|
createDmFabMenu.listener = null
|
||||||
createChatFabMenu.listener = null
|
createChatFabMenu.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -140,33 +142,32 @@ class RoomListFragment @Inject constructor(
|
||||||
private fun setupCreateRoomButton() {
|
private fun setupCreateRoomButton() {
|
||||||
when (roomListParams.displayMode) {
|
when (roomListParams.displayMode) {
|
||||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true
|
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true
|
||||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
|
RoomListDisplayMode.PEOPLE -> createDmFabMenu.isVisible = true
|
||||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
|
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
|
||||||
else -> Unit // No button in this mode
|
else -> Unit // No button in this mode
|
||||||
}
|
}
|
||||||
|
|
||||||
createChatRoomButton.debouncedClicks {
|
|
||||||
createDirectChat()
|
|
||||||
}
|
|
||||||
createGroupRoomButton.debouncedClicks {
|
createGroupRoomButton.debouncedClicks {
|
||||||
openRoomDirectory()
|
openRoomDirectory()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide FAB when list is scrolling
|
// Hide FABs when list is scrolling
|
||||||
roomListView.addOnScrollListener(
|
roomListView.addOnScrollListener(
|
||||||
object : RecyclerView.OnScrollListener() {
|
object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
createDmFabMenu.removeCallbacks(showFabRunnable)
|
||||||
createChatFabMenu.removeCallbacks(showFabRunnable)
|
createChatFabMenu.removeCallbacks(showFabRunnable)
|
||||||
|
|
||||||
when (newState) {
|
when (newState) {
|
||||||
RecyclerView.SCROLL_STATE_IDLE -> {
|
RecyclerView.SCROLL_STATE_IDLE -> {
|
||||||
|
createDmFabMenu.postDelayed(showFabRunnable, 250)
|
||||||
createChatFabMenu.postDelayed(showFabRunnable, 250)
|
createChatFabMenu.postDelayed(showFabRunnable, 250)
|
||||||
}
|
}
|
||||||
RecyclerView.SCROLL_STATE_DRAGGING,
|
RecyclerView.SCROLL_STATE_DRAGGING,
|
||||||
RecyclerView.SCROLL_STATE_SETTLING -> {
|
RecyclerView.SCROLL_STATE_SETTLING -> {
|
||||||
when (roomListParams.displayMode) {
|
when (roomListParams.displayMode) {
|
||||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide()
|
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide()
|
||||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide()
|
RoomListDisplayMode.PEOPLE -> createDmFabMenu.hide()
|
||||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
|
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
@ -191,6 +192,10 @@ class RoomListFragment @Inject constructor(
|
||||||
navigator.openCreateDirectRoom(requireActivity())
|
navigator.openCreateDirectRoom(requireActivity())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createDirectChatByQrCode() {
|
||||||
|
navigator.openCreateDirectRoom(requireContext(), true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
val layoutManager = LinearLayoutManager(context)
|
val layoutManager = LinearLayoutManager(context)
|
||||||
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||||
|
@ -209,7 +214,7 @@ class RoomListFragment @Inject constructor(
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
when (roomListParams.displayMode) {
|
when (roomListParams.displayMode) {
|
||||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show()
|
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show()
|
||||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.show()
|
RoomListDisplayMode.PEOPLE -> createDmFabMenu.show()
|
||||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
|
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
@ -338,6 +343,9 @@ class RoomListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||||
|
if (createDmFabMenu.onBackPressed()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if (createChatFabMenu.onBackPressed()) {
|
if (createChatFabMenu.onBackPressed()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.widget
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import im.vector.app.R
|
||||||
|
import kotlinx.android.synthetic.main.motion_dms_fab_menu_merge.view.*
|
||||||
|
|
||||||
|
class DmsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
inflate(context, R.layout.motion_dms_fab_menu_merge, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinishInflate() {
|
||||||
|
super.onFinishInflate()
|
||||||
|
|
||||||
|
listOf(createDmByMxid, createDmByMxidLabel)
|
||||||
|
.forEach {
|
||||||
|
it.setOnClickListener {
|
||||||
|
closeFabMenu()
|
||||||
|
listener?.createDirectChat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listOf(createDmByQrCode, createDmByQrCodeLabel)
|
||||||
|
.forEach {
|
||||||
|
it.setOnClickListener {
|
||||||
|
closeFabMenu()
|
||||||
|
listener?.createDirectChatByQrCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dmsCreateRoomTouchGuard.setOnClickListener {
|
||||||
|
closeFabMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transitionToEnd() {
|
||||||
|
super.transitionToEnd()
|
||||||
|
|
||||||
|
dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transitionToStart() {
|
||||||
|
super.transitionToStart()
|
||||||
|
|
||||||
|
dmsCreateRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() {
|
||||||
|
isVisible = true
|
||||||
|
dmsCreateRoomButton.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide() {
|
||||||
|
dmsCreateRoomButton.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
|
||||||
|
override fun onHidden(fab: FloatingActionButton?) {
|
||||||
|
super.onHidden(fab)
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun closeFabMenu() {
|
||||||
|
transitionToStart()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBackPressed(): Boolean {
|
||||||
|
if (currentState == R.id.constraint_set_fab_menu_open) {
|
||||||
|
closeFabMenu()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun createDirectChat()
|
||||||
|
fun createDirectChatByQrCode()
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,15 +22,15 @@ import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import kotlinx.android.synthetic.main.motion_fab_menu_merge.view.*
|
import kotlinx.android.synthetic.main.motion_notifs_fab_menu_merge.view.*
|
||||||
|
|
||||||
class FabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) {
|
defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
var listener: Listener? = null
|
var listener: Listener? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.motion_fab_menu_merge, this)
|
inflate(context, R.layout.motion_notifs_fab_menu_merge, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinishInflate() {
|
override fun onFinishInflate() {
|
|
@ -203,8 +203,8 @@ class DefaultNavigator @Inject constructor(
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openCreateDirectRoom(context: Context) {
|
override fun openCreateDirectRoom(context: Context, byQrCode: Boolean) {
|
||||||
val intent = CreateDirectRoomActivity.getIntent(context)
|
val intent = CreateDirectRoomActivity.getIntent(context, byQrCode)
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ interface Navigator {
|
||||||
|
|
||||||
fun openCreateRoom(context: Context, initialName: String = "")
|
fun openCreateRoom(context: Context, initialName: String = "")
|
||||||
|
|
||||||
fun openCreateDirectRoom(context: Context)
|
fun openCreateDirectRoom(context: Context, byQrCode: Boolean = false)
|
||||||
|
|
||||||
fun openInviteUsersToRoom(context: Context, roomId: String)
|
fun openInviteUsersToRoom(context: Context, roomId: String)
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
|
||||||
holder.avatarView.isInvisible = directoryAvatarUrl.isNullOrBlank() && includeAllNetworks
|
holder.avatarView.isInvisible = directoryAvatarUrl.isNullOrBlank() && includeAllNetworks
|
||||||
|
|
||||||
holder.nameView.text = directoryName
|
holder.nameView.text = directoryName
|
||||||
holder.descritionView.setTextOrHide(directoryDescription)
|
holder.descriptionView.setTextOrHide(directoryDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
@ -70,6 +70,6 @@ abstract class RoomDirectoryItem : VectorEpoxyModel<RoomDirectoryItem.Holder>()
|
||||||
|
|
||||||
val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
|
val avatarView by bind<ImageView>(R.id.itemRoomDirectoryAvatar)
|
||||||
val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
|
val nameView by bind<TextView>(R.id.itemRoomDirectoryName)
|
||||||
val descritionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
|
val descriptionView by bind<TextView>(R.id.itemRoomDirectoryDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,12 +294,20 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleShareRoomMemberProfile(permalink: String) {
|
private fun handleShareRoomMemberProfile(permalink: String) {
|
||||||
startSharePlainTextIntent(
|
val view = layoutInflater.inflate(R.layout.dialog_share_qr_code, null)
|
||||||
fragment = this,
|
val qrCode = view.findViewById<im.vector.app.core.ui.views.QrCodeImageView>(R.id.itemShareQrCodeImage)
|
||||||
activityResultLauncher = null,
|
qrCode.setData(permalink)
|
||||||
chooserTitle = null,
|
AlertDialog.Builder(requireContext())
|
||||||
text = permalink
|
.setView(view)
|
||||||
)
|
.setNeutralButton(R.string.ok, null)
|
||||||
|
.setPositiveButton(R.string.share_by_text) { _, _ ->
|
||||||
|
startSharePlainTextIntent(
|
||||||
|
fragment = this,
|
||||||
|
activityResultLauncher = null,
|
||||||
|
chooserTitle = null,
|
||||||
|
text = permalink
|
||||||
|
)
|
||||||
|
}.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onAvatarClicked(view: View, userMatrixItem: MatrixItem) {
|
private fun onAvatarClicked(view: View, userMatrixItem: MatrixItem) {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="37dp"
|
||||||
|
android:height="36dp"
|
||||||
|
android:viewportWidth="37"
|
||||||
|
android:viewportHeight="36">
|
||||||
|
<path
|
||||||
|
android:pathData="M17.5911,26.2922C15.9951,27.3704 14.0711,28 12,28C9.7488,28 7.6713,27.2561 6,26.0007C3.5711,24.1763 2,21.2716 2,18C2,12.4772 6.4771,8 12,8C17.5228,8 22,12.4772 22,18C22,21.4518 20.2511,24.4951 17.5911,26.2922ZM12,18.5C13.6569,18.5 15,17.0449 15,15.25C15,13.4551 13.6569,12 12,12C10.3431,12 9,13.4551 9,15.25C9,17.0449 10.3431,18.5 12,18.5ZM12,26C14.162,26 16.1236,25.1424 17.5634,23.7488C16.673,21.5506 14.5176,20 12,20C9.4824,20 7.327,21.5506 6.4366,23.7488C7.8763,25.1424 9.838,26 12,26Z"
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M17.5911,26.2922C15.9951,27.3704 14.0711,28 12,28C9.7488,28 7.6713,27.2561 6,26.0007C3.5711,24.1763 2,21.2716 2,18C2,12.4772 6.4771,8 12,8C17.5228,8 22,12.4772 22,18C22,21.4518 20.2511,24.4951 17.5911,26.2922ZM12,18.5C13.6569,18.5 15,17.0449 15,15.25C15,13.4551 13.6569,12 12,12C10.3431,12 9,13.4551 9,15.25C9,17.0449 10.3431,18.5 12,18.5ZM12,26C14.162,26 16.1236,25.1424 17.5634,23.7488C16.673,21.5506 14.5176,20 12,20C9.4824,20 7.327,21.5506 6.4366,23.7488C7.8763,25.1424 9.838,26 12,26Z"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M17.5911,26.2922L16.4715,24.6349L17.5911,26.2922ZM6,26.0007L4.7989,27.5999L4.7989,27.5999L6,26.0007ZM17.5634,23.7488L18.9544,25.1859L19.9234,24.2479L19.4171,22.998L17.5634,23.7488ZM6.4366,23.7488L4.5829,22.998L4.0766,24.2479L5.0456,25.1859L6.4366,23.7488ZM12,30C14.4825,30 16.7945,29.244 18.7107,27.9494L16.4715,24.6349C15.1957,25.4968 13.6596,26 12,26V30ZM4.7989,27.5999C6.8046,29.1065 9.3008,30 12,30V26C10.1967,26 8.538,25.4058 7.2011,24.4016L4.7989,27.5999ZM0,18C0,21.9273 1.8887,25.414 4.7989,27.5999L7.2011,24.4016C5.2535,22.9387 4,20.616 4,18H0ZM12,6C5.3726,6 0,11.3726 0,18H4C4,13.5817 7.5817,10 12,10V6ZM24,18C24,11.3726 18.6274,6 12,6V10C16.4183,10 20,13.5817 20,18H24ZM18.7107,27.9494C21.8977,25.7963 24,22.144 24,18H20C20,20.7596 18.6045,23.1939 16.4715,24.6349L18.7107,27.9494ZM13,15.25C13,16.0941 12.4046,16.5 12,16.5V20.5C14.9091,20.5 17,17.9958 17,15.25H13ZM12,14C12.4046,14 13,14.4059 13,15.25H17C17,12.5042 14.9091,10 12,10V14ZM11,15.25C11,14.4059 11.5954,14 12,14V10C9.0909,10 7,12.5042 7,15.25H11ZM12,16.5C11.5954,16.5 11,16.0941 11,15.25H7C7,17.9958 9.0909,20.5 12,20.5V16.5ZM16.1724,22.3118C15.0906,23.3588 13.6223,24 12,24V28C14.7017,28 17.1567,26.926 18.9544,25.1859L16.1724,22.3118ZM12,22C13.6752,22 15.1146,23.0305 15.7097,24.4996L19.4171,22.998C18.2314,20.0707 15.3599,18 12,18V22ZM8.2903,24.4996C8.8854,23.0305 10.3248,22 12,22V18C8.6401,18 5.7686,20.0707 4.5829,22.998L8.2903,24.4996ZM12,24C10.3777,24 8.9094,23.3588 7.8276,22.3118L5.0456,25.1859C6.8433,26.926 9.2983,28 12,28V24Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</group>
|
||||||
|
<path
|
||||||
|
android:pathData="M27,18H35"
|
||||||
|
android:strokeWidth="2.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M31,14L31,22"
|
||||||
|
android:strokeWidth="2.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="37dp"
|
||||||
|
android:height="36dp"
|
||||||
|
android:viewportWidth="37"
|
||||||
|
android:viewportHeight="36">
|
||||||
|
<path
|
||||||
|
android:pathData="M17.5911,26.2922C15.9951,27.3704 14.0711,28 12,28C9.7488,28 7.6713,27.2561 6,26.0007C3.5711,24.1763 2,21.2716 2,18C2,12.4772 6.4771,8 12,8C17.5228,8 22,12.4772 22,18C22,21.4518 20.2511,24.4951 17.5911,26.2922ZM12,18.5C13.6569,18.5 15,17.0449 15,15.25C15,13.4551 13.6569,12 12,12C10.3431,12 9,13.4551 9,15.25C9,17.0449 10.3431,18.5 12,18.5ZM12,26C14.162,26 16.1236,25.1424 17.5634,23.7488C16.673,21.5506 14.5176,20 12,20C9.4824,20 7.327,21.5506 6.4366,23.7488C7.8763,25.1424 9.838,26 12,26Z"
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M17.5911,26.2922C15.9951,27.3704 14.0711,28 12,28C9.7488,28 7.6713,27.2561 6,26.0007C3.5711,24.1763 2,21.2716 2,18C2,12.4772 6.4771,8 12,8C17.5228,8 22,12.4772 22,18C22,21.4518 20.2511,24.4951 17.5911,26.2922ZM12,18.5C13.6569,18.5 15,17.0449 15,15.25C15,13.4551 13.6569,12 12,12C10.3431,12 9,13.4551 9,15.25C9,17.0449 10.3431,18.5 12,18.5ZM12,26C14.162,26 16.1236,25.1424 17.5634,23.7488C16.673,21.5506 14.5176,20 12,20C9.4824,20 7.327,21.5506 6.4366,23.7488C7.8763,25.1424 9.838,26 12,26Z"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M17.5911,26.2922L16.4715,24.6349L17.5911,26.2922ZM6,26.0007L4.7989,27.5999L4.7989,27.5999L6,26.0007ZM17.5634,23.7488L18.9544,25.1859L19.9234,24.2479L19.4171,22.998L17.5634,23.7488ZM6.4366,23.7488L4.5829,22.998L4.0766,24.2479L5.0456,25.1859L6.4366,23.7488ZM12,30C14.4825,30 16.7945,29.244 18.7107,27.9494L16.4715,24.6349C15.1957,25.4968 13.6596,26 12,26V30ZM4.7989,27.5999C6.8046,29.1065 9.3008,30 12,30V26C10.1967,26 8.538,25.4058 7.2011,24.4016L4.7989,27.5999ZM0,18C0,21.9273 1.8887,25.414 4.7989,27.5999L7.2011,24.4016C5.2535,22.9387 4,20.616 4,18H0ZM12,6C5.3726,6 0,11.3726 0,18H4C4,13.5817 7.5817,10 12,10V6ZM24,18C24,11.3726 18.6274,6 12,6V10C16.4183,10 20,13.5817 20,18H24ZM18.7107,27.9494C21.8977,25.7963 24,22.144 24,18H20C20,20.7596 18.6045,23.1939 16.4715,24.6349L18.7107,27.9494ZM13,15.25C13,16.0941 12.4046,16.5 12,16.5V20.5C14.9091,20.5 17,17.9958 17,15.25H13ZM12,14C12.4046,14 13,14.4059 13,15.25H17C17,12.5042 14.9091,10 12,10V14ZM11,15.25C11,14.4059 11.5954,14 12,14V10C9.0909,10 7,12.5042 7,15.25H11ZM12,16.5C11.5954,16.5 11,16.0941 11,15.25H7C7,17.9958 9.0909,20.5 12,20.5V16.5ZM16.1724,22.3118C15.0906,23.3588 13.6223,24 12,24V28C14.7017,28 17.1567,26.926 18.9544,25.1859L16.1724,22.3118ZM12,22C13.6752,22 15.1146,23.0305 15.7097,24.4996L19.4171,22.998C18.2314,20.0707 15.3599,18 12,18V22ZM8.2903,24.4996C8.8854,23.0305 10.3248,22 12,22V18C8.6401,18 5.7686,20.0707 4.5829,22.998L8.2903,24.4996ZM12,24C10.3777,24 8.9094,23.3588 7.8276,22.3118L5.0456,25.1859C6.8433,26.926 9.2983,28 12,28V24Z"
|
||||||
|
android:fillColor="#000000"/>
|
||||||
|
</group>
|
||||||
|
<path
|
||||||
|
android:pathData="M27,18H35"
|
||||||
|
android:strokeWidth="2.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M31,14L31,22"
|
||||||
|
android:strokeWidth="2.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<im.vector.app.core.ui.views.QrCodeImageView
|
||||||
|
android:id="@+id/itemShareQrCodeImage"
|
||||||
|
android:layout_width="300dp"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:contentDescription="@string/a11y_qr_code_for_verification"
|
||||||
|
tools:src="@color/riotx_header_panel_background_black" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -14,29 +14,25 @@
|
||||||
android:overScrollMode="always"
|
android:overScrollMode="always"
|
||||||
tools:listitem="@layout/item_room" />
|
tools:listitem="@layout/item_room" />
|
||||||
|
|
||||||
<im.vector.app.features.home.room.list.widget.FabMenuView
|
<im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
||||||
android:id="@+id/createChatFabMenu"
|
android:id="@+id/createChatFabMenu"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layoutDescription="@xml/motion_scene_fab_menu"
|
app:layoutDescription="@xml/motion_scene_notifs_fab_menu"
|
||||||
tools:showPaths="true"
|
tools:showPaths="true"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<im.vector.app.features.home.room.list.widget.DmsFabMenuView
|
||||||
android:id="@+id/createChatRoomButton"
|
android:id="@+id/createDmFabMenu"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:accessibilityTraversalBefore="@+id/roomListView"
|
|
||||||
android:contentDescription="@string/a11y_create_direct_message"
|
android:contentDescription="@string/a11y_create_direct_message"
|
||||||
android:scaleType="center"
|
|
||||||
android:src="@drawable/ic_fab_add_chat"
|
android:src="@drawable/ic_fab_add_chat"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:maxImageSize="34dp"
|
app:maxImageSize="34dp"
|
||||||
tools:layout_marginEnd="80dp"
|
app:layoutDescription="@xml/motion_scene_dms_fab_menu"
|
||||||
|
tools:showPaths="true"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutDescription="@xml/motion_scene_dms_fab_menu"
|
||||||
|
tools:motionProgress="0.65"
|
||||||
|
tools:parentTag="androidx.constraintlayout.motion.widget.MotionLayout"
|
||||||
|
tools:showPaths="true">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/dmsCreateRoomTouchGuard"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_touch_guard_bg"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/a11y_create_menu_close"
|
||||||
|
android:focusable="true" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 2 -->
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/createDmByQrCode"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:accessibilityTraversalBefore="@+id/roomListView"
|
||||||
|
android:contentDescription="@string/a11y_create_direct_message_by_qr_code"
|
||||||
|
android:src="@drawable/ic_fab_add_by_qr_code"
|
||||||
|
app:backgroundTint="#FFFFFF"
|
||||||
|
app:fabCustomSize="48dp"
|
||||||
|
app:maxImageSize="26dp"
|
||||||
|
app:tint="@color/black" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/createDmByQrCodeLabel"
|
||||||
|
style="@style/VectorLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:text="@string/add_by_qr_code" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 1 -->
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/createDmByMxid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:accessibilityTraversalBefore="@+id/createDmByQrCode"
|
||||||
|
android:contentDescription="@string/a11y_create_direct_message_by_mxid"
|
||||||
|
android:src="@drawable/ic_fab_add_by_mxid"
|
||||||
|
app:backgroundTint="#FFFFFF"
|
||||||
|
app:fabCustomSize="48dp"
|
||||||
|
app:maxImageSize="29dp"
|
||||||
|
app:tint="@color/black" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/createDmByMxidLabel"
|
||||||
|
style="@style/VectorLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:text="@string/add_by_matrix_id" />
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/dmsCreateRoomButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:accessibilityTraversalBefore="@+id/createDmByMxid"
|
||||||
|
android:contentDescription="@string/a11y_create_menu_open"
|
||||||
|
android:src="@drawable/ic_fab_add"
|
||||||
|
app:maxImageSize="14dp" />
|
||||||
|
|
||||||
|
</merge>
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layoutDescription="@xml/motion_scene_fab_menu"
|
app:layoutDescription="@xml/motion_scene_notifs_fab_menu"
|
||||||
tools:motionProgress="0.65"
|
tools:motionProgress="0.65"
|
||||||
tools:parentTag="androidx.constraintlayout.motion.widget.MotionLayout"
|
tools:parentTag="androidx.constraintlayout.motion.widget.MotionLayout"
|
||||||
tools:showPaths="true">
|
tools:showPaths="true">
|
|
@ -1761,6 +1761,7 @@
|
||||||
<string name="link_copied_to_clipboard">Link copied to clipboard</string>
|
<string name="link_copied_to_clipboard">Link copied to clipboard</string>
|
||||||
|
|
||||||
<string name="add_by_matrix_id">Add by matrix ID</string>
|
<string name="add_by_matrix_id">Add by matrix ID</string>
|
||||||
|
<string name="add_by_qr_code">Add by QR code</string>
|
||||||
<string name="creating_direct_room">"Creating room…"</string>
|
<string name="creating_direct_room">"Creating room…"</string>
|
||||||
<string name="direct_room_no_known_users">"No result found, use Add by matrix ID to search on server."</string>
|
<string name="direct_room_no_known_users">"No result found, use Add by matrix ID to search on server."</string>
|
||||||
<string name="direct_room_start_search">"Start typing to get results"</string>
|
<string name="direct_room_start_search">"Start typing to get results"</string>
|
||||||
|
@ -1828,6 +1829,8 @@
|
||||||
<string name="a11y_create_menu_open">Open the create room menu</string>
|
<string name="a11y_create_menu_open">Open the create room menu</string>
|
||||||
<string name="a11y_create_menu_close">Close the create room menu…</string>
|
<string name="a11y_create_menu_close">Close the create room menu…</string>
|
||||||
<string name="a11y_create_direct_message">Create a new direct conversation</string>
|
<string name="a11y_create_direct_message">Create a new direct conversation</string>
|
||||||
|
<string name="a11y_create_direct_message_by_mxid">Create a new direct conversation by Matrix ID</string>
|
||||||
|
<string name="a11y_create_direct_message_by_qr_code">Create a new direct conversation by scanning a QR code</string>
|
||||||
<string name="a11y_create_room">Create a new room</string>
|
<string name="a11y_create_room">Create a new room</string>
|
||||||
<string name="a11y_close_keys_backup_banner">Close keys backup banner</string>
|
<string name="a11y_close_keys_backup_banner">Close keys backup banner</string>
|
||||||
<string name="a11y_show_password">Show password</string>
|
<string name="a11y_show_password">Show password</string>
|
||||||
|
@ -2674,4 +2677,10 @@
|
||||||
<string name="warning_room_not_created_yet">The room is not yet created. Cancel the room creation?</string>
|
<string name="warning_room_not_created_yet">The room is not yet created. Cancel the room creation?</string>
|
||||||
<string name="warning_unsaved_change">There are unsaved changes. Discard the changes?</string>
|
<string name="warning_unsaved_change">There are unsaved changes. Discard the changes?</string>
|
||||||
<string name="warning_unsaved_change_discard">Discard changes</string>
|
<string name="warning_unsaved_change_discard">Discard changes</string>
|
||||||
|
|
||||||
|
<!-- Add by QR code -->
|
||||||
|
<string name="share_by_text">Share by text</string>
|
||||||
|
<string name="cannot_dm_self">Cannot DM yourself!</string>
|
||||||
|
<string name="invalid_qr_code_uri">Invalid QR code (Invalid URI)!</string>
|
||||||
|
<string name="qr_code_not_scanned">QR code not scanned!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:motion="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<!-- Click on main FAB: toggle -->
|
||||||
|
<Transition
|
||||||
|
motion:constraintSetEnd="@+id/constraint_set_fab_menu_open"
|
||||||
|
motion:constraintSetStart="@+id/constraint_set_fab_menu_close"
|
||||||
|
motion:duration="300"
|
||||||
|
motion:motionInterpolator="easeInOut">
|
||||||
|
|
||||||
|
<OnClick
|
||||||
|
motion:clickAction="toggle"
|
||||||
|
motion:targetId="@+id/dmsCreateRoomButton" />
|
||||||
|
|
||||||
|
<KeyFrameSet>
|
||||||
|
|
||||||
|
<!-- First icon goes up quickly to let room for other-->
|
||||||
|
<KeyPosition
|
||||||
|
motion:framePosition="50"
|
||||||
|
motion:keyPositionType="deltaRelative"
|
||||||
|
motion:motionTarget="@id/createDmByQrCode"
|
||||||
|
motion:percentX="0.8"
|
||||||
|
motion:percentY="0.8" />
|
||||||
|
<KeyPosition
|
||||||
|
motion:framePosition="50"
|
||||||
|
motion:keyPositionType="deltaRelative"
|
||||||
|
motion:motionTarget="@id/createDmByQrCodeLabel"
|
||||||
|
motion:percentX="0.9"
|
||||||
|
motion:percentY="0.8" />
|
||||||
|
|
||||||
|
<!-- Delay apparition of labels-->
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0.4"
|
||||||
|
motion:framePosition="80"
|
||||||
|
motion:motionTarget="@id/createDmByMxidLabel" />
|
||||||
|
<KeyAttribute
|
||||||
|
android:alpha="0.4"
|
||||||
|
motion:framePosition="80"
|
||||||
|
motion:motionTarget="@id/createDmByQrCodeLabel" />
|
||||||
|
|
||||||
|
</KeyFrameSet>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/constraint_set_fab_menu_close">
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/dmsCreateRoomTouchGuard"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_touch_guard_bg"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 2 -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByQrCode"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:src="@drawable/ic_fab_add_room"
|
||||||
|
android:visibility="invisible"
|
||||||
|
motion:backgroundTint="#FFFFFF"
|
||||||
|
motion:fabCustomSize="48dp"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintStart_toStartOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:maxImageSize="26dp"
|
||||||
|
motion:tint="@color/black" />
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByQrCodeLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/fab_menu_create_room"
|
||||||
|
android:visibility="invisible"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/createDmByQrCode"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/createDmByQrCode"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/createDmByQrCode" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 1 -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByMxid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:src="@drawable/ic_fab_add_chat"
|
||||||
|
android:visibility="invisible"
|
||||||
|
motion:backgroundTint="#FFFFFF"
|
||||||
|
motion:fabCustomSize="48dp"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintStart_toStartOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:maxImageSize="29dp"
|
||||||
|
motion:tint="@color/black" />
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByMxidLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/fab_menu_create_chat"
|
||||||
|
android:visibility="invisible"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/createDmByMxid"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/createDmByMxid"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/createDmByMxid" />
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/dmsCreateRoomButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:src="@drawable/ic_fab_add"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
motion:layout_constraintEnd_toEndOf="parent"
|
||||||
|
motion:maxImageSize="14dp" />
|
||||||
|
|
||||||
|
</ConstraintSet>
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/constraint_set_fab_menu_open">
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/dmsCreateRoomTouchGuard"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_touch_guard_bg" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 2 -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByQrCode"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginBottom="14dp"
|
||||||
|
android:src="@drawable/ic_fab_add_room"
|
||||||
|
motion:backgroundTint="#FFFFFF"
|
||||||
|
motion:fabCustomSize="48dp"
|
||||||
|
motion:layout_constraintBottom_toTopOf="@+id/createDmByMxid"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintStart_toStartOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:maxImageSize="26dp"
|
||||||
|
motion:tint="@color/black" />
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByQrCodeLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/fab_menu_create_room"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/createDmByQrCode"
|
||||||
|
motion:layout_constraintEnd_toStartOf="@+id/createDmByQrCode"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/createDmByQrCode" />
|
||||||
|
|
||||||
|
<!-- Sub menu item 1 -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByMxid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginBottom="25dp"
|
||||||
|
android:src="@drawable/ic_fab_add_chat"
|
||||||
|
motion:backgroundTint="#FFFFFF"
|
||||||
|
motion:fabCustomSize="48dp"
|
||||||
|
motion:layout_constraintBottom_toTopOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintEnd_toEndOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:layout_constraintStart_toStartOf="@+id/dmsCreateRoomButton"
|
||||||
|
motion:maxImageSize="29dp"
|
||||||
|
motion:tint="@color/black" />
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/createDmByMxidLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/fab_menu_create_chat"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="@+id/createDmByMxid"
|
||||||
|
motion:layout_constraintEnd_toStartOf="@+id/createDmByMxid"
|
||||||
|
motion:layout_constraintTop_toTopOf="@+id/createDmByMxid" />
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/dmsCreateRoomButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:rotation="135"
|
||||||
|
android:src="@drawable/ic_fab_add"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
motion:layout_constraintEnd_toEndOf="parent"
|
||||||
|
motion:maxImageSize="14dp" />
|
||||||
|
|
||||||
|
</ConstraintSet>
|
||||||
|
|
||||||
|
</MotionScene>
|
Loading…
Reference in New Issue