diff --git a/changelog.d/7436.feature b/changelog.d/7436.feature
new file mode 100644
index 0000000000..b038c975e1
--- /dev/null
+++ b/changelog.d/7436.feature
@@ -0,0 +1 @@
+Rich text editor: add full screen mode.
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index ea9b4b5999..450dcab1f7 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -3423,5 +3423,6 @@
Apply italic format
Apply strikethrough format
Apply underline format
+ Toggle full screen mode
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index b0cd202d12..11a54e9f82 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -150,7 +150,8 @@
+ android:parentActivityName=".features.home.HomeActivity"
+ android:windowSoftInputMode="adjustResize">
diff --git a/vector/src/main/java/im/vector/app/core/extensions/ViewExtensions.kt b/vector/src/main/java/im/vector/app/core/extensions/ViewExtensions.kt
index 625ff15ef7..156809d5ad 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/ViewExtensions.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/ViewExtensions.kt
@@ -29,7 +29,13 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
+import androidx.transition.ChangeBounds
+import androidx.transition.Fade
+import androidx.transition.Transition
+import androidx.transition.TransitionManager
+import androidx.transition.TransitionSet
import im.vector.app.R
+import im.vector.app.core.animations.SimpleTransitionListener
import im.vector.app.features.themes.ThemeUtils
/**
@@ -90,3 +96,18 @@ fun View.setAttributeBackground(@AttrRes attributeId: Int) {
val attribute = ThemeUtils.getAttribute(context, attributeId)!!
setBackgroundResource(attribute.resourceId)
}
+
+fun ViewGroup.animateLayoutChange(animationDuration: Long, transitionComplete: (() -> Unit)? = null) {
+ val transition = TransitionSet().apply {
+ ordering = TransitionSet.ORDERING_SEQUENTIAL
+ addTransition(ChangeBounds())
+ addTransition(Fade(Fade.IN))
+ duration = animationDuration
+ addListener(object : SimpleTransitionListener() {
+ override fun onTransitionEnd(transition: Transition) {
+ transitionComplete?.invoke()
+ }
+ })
+ }
+ TransitionManager.beginDelayedTransition((parent as? ViewGroup ?: this), transition)
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/JumpToBottomViewVisibilityManager.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/JumpToBottomViewVisibilityManager.kt
index 0f7dc251ae..1368b71ec6 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/JumpToBottomViewVisibilityManager.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/JumpToBottomViewVisibilityManager.kt
@@ -34,6 +34,8 @@ class JumpToBottomViewVisibilityManager(
private val layoutManager: LinearLayoutManager
) {
+ private var canShowButtonOnScroll = true
+
init {
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -43,7 +45,7 @@ class JumpToBottomViewVisibilityManager(
if (scrollingToPast) {
jumpToBottomView.hide()
- } else {
+ } else if (canShowButtonOnScroll) {
maybeShowJumpToBottomViewVisibility()
}
}
@@ -66,7 +68,13 @@ class JumpToBottomViewVisibilityManager(
}
}
+ fun hideAndPreventVisibilityChangesWithScrolling() {
+ jumpToBottomView.hide()
+ canShowButtonOnScroll = false
+ }
+
private fun maybeShowJumpToBottomViewVisibility() {
+ canShowButtonOnScroll = true
if (layoutManager.findFirstVisibleItemPosition() > 1) {
jumpToBottomView.show()
} else {
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 9d50cdb070..4f51922a62 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
@@ -32,7 +32,9 @@ import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
+import androidx.activity.addCallback
import androidx.appcompat.view.menu.MenuBuilder
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.net.toUri
@@ -64,6 +66,7 @@ import im.vector.app.core.dialogs.ConfirmationDialogBuilder
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelperFactory
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
+import im.vector.app.core.extensions.animateLayoutChange
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.extensions.containsRtLOverride
@@ -183,7 +186,9 @@ import im.vector.app.features.widgets.WidgetArgs
import im.vector.app.features.widgets.WidgetKind
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -337,6 +342,7 @@ class TimelineFragment :
setupJumpToBottomView()
setupRemoveJitsiWidgetView()
setupLiveLocationIndicator()
+ setupBackPressHandling()
views.includeRoomToolbar.roomToolbarContentView.debouncedClicks {
navigator.openRoomProfile(requireActivity(), timelineArgs.roomId)
@@ -414,6 +420,31 @@ class TimelineFragment :
if (savedInstanceState == null) {
handleSpaceShare()
}
+
+ views.scrim.setOnClickListener {
+ messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(false))
+ }
+
+ messageComposerViewModel.stateFlow.map { it.isFullScreen }
+ .distinctUntilChanged()
+ .onEach { isFullScreen ->
+ toggleFullScreenEditor(isFullScreen)
+ }
+ .launchIn(viewLifecycleOwner.lifecycleScope)
+ }
+
+ private fun setupBackPressHandling() {
+ requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
+ withState(messageComposerViewModel) { state ->
+ if (state.isFullScreen) {
+ messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(false))
+ } else {
+ remove() // Remove callback to avoid infinite loop
+ @Suppress("DEPRECATION")
+ requireActivity().onBackPressed()
+ }
+ }
+ }
}
private fun setupRemoveJitsiWidgetView() {
@@ -1016,7 +1047,13 @@ class TimelineFragment :
override fun onLayoutCompleted(state: RecyclerView.State) {
super.onLayoutCompleted(state)
updateJumpToReadMarkerViewVisibility()
- jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
+ withState(messageComposerViewModel) { composerState ->
+ if (!composerState.isFullScreen) {
+ jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
+ } else {
+ jumpToBottomViewVisibilityManager.hideAndPreventVisibilityChangesWithScrolling()
+ }
+ }
}
}.apply {
// For local rooms, pin the view's content to the top edge (the layout is reversed)
@@ -2002,6 +2039,19 @@ class TimelineFragment :
}
}
+ private fun toggleFullScreenEditor(isFullScreen: Boolean) {
+ views.composerContainer.animateLayoutChange(200)
+
+ val constraintSet = ConstraintSet()
+ val constraintSetId = if (isFullScreen) {
+ R.layout.fragment_timeline_fullscreen
+ } else {
+ R.layout.fragment_timeline
+ }
+ constraintSet.clone(requireContext(), constraintSetId)
+ constraintSet.applyTo(views.rootConstraintLayout)
+ }
+
/**
* Returns true if the current room is a Thread room, false otherwise.
*/
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerAction.kt
index 82adcd014a..30437a016d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerAction.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerAction.kt
@@ -34,6 +34,8 @@ sealed class MessageComposerAction : VectorViewModelAction {
data class SlashCommandConfirmed(val parsedCommand: ParsedCommand) : MessageComposerAction()
data class InsertUserDisplayName(val userId: String) : MessageComposerAction()
+ data class SetFullScreen(val isFullScreen: Boolean) : MessageComposerAction()
+
// Voice Message
data class InitializeVoiceRecorder(val attachmentData: ContentAttachmentData) : MessageComposerAction()
data class OnVoiceRecordingUiStateChanged(val uiState: VoiceMessageRecorderView.RecordingUiState) : MessageComposerAction()
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..beb7215c22 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
@@ -92,6 +92,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.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -219,6 +220,13 @@ class MessageComposerFragment : VectorBaseFragment(), A
}
}
+ messageComposerViewModel.stateFlow.map { it.isFullScreen }
+ .distinctUntilChanged()
+ .onEach { isFullScreen ->
+ composer.toggleFullScreen(isFullScreen)
+ }
+ .launchIn(viewLifecycleOwner.lifecycleScope)
+
if (savedInstanceState != null) {
handleShareData()
}
@@ -297,7 +305,7 @@ class MessageComposerFragment : VectorBaseFragment(), A
// Show keyboard when the user started a thread
composerEditText.showKeyboard(andRequestFocus = true)
}
- composer.callback = object : PlainTextComposerLayout.Callback {
+ composer.callback = object : Callback {
override fun onAddAttachment() {
if (!::attachmentTypeSelector.isInitialized) {
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@MessageComposerFragment)
@@ -320,8 +328,12 @@ class MessageComposerFragment : VectorBaseFragment(), A
composer.emojiButton?.isVisible = isEmojiKeyboardVisible
}
- override fun onSendMessage(text: CharSequence) {
+ override fun onSendMessage(text: CharSequence) = withState(messageComposerViewModel) { state ->
sendTextMessage(text, composer.formattedText)
+
+ if (state.isFullScreen) {
+ messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(false))
+ }
}
override fun onCloseRelatedMessage() {
@@ -335,6 +347,10 @@ class MessageComposerFragment : VectorBaseFragment(), A
override fun onTextChanged(text: CharSequence) {
messageComposerViewModel.handle(MessageComposerAction.OnTextChanged(text))
}
+
+ override fun onFullScreenModeChanged() = withState(messageComposerViewModel) { state ->
+ messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(!state.isFullScreen))
+ }
}
}
@@ -461,7 +477,7 @@ class MessageComposerFragment : VectorBaseFragment(), A
composer.sendButton.alpha = 0f
composer.sendButton.isVisible = true
composer.sendButton.animate().alpha(1f).setDuration(150).start()
- } else {
+ } else if (!event.isVisible) {
composer.sendButton.isInvisible = true
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerView.kt
index 09357191b4..b7e0e29679 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerView.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerView.kt
@@ -30,13 +30,14 @@ interface MessageComposerView {
val emojiButton: ImageButton?
val sendButton: ImageButton
val attachmentButton: ImageButton
+ val fullScreenButton: ImageButton?
val composerRelatedMessageTitle: TextView
val composerRelatedMessageContent: TextView
val composerRelatedMessageImage: ImageView
val composerRelatedMessageActionIcon: ImageView
val composerRelatedMessageAvatar: ImageView
- var callback: PlainTextComposerLayout.Callback?
+ var callback: Callback?
var isVisible: Boolean
@@ -44,6 +45,15 @@ interface MessageComposerView {
fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null)
fun setTextIfDifferent(text: CharSequence?): Boolean
fun replaceFormattedContent(text: CharSequence)
+ fun toggleFullScreen(newValue: Boolean)
fun setInvisible(isInvisible: Boolean)
}
+
+interface Callback : ComposerEditText.Callback {
+ fun onCloseRelatedMessage()
+ fun onSendMessage(text: CharSequence)
+ fun onAddAttachment()
+ fun onExpandOrCompactChange()
+ fun onFullScreenModeChanged()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
index 1a9f9e6291..23d6e71114 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt
@@ -16,6 +16,7 @@
package im.vector.app.features.home.room.detail.composer
+import android.text.SpannableString
import androidx.lifecycle.asFlow
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
@@ -122,6 +123,7 @@ class MessageComposerViewModel @AssistedInject constructor(
is MessageComposerAction.AudioSeekBarMovedTo -> handleAudioSeekBarMovedTo(action)
is MessageComposerAction.SlashCommandConfirmed -> handleSlashCommandConfirmed(action)
is MessageComposerAction.InsertUserDisplayName -> handleInsertUserDisplayName(action)
+ is MessageComposerAction.SetFullScreen -> handleSetFullScreen(action)
}
}
@@ -130,12 +132,11 @@ class MessageComposerViewModel @AssistedInject constructor(
}
private fun handleOnTextChanged(action: MessageComposerAction.OnTextChanged) {
- setState {
- // Makes sure currentComposerText is upToDate when accessing further setState
- currentComposerText = action.text
- this
+ val needsSendButtonVisibilityUpdate = currentComposerText.isEmpty() != action.text.isEmpty()
+ currentComposerText = SpannableString(action.text)
+ if (needsSendButtonVisibilityUpdate) {
+ updateIsSendButtonVisibility(true)
}
- updateIsSendButtonVisibility(true)
}
private fun subscribeToStateInternal() {
@@ -163,6 +164,10 @@ class MessageComposerViewModel @AssistedInject constructor(
}
}
+ private fun handleSetFullScreen(action: MessageComposerAction.SetFullScreen) {
+ setState { copy(isFullScreen = action.isFullScreen) }
+ }
+
private fun observePowerLevelAndEncryption() {
combine(
PowerLevelsFlowFactory(room).createFlow(),
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt
index 0df1dbebd8..7bb9509599 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewState.kt
@@ -70,6 +70,7 @@ data class MessageComposerViewState(
val voiceRecordingUiState: VoiceMessageRecorderView.RecordingUiState = VoiceMessageRecorderView.RecordingUiState.Idle,
val voiceBroadcastState: VoiceBroadcastState? = null,
val text: CharSequence? = null,
+ val isFullScreen: Boolean = false,
) : MavericksState {
val isVoiceRecording = when (voiceRecordingUiState) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/PlainTextComposerLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/PlainTextComposerLayout.kt
index acb5a1b42a..939a59fcca 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/PlainTextComposerLayout.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/PlainTextComposerLayout.kt
@@ -49,13 +49,6 @@ class PlainTextComposerLayout @JvmOverloads constructor(
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), MessageComposerView {
- interface Callback : ComposerEditText.Callback {
- fun onCloseRelatedMessage()
- fun onSendMessage(text: CharSequence)
- fun onAddAttachment()
- fun onExpandOrCompactChange()
- }
-
private val views: ComposerLayoutBinding
override var callback: Callback? = null
@@ -83,6 +76,7 @@ class PlainTextComposerLayout @JvmOverloads constructor(
}
override val attachmentButton: ImageButton
get() = views.attachmentButton
+ override val fullScreenButton: ImageButton? = null
override val composerRelatedMessageActionIcon: ImageView
get() = views.composerRelatedMessageActionIcon
override val composerRelatedMessageAvatar: ImageView
@@ -155,6 +149,10 @@ class PlainTextComposerLayout @JvmOverloads constructor(
return views.composerEditText.setTextIfDifferent(text)
}
+ override fun toggleFullScreen(newValue: Boolean) {
+ // Plain text composer has no full screen
+ }
+
private fun applyNewConstraintSet(animate: Boolean, transitionComplete: (() -> Unit)?) {
// val wasSendButtonInvisible = views.sendButton.isInvisible
if (animate) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt
index 07b7d151ad..cac8f8bed4 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt
@@ -21,7 +21,6 @@ import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ImageView
@@ -33,13 +32,8 @@ import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.text.toSpannable
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
-import androidx.transition.ChangeBounds
-import androidx.transition.Fade
-import androidx.transition.Transition
-import androidx.transition.TransitionManager
-import androidx.transition.TransitionSet
import im.vector.app.R
-import im.vector.app.core.animations.SimpleTransitionListener
+import im.vector.app.core.extensions.animateLayoutChange
import im.vector.app.core.extensions.setTextIfDifferent
import im.vector.app.databinding.ComposerRichTextLayoutBinding
import im.vector.app.databinding.ViewRichTextMenuButtonBinding
@@ -56,12 +50,13 @@ class RichTextComposerLayout @JvmOverloads constructor(
private val views: ComposerRichTextLayoutBinding
- override var callback: PlainTextComposerLayout.Callback? = null
+ override var callback: Callback? = null
private var currentConstraintSetId: Int = -1
-
private val animationDuration = 100L
+ private var isFullScreen = false
+
override val text: Editable?
get() = views.composerEditText.text
override val formattedText: String?
@@ -74,6 +69,8 @@ class RichTextComposerLayout @JvmOverloads constructor(
get() = views.sendButton
override val attachmentButton: ImageButton
get() = views.attachmentButton
+ override val fullScreenButton: ImageButton?
+ get() = views.composerFullScreenButton
override val composerRelatedMessageActionIcon: ImageView
get() = views.composerRelatedMessageActionIcon
override val composerRelatedMessageAvatar: ImageView
@@ -124,6 +121,10 @@ class RichTextComposerLayout @JvmOverloads constructor(
callback?.onAddAttachment()
}
+ views.composerFullScreenButton.setOnClickListener {
+ callback?.onFullScreenModeChanged()
+ }
+
setupRichTextMenu()
}
@@ -205,34 +206,30 @@ class RichTextComposerLayout @JvmOverloads constructor(
return views.composerEditText.setTextIfDifferent(text)
}
+ override fun toggleFullScreen(newValue: Boolean) {
+ val constraintSetId = if (newValue) R.layout.composer_rich_text_layout_constraint_set_fullscreen else currentConstraintSetId
+ ConstraintSet().also {
+ it.clone(context, constraintSetId)
+ it.applyTo(this)
+ }
+
+ updateTextFieldBorder(newValue)
+ }
+
private fun applyNewConstraintSet(animate: Boolean, transitionComplete: (() -> Unit)?) {
// val wasSendButtonInvisible = views.sendButton.isInvisible
if (animate) {
- configureAndBeginTransition(transitionComplete)
+ animateLayoutChange(animationDuration, transitionComplete)
}
ConstraintSet().also {
it.clone(context, currentConstraintSetId)
it.applyTo(this)
}
+
// Might be updated by view state just after, but avoid blinks
// views.sendButton.isInvisible = wasSendButtonInvisible
}
- private fun configureAndBeginTransition(transitionComplete: (() -> Unit)? = null) {
- val transition = TransitionSet().apply {
- ordering = TransitionSet.ORDERING_SEQUENTIAL
- addTransition(ChangeBounds())
- addTransition(Fade(Fade.IN))
- duration = animationDuration
- addListener(object : SimpleTransitionListener() {
- override fun onTransitionEnd(transition: Transition) {
- transitionComplete?.invoke()
- }
- })
- }
- TransitionManager.beginDelayedTransition((parent as? ViewGroup ?: this), transition)
- }
-
override fun setInvisible(isInvisible: Boolean) {
this.isInvisible = isInvisible
}
diff --git a/vector/src/main/res/drawable/ic_composer_full_screen.xml b/vector/src/main/res/drawable/ic_composer_full_screen.xml
new file mode 100644
index 0000000000..394dc52279
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_composer_full_screen.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/vector/src/main/res/layout/composer_rich_text_layout.xml b/vector/src/main/res/layout/composer_rich_text_layout.xml
index 09e4b03887..9f49b8f9d6 100644
--- a/vector/src/main/res/layout/composer_rich_text_layout.xml
+++ b/vector/src/main/res/layout/composer_rich_text_layout.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
tools:constraintSet="@layout/composer_rich_text_layout_constraint_set_compact"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
@@ -108,12 +108,24 @@
style="@style/Widget.Vector.EditText.RichTextComposer"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:gravity="top"
android:nextFocusLeft="@id/composerEditText"
android:nextFocusUp="@id/composerEditText"
tools:hint="@string/room_message_placeholder"
tools:text="@tools:sample/lorem/random"
tools:ignore="MissingConstraints" />
+
+
@@ -114,6 +114,7 @@
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/option_send_files"
android:src="@drawable/ic_attachment"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintBottom_toBottomOf="@id/sendButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/sendButton"
@@ -142,14 +143,26 @@
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/composerEditText"
android:nextFocusUp="@id/composerEditText"
- android:layout_marginHorizontal="12dp"
+ android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
- app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
+ app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
+
+
@@ -173,6 +187,7 @@
app:layout_constraintStart_toEndOf="@id/attachmentButton"
app:layout_constraintEnd_toStartOf="@id/sendButton"
app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintVertical_bias="1"
android:fillViewport="true">
@@ -156,14 +156,26 @@
android:hint="@string/room_message_placeholder"
android:nextFocusLeft="@id/composerEditText"
android:nextFocusUp="@id/composerEditText"
- android:layout_marginHorizontal="12dp"
+ android:layout_marginStart="12dp"
android:layout_marginVertical="10dp"
app:layout_constraintBottom_toBottomOf="@id/composerEditTextOuterBorder"
- app:layout_constraintEnd_toEndOf="@id/composerEditTextOuterBorder"
+ app:layout_constraintEnd_toStartOf="@id/composerFullScreenButton"
app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder"
app:layout_constraintTop_toTopOf="@id/composerEditTextOuterBorder"
tools:text="@tools:sample/lorem/random" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/fragment_composer.xml b/vector/src/main/res/layout/fragment_composer.xml
index 8703af7471..41c052367a 100644
--- a/vector/src/main/res/layout/fragment_composer.xml
+++ b/vector/src/main/res/layout/fragment_composer.xml
@@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="match_parent">
+
+
+
+
@@ -165,6 +182,7 @@
android:layout_margin="16dp"
android:contentDescription="@string/a11y_jump_to_bottom"
android:src="@drawable/ic_expand_more"
+ android:visibility="gone"
app:backgroundTint="#FFFFFF"
app:badgeBackgroundColor="?colorPrimary"
app:badgeTextColor="?colorOnPrimary"
diff --git a/vector/src/main/res/layout/fragment_timeline_fullscreen.xml b/vector/src/main/res/layout/fragment_timeline_fullscreen.xml
new file mode 100644
index 0000000000..373ca74f56
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_timeline_fullscreen.xml
@@ -0,0 +1,258 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+