Signal-Android/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt

219 wiersze
6.6 KiB
Kotlin

package org.thoughtcrime.securesms.stories
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.widget.ImageView
import androidx.annotation.ColorInt
import androidx.annotation.Px
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.graphics.ColorUtils
import androidx.core.view.doOnNextLayout
import androidx.core.view.isVisible
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.conversation.colors.ChatColors
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.fonts.TextFont
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
import org.thoughtcrime.securesms.mediasend.v2.text.TextAlignment
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryScale
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryTextWatcher
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture
import org.thoughtcrime.securesms.util.visible
import java.util.Locale
class StoryTextPostView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
init {
inflate(context, R.layout.stories_text_post_view, this)
}
private var textAlignment: TextAlignment? = null
private val backgroundView: ImageView = findViewById(R.id.text_story_post_background)
private val textView: StoryTextView = findViewById(R.id.text_story_post_text)
private val linkPreviewView: StoryLinkPreviewView = findViewById(R.id.text_story_post_link_preview)
private var isPlaceholder: Boolean = true
init {
TextStoryTextWatcher.install(textView)
}
fun showCloseButton() {
linkPreviewView.setCanClose(true)
}
fun hideCloseButton() {
linkPreviewView.setCanClose(false)
}
fun setTypeface(typeface: Typeface) {
textView.typeface = typeface
}
private fun setPostBackground(drawable: Drawable) {
backgroundView.setImageDrawable(drawable)
}
private fun setTextColor(@ColorInt color: Int, isPlaceholder: Boolean) {
if (isPlaceholder) {
textView.setTextColor(ColorUtils.setAlphaComponent(color, 0x99))
} else {
textView.setTextColor(color)
}
}
private fun setText(text: CharSequence, isPlaceholder: Boolean) {
this.isPlaceholder = isPlaceholder
textView.text = text
}
private fun setTextSize(@Px textSize: Float) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
}
private fun setTextGravity(textAlignment: TextAlignment) {
textView.gravity = textAlignment.gravity
}
private fun setTextScale(scalePercent: Int) {
val scale = TextStoryScale.convertToScale(scalePercent)
textView.scaleX = scale
textView.scaleY = scale
}
private fun setTextVisible(visible: Boolean) {
textView.visible = visible
}
private fun setTextBackgroundColor(@ColorInt color: Int) {
textView.setWrappedBackgroundColor(color)
}
fun bindFromCreationState(state: TextStoryPostCreationState) {
textAlignment = state.textAlignment
setPostBackground(state.backgroundColor.chatBubbleMask)
setText(
state.body.ifEmpty {
context.getString(R.string.TextStoryPostCreationFragment__tap_to_add_text)
}.let {
if (state.textFont.isAllCaps) {
it.toString().uppercase(Locale.getDefault())
} else {
it
}
},
state.body.isEmpty()
)
setTextColor(state.textForegroundColor, state.body.isEmpty())
setTextBackgroundColor(state.textBackgroundColor)
setTextGravity(state.textAlignment)
setTextScale(state.textScale)
postAdjustLinkPreviewTranslationY()
}
fun bindFromStoryTextPost(storyTextPost: StoryTextPost) {
visible = true
linkPreviewView.visible = false
textAlignment = TextAlignment.CENTER
val font = TextFont.fromStyle(storyTextPost.style)
setPostBackground(ChatColors.forChatColor(ChatColors.Id.NotSet, storyTextPost.background).chatBubbleMask)
if (font.isAllCaps) {
setText(storyTextPost.body.uppercase(Locale.getDefault()), false)
} else {
setText(storyTextPost.body, false)
}
setTextColor(storyTextPost.textForegroundColor, false)
setTextBackgroundColor(storyTextPost.textBackgroundColor)
setTextGravity(TextAlignment.CENTER)
hideCloseButton()
postAdjustLinkPreviewTranslationY()
}
fun bindLinkPreview(linkPreview: LinkPreview?): ListenableFuture<Boolean> {
return linkPreviewView.bind(linkPreview, View.GONE)
}
fun bindLinkPreviewState(linkPreviewState: LinkPreviewViewModel.LinkPreviewState, hiddenVisibility: Int) {
linkPreviewView.bind(linkPreviewState, hiddenVisibility)
}
fun postAdjustLinkPreviewTranslationY() {
setTextVisible(canDisplayText())
doOnNextLayout {
adjustLinkPreviewTranslationY()
}
}
fun setTextViewClickListener(onClickListener: OnClickListener) {
setOnClickListener(onClickListener)
}
fun setLinkPreviewCloseListener(onClickListener: OnClickListener) {
linkPreviewView.setOnCloseClickListener(onClickListener)
}
fun setLinkPreviewClickListener(onClickListener: OnClickListener?) {
linkPreviewView.setOnClickListener(onClickListener)
}
fun showPostContent() {
textView.alpha = 1f
linkPreviewView.alpha = 1f
}
fun hidePostContent() {
textView.alpha = 0f
linkPreviewView.alpha = 0f
}
private fun canDisplayText(): Boolean {
return !(linkPreviewView.isVisible && isPlaceholder)
}
private fun adjustLinkPreviewTranslationY() {
val backgroundHeight = backgroundView.measuredHeight
val textHeight = if (canDisplayText()) textView.measuredHeight * textView.scaleY else 0f
val previewHeight = if (linkPreviewView.visible) linkPreviewView.measuredHeight else 0
val availableHeight = backgroundHeight - textHeight
if (availableHeight >= previewHeight) {
val totalContentHeight = textHeight + previewHeight
val topAndBottomMargin = backgroundHeight - totalContentHeight
val margin = topAndBottomMargin / 2f
linkPreviewView.translationY = -margin
val originPoint = textView.measuredHeight / 2f
val desiredPoint = (textHeight / 2f) + margin
textView.translationY = desiredPoint - originPoint
} else {
linkPreviewView.translationY = 0f
val originPoint = textView.measuredHeight / 2f
val desiredPoint = backgroundHeight / 2f
textView.translationY = desiredPoint - originPoint
}
}
}