diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentTypeSelectorView.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentTypeSelectorView.kt index 9acdd6ae1f..bc34353467 100644 --- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentTypeSelectorView.kt +++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentTypeSelectorView.kt @@ -32,6 +32,7 @@ import android.view.animation.AnimationSet import android.view.animation.OvershootInterpolator import android.view.animation.ScaleAnimation import android.view.animation.TranslateAnimation +import android.widget.FrameLayout import android.widget.ImageButton import android.widget.LinearLayout import android.widget.PopupWindow @@ -39,9 +40,12 @@ import androidx.core.view.doOnNextLayout import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.util.ColorGenerator import im.vector.riotx.R +import im.vector.riotx.core.utils.DimensionConverter import kotlin.math.max -class AttachmentTypeSelectorView(context: Context, var callback: Callback?) +class AttachmentTypeSelectorView(context: Context, + inflater: LayoutInflater, + var callback: Callback?) : PopupWindow(context) { interface Callback { @@ -54,21 +58,25 @@ class AttachmentTypeSelectorView(context: Context, var callback: Callback?) private var cameraButton: ImageButton private var fileButton: ImageButton private var stickersButton: ImageButton + private var audioButton: ImageButton + private var contactButton: ImageButton private var anchor: View? = null init { - val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater - val layout = inflater.inflate(R.layout.attachment_type_selector, null, true) + val root = FrameLayout(context) + val layout = inflater.inflate(R.layout.view_attachment_type_selector, root, true) galleryButton = layout.findViewById(R.id.attachmentGalleryButton).configure(TYPE_GALLERY) cameraButton = layout.findViewById(R.id.attachmentCameraButton).configure(TYPE_CAMERA) fileButton = layout.findViewById(R.id.attachmentFileButton).configure(TYPE_FILE) stickersButton = layout.findViewById(R.id.attachmentStickersButton).configure(TYPE_STICKER) + audioButton = layout.findViewById(R.id.attachmentAudioButton).configure(TYPE_AUDIO) + contactButton = layout.findViewById(R.id.attachmentContactButton).configure(TYPE_CONTACT) contentView = layout width = LinearLayout.LayoutParams.MATCH_PARENT height = LinearLayout.LayoutParams.WRAP_CONTENT - setBackgroundDrawable(BitmapDrawable()) animationStyle = 0 + setBackgroundDrawable(BitmapDrawable()) inputMethodMode = INPUT_METHOD_NOT_NEEDED isFocusable = true isTouchable = true @@ -87,6 +95,8 @@ class AttachmentTypeSelectorView(context: Context, var callback: Callback?) animateButtonIn(galleryButton, ANIMATION_DURATION / 2) animateButtonIn(cameraButton, ANIMATION_DURATION / 2) animateButtonIn(fileButton, ANIMATION_DURATION / 4) + animateButtonIn(audioButton, ANIMATION_DURATION / 2) + animateButtonIn(contactButton, ANIMATION_DURATION / 4) animateButtonIn(stickersButton, 0) } } @@ -193,6 +203,8 @@ class AttachmentTypeSelectorView(context: Context, var callback: Callback?) const val TYPE_GALLERY = 1 const val TYPE_FILE = 2 const val TYPE_STICKER = 3 + const val TYPE_AUDIO = 4 + const val TYPE_CONTACT = 5 private const val ANIMATION_DURATION = 250 } diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt index 3d770f9263..b1b10a7797 100644 --- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt +++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsHelper.kt @@ -66,6 +66,10 @@ class AttachmentsHelper private constructor(private val pickerManagerFactory: Pi pickerManagerFactory.createFilePicker() } + private val audioPicker by lazy { + pickerManagerFactory.createAudioPicker() + } + // Restorable override fun onSaveInstanceState(outState: Bundle) { @@ -97,6 +101,13 @@ class AttachmentsHelper private constructor(private val pickerManagerFactory: Pi imagePicker.pickImage() } + /** + * Starts the process for handling audio picking + */ + fun selectAudio() { + audioPicker.pickAudio() + } + /** * Starts the process for handling capture image picking */ diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt index fdb9277395..469cef1427 100644 --- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt +++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsMapper.kt @@ -16,6 +16,7 @@ package im.vector.riotx.features.attachments +import com.kbeanie.multipicker.api.entity.ChosenAudio import com.kbeanie.multipicker.api.entity.ChosenFile import com.kbeanie.multipicker.api.entity.ChosenImage import com.kbeanie.multipicker.api.entity.ChosenVideo @@ -32,6 +33,18 @@ fun ChosenFile.toContentAttachmentData(): ContentAttachmentData { ) } +fun ChosenAudio.toContentAttachmentData(): ContentAttachmentData { + return ContentAttachmentData( + path = originalPath, + mimeType = mimeType, + type = mapType(), + size = size, + date = createdAt.time, + name = displayName, + duration = duration + ) +} + fun ChosenFile.mapType(): ContentAttachmentData.Type { return when { mimeType.startsWith("image/") -> ContentAttachmentData.Type.IMAGE diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt index fc8200fe55..7df0b6f15b 100644 --- a/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt +++ b/vector/src/main/java/im/vector/riotx/features/attachments/AttachmentsPickerCallback.kt @@ -16,9 +16,12 @@ package im.vector.riotx.features.attachments +import com.kbeanie.multipicker.api.callbacks.AudioPickerCallback +import com.kbeanie.multipicker.api.callbacks.ContactPickerCallback import com.kbeanie.multipicker.api.callbacks.FilePickerCallback import com.kbeanie.multipicker.api.callbacks.ImagePickerCallback import com.kbeanie.multipicker.api.callbacks.VideoPickerCallback +import com.kbeanie.multipicker.api.entity.ChosenAudio import com.kbeanie.multipicker.api.entity.ChosenFile import com.kbeanie.multipicker.api.entity.ChosenImage import com.kbeanie.multipicker.api.entity.ChosenVideo @@ -26,7 +29,18 @@ import com.kbeanie.multipicker.api.entity.ChosenVideo /** * This class delegates the PickerManager callbacks to an [AttachmentsHelper.Callback] */ -class AttachmentsPickerCallback(private val callback: AttachmentsHelper.Callback) : ImagePickerCallback, FilePickerCallback, VideoPickerCallback { +class AttachmentsPickerCallback(private val callback: AttachmentsHelper.Callback) : ImagePickerCallback, FilePickerCallback, VideoPickerCallback, AudioPickerCallback { + + override fun onAudiosChosen(audios: MutableList?) { + if (audios.isNullOrEmpty()) { + callback.onAttachmentsProcessFailed() + } else { + val attachments = audios.map { + it.toContentAttachmentData() + } + callback.onAttachmentsReady(attachments) + } + } override fun onFilesChosen(files: MutableList?) { if (files.isNullOrEmpty()) { diff --git a/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt b/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt index c0dbcafc48..23344b81ba 100644 --- a/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/attachments/PickerManagerFactory.kt @@ -18,7 +18,9 @@ package im.vector.riotx.features.attachments import android.app.Activity import androidx.fragment.app.Fragment +import com.kbeanie.multipicker.api.AudioPicker import com.kbeanie.multipicker.api.CameraImagePicker +import com.kbeanie.multipicker.api.ContactPicker import com.kbeanie.multipicker.api.FilePicker import com.kbeanie.multipicker.api.ImagePicker import com.kbeanie.multipicker.api.VideoPicker @@ -33,6 +35,7 @@ interface PickerManagerFactory { fun createFilePicker(): FilePicker + fun createAudioPicker(): AudioPicker } @@ -67,6 +70,12 @@ class ActivityPickerManagerFactory(private val activity: Activity, callback: Att } } + override fun createAudioPicker(): AudioPicker { + return AudioPicker(activity).also { + it.allowMultiple() + it.setAudioPickerCallback(attachmentsPickerCallback) + } + } } class FragmentPickerManagerFactory(private val fragment: Fragment, callback: AttachmentsHelper.Callback) : PickerManagerFactory { @@ -100,5 +109,12 @@ class FragmentPickerManagerFactory(private val fragment: Fragment, callback: Att } } + override fun createAudioPicker(): AudioPicker { + return AudioPicker(fragment).also { + it.allowMultiple() + it.setAudioPickerCallback(attachmentsPickerCallback) + } + } + } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 734337a108..d3ce4cacb1 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -622,9 +622,9 @@ class RoomDetailFragment : private fun setupAttachmentButton() { composerLayout.attachmentButton.setOnClickListener { if (!::attachmentTypeSelector.isInitialized) { - attachmentTypeSelector = AttachmentTypeSelectorView(requireContext(), this) + attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this) } - attachmentTypeSelector.show(it) + attachmentTypeSelector.show(composerLayout.attachmentButton) } } @@ -1114,7 +1114,10 @@ class RoomDetailFragment : AttachmentTypeSelectorView.TYPE_CAMERA -> attachmentsHelper.openCamera() AttachmentTypeSelectorView.TYPE_FILE -> attachmentsHelper.selectFile() AttachmentTypeSelectorView.TYPE_GALLERY -> attachmentsHelper.selectGallery() + AttachmentTypeSelectorView.TYPE_AUDIO -> attachmentsHelper.selectAudio() + AttachmentTypeSelectorView.TYPE_CONTACT -> vectorBaseActivity.notImplemented("Picking contacts") AttachmentTypeSelectorView.TYPE_STICKER -> vectorBaseActivity.notImplemented("Adding stickers") + } } diff --git a/vector/src/main/res/drawable-hdpi/ic_attachment_stickers_white_24dp.png b/vector/src/main/res/drawable-hdpi/ic_attachment_stickers_white_24dp.png new file mode 100644 index 0000000000..bf765cfc6d Binary files /dev/null and b/vector/src/main/res/drawable-hdpi/ic_attachment_stickers_white_24dp.png differ diff --git a/vector/src/main/res/drawable-mdpi/ic_attachment_stickers_white_24dp.png b/vector/src/main/res/drawable-mdpi/ic_attachment_stickers_white_24dp.png new file mode 100644 index 0000000000..3f4b3e50a5 Binary files /dev/null and b/vector/src/main/res/drawable-mdpi/ic_attachment_stickers_white_24dp.png differ diff --git a/vector/src/main/res/drawable-xhdpi/ic_attachment_stickers_white_24dp.png b/vector/src/main/res/drawable-xhdpi/ic_attachment_stickers_white_24dp.png new file mode 100644 index 0000000000..0a96b2bc5d Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/ic_attachment_stickers_white_24dp.png differ diff --git a/vector/src/main/res/drawable-xxhdpi/ic_attachment_stickers_white_24dp.png b/vector/src/main/res/drawable-xxhdpi/ic_attachment_stickers_white_24dp.png new file mode 100644 index 0000000000..6cd7ac653d Binary files /dev/null and b/vector/src/main/res/drawable-xxhdpi/ic_attachment_stickers_white_24dp.png differ diff --git a/vector/src/main/res/drawable-xxxhdpi/ic_attachment_stickers_white_24dp.png b/vector/src/main/res/drawable-xxxhdpi/ic_attachment_stickers_white_24dp.png new file mode 100644 index 0000000000..eab49d19f6 Binary files /dev/null and b/vector/src/main/res/drawable-xxxhdpi/ic_attachment_stickers_white_24dp.png differ diff --git a/vector/src/main/res/drawable/bg_attachment_type_selector.xml b/vector/src/main/res/drawable/bg_attachment_type_selector.xml new file mode 100644 index 0000000000..53c7c1f1c9 --- /dev/null +++ b/vector/src/main/res/drawable/bg_attachment_type_selector.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/drawable/ic_attachment_audio_white_24dp.xml b/vector/src/main/res/drawable/ic_attachment_audio_white_24dp.xml new file mode 100644 index 0000000000..3de9a237e8 --- /dev/null +++ b/vector/src/main/res/drawable/ic_attachment_audio_white_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/vector/src/main/res/drawable/ic_attachment_contact_white_24dp.xml b/vector/src/main/res/drawable/ic_attachment_contact_white_24dp.xml new file mode 100644 index 0000000000..20f05d692e --- /dev/null +++ b/vector/src/main/res/drawable/ic_attachment_contact_white_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/vector/src/main/res/layout/attachment_type_selector.xml b/vector/src/main/res/layout/view_attachment_type_selector.xml similarity index 50% rename from vector/src/main/res/layout/attachment_type_selector.xml rename to vector/src/main/res/layout/view_attachment_type_selector.xml index 603cb9d72d..772407ba3f 100644 --- a/vector/src/main/res/layout/attachment_type_selector.xml +++ b/vector/src/main/res/layout/view_attachment_type_selector.xml @@ -1,11 +1,15 @@ - - + android:background="@drawable/bg_attachment_type_selector" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:orientation="vertical" + android:paddingTop="16dp" + android:paddingBottom="16dp"> + android:weightSum="3"> @@ -48,16 +48,12 @@ @@ -72,20 +68,66 @@ + + + + + + + + + + + + + + + + + + + + + + - - - \ No newline at end of file + + + \ No newline at end of file diff --git a/vector/src/main/res/values/styles_riot.xml b/vector/src/main/res/values/styles_riot.xml index 1b19c87e08..2019fd8a2a 100644 --- a/vector/src/main/res/values/styles_riot.xml +++ b/vector/src/main/res/values/styles_riot.xml @@ -324,4 +324,19 @@ 12sp + + + + + \ No newline at end of file