Setting for more rounded bubbles

Closes https://github.com/SchildiChat/SchildiChat-android/issues/48

Change-Id: I51dabc18c1542dcd4b8d12769fe1cc76573441c5
This commit is contained in:
SpiritCroc 2022-03-03 09:03:27 +01:00
parent 20ba02db57
commit fe5eaece47
31 changed files with 795 additions and 43 deletions

View file

@ -5,7 +5,7 @@ set -e
my_dir="$(dirname "$(realpath "$0")")"
pushd "$my_dir" > /dev/null
res_dir="vector/src/main/res/"
res_dir="vector/src/main/res"
god_bubble="vector/src/main/res/drawable/msg_godbubble.xml"
# Multiline sed -i
@ -27,6 +27,7 @@ function create_msg_bubble() {
local is_rtl="$2"
local is_notice="$3"
local has_tail="$4"
local roundness="$5"
# Out file name
local out_bubble="$res_dir/drawable"
@ -34,6 +35,9 @@ function create_msg_bubble() {
local out_bubble="$out_bubble-ldrtl"
fi
local out_bubble="$out_bubble/msg_bubble"
if [ ! -z "$roundness" ]; then
local out_bubble="${out_bubble}_$roundness"
fi
if ((is_notice)); then
local out_bubble="${out_bubble}_notice"
else
@ -79,19 +83,25 @@ function create_msg_bubble() {
if ((is_outgoing)); then
sed -i 's|_incoming|_outgoing|g' "$out_bubble"
fi
# Modify roundness
if [ ! -z "$roundness" ]; then
sed -i "s|sc_bubble_radius|sc_bubble_${roundness}_radius|g" "$out_bubble"
fi
# Remove unneeded size, which only exists to make it look nicer in drawable preview
sed -i 's|<size.*/>||g' "$out_bubble"
}
for is_outgoing in 0 1; do
for is_rtl in 0 1; do
# Notices are handled via transparency and do not need own drawables right now
is_notice=0
#for is_notice in 0 1; do
for has_tail in 0 1; do
create_msg_bubble "$is_outgoing" "$is_rtl" "$is_notice" "$has_tail"
done
#done
for roundness in "" "r1" "r2"; do
for is_outgoing in 0 1; do
for is_rtl in 0 1; do
# Notices are handled via transparency and do not need own drawables right now
is_notice=0
#for is_notice in 0 1; do
for has_tail in 0 1; do
create_msg_bubble "$is_outgoing" "$is_rtl" "$is_notice" "$has_tail" "$roundness"
done
#done
done
done
done

View file

@ -17,6 +17,7 @@
package im.vector.app.features.home.room.detail.timeline.item
import android.content.res.Resources
import android.graphics.Bitmap
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@ -25,6 +26,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import com.bumptech.glide.load.Transformation
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener
@ -37,7 +39,9 @@ import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLay
import im.vector.app.features.home.room.detail.timeline.style.granularRoundedCorners
import im.vector.app.features.home.room.detail.timeline.view.ScMessageBubbleWrapView
import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.themes.defaultScBubbleAppearance
import org.matrix.android.sdk.api.util.MimeTypes
import kotlin.math.round
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Holder>() {
@ -90,12 +94,23 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
val messageLayout = baseAttributes.informationData.messageLayout
val dimensionConverter = DimensionConverter(holder.view.resources)
val imageCornerTransformation = when (messageLayout) {
is TimelineMessageLayout.ScBubble -> RoundedCorners(dimensionConverter.dpToPx(3))
is TimelineMessageLayout.Bubble -> messageLayout.cornersRadius.granularRoundedCorners()
else -> RoundedCorners(dimensionConverter.dpToPx(8))
val cornerRoundnessDp: Int
val imageCornerTransformation: Transformation<Bitmap>
when (messageLayout) {
is TimelineMessageLayout.ScBubble -> {
cornerRoundnessDp = round(messageLayout.bubbleAppearance.getBubbleRadiusDp(holder.view.context)).toInt()
imageCornerTransformation = RoundedCorners(dimensionConverter.dpToPx(cornerRoundnessDp))
}
is TimelineMessageLayout.Bubble -> {
cornerRoundnessDp = 8
imageCornerTransformation = messageLayout.cornersRadius.granularRoundedCorners()
}
else -> {
cornerRoundnessDp = 8
imageCornerTransformation = RoundedCorners(dimensionConverter.dpToPx(cornerRoundnessDp))
}
}
imageContentRenderer.render(mediaData, effectiveMode, holder.imageView, imageCornerTransformation, onImageSizeListener)
imageContentRenderer.render(mediaData, effectiveMode, holder.imageView, cornerRoundnessDp, imageCornerTransformation, onImageSizeListener)
if (!attributes.informationData.sendState.hasFailed()) {
contentUploadStateTrackerBinder.bind(
attributes.informationData.eventId,
@ -180,14 +195,16 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
// Image outline
when {
!(messageLayout.isRealBubble || messageLayout.isPseudoBubble) || mode != ImageContentRenderer.Mode.THUMBNAIL -> {
// Don't show it for non-bubble layouts, don't show for Stickers, ...
// Don't show it for non-bubble layouts, don't show for Stickers, ...
// Also only supported for default corner radius
!(messageLayout.isRealBubble || messageLayout.isPseudoBubble) || mode != ImageContentRenderer.Mode.THUMBNAIL
|| messageLayout.bubbleAppearance != defaultScBubbleAppearance -> {
holder.mediaContentView.background = null
}
attributes.informationData.sentByMe -> {
attributes.informationData.sentByMe -> {
holder.mediaContentView.setBackgroundResource(R.drawable.background_image_border_outgoing)
}
else -> {
else -> {
holder.mediaContentView.setBackgroundResource(R.drawable.background_image_border_incoming)
}
}

View file

@ -61,7 +61,7 @@ abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>(
val messageLayout = attributes.informationData.messageLayout
val dimensionConverter = DimensionConverter(holder.view.resources)
val imageCornerTransformation = when (messageLayout) {
is TimelineMessageLayout.ScBubble -> RoundedCorners(dimensionConverter.dpToPx(3))
is TimelineMessageLayout.ScBubble -> RoundedCorners(messageLayout.bubbleAppearance.getBubbleRadiusPx(holder.view.context))
is TimelineMessageLayout.Bubble -> messageLayout.cornersRadius.granularRoundedCorners()
else -> RoundedCorners(dimensionConverter.dpToPx(8))
}

View file

@ -17,8 +17,9 @@
package im.vector.app.features.home.room.detail.timeline.style
import android.os.Parcelable
import androidx.annotation.DrawableRes
import im.vector.app.R
import im.vector.app.features.home.room.detail.timeline.item.AnonymousReadReceipt
import im.vector.app.features.themes.ScBubbleAppearance
import kotlinx.parcelize.Parcelize
sealed interface TimelineMessageLayout : Parcelable {
@ -68,6 +69,7 @@ sealed interface TimelineMessageLayout : Parcelable {
override val showDisplayName: Boolean,
override val showTimestamp: Boolean = true,
override val showE2eDecoration: Boolean = false,
val bubbleAppearance: ScBubbleAppearance,
val isIncoming: Boolean,
val reverseBubble: Boolean,
val singleSidedLayout: Boolean,
@ -79,6 +81,22 @@ sealed interface TimelineMessageLayout : Parcelable {
R.layout.item_timeline_event_sc_bubble_incoming_base
} else {
R.layout.item_timeline_event_sc_bubble_outgoing_base
},
@DrawableRes
val bubbleDrawable: Int = if (isPseudoBubble) {
0
} else if (showAvatar) { // tail
if (reverseBubble) { // outgoing
bubbleAppearance.textBubbleOutgoing
} else { // incoming
bubbleAppearance.textBubbleIncoming
}
} else { // notail
if (reverseBubble) { // outgoing
bubbleAppearance.textBubbleOutgoingNoTail
} else { // incoming
bubbleAppearance.textBubbleIncomingNoTail
}
}
) : TimelineMessageLayout

View file

@ -112,6 +112,7 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
// Display name still required for single sided layout if timestamp is shown (empty space looks bad otherwise)
showDisplayName = showInformation && ((singleSidedLayout && showTimestamp) || !messageContent.redundantDisplayName()),
showTimestamp = showTimestamp,
bubbleAppearance = bubbleThemeUtils.getBubbleAppearance(),
isIncoming = !isSentByMe,
isNotice = messageContent is MessageNoticeContent,
reverseBubble = isSentByMe && !singleSidedLayout,
@ -168,6 +169,7 @@ class TimelineMessageLayoutFactory @Inject constructor(private val session: Sess
showAvatar = false,
showDisplayName = false,
showTimestamp = true,
bubbleAppearance = bubbleThemeUtils.getBubbleAppearance(),
isIncoming = false,
isNotice = false,
reverseBubble = false,

View file

@ -264,21 +264,8 @@ class ScMessageBubbleWrapView @JvmOverloads constructor(context: Context, attrs:
// Padding for bubble content: long for side with tail, short for other sides
val longPaddingDp: Int
val shortPaddingDp: Int
bubbleView.setBackgroundResource(messageLayout.bubbleDrawable)
if (!messageLayout.isPseudoBubble) {
val bubbleRes = if (messageLayout.showAvatar) { // tail
if (messageLayout.reverseBubble) { // outgoing
R.drawable.msg_bubble_text_outgoing
} else { // incoming
R.drawable.msg_bubble_text_incoming
}
} else { // notail
if (messageLayout.reverseBubble) { // outgoing
R.drawable.msg_bubble_text_outgoing_notail
} else { // incoming
R.drawable.msg_bubble_text_incoming_notail
}
}
bubbleView.setBackgroundResource(bubbleRes)
longPaddingDp = bubbleView.resources.getDimensionPixelSize(R.dimen.sc_bubble_inner_padding_long_side)
shortPaddingDp = bubbleView.resources.getDimensionPixelSize(R.dimen.sc_bubble_inner_padding_short_side)
} else {

View file

@ -146,7 +146,7 @@ class ImageContentRenderer @Inject constructor(private val localFilesHelper: Loc
.into(imageView)
}
fun render(data: Data, mode: Mode, imageView: ImageView, cornerTransformation: Transformation<Bitmap> = RoundedCorners(dimensionConverter.dpToPx(3)), onImageSizeListener: OnImageSizeListener? = null, animate: Boolean = false) {
fun render(data: Data, mode: Mode, imageView: ImageView, cornerRoundnessDp: Int = 3, cornerTransformation: Transformation<Bitmap> = RoundedCorners(dimensionConverter.dpToPx(cornerRoundnessDp)), onImageSizeListener: OnImageSizeListener? = null, animate: Boolean = false) {
val size = processSize(data, mode)
imageView.updateLayoutParams {
width = size.width
@ -177,8 +177,7 @@ class ImageContentRenderer @Inject constructor(private val localFilesHelper: Loc
})
request = if (animate) {
// Glide seems to already do some dp to px calculation for animated gifs?
// SC-TODO extract dp from cornerTransformation
request.transform(RoundedCorners(3))
request.transform(RoundedCorners(cornerRoundnessDp))
//request.apply(RequestOptions.bitmapTransform(RoundedCorners(3)))
} else {
request.dontAnimate()

View file

@ -0,0 +1,31 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.settings
import im.vector.app.R
import javax.inject.Inject
class VectorSettingsBubbleAppearanceFragment @Inject constructor(
//private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
override var titleRes = R.string.bubble_appearance
override val preferenceXmlRes = R.xml.vector_settings_bubble_appearance
override fun bindPref() {
}
}

View file

@ -43,11 +43,16 @@ class VectorSettingsPreferencesFragment @Inject constructor(
private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
companion object {
const val BUBBLE_APPEARANCE_KEY = "BUBBLE_APPEARANCE_KEY"
}
override var titleRes = R.string.settings_preferences
override val preferenceXmlRes = R.xml.vector_settings_preferences
//private var bubbleTimeLocationPref: VectorListPreference? = null
private var alwaysShowTimestampsPref: VectorSwitchPreference? = null
private var bubbleAppearancePref: VectorPreference? = null
private val selectedLanguagePreference by lazy {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_INTERFACE_LANGUAGE_PREFERENCE_KEY)!!
@ -104,6 +109,7 @@ class VectorSettingsPreferencesFragment @Inject constructor(
}
alwaysShowTimestampsPref = findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_ALWAYS_SHOW_TIMESTAMPS_KEY)
bubbleAppearancePref = findPreference(BUBBLE_APPEARANCE_KEY)
updateBubbleDependencies(bubbleStyle = bubbleStylePreference.value)
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME)!!.let { pref ->
@ -246,6 +252,7 @@ class VectorSettingsPreferencesFragment @Inject constructor(
private fun updateBubbleDependencies(bubbleStyle: String) {
//bubbleTimeLocationPref?.setEnabled(BubbleThemeUtils.isBubbleTimeLocationSettingAllowed(bubbleStyle))
alwaysShowTimestampsPref?.setEnabled(bubbleStyle in listOf(BubbleThemeUtils.BUBBLE_STYLE_NONE, BubbleThemeUtils.BUBBLE_STYLE_START))
alwaysShowTimestampsPref?.isEnabled = bubbleStyle in listOf(BubbleThemeUtils.BUBBLE_STYLE_NONE, BubbleThemeUtils.BUBBLE_STYLE_START)
bubbleAppearancePref?.isEnabled = bubbleStyle in listOf(BubbleThemeUtils.BUBBLE_STYLE_START, BubbleThemeUtils.BUBBLE_STYLE_BOTH)
}
}

View file

@ -2,9 +2,14 @@ package im.vector.app.features.themes
import android.content.Context
import android.graphics.Paint
import android.os.Parcelable
import android.widget.TextView
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.preference.PreferenceManager
import im.vector.app.R
import im.vector.app.features.home.room.detail.timeline.item.AnonymousReadReceipt
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import timber.log.Timber
@ -16,6 +21,11 @@ import javax.inject.Inject
class BubbleThemeUtils @Inject constructor(private val context: Context) {
companion object {
const val BUBBLE_STYLE_KEY = "BUBBLE_STYLE_KEY"
const val BUBBLE_ROUNDNESS_KEY = "SETTINGS_SC_BUBBLE_ROUNDED_CORNERS"
const val BUBBLE_ROUNDNESS_DEFAULT = "default"
const val BUBBLE_ROUNDNESS_R1 = "r1"
const val BUBBLE_ROUNDNESS_R2 = "r2"
const val BUBBLE_TAIL_KEY = "SETTINGS_SC_BUBBLE_TAIL"
const val BUBBLE_STYLE_NONE = "none"
const val BUBBLE_STYLE_ELEMENT = "element"
@ -62,6 +72,22 @@ class BubbleThemeUtils @Inject constructor(private val context: Context) {
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(BUBBLE_STYLE_KEY, value).apply()
}
fun getBubbleAppearance(): ScBubbleAppearance {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val baseAppearance = when (prefs.getString(BUBBLE_ROUNDNESS_KEY, BUBBLE_ROUNDNESS_DEFAULT)) {
BUBBLE_ROUNDNESS_R1 -> r1ScBubbleAppearance
BUBBLE_ROUNDNESS_R2 -> r2ScBubbleAppearance
else -> defaultScBubbleAppearance
}
return if (prefs.getBoolean(BUBBLE_TAIL_KEY, true)) {
baseAppearance
} else {
baseAppearance.copy(
textBubbleOutgoing = baseAppearance.textBubbleOutgoingNoTail,
textBubbleIncoming = baseAppearance.textBubbleIncomingNoTail
)
}
}
}
fun guessTextWidth(view: TextView): Float {
@ -77,3 +103,49 @@ fun guessTextWidth(textSize: Float, text: CharSequence): Float {
paint.textSize = textSize
return paint.measureText(text.toString())
}
@Parcelize
data class ScBubbleAppearance(
@DimenRes
val roundness: Int,
@DrawableRes
val textBubbleOutgoing: Int,
@DrawableRes
val textBubbleIncoming: Int,
@DrawableRes
val textBubbleOutgoingNoTail: Int,
@DrawableRes
val textBubbleIncomingNoTail: Int,
) : Parcelable {
fun getBubbleRadiusPx(context: Context): Int {
return context.resources.getDimensionPixelSize(roundness)
}
fun getBubbleRadiusDp(context: Context): Float {
return context.resources.getDimension(roundness)
}
}
val defaultScBubbleAppearance = ScBubbleAppearance(
R.dimen.sc_bubble_radius,
R.drawable.msg_bubble_text_outgoing,
R.drawable.msg_bubble_text_incoming,
R.drawable.msg_bubble_text_outgoing_notail,
R.drawable.msg_bubble_text_incoming_notail,
)
val r1ScBubbleAppearance = ScBubbleAppearance(
R.dimen.sc_bubble_r1_radius,
R.drawable.msg_bubble_r1_text_outgoing,
R.drawable.msg_bubble_r1_text_incoming,
R.drawable.msg_bubble_r1_text_outgoing_notail,
R.drawable.msg_bubble_r1_text_incoming_notail,
)
val r2ScBubbleAppearance = ScBubbleAppearance(
R.dimen.sc_bubble_r2_radius,
R.drawable.msg_bubble_r2_text_outgoing,
R.drawable.msg_bubble_r2_text_incoming,
R.drawable.msg_bubble_r2_text_outgoing_notail,
R.drawable.msg_bubble_r2_text_incoming_notail,
)

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:bottomRightRadius="@dimen/sc_bubble_r1_radius"
android:bottomLeftRadius="@dimen/sc_bubble_r1_radius"
android:topLeftRadius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|right">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<path
android:pathData="M10,0 L0,10 L0,0 Z"
android:fillColor="?sc_message_bg_incoming" />
<!-- tail end -->
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:radius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:bottomLeftRadius="@dimen/sc_bubble_r1_radius"
android:bottomRightRadius="@dimen/sc_bubble_r1_radius"
android:topRightRadius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|left">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<!-- LTR tail -->
<path
android:pathData="M0,0 L10,10 L10,0 Z"
android:fillColor="?sc_message_bg_outgoing" />
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:radius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:bottomRightRadius="@dimen/sc_bubble_r2_radius"
android:bottomLeftRadius="@dimen/sc_bubble_r2_radius"
android:topLeftRadius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|right">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<path
android:pathData="M10,0 L0,10 L0,0 Z"
android:fillColor="?sc_message_bg_incoming" />
<!-- tail end -->
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:radius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:bottomLeftRadius="@dimen/sc_bubble_r2_radius"
android:bottomRightRadius="@dimen/sc_bubble_r2_radius"
android:topRightRadius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|left">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<!-- LTR tail -->
<path
android:pathData="M0,0 L10,10 L10,0 Z"
android:fillColor="?sc_message_bg_outgoing" />
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:radius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:bottomLeftRadius="@dimen/sc_bubble_r1_radius"
android:bottomRightRadius="@dimen/sc_bubble_r1_radius"
android:topRightRadius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|left">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<!-- LTR tail -->
<path
android:pathData="M0,0 L10,10 L10,0 Z"
android:fillColor="?sc_message_bg_incoming" />
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:radius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:bottomRightRadius="@dimen/sc_bubble_r1_radius"
android:bottomLeftRadius="@dimen/sc_bubble_r1_radius"
android:topLeftRadius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|right">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<path
android:pathData="M10,0 L0,10 L0,0 Z"
android:fillColor="?sc_message_bg_outgoing" />
<!-- tail end -->
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:radius="@dimen/sc_bubble_r1_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:bottomLeftRadius="@dimen/sc_bubble_r2_radius"
android:bottomRightRadius="@dimen/sc_bubble_r2_radius"
android:topRightRadius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|left">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<!-- LTR tail -->
<path
android:pathData="M0,0 L10,10 L10,0 Z"
android:fillColor="?sc_message_bg_incoming" />
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:left="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_incoming" />
<corners android:radius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:bottomRightRadius="@dimen/sc_bubble_r2_radius"
android:bottomLeftRadius="@dimen/sc_bubble_r2_radius"
android:topLeftRadius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Tail -->
<item
android:gravity="top|right">
<vector
android:width="@dimen/sc_bubble_tail_size"
android:height="@dimen/sc_bubble_tail_size"
android:viewportWidth="10.0"
android:viewportHeight="10.0">
<path
android:pathData="M10,0 L0,10 L0,0 Z"
android:fillColor="?sc_message_bg_outgoing" />
<!-- tail end -->
</vector>
</item>
<!-- Tail end -->
</layer-list>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
IMPORTANT:
Only modify msg_godbubble.xml, then run `generate_bubbles.sh` to update all actually used msg_bubble_*.xml drawables.
Note also that most of the comments should not be changed without checking their use in `generate_bubbles.sh`.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Filled for no tail -->
<item android:right="@dimen/sc_bubble_tail_size">
<shape
android:shape="rectangle">
<solid android:color="?sc_message_bg_outgoing" />
<corners android:radius="@dimen/sc_bubble_r2_radius" />
</shape>
</item>
<!-- Filled end -->
</layer-list>

View file

@ -14,6 +14,17 @@
<item>none</item>
</string-array>
<string-array name="bubble_appearance_roundness_entries" translatable="false">
<item>@string/bubble_rounded_corners_default</item>
<item>@string/bubble_rounded_corners_r1</item>
<item>@string/bubble_rounded_corners_r2</item>
</string-array>
<string-array name="bubble_appearance_roundness_values" translatable="false">
<item>default</item>
<item>r1</item>
<item>r2</item>
</string-array>
<string-array name="bubble_time_location_entries" translatable="false">
<item>@string/bubble_time_location_top</item>
<item>@string/bubble_time_location_bottom</item>

View file

@ -20,6 +20,12 @@
<!-- inner_padding_short_side + inner_padding_long_side (+ some extra to make sure?) -->
<dimen name="sc_bubble_guess_minimum_width_padding">32dp</dimen>
<!-- Extra round bubbles -->
<dimen name="sc_bubble_r1_radius">8dp</dimen>
<dimen name="sc_bubble_r2_radius">12dp</dimen>
<dimen name="sc_bubble_r1_radius_in_tail">@dimen/sc_bubble_radius_in_tail</dimen>
<dimen name="sc_bubble_r2_radius_in_tail">@dimen/sc_bubble_radius_in_tail</dimen>
<!-- Footer dimensions -->
<dimen name="sc_footer_overlay_padding">2dp</dimen>
<dimen name="sc_footer_noverlay_padding_top">4dp</dimen>

View file

@ -45,6 +45,14 @@
<string name="bubble_time_location_top">Top</string>
<string name="bubble_time_location_bottom">Bottom</string>
<string name="bubble_appearance">Bubble appearance</string>
<string name="bubble_rounded_corners">Corners</string>
<string name="bubble_rounded_corners_default">Default</string>
<string name="bubble_rounded_corners_r1">Round</string>
<string name="bubble_rounded_corners_r2">Extra round</string>
<string name="bubble_tail">Bubble tail</string>
<string name="bubble_tail_summary">Include bubble tail for a sender\'s first message</string>
<string name="settings_unread_counter">Unread counter</string>
<string name="settings_unimportant_counter_badge_v2">Count muted messages</string>
<string name="settings_unimportant_counter_badge_summary_v2">Show counts for muted messages in the chat overview</string>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<im.vector.app.core.preference.VectorListPreference
android:defaultValue="default"
android:key="SETTINGS_SC_BUBBLE_ROUNDED_CORNERS"
android:title="@string/bubble_rounded_corners"
android:summary="%s"
android:entries="@array/bubble_appearance_roundness_entries"
android:entryValues="@array/bubble_appearance_roundness_values" />
<im.vector.app.core.preference.VectorSwitchPreference
android:defaultValue="true"
android:key="SETTINGS_SC_BUBBLE_TAIL"
android:title="@string/bubble_tail"
android:summary="@string/bubble_tail_summary" />
</androidx.preference.PreferenceScreen>

View file

@ -38,6 +38,10 @@
android:title="@string/settings_dark_theme"
app:iconSpaceReserved="false" />
<im.vector.app.core.preference.VectorPreference
android:title="@string/settings_advanced_theme_settings"
app:fragment="im.vector.app.features.settings.VectorSettingsAdvancedThemeFragment" />
<im.vector.app.core.preference.VectorListPreference
android:defaultValue="both"
android:entries="@array/bubble_style_entries"
@ -47,6 +51,11 @@
android:title="@string/bubble_style"
app:iconSpaceReserved="false" />
<im.vector.app.core.preference.VectorPreference
android:key="BUBBLE_APPEARANCE_KEY"
android:title="@string/bubble_appearance"
app:fragment="im.vector.app.features.settings.VectorSettingsBubbleAppearanceFragment" />
<!--
<im.vector.app.core.preference.VectorListPreference
android:key="BUBBLE_TIME_LOCATION_KEY"
@ -64,10 +73,6 @@
android:persistent="false"
android:title="@string/font_size" />
<im.vector.app.core.preference.VectorPreference
android:title="@string/settings_advanced_theme_settings"
app:fragment="im.vector.app.features.settings.VectorSettingsAdvancedThemeFragment" />
</im.vector.app.core.preference.VectorPreferenceCategory>
<im.vector.app.core.preference.VectorPreferenceCategory