diff --git a/changelog.d/7258.wip b/changelog.d/7258.wip
new file mode 100644
index 0000000000..ee4c2b85f3
--- /dev/null
+++ b/changelog.d/7258.wip
@@ -0,0 +1 @@
+[Voice Broadcast] Add a feature flag with the composer action
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 7925ac02c4..2ad3fdfb58 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -1872,6 +1872,7 @@
"Sticker"
Poll
Location
+ Voice Broadcast
Rotate and crop
Couldn\'t handle share data
@@ -3177,6 +3178,7 @@
Open contacts
Create poll
Share location
+ Start a voice broadcast
Show less
diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
index 9118dea1e3..b927d66b69 100644
--- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
+++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
@@ -90,6 +90,11 @@ class DebugFeaturesStateFactory @Inject constructor(
key = DebugFeatureKeys.newDeviceManagementEnabled,
factory = VectorFeatures::isNewDeviceManagementEnabled
),
+ createBooleanFeature(
+ label = "Enable Voice Broadcast",
+ key = DebugFeatureKeys.voiceBroadcastEnabled,
+ factory = VectorFeatures::isVoiceBroadcastEnabled
+ ),
)
)
}
diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
index c01c058fc6..c347accfc3 100644
--- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
+++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
@@ -79,6 +79,9 @@ class DebugVectorFeatures(
override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled)
?: vectorFeatures.isNewDeviceManagementEnabled()
+ override fun isVoiceBroadcastEnabled(): Boolean = read(DebugFeatureKeys.voiceBroadcastEnabled)
+ ?: vectorFeatures.isVoiceBroadcastEnabled()
+
fun override(value: T?, key: Preferences.Key) = updatePreferences {
if (value == null) {
it.remove(key)
@@ -140,4 +143,5 @@ object DebugFeatureKeys {
val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg")
val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled")
val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled")
+ val voiceBroadcastEnabled = booleanPreferencesKey("voice-broadcast-enabled")
}
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/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
index e1c083db29..9c3ebae641 100644
--- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
+++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
@@ -41,6 +41,7 @@ interface VectorFeatures {
*/
fun isNewAppLayoutFeatureEnabled(): Boolean
fun isNewDeviceManagementEnabled(): Boolean
+ fun isVoiceBroadcastEnabled(): Boolean
}
class DefaultVectorFeatures : VectorFeatures {
@@ -57,4 +58,5 @@ class DefaultVectorFeatures : VectorFeatures {
override fun forceUsageOfOpusEncoder(): Boolean = false
override fun isNewAppLayoutFeatureEnabled(): Boolean = true
override fun isNewDeviceManagementEnabled(): Boolean = false
+ override fun isVoiceBroadcastEnabled(): Boolean = 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 @@
+
+
+
+
+
+
+
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" />
+
+