From bec71438247f6fdf67b429499d92731ed2264259 Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Thu, 20 Oct 2022 16:13:17 +0100 Subject: [PATCH 01/10] Add new attachments selection dialog --- .../src/main/res/values/strings.xml | 10 ++ .../app/core/di/MavericksViewModelModule.kt | 6 ++ .../core/ui/views/BottomSheetActionButton.kt | 5 + .../features/attachments/AttachmentType.kt | 37 ++++++++ .../AttachmentTypeSelectorBottomSheet.kt | 79 ++++++++++++++++ ...chmentTypeSelectorSharedActionViewModel.kt | 30 ++++++ .../attachments/AttachmentTypeSelectorView.kt | 70 +++++++------- .../AttachmentTypeSelectorViewModel.kt | 59 ++++++++++++ .../features/attachments/AttachmentsHelper.kt | 2 +- .../composer/MessageComposerFragment.kt | 64 ++++++++----- .../bottom_sheet_attachment_type_selector.xml | 92 +++++++++++++++++++ .../AttachmentTypeSelectorViewModelTest.kt | 91 ++++++++++++++++++ .../app/test/fakes/FakeVectorFeatures.kt | 8 ++ 13 files changed, 492 insertions(+), 61 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/attachments/AttachmentType.kt create mode 100644 vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt create mode 100644 vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt create mode 100644 vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml create mode 100644 vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index ea9b4b5999..9ce87199b0 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3205,6 +3205,16 @@ <string name="tooltip_attachment_location">Share location</string> <string name="tooltip_attachment_voice_broadcast">Start a voice broadcast</string> + <string name="attachment_type_selector_gallery">Photo library</string> + <string name="attachment_type_selector_sticker">Stickers</string> + <string name="attachment_type_selector_file">Attachments</string> + <string name="attachment_type_selector_voice_broadcast">Voice broadcast</string> + <string name="attachment_type_selector_poll">Polls</string> + <string name="attachment_type_selector_location">Location</string> + <string name="attachment_type_selector_camera">Camera</string> + <string name="attachment_type_selector_contact">Contact</string> + <string name="attachment_type_selector_text_formatting">Text formatting</string> + <string name="message_reaction_show_less">Show less</string> <plurals name="message_reaction_show_more"> <item quantity="one">"%1$d more"</item> diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 97590028d8..2242abb7aa 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -22,6 +22,7 @@ import dagger.hilt.InstallIn import dagger.multibindings.IntoMap import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel +import im.vector.app.features.attachments.AttachmentTypeSelectorViewModel import im.vector.app.features.auth.ReAuthViewModel import im.vector.app.features.call.VectorCallViewModel import im.vector.app.features.call.conference.JitsiCallViewModel @@ -677,4 +678,9 @@ interface MavericksViewModelModule { @IntoMap @MavericksViewModelKey(VectorSettingsLabsViewModel::class) fun vectorSettingsLabsViewModelFactory(factory: VectorSettingsLabsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(AttachmentTypeSelectorViewModel::class) + fun attachmentTypeSelectorViewModelFactory(factory: AttachmentTypeSelectorViewModel.Factory): MavericksAssistedViewModelFactory<*, *> } diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt index a3e8b3780c..d16bf67a34 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt @@ -38,6 +38,11 @@ class BottomSheetActionButton @JvmOverloads constructor( ) : FrameLayout(context, attrs, defStyleAttr) { val views: ViewBottomSheetActionButtonBinding + override fun setOnClickListener(l: OnClickListener?) { + super.setOnClickListener(l) + views.bottomSheetActionClickableZone.setOnClickListener(l) + } + var title: String? = null set(value) { field = value diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentType.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentType.kt new file mode 100644 index 0000000000..f4b97b9f9c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentType.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 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.attachments + +import im.vector.app.core.utils.PERMISSIONS_EMPTY +import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING +import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT +import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.app.core.utils.PERMISSIONS_FOR_VOICE_BROADCAST + +/** + * The all possible types to pick with their required permissions. + */ +enum class AttachmentType(val permissions: List<String>) { + CAMERA(PERMISSIONS_FOR_TAKING_PHOTO), + GALLERY(PERMISSIONS_EMPTY), + FILE(PERMISSIONS_EMPTY), + STICKER(PERMISSIONS_EMPTY), + CONTACT(PERMISSIONS_FOR_PICKING_CONTACT), + POLL(PERMISSIONS_EMPTY), + LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING), + VOICE_BROADCAST(PERMISSIONS_FOR_VOICE_BROADCAST), +} diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt new file mode 100644 index 0000000000..88cad2ab0b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 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.attachments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.viewModels +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.parentFragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment +import im.vector.app.databinding.BottomSheetAttachmentTypeSelectorBinding +import im.vector.app.features.home.room.detail.TimelineViewModel + +@AndroidEntryPoint +class AttachmentTypeSelectorBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetAttachmentTypeSelectorBinding>() { + + private val viewModel: AttachmentTypeSelectorViewModel by fragmentViewModel() + private val timelineViewModel: TimelineViewModel by parentFragmentViewModel() + private val sharedActionViewModel: AttachmentTypeSelectorSharedActionViewModel by viewModels( + ownerProducer = { requireParentFragment() } + ) + + override val showExpanded = true + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetAttachmentTypeSelectorBinding { + return BottomSheetAttachmentTypeSelectorBinding.inflate(inflater, container, false) + } + + override fun invalidate() = withState(viewModel, timelineViewModel) { viewState, timelineState -> + super.invalidate() + views.location.visibility = if (viewState.isLocationVisible) View.VISIBLE else View.GONE + views.voiceBroadcast.visibility = if (viewState.isVoiceBroadcastVisible) View.VISIBLE else View.GONE + views.poll.visibility = if (!timelineState.isThreadTimeline()) View.VISIBLE else View.GONE + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + views.gallery.debouncedClicks { onAttachmentSelected(AttachmentType.GALLERY) } + views.stickers.debouncedClicks { onAttachmentSelected(AttachmentType.STICKER) } + views.file.debouncedClicks { onAttachmentSelected(AttachmentType.FILE) } + views.voiceBroadcast.debouncedClicks { onAttachmentSelected(AttachmentType.VOICE_BROADCAST) } + views.poll.debouncedClicks { onAttachmentSelected(AttachmentType.POLL) } + views.location.debouncedClicks { onAttachmentSelected(AttachmentType.LOCATION) } + views.camera.debouncedClicks { onAttachmentSelected(AttachmentType.CAMERA) } + views.contact.debouncedClicks { onAttachmentSelected(AttachmentType.CONTACT) } + } + + private fun onAttachmentSelected(attachmentType: AttachmentType) { + val action = AttachmentTypeSelectorSharedAction.SelectAttachmentTypeAction(attachmentType) + sharedActionViewModel.post(action) + dismiss() + } + + companion object { + fun show(fragmentManager: FragmentManager) { + val bottomSheet = AttachmentTypeSelectorBottomSheet() + bottomSheet.show(fragmentManager, "AttachmentTypeSelectorBottomSheet") + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt new file mode 100644 index 0000000000..2b85b6882a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 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.attachments + +import im.vector.app.core.platform.VectorSharedAction +import im.vector.app.core.platform.VectorSharedActionViewModel +import javax.inject.Inject + +class AttachmentTypeSelectorSharedActionViewModel @Inject constructor() : + VectorSharedActionViewModel<AttachmentTypeSelectorSharedAction>() + +sealed class AttachmentTypeSelectorSharedAction : VectorSharedAction { + data class SelectAttachmentTypeAction( + val attachmentType: AttachmentType + ) : AttachmentTypeSelectorSharedAction() +} diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt index 8536b765d4..55805a0728 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt @@ -30,17 +30,11 @@ import android.view.animation.TranslateAnimation import android.widget.ImageButton import android.widget.LinearLayout import android.widget.PopupWindow -import androidx.annotation.StringRes import androidx.appcompat.widget.TooltipCompat import androidx.core.view.doOnNextLayout import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.core.epoxy.onClick -import im.vector.app.core.utils.PERMISSIONS_EMPTY -import im.vector.app.core.utils.PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING -import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT -import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO -import im.vector.app.core.utils.PERMISSIONS_FOR_VOICE_BROADCAST import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback import kotlin.math.max @@ -59,7 +53,7 @@ class AttachmentTypeSelectorView( ) : PopupWindow(context) { interface Callback { - fun onTypeSelected(type: Type) + fun onTypeSelected(type: AttachmentType) } private val views: ViewAttachmentTypeSelectorBinding @@ -69,14 +63,14 @@ class AttachmentTypeSelectorView( init { contentView = inflater.inflate(R.layout.view_attachment_type_selector, null, false) views = ViewAttachmentTypeSelectorBinding.bind(contentView) - views.attachmentGalleryButton.configure(Type.GALLERY) - views.attachmentCameraButton.configure(Type.CAMERA) - views.attachmentFileButton.configure(Type.FILE) - views.attachmentStickersButton.configure(Type.STICKER) - views.attachmentContactButton.configure(Type.CONTACT) - views.attachmentPollButton.configure(Type.POLL) - views.attachmentLocationButton.configure(Type.LOCATION) - views.attachmentVoiceBroadcast.configure(Type.VOICE_BROADCAST) + views.attachmentGalleryButton.configure(AttachmentType.GALLERY) + views.attachmentCameraButton.configure(AttachmentType.CAMERA) + views.attachmentFileButton.configure(AttachmentType.FILE) + views.attachmentStickersButton.configure(AttachmentType.STICKER) + views.attachmentContactButton.configure(AttachmentType.CONTACT) + views.attachmentPollButton.configure(AttachmentType.POLL) + views.attachmentLocationButton.configure(AttachmentType.LOCATION) + views.attachmentVoiceBroadcast.configure(AttachmentType.VOICE_BROADCAST) width = LinearLayout.LayoutParams.MATCH_PARENT height = LinearLayout.LayoutParams.WRAP_CONTENT animationStyle = 0 @@ -127,16 +121,16 @@ class AttachmentTypeSelectorView( } } - fun setAttachmentVisibility(type: Type, isVisible: Boolean) { + fun setAttachmentVisibility(type: AttachmentType, isVisible: Boolean) { when (type) { - Type.CAMERA -> views.attachmentCameraButton - Type.GALLERY -> views.attachmentGalleryButton - Type.FILE -> views.attachmentFileButton - Type.STICKER -> views.attachmentStickersButton - Type.CONTACT -> views.attachmentContactButton - Type.POLL -> views.attachmentPollButton - Type.LOCATION -> views.attachmentLocationButton - Type.VOICE_BROADCAST -> views.attachmentVoiceBroadcast + AttachmentType.CAMERA -> views.attachmentCameraButton + AttachmentType.GALLERY -> views.attachmentGalleryButton + AttachmentType.FILE -> views.attachmentFileButton + AttachmentType.STICKER -> views.attachmentStickersButton + AttachmentType.CONTACT -> views.attachmentContactButton + AttachmentType.POLL -> views.attachmentPollButton + AttachmentType.LOCATION -> views.attachmentLocationButton + AttachmentType.VOICE_BROADCAST -> views.attachmentVoiceBroadcast }.let { it.isVisible = isVisible } @@ -200,13 +194,13 @@ class AttachmentTypeSelectorView( return Pair(x, y) } - private fun ImageButton.configure(type: Type): ImageButton { + private fun ImageButton.configure(type: AttachmentType): ImageButton { this.setOnClickListener(TypeClickListener(type)) - TooltipCompat.setTooltipText(this, context.getString(type.tooltipRes)) + TooltipCompat.setTooltipText(this, context.getString(attachmentTooltipLabels.getValue(type))) return this } - private inner class TypeClickListener(private val type: Type) : View.OnClickListener { + private inner class TypeClickListener(private val type: AttachmentType) : View.OnClickListener { override fun onClick(v: View) { dismiss() @@ -217,14 +211,18 @@ class AttachmentTypeSelectorView( /** * The all possible types to pick with their required permissions and tooltip resource. */ - enum class Type(val permissions: List<String>, @StringRes val tooltipRes: Int) { - CAMERA(PERMISSIONS_FOR_TAKING_PHOTO, R.string.tooltip_attachment_photo), - GALLERY(PERMISSIONS_EMPTY, R.string.tooltip_attachment_gallery), - FILE(PERMISSIONS_EMPTY, R.string.tooltip_attachment_file), - STICKER(PERMISSIONS_EMPTY, R.string.tooltip_attachment_sticker), - CONTACT(PERMISSIONS_FOR_PICKING_CONTACT, R.string.tooltip_attachment_contact), - POLL(PERMISSIONS_EMPTY, R.string.tooltip_attachment_poll), - LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, R.string.tooltip_attachment_location), - VOICE_BROADCAST(PERMISSIONS_FOR_VOICE_BROADCAST, R.string.tooltip_attachment_voice_broadcast), + private companion object { + private val attachmentTooltipLabels: Map<AttachmentType, Int> = AttachmentType.values().associateWith { + when (it) { + AttachmentType.CAMERA -> R.string.tooltip_attachment_photo + AttachmentType.GALLERY -> R.string.tooltip_attachment_gallery + AttachmentType.FILE -> R.string.tooltip_attachment_file + AttachmentType.STICKER -> R.string.tooltip_attachment_sticker + AttachmentType.CONTACT -> R.string.tooltip_attachment_contact + AttachmentType.POLL -> R.string.tooltip_attachment_poll + AttachmentType.LOCATION -> R.string.tooltip_attachment_location + AttachmentType.VOICE_BROADCAST -> R.string.tooltip_attachment_voice_broadcast + } + } } } diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt new file mode 100644 index 0000000000..ec45e226be --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 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.attachments + +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyAction +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.VectorFeatures + +class AttachmentTypeSelectorViewModel @AssistedInject constructor( + @Assisted initialState: AttachmentTypeSelectorViewState, + private val vectorFeatures: VectorFeatures, +) : VectorViewModel<AttachmentTypeSelectorViewState, EmptyAction, EmptyViewEvents>(initialState) { + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory<AttachmentTypeSelectorViewModel, AttachmentTypeSelectorViewState> { + override fun create(initialState: AttachmentTypeSelectorViewState): AttachmentTypeSelectorViewModel + } + + companion object : MavericksViewModelFactory<AttachmentTypeSelectorViewModel, AttachmentTypeSelectorViewState> by hiltMavericksViewModelFactory() + + override fun handle(action: EmptyAction) { + // do nothing + } + + init { + setState { + this.copy( + isLocationVisible = vectorFeatures.isLocationSharingEnabled(), + isVoiceBroadcastVisible = vectorFeatures.isVoiceBroadcastEnabled(), + ) + } + } +} + +data class AttachmentTypeSelectorViewState( + val isLocationVisible: Boolean = false, + val isVoiceBroadcastVisible: Boolean = false, +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt index 1a8e10d102..9692777e15 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt @@ -54,7 +54,7 @@ class AttachmentsHelper( private var captureUri: Uri? = null // The pending type is set if we have to handle permission request. It must be restored if the activity gets killed. - var pendingType: AttachmentTypeSelectorView.Type? = null + var pendingType: AttachmentType? = null // Restorable diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt index 55ec922a57..afa9c84353 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerFragment.kt @@ -40,6 +40,7 @@ import androidx.core.text.buildSpannedString import androidx.core.view.isGone import androidx.core.view.isInvisible import androidx.core.view.isVisible +import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.parentFragmentViewModel @@ -63,6 +64,10 @@ import im.vector.app.core.utils.onPermissionDeniedDialog import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.databinding.FragmentComposerBinding import im.vector.app.features.VectorFeatures +import im.vector.app.features.attachments.AttachmentType +import im.vector.app.features.attachments.AttachmentTypeSelectorBottomSheet +import im.vector.app.features.attachments.AttachmentTypeSelectorSharedAction +import im.vector.app.features.attachments.AttachmentTypeSelectorSharedActionViewModel import im.vector.app.features.attachments.AttachmentTypeSelectorView import im.vector.app.features.attachments.AttachmentsHelper import im.vector.app.features.attachments.ContactAttachment @@ -92,6 +97,7 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.share.SharedData import im.vector.app.features.voice.VoiceFailure import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -161,6 +167,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A private val timelineViewModel: TimelineViewModel by parentFragmentViewModel() private val messageComposerViewModel: MessageComposerViewModel by parentFragmentViewModel() private lateinit var sharedActionViewModel: MessageSharedActionViewModel + private val attachmentViewModel: AttachmentTypeSelectorSharedActionViewModel by viewModels() private val composer: MessageComposerView get() { return if (vectorPreferences.isRichTextEditorEnabled()) { @@ -219,6 +226,11 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A } } + attachmentViewModel.stream() + .filterIsInstance<AttachmentTypeSelectorSharedAction.SelectAttachmentTypeAction>() + .onEach { onTypeSelected(it.attachmentType) } + .launchIn(lifecycleScope) + if (savedInstanceState != null) { handleShareData() } @@ -299,21 +311,25 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A } composer.callback = object : PlainTextComposerLayout.Callback { override fun onAddAttachment() { - if (!::attachmentTypeSelector.isInitialized) { - attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@MessageComposerFragment) - attachmentTypeSelector.setAttachmentVisibility( - AttachmentTypeSelectorView.Type.LOCATION, - vectorFeatures.isLocationSharingEnabled(), - ) - attachmentTypeSelector.setAttachmentVisibility( - AttachmentTypeSelectorView.Type.POLL, !isThreadTimeLine() - ) - attachmentTypeSelector.setAttachmentVisibility( - AttachmentTypeSelectorView.Type.VOICE_BROADCAST, - vectorPreferences.isVoiceBroadcastEnabled(), // TODO check user permission - ) + if (vectorPreferences.isRichTextEditorEnabled()) { + AttachmentTypeSelectorBottomSheet.show(childFragmentManager) + } else { + if (!::attachmentTypeSelector.isInitialized) { + attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@MessageComposerFragment) + attachmentTypeSelector.setAttachmentVisibility( + AttachmentType.LOCATION, + vectorFeatures.isLocationSharingEnabled(), + ) + attachmentTypeSelector.setAttachmentVisibility( + AttachmentType.POLL, !isThreadTimeLine() + ) + attachmentTypeSelector.setAttachmentVisibility( + AttachmentType.VOICE_BROADCAST, + vectorPreferences.isVoiceBroadcastEnabled(), // TODO check user permission + ) + } + attachmentTypeSelector.show(composer.attachmentButton) } - attachmentTypeSelector.show(composer.attachmentButton) } override fun onExpandOrCompactChange() { @@ -662,20 +678,20 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A } } - private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) { + private fun launchAttachmentProcess(type: AttachmentType) { when (type) { - AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera( + AttachmentType.CAMERA -> attachmentsHelper.openCamera( activity = requireActivity(), vectorPreferences = vectorPreferences, cameraActivityResultLauncher = attachmentCameraActivityResultLauncher, cameraVideoActivityResultLauncher = attachmentCameraVideoActivityResultLauncher ) - AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher) - AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher) - AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher) - AttachmentTypeSelectorView.Type.STICKER -> timelineViewModel.handle(RoomDetailAction.SelectStickerAttachment) - AttachmentTypeSelectorView.Type.POLL -> navigator.openCreatePoll(requireContext(), roomId, null, PollMode.CREATE) - AttachmentTypeSelectorView.Type.LOCATION -> { + AttachmentType.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher) + AttachmentType.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher) + AttachmentType.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher) + AttachmentType.STICKER -> timelineViewModel.handle(RoomDetailAction.SelectStickerAttachment) + AttachmentType.POLL -> navigator.openCreatePoll(requireContext(), roomId, null, PollMode.CREATE) + AttachmentType.LOCATION -> { navigator .openLocationSharing( context = requireContext(), @@ -685,11 +701,11 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A locationOwnerId = session.myUserId ) } - AttachmentTypeSelectorView.Type.VOICE_BROADCAST -> timelineViewModel.handle(VoiceBroadcastAction.Recording.Start) + AttachmentType.VOICE_BROADCAST -> timelineViewModel.handle(VoiceBroadcastAction.Recording.Start) } } - override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) { + override fun onTypeSelected(type: AttachmentType) { if (checkPermissions(type.permissions, requireActivity(), typeSelectedActivityResultLauncher)) { launchAttachmentProcess(type) } else { diff --git a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml new file mode 100644 index 0000000000..3aec5b5c20 --- /dev/null +++ b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?colorSurface" + android:orientation="vertical"> + + <androidx.core.widget.NestedScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/gallery" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_gallery" + app:leftIcon="@drawable/ic_attachment_gallery" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/stickers" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_sticker" + app:leftIcon="@drawable/ic_attachment_sticker" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/file" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_file" + app:leftIcon="@drawable/ic_attachment_file" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/voiceBroadcast" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_voice_broadcast" + app:leftIcon="@drawable/ic_attachment_voice_broadcast" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/poll" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_poll" + app:leftIcon="@drawable/ic_attachment_poll" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/location" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_location" + app:leftIcon="@drawable/ic_attachment_location" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/camera" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_camera" + app:leftIcon="@drawable/ic_attachment_camera" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/contact" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_contact" + app:leftIcon="@drawable/ic_attachment_contact_white_24dp" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> + + </LinearLayout> + </androidx.core.widget.NestedScrollView> +</LinearLayout> diff --git a/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt b/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt new file mode 100644 index 0000000000..478f631c06 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 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.attachments + +import com.airbnb.mvrx.test.MavericksTestRule +import im.vector.app.test.fakes.FakeVectorFeatures +import im.vector.app.test.test +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +internal class AttachmentTypeSelectorViewModelTest { + + @get:Rule + val mavericksTestRule = MavericksTestRule() + + private val fakeVectorFeatures = FakeVectorFeatures() + private val initialState = AttachmentTypeSelectorViewState() + + @Before + fun setUp() { + // Disable all features by default + fakeVectorFeatures.givenLocationSharing(isEnabled = false) + fakeVectorFeatures.givenVoiceBroadcast(isEnabled = false) + } + + @Test + fun `given features are not enabled, then options are not visible`() { + createViewModel() + .test() + .assertStates( + listOf( + initialState, + ) + ) + .finish() + } + + @Test + fun `given location sharing is enabled, then location sharing option is visible`() { + fakeVectorFeatures.givenLocationSharing(isEnabled = true) + + createViewModel() + .test() + .assertStates( + listOf( + initialState.copy( + isLocationVisible = true + ), + ) + ) + .finish() + } + + @Test + fun `given voice broadcast is enabled, then voice broadcast option is visible`() { + fakeVectorFeatures.givenVoiceBroadcast(isEnabled = true) + + createViewModel() + .test() + .assertStates( + listOf( + initialState.copy( + isVoiceBroadcastVisible = true + ), + ) + ) + .finish() + } + + private fun createViewModel(): AttachmentTypeSelectorViewModel { + return AttachmentTypeSelectorViewModel( + initialState, + vectorFeatures = fakeVectorFeatures, + ) + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorFeatures.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorFeatures.kt index 4e6b4fc3df..d989abc214 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorFeatures.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorFeatures.kt @@ -42,4 +42,12 @@ class FakeVectorFeatures : VectorFeatures by spyk<DefaultVectorFeatures>() { fun givenCombinedLoginDisabled() { every { isOnboardingCombinedLoginEnabled() } returns false } + + fun givenLocationSharing(isEnabled: Boolean) { + every { isLocationSharingEnabled() } returns isEnabled + } + + fun givenVoiceBroadcast(isEnabled: Boolean) { + every { isVoiceBroadcastEnabled() } returns isEnabled + } } From 17c43c91888162d3c7675511ff910c46c3aa32fc Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Thu, 20 Oct 2022 16:13:18 +0100 Subject: [PATCH 02/10] Add rounded corners to bottom sheet dialog. Note these are currently only visible in the collapsed state. - [Google issue](https://issuetracker.google.com/issues/144859239) - [Rejected PR](https://github.com/material-components/material-components-android/pull/437) - [Github issue](https://github.com/material-components/material-components-android/issues/1278) --- .../src/main/res/values/styles_bottom_sheet.xml | 11 +++++++++++ .../layout/bottom_sheet_attachment_type_selector.xml | 1 - .../res/layout/view_bottom_sheet_action_button.xml | 3 +-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml index f6c30040d9..7b704a6331 100644 --- a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml +++ b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml @@ -14,6 +14,7 @@ <!-- Default color for text View --> <item name="android:textColorTertiary">@color/element_content_primary_light</item> <item name="android:textColorLink">@color/element_link_light</item> + <item name="bottomSheetStyle">@style/BottomSheetStyle</item> </style> <style name="Theme.Vector.BottomSheetDialog.Dark" parent="Theme.MaterialComponents.BottomSheetDialog"> @@ -28,6 +29,7 @@ <!-- Default color for text View --> <item name="android:textColorTertiary">@color/element_content_primary_dark</item> <item name="android:textColorLink">@color/element_link_dark</item> + <item name="bottomSheetStyle">@style/BottomSheetStyle</item> </style> <style name="Theme.Vector.BottomSheetDialog.Black" parent="Theme.Vector.BottomSheetDialog.Dark"> @@ -35,6 +37,15 @@ </style> <!-- BottomSheet style --> + <style name="BottomSheetStyle" parent="Widget.MaterialComponents.BottomSheet.Modal"> + <item name="shapeAppearance">@style/BottomSheetShapeAppearance</item> + </style> + + <style name="BottomSheetShapeAppearance" parent=""> + <item name="cornerFamily">rounded</item> + <item name="cornerSize">20dp</item> + </style> + <style name="BottomSheetItemTextMain"> <item name="android:fontFamily">sans-serif-medium</item> <item name="android:layout_width">0dp</item> diff --git a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml index 3aec5b5c20..559673716e 100644 --- a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml +++ b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml @@ -3,7 +3,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?colorSurface" android:orientation="vertical"> <androidx.core.widget.NestedScrollView diff --git a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml index f8521c7eba..05a99fe8ae 100644 --- a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml +++ b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml @@ -10,7 +10,6 @@ android:id="@+id/bottomSheetActionClickableZone" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?colorSurface" android:clickable="true" android:focusable="true" android:foreground="?attr/selectableItemBackground" @@ -93,4 +92,4 @@ </androidx.constraintlayout.widget.ConstraintLayout> -</merge> \ No newline at end of file +</merge> From f52aaef6459254ecceb49744ce64b32877b621d2 Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Fri, 21 Oct 2022 12:43:11 +0100 Subject: [PATCH 03/10] Add changelog entry --- changelog.d/7429.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7429.feature diff --git a/changelog.d/7429.feature b/changelog.d/7429.feature new file mode 100644 index 0000000000..9857452eca --- /dev/null +++ b/changelog.d/7429.feature @@ -0,0 +1 @@ +Add new UI for selecting an attachment From 9da575b4d0c616997ca8e18d8f62c6a6a414acb9 Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:19:01 +0100 Subject: [PATCH 04/10] Remove redundant call to superclass click listener --- .../java/im/vector/app/core/ui/views/BottomSheetActionButton.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt index d16bf67a34..ca3e6a360a 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt @@ -39,7 +39,6 @@ class BottomSheetActionButton @JvmOverloads constructor( val views: ViewBottomSheetActionButtonBinding override fun setOnClickListener(l: OnClickListener?) { - super.setOnClickListener(l) views.bottomSheetActionClickableZone.setOnClickListener(l) } From 74591f526111eb5472a3090014488170ca7944ff Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:20:51 +0100 Subject: [PATCH 05/10] Refactor to use view visibility helper --- .../attachments/AttachmentTypeSelectorBottomSheet.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt index 88cad2ab0b..af17800455 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorBottomSheet.kt @@ -20,6 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import com.airbnb.mvrx.fragmentViewModel @@ -47,9 +48,9 @@ class AttachmentTypeSelectorBottomSheet : VectorBaseBottomSheetDialogFragment<Bo override fun invalidate() = withState(viewModel, timelineViewModel) { viewState, timelineState -> super.invalidate() - views.location.visibility = if (viewState.isLocationVisible) View.VISIBLE else View.GONE - views.voiceBroadcast.visibility = if (viewState.isVoiceBroadcastVisible) View.VISIBLE else View.GONE - views.poll.visibility = if (!timelineState.isThreadTimeline()) View.VISIBLE else View.GONE + views.location.isVisible = viewState.isLocationVisible + views.voiceBroadcast.isVisible = viewState.isVoiceBroadcastVisible + views.poll.isVisible = !timelineState.isThreadTimeline() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { From c401d55dea49b47f2e3123ed385c092d73dbfeda Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:21:52 +0100 Subject: [PATCH 06/10] Change redundant sealed class to interface --- .../AttachmentTypeSelectorSharedActionViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt index 2b85b6882a..e02b10c54b 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorSharedActionViewModel.kt @@ -23,8 +23,8 @@ import javax.inject.Inject class AttachmentTypeSelectorSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<AttachmentTypeSelectorSharedAction>() -sealed class AttachmentTypeSelectorSharedAction : VectorSharedAction { +sealed interface AttachmentTypeSelectorSharedAction : VectorSharedAction { data class SelectAttachmentTypeAction( val attachmentType: AttachmentType - ) : AttachmentTypeSelectorSharedAction() + ) : AttachmentTypeSelectorSharedAction } From 0650b6ae22d0f0459e03ec6533d1fbde30b17203 Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:24:00 +0100 Subject: [PATCH 07/10] Remove unused string --- library/ui-strings/src/main/res/values/strings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 9ce87199b0..d5223a0638 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3213,7 +3213,6 @@ <string name="attachment_type_selector_location">Location</string> <string name="attachment_type_selector_camera">Camera</string> <string name="attachment_type_selector_contact">Contact</string> - <string name="attachment_type_selector_text_formatting">Text formatting</string> <string name="message_reaction_show_less">Show less</string> <plurals name="message_reaction_show_more"> From 293811220d52b3ea9da0796cbd99ba46dd4fbe25 Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:26:11 +0100 Subject: [PATCH 08/10] Revert "Add rounded corners to bottom sheet dialog." This reverts commit 17c43c91888162d3c7675511ff910c46c3aa32fc. --- .../src/main/res/values/styles_bottom_sheet.xml | 11 ----------- .../layout/bottom_sheet_attachment_type_selector.xml | 1 + .../res/layout/view_bottom_sheet_action_button.xml | 3 ++- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml index 7b704a6331..f6c30040d9 100644 --- a/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml +++ b/library/ui-styles/src/main/res/values/styles_bottom_sheet.xml @@ -14,7 +14,6 @@ <!-- Default color for text View --> <item name="android:textColorTertiary">@color/element_content_primary_light</item> <item name="android:textColorLink">@color/element_link_light</item> - <item name="bottomSheetStyle">@style/BottomSheetStyle</item> </style> <style name="Theme.Vector.BottomSheetDialog.Dark" parent="Theme.MaterialComponents.BottomSheetDialog"> @@ -29,7 +28,6 @@ <!-- Default color for text View --> <item name="android:textColorTertiary">@color/element_content_primary_dark</item> <item name="android:textColorLink">@color/element_link_dark</item> - <item name="bottomSheetStyle">@style/BottomSheetStyle</item> </style> <style name="Theme.Vector.BottomSheetDialog.Black" parent="Theme.Vector.BottomSheetDialog.Dark"> @@ -37,15 +35,6 @@ </style> <!-- BottomSheet style --> - <style name="BottomSheetStyle" parent="Widget.MaterialComponents.BottomSheet.Modal"> - <item name="shapeAppearance">@style/BottomSheetShapeAppearance</item> - </style> - - <style name="BottomSheetShapeAppearance" parent=""> - <item name="cornerFamily">rounded</item> - <item name="cornerSize">20dp</item> - </style> - <style name="BottomSheetItemTextMain"> <item name="android:fontFamily">sans-serif-medium</item> <item name="android:layout_width">0dp</item> diff --git a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml index 559673716e..3aec5b5c20 100644 --- a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml +++ b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="?colorSurface" android:orientation="vertical"> <androidx.core.widget.NestedScrollView diff --git a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml index 05a99fe8ae..f8521c7eba 100644 --- a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml +++ b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml @@ -10,6 +10,7 @@ android:id="@+id/bottomSheetActionClickableZone" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="?colorSurface" android:clickable="true" android:focusable="true" android:foreground="?attr/selectableItemBackground" @@ -92,4 +93,4 @@ </androidx.constraintlayout.widget.ConstraintLayout> -</merge> +</merge> \ No newline at end of file From b9c1aa6ded4edcf9caa0c6ad250845cc332e53ab Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:31:15 +0100 Subject: [PATCH 09/10] Remove redundant view group --- .../bottom_sheet_attachment_type_selector.xml | 144 +++++++++--------- 1 file changed, 69 insertions(+), 75 deletions(-) diff --git a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml index 3aec5b5c20..79a60624cf 100644 --- a/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml +++ b/vector/src/main/res/layout/bottom_sheet_attachment_type_selector.xml @@ -1,92 +1,86 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?colorSurface" - android:orientation="vertical"> + android:background="?colorSurface"> - <androidx.core.widget.NestedScrollView + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="wrap_content" + android:orientation="vertical"> - <LinearLayout + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/gallery" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> + app:actionTitle="@string/attachment_type_selector_gallery" + app:leftIcon="@drawable/ic_attachment_gallery" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/gallery" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_gallery" - app:leftIcon="@drawable/ic_attachment_gallery" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/stickers" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_sticker" + app:leftIcon="@drawable/ic_attachment_sticker" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/stickers" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_sticker" - app:leftIcon="@drawable/ic_attachment_sticker" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/file" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_file" + app:leftIcon="@drawable/ic_attachment_file" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/file" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_file" - app:leftIcon="@drawable/ic_attachment_file" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/voiceBroadcast" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_voice_broadcast" + app:leftIcon="@drawable/ic_attachment_voice_broadcast" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/voiceBroadcast" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_voice_broadcast" - app:leftIcon="@drawable/ic_attachment_voice_broadcast" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/poll" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_poll" + app:leftIcon="@drawable/ic_attachment_poll" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/poll" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_poll" - app:leftIcon="@drawable/ic_attachment_poll" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/location" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_location" + app:leftIcon="@drawable/ic_attachment_location" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/location" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_location" - app:leftIcon="@drawable/ic_attachment_location" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/camera" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_camera" + app:leftIcon="@drawable/ic_attachment_camera" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/camera" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_camera" - app:leftIcon="@drawable/ic_attachment_camera" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> + <im.vector.app.core.ui.views.BottomSheetActionButton + android:id="@+id/contact" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:actionTitle="@string/attachment_type_selector_contact" + app:leftIcon="@drawable/ic_attachment_contact_white_24dp" + app:tint="?colorPrimary" + app:titleTextColor="?vctr_content_primary" /> - <im.vector.app.core.ui.views.BottomSheetActionButton - android:id="@+id/contact" - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:actionTitle="@string/attachment_type_selector_contact" - app:leftIcon="@drawable/ic_attachment_contact_white_24dp" - app:tint="?colorPrimary" - app:titleTextColor="?vctr_content_primary" /> - - </LinearLayout> - </androidx.core.widget.NestedScrollView> -</LinearLayout> + </LinearLayout> +</androidx.core.widget.NestedScrollView> From cdc8f7fea7b742f4206f9af9e789fe59d25637dc Mon Sep 17 00:00:00 2001 From: Jonny Andrew <jonny.andrew@protonmail.com> Date: Mon, 24 Oct 2022 09:43:03 +0100 Subject: [PATCH 10/10] Remove redundant `this` --- .../app/features/attachments/AttachmentTypeSelectorViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt index ec45e226be..fe6616e53a 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt @@ -45,7 +45,7 @@ class AttachmentTypeSelectorViewModel @AssistedInject constructor( init { setState { - this.copy( + copy( isLocationVisible = vectorFeatures.isLocationSharingEnabled(), isVoiceBroadcastVisible = vectorFeatures.isVoiceBroadcastEnabled(), )