mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-16 20:10:04 +03:00
Bubbles: continue R&D on UI
This commit is contained in:
parent
e540b26112
commit
bde1df0322
10 changed files with 109 additions and 19 deletions
|
@ -13,6 +13,9 @@
|
|||
<color name="button_bot_background_color">#14368BD6</color>
|
||||
<color name="button_bot_enabled_text_color">@color/palette_azure</color>
|
||||
|
||||
<color name="bubble_background_outgoing">#0F0DBD8B</color>
|
||||
<color name="bubble_background_incoming">@color/element_system_light</color>
|
||||
|
||||
<!-- Notification (do not depends on theme) -->
|
||||
<color name="notification_accent_color">@color/palette_azure</color>
|
||||
<color name="key_share_req_accent_color">@color/palette_melon</color>
|
||||
|
@ -137,4 +140,5 @@
|
|||
<attr name="vctr_presence_indicator_offline" format="color" />
|
||||
<color name="vctr_presence_indicator_offline_light">@color/palette_gray_100</color>
|
||||
<color name="vctr_presence_indicator_offline_dark">@color/palette_gray_450</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -47,4 +47,8 @@
|
|||
<dimen name="composer_min_height">56dp</dimen>
|
||||
<dimen name="composer_attachment_size">52dp</dimen>
|
||||
<dimen name="composer_attachment_margin">1dp</dimen>
|
||||
|
||||
<dimen name="chat_bubble_margin_start">28dp</dimen>
|
||||
<dimen name="chat_bubble_margin_end">62dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
<declare-styleable name="MessageBubble">
|
||||
<attr name="incoming_style" format="boolean" />
|
||||
<attr name="is_first" format="boolean" />
|
||||
<attr name="is_last" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -145,6 +145,7 @@ class AvatarRenderer @Inject constructor(private val activeSessionHolder: Active
|
|||
}
|
||||
else -> {
|
||||
it.apply(RequestOptions.circleCropTransform())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class AvatarSizeProvider @Inject constructor(private val dimensionConverter: Dim
|
|||
private val avatarStyle = AvatarStyle.X_SMALL
|
||||
|
||||
val leftGuideline: Int by lazy {
|
||||
dimensionConverter.dpToPx(avatarStyle.avatarSizeDP)
|
||||
dimensionConverter.dpToPx(avatarStyle.avatarSizeDP + 4)
|
||||
}
|
||||
|
||||
val avatarSize: Int by lazy {
|
||||
|
@ -37,7 +37,7 @@ class AvatarSizeProvider @Inject constructor(private val dimensionConverter: Dim
|
|||
BIG(50),
|
||||
MEDIUM(40),
|
||||
SMALL(30),
|
||||
X_SMALL(24),
|
||||
X_SMALL(28),
|
||||
NONE(0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,42 +17,94 @@
|
|||
package im.vector.app.features.home.room.detail.timeline.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.google.android.material.shape.CornerFamily
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.google.android.material.shape.ShapeAppearanceModel
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
|
||||
class MessageBubbleView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0) : RelativeLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
var incoming: Boolean = false
|
||||
var isFirst: Boolean = false
|
||||
var isLast: Boolean = false
|
||||
var cornerRadius = DimensionConverter(resources).dpToPx(12).toFloat()
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.view_message_bubble, this)
|
||||
context.withStyledAttributes(attrs, R.styleable.MessageBubble) {
|
||||
incoming = getBoolean(R.styleable.MessageBubble_incoming_style, false)
|
||||
isFirst = getBoolean(R.styleable.MessageBubble_is_first, false)
|
||||
isLast = getBoolean(R.styleable.MessageBubble_is_last, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
val currentLayoutDirection = layoutDirection
|
||||
findViewById<ViewGroup>(R.id.bubbleView).apply {
|
||||
background = createBackgroundDrawable()
|
||||
outlineProvider = ViewOutlineProvider.BACKGROUND
|
||||
clipToOutline = true
|
||||
}
|
||||
if (incoming) {
|
||||
findViewById<View>(R.id.informationBottom).layoutDirection = currentLayoutDirection
|
||||
findViewById<View>(R.id.bubbleWrapper).layoutDirection = currentLayoutDirection
|
||||
findViewById<View>(R.id.bubbleView).layoutDirection = currentLayoutDirection
|
||||
findViewById<RelativeLayout>(R.id.bubbleView).setBackgroundResource(R.drawable.bg_timeline_incoming_message)
|
||||
findViewById<View>(R.id.messageEndGuideline).updateLayoutParams<LayoutParams> {
|
||||
marginEnd = resources.getDimensionPixelSize(R.dimen.chat_bubble_margin_end)
|
||||
}
|
||||
} else {
|
||||
val oppositeLayoutDirection = if (currentLayoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||
View.LAYOUT_DIRECTION_RTL
|
||||
} else {
|
||||
View.LAYOUT_DIRECTION_LTR
|
||||
}
|
||||
|
||||
findViewById<View>(R.id.informationBottom).layoutDirection = oppositeLayoutDirection
|
||||
findViewById<View>(R.id.bubbleWrapper).layoutDirection = oppositeLayoutDirection
|
||||
findViewById<View>(R.id.bubbleView).layoutDirection = currentLayoutDirection
|
||||
findViewById<RelativeLayout>(R.id.bubbleView).setBackgroundResource(R.drawable.bg_timeline_outgoing_message)
|
||||
findViewById<View>(R.id.messageEndGuideline).updateLayoutParams<LayoutParams> {
|
||||
marginEnd = resources.getDimensionPixelSize(R.dimen.chat_bubble_margin_start)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBackgroundDrawable(): Drawable {
|
||||
val topCornerFamily = if (isFirst) CornerFamily.ROUNDED else CornerFamily.CUT
|
||||
val bottomCornerFamily = if (isLast) CornerFamily.ROUNDED else CornerFamily.CUT
|
||||
val topRadius = if (isFirst) cornerRadius else 0f
|
||||
val bottomRadius = if (isLast) cornerRadius else 0f
|
||||
val shapeAppearanceModelBuilder = ShapeAppearanceModel().toBuilder()
|
||||
val backgroundColor: Int
|
||||
if (incoming) {
|
||||
backgroundColor = R.color.bubble_background_incoming
|
||||
shapeAppearanceModelBuilder
|
||||
.setTopRightCorner(CornerFamily.ROUNDED, cornerRadius)
|
||||
.setBottomRightCorner(CornerFamily.ROUNDED, cornerRadius)
|
||||
.setTopLeftCorner(topCornerFamily, topRadius)
|
||||
.setBottomLeftCorner(bottomCornerFamily, bottomRadius)
|
||||
} else {
|
||||
backgroundColor = R.color.bubble_background_outgoing
|
||||
shapeAppearanceModelBuilder
|
||||
.setTopLeftCorner(CornerFamily.ROUNDED, cornerRadius)
|
||||
.setBottomLeftCorner(CornerFamily.ROUNDED, cornerRadius)
|
||||
.setTopRightCorner(topCornerFamily, topRadius)
|
||||
.setBottomRightCorner(bottomCornerFamily, bottomRadius)
|
||||
}
|
||||
val shapeAppearanceModel = shapeAppearanceModelBuilder.build()
|
||||
val shapeDrawable = MaterialShapeDrawable(shapeAppearanceModel)
|
||||
shapeDrawable.fillColor = ContextCompat.getColorStateList(context, backgroundColor)
|
||||
return shapeDrawable
|
||||
}
|
||||
}
|
||||
|
|
12
vector/src/main/res/drawable/bg_avatar_border.xml
Normal file
12
vector/src/main/res/drawable/bg_avatar_border.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
|
||||
<solid android:color="@android:color/transparent"/>
|
||||
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="?android:colorBackground"/>
|
||||
|
||||
</shape>
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?attr/vctr_system" />
|
||||
<corners android:radius="12dp"/>
|
||||
</shape>
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#0F0DBD8B" />
|
||||
<corners android:radius="12dp"/>
|
||||
</shape>
|
|
@ -19,9 +19,12 @@
|
|||
android:id="@+id/messageAvatarImageView"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:padding="2dp"
|
||||
android:background="@drawable/bg_avatar_border"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:elevation="2dp"
|
||||
tools:src="@sample/user_round_avatars" />
|
||||
|
||||
<TextView
|
||||
|
@ -31,7 +34,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_toEndOf="@id/messageStartGuideline"
|
||||
android:ellipsize="end"
|
||||
|
@ -46,6 +49,13 @@
|
|||
android:layout_height="0dp"
|
||||
tools:layout_marginStart="52dp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/messageEndGuideline"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="64dp" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/decorationSpace"
|
||||
android:layout_width="4dp"
|
||||
|
@ -59,6 +69,7 @@
|
|||
android:layout_alignTop="@id/bubbleWrapper"
|
||||
android:layout_alignEnd="@id/decorationSpace"
|
||||
android:layout_marginTop="7dp"
|
||||
android:elevation="2dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
@ -67,45 +78,49 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/messageMemberNameView"
|
||||
android:layout_toStartOf="@id/messageSendStateImageView"
|
||||
android:layout_toStartOf="@id/messageEndGuideline"
|
||||
android:layout_toEndOf="@id/messageStartGuideline"
|
||||
android:addStatesFromChildren="true"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<RelativeLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/bubbleView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:addStatesFromChildren="true"
|
||||
android:background="@drawable/bg_timeline_incoming_message"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
tools:ignore="UselessParent">
|
||||
android:paddingStart="4dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<include
|
||||
android:id="@+id/viewStubContainer"
|
||||
layout="@layout/item_timeline_event_view_stubs_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:addStatesFromChildren="true" />
|
||||
android:addStatesFromChildren="true"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@id/messageTimeView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth_max="300dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/messageTimeView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@id/viewStubContainer"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_toEndOf="@id/viewStubContainer"
|
||||
android:textColor="?vctr_content_tertiary"
|
||||
android:textSize="10sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/viewStubContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:text="@tools:sample/date/hhmm" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<im.vector.app.core.ui.views.SendStateImageView
|
||||
|
@ -143,6 +158,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/bubbleWrapper"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_toStartOf="@id/messageEndGuideline"
|
||||
android:layout_toEndOf="@id/messageStartGuideline"
|
||||
android:addStatesFromChildren="true"
|
||||
android:orientation="vertical">
|
||||
|
@ -151,7 +169,6 @@
|
|||
android:id="@+id/reactionsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:dividerDrawable="@drawable/reaction_divider"
|
||||
app:flexWrap="wrap"
|
||||
|
|
Loading…
Add table
Reference in a new issue