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" /> + +