From 2bc08069cc1593663f0f4ef6187c5360af007af6 Mon Sep 17 00:00:00 2001
From: Florian Renaud <florianr@element.io>
Date: Wed, 21 Sep 2022 15:51:44 +0200
Subject: [PATCH] Add Voice Broadcast action in the composer

---
 .../src/main/res/values/strings.xml           |  2 ++
 .../vector/app/core/utils/PermissionsTools.kt |  1 +
 .../attachments/AttachmentTypeSelectorView.kt |  6 +++++-
 .../home/room/detail/RoomDetailAction.kt      |  1 +
 .../home/room/detail/TimelineFragment.kt      |  5 +++++
 .../home/room/detail/TimelineViewModel.kt     |  6 ++++++
 .../ic_attachment_voice_broadcast.xml         | 21 +++++++++++++++++++
 .../layout/view_attachment_type_selector.xml  | 10 +++++++++
 8 files changed, 51 insertions(+), 1 deletion(-)
 create mode 100644 vector/src/main/res/drawable/ic_attachment_voice_broadcast.xml

diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 4ff7aae750..a1d4bd302e 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -1871,6 +1871,7 @@
     <string name="attachment_type_sticker">"Sticker"</string>
     <string name="attachment_type_poll">Poll</string>
     <string name="attachment_type_location">Location</string>
+    <string name="attachment_type_voice_broadcast">Voice Broadcast</string>
     <string name="rotate_and_crop_screen_title">Rotate and crop</string>
     <string name="error_handling_incoming_share">Couldn\'t handle share data</string>
 
@@ -3179,6 +3180,7 @@
     <string name="tooltip_attachment_contact">Open contacts</string>
     <string name="tooltip_attachment_poll">Create poll</string>
     <string name="tooltip_attachment_location">Share location</string>
+    <string name="tooltip_attachment_voice_broadcast">Start a voice broadcast</string>
 
     <string name="message_reaction_show_less">Show less</string>
     <plurals name="message_reaction_show_more">
diff --git a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
index 9ad95d3c55..a287626671 100644
--- a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
@@ -42,6 +42,7 @@ val PERMISSIONS_FOR_ROOM_AVATAR = listOf(Manifest.permission.CAMERA)
 val PERMISSIONS_FOR_WRITING_FILES = listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
 val PERMISSIONS_FOR_PICKING_CONTACT = listOf(Manifest.permission.READ_CONTACTS)
 val PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING = listOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
+val PERMISSIONS_FOR_VOICE_BROADCAST = listOf(Manifest.permission.RECORD_AUDIO)
 
 // This is not ideal to store the value like that, but it works
 private var permissionDialogDisplayed = false
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 c85c3aa6b5..8536b765d4 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
@@ -40,6 +40,7 @@ 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
@@ -75,6 +76,7 @@ class AttachmentTypeSelectorView(
         views.attachmentContactButton.configure(Type.CONTACT)
         views.attachmentPollButton.configure(Type.POLL)
         views.attachmentLocationButton.configure(Type.LOCATION)
+        views.attachmentVoiceBroadcast.configure(Type.VOICE_BROADCAST)
         width = LinearLayout.LayoutParams.MATCH_PARENT
         height = LinearLayout.LayoutParams.WRAP_CONTENT
         animationStyle = 0
@@ -134,6 +136,7 @@ class AttachmentTypeSelectorView(
             Type.CONTACT -> views.attachmentContactButton
             Type.POLL -> views.attachmentPollButton
             Type.LOCATION -> views.attachmentLocationButton
+            Type.VOICE_BROADCAST -> views.attachmentVoiceBroadcast
         }.let {
             it.isVisible = isVisible
         }
@@ -221,6 +224,7 @@ class AttachmentTypeSelectorView(
         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)
+        LOCATION(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, R.string.tooltip_attachment_location),
+        VOICE_BROADCAST(PERMISSIONS_FOR_VOICE_BROADCAST, R.string.tooltip_attachment_voice_broadcast),
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt
index c1e3b58a80..10708d2290 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt
@@ -79,6 +79,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
     data class ReRequestKeys(val eventId: String) : RoomDetailAction()
 
     object SelectStickerAttachment : RoomDetailAction()
+    object StartVoiceBroadcast : RoomDetailAction()
     object OpenIntegrationManager : RoomDetailAction()
     object ManageIntegrations : RoomDetailAction()
     data class AddJitsiWidget(val withVideo: Boolean) : RoomDetailAction()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index bba607eeb4..f758d4a684 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -1575,6 +1575,10 @@ class TimelineFragment :
                     attachmentTypeSelector.setAttachmentVisibility(
                             AttachmentTypeSelectorView.Type.POLL, !isThreadTimeLine()
                     )
+                    attachmentTypeSelector.setAttachmentVisibility(
+                            AttachmentTypeSelectorView.Type.VOICE_BROADCAST,
+                            vectorFeatures.isVoiceBroadcastEnabled(), // TODO check user permission
+                    )
                 }
                 attachmentTypeSelector.show(views.composerLayout.views.attachmentButton)
             }
@@ -2668,6 +2672,7 @@ class TimelineFragment :
                                 locationOwnerId = session.myUserId
                         )
             }
+            AttachmentTypeSelectorView.Type.VOICE_BROADCAST -> timelineViewModel.handle(RoomDetailAction.StartVoiceBroadcast)
         }
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
index 02dd2604e1..4bed477711 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt
@@ -456,6 +456,7 @@ class TimelineViewModel @AssistedInject constructor(
             is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
             is RoomDetailAction.TapOnFailedToDecrypt -> handleTapOnFailedToDecrypt(action)
             is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
+            is RoomDetailAction.StartVoiceBroadcast -> handleStartVoiceBroadcast()
             is RoomDetailAction.OpenIntegrationManager -> handleOpenIntegrationManager()
             is RoomDetailAction.StartCall -> handleStartCall(action)
             is RoomDetailAction.AcceptCall -> handleAcceptCall(action)
@@ -597,6 +598,11 @@ class TimelineViewModel @AssistedInject constructor(
         }
     }
 
+    private fun handleStartVoiceBroadcast() {
+        // Todo implement start voice broadcast action
+        Timber.d("Start voice broadcast clicked")
+    }
+
     private fun handleOpenIntegrationManager() {
         viewModelScope.launch {
             val viewEvent = withContext(Dispatchers.Default) {
diff --git a/vector/src/main/res/drawable/ic_attachment_voice_broadcast.xml b/vector/src/main/res/drawable/ic_attachment_voice_broadcast.xml
new file mode 100644
index 0000000000..3e93522b18
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_attachment_voice_broadcast.xml
@@ -0,0 +1,21 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M20.189,4.187C19.85,3.751 19.222,3.672 18.785,4.011C18.35,4.35 18.271,4.977 18.609,5.413L18.61,5.414L18.611,5.415L18.624,5.434C18.638,5.451 18.659,5.48 18.687,5.52C18.744,5.6 18.828,5.722 18.931,5.884C19.137,6.207 19.415,6.683 19.693,7.281C20.253,8.481 20.799,10.134 20.799,12.001C20.799,13.867 20.253,15.52 19.693,16.721C19.415,17.318 19.137,17.794 18.931,18.117C18.828,18.279 18.744,18.401 18.687,18.481C18.659,18.521 18.638,18.55 18.624,18.568L18.611,18.586L18.61,18.587L18.609,18.588C18.271,19.024 18.35,19.651 18.785,19.99C19.222,20.329 19.85,20.25 20.189,19.815L19.444,19.235C20.189,19.815 20.189,19.815 20.189,19.815L20.191,19.812L20.194,19.808L20.202,19.797L20.229,19.762C20.25,19.733 20.281,19.691 20.318,19.639C20.393,19.534 20.496,19.383 20.618,19.191C20.862,18.807 21.184,18.255 21.506,17.566C22.145,16.195 22.799,14.248 22.799,12.001C22.799,9.753 22.145,7.806 21.506,6.435C21.184,5.746 20.862,5.194 20.618,4.81C20.496,4.618 20.393,4.467 20.318,4.362C20.281,4.31 20.25,4.268 20.229,4.239L20.202,4.204L20.194,4.193L20.191,4.189L20.19,4.188C20.19,4.188 20.189,4.187 19.399,4.801L20.189,4.187Z"
+        android:fillColor="#737D8C" />
+    <path
+        android:pathData="M17.59,7.787C17.251,7.351 16.622,7.272 16.186,7.611C15.752,7.95 15.672,8.576 16.008,9.011L16.012,9.016C16.016,9.022 16.025,9.033 16.037,9.05C16.06,9.084 16.098,9.138 16.144,9.211C16.237,9.357 16.365,9.576 16.494,9.852C16.754,10.41 17,11.163 17,12.001C17,12.839 16.754,13.592 16.494,14.149C16.365,14.425 16.237,14.644 16.144,14.791C16.098,14.864 16.06,14.918 16.037,14.951C16.025,14.968 16.016,14.98 16.012,14.986L16.008,14.99C15.672,15.426 15.752,16.052 16.186,16.39C16.622,16.729 17.251,16.651 17.59,16.215L16.8,15.601C17.59,16.215 17.59,16.215 17.59,16.215L17.591,16.212L17.594,16.21L17.599,16.202L17.616,16.18C17.629,16.163 17.646,16.139 17.667,16.11C17.709,16.051 17.765,15.968 17.831,15.865C17.963,15.657 18.135,15.362 18.306,14.995C18.646,14.267 19,13.22 19,12.001C19,10.782 18.646,9.735 18.306,9.006C18.135,8.639 17.963,8.344 17.831,8.137C17.765,8.033 17.709,7.951 17.667,7.892C17.646,7.863 17.629,7.839 17.616,7.821L17.599,7.799L17.594,7.792L17.591,7.789L17.59,7.788C17.59,7.788 17.59,7.787 16.8,8.401L17.59,7.787Z"
+        android:fillColor="#737D8C" />
+    <path
+        android:pathData="M3.611,19.815C3.95,20.25 4.578,20.329 5.014,19.99C5.45,19.651 5.528,19.024 5.191,18.588L5.19,18.587L5.189,18.586L5.175,18.568C5.162,18.55 5.141,18.521 5.112,18.481C5.056,18.401 4.971,18.279 4.869,18.117C4.663,17.794 4.385,17.318 4.106,16.721C3.546,15.52 3,13.867 3,12C3,10.134 3.546,8.481 4.106,7.281C4.385,6.683 4.663,6.207 4.869,5.884C4.971,5.722 5.056,5.6 5.112,5.52C5.141,5.48 5.162,5.451 5.175,5.433L5.189,5.415L5.19,5.414L5.191,5.413C5.528,4.977 5.449,4.35 5.014,4.011C4.578,3.672 3.95,3.751 3.611,4.187L4.356,4.766C3.611,4.187 3.611,4.187 3.611,4.187L3.609,4.189L3.606,4.193L3.598,4.204L3.571,4.239C3.549,4.268 3.519,4.31 3.482,4.362C3.407,4.467 3.304,4.618 3.181,4.81C2.937,5.194 2.615,5.746 2.294,6.435C1.654,7.806 1,9.753 1,12C1,14.248 1.654,16.195 2.294,17.566C2.615,18.255 2.937,18.807 3.181,19.191C3.304,19.383 3.407,19.534 3.482,19.639C3.519,19.691 3.549,19.733 3.571,19.762L3.598,19.797L3.606,19.808L3.609,19.812L3.61,19.813C3.61,19.813 3.611,19.815 4.4,19.201L3.611,19.815Z"
+        android:fillColor="#737D8C" />
+    <path
+        android:pathData="M6.21,16.214C6.549,16.65 7.177,16.729 7.613,16.39C8.048,16.052 8.127,15.426 7.791,14.99L7.788,14.985C7.783,14.979 7.775,14.968 7.763,14.951C7.739,14.917 7.702,14.863 7.655,14.79C7.562,14.644 7.434,14.425 7.305,14.149C7.045,13.591 6.799,12.838 6.799,12C6.799,11.162 7.045,10.409 7.305,9.852C7.434,9.576 7.562,9.357 7.655,9.21C7.702,9.137 7.739,9.083 7.763,9.05C7.775,9.033 7.783,9.021 7.788,9.015L7.791,9.011C8.127,8.575 8.048,7.949 7.613,7.611C7.177,7.272 6.549,7.35 6.21,7.786L6.999,8.4C6.21,7.786 6.21,7.786 6.21,7.786L6.208,7.789L6.206,7.792L6.2,7.799L6.184,7.821C6.171,7.838 6.153,7.862 6.132,7.892C6.091,7.951 6.034,8.033 5.968,8.137C5.836,8.344 5.664,8.639 5.493,9.006C5.153,9.734 4.799,10.781 4.799,12C4.799,13.219 5.153,14.267 5.493,14.995C5.664,15.362 5.836,15.657 5.968,15.864C6.034,15.968 6.091,16.05 6.132,16.109C6.153,16.139 6.171,16.162 6.184,16.18L6.2,16.202L6.206,16.209L6.208,16.212L6.209,16.213C6.209,16.213 6.21,16.214 6.999,15.6L6.21,16.214Z"
+        android:fillColor="#737D8C" />
+    <path
+        android:pathData="M12,12m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"
+        android:fillColor="#737D8C" />
+</vector>
diff --git a/vector/src/main/res/layout/view_attachment_type_selector.xml b/vector/src/main/res/layout/view_attachment_type_selector.xml
index c108dfd96e..6ce96111e9 100644
--- a/vector/src/main/res/layout/view_attachment_type_selector.xml
+++ b/vector/src/main/res/layout/view_attachment_type_selector.xml
@@ -63,6 +63,16 @@
                 android:src="@drawable/ic_attachment_file"
                 app:tint="?colorPrimary" />
 
+            <ImageButton
+                android:id="@+id/attachmentVoiceBroadcast"
+                android:layout_width="@dimen/layout_touch_size"
+                android:layout_height="@dimen/layout_touch_size"
+                android:layout_marginStart="2dp"
+                android:background="?android:attr/selectableItemBackground"
+                android:contentDescription="@string/attachment_type_voice_broadcast"
+                android:src="@drawable/ic_attachment_voice_broadcast"
+                app:tint="?colorPrimary" />
+
             <ImageButton
                 android:id="@+id/attachmentPollButton"
                 android:layout_width="@dimen/layout_touch_size"