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

173 wiersze
5.0 KiB
Kotlin

package org.thoughtcrime.securesms.stories
import android.content.Context
import android.os.Bundle
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import org.signal.core.util.getParcelableCompat
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.visible
/**
* Displays loading / error slate in Story viewer.
*/
class StorySlateView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
var callback: Callback? = null
var state: State = State.HIDDEN
private set
private var postId: Long = 0L
init {
inflate(context, R.layout.stories_slate_view, this)
}
private val background: ImageView = findViewById(R.id.background)
private val loadingSpinner: View = findViewById(R.id.loading_spinner)
private val errorCircle: View = findViewById(R.id.error_circle)
private val errorBackground: View = findViewById(R.id.stories_error_background)
private val unavailableText: TextView = findViewById(R.id.unavailable)
private val errorText: TextView = findViewById(R.id.error_text)
fun moveToState(state: State, postId: Long, sender: Recipient? = null) {
if (this.state == state && this.postId == postId) {
return
}
if (this.postId != postId) {
this.postId = postId
moveToHiddenState()
callback?.onStateChanged(State.HIDDEN, postId)
}
when (state) {
State.LOADING -> moveToProgressState(State.LOADING)
State.ERROR -> moveToErrorState()
State.RETRY -> moveToProgressState(State.RETRY)
State.NOT_FOUND, State.FAILED -> moveToNotFoundState(state, sender)
State.HIDDEN -> moveToHiddenState()
}
callback?.onStateChanged(state, postId)
}
fun setBackground(blur: BlurHash?) {
if (blur != null) {
GlideApp.with(background)
.load(blur)
.into(background)
} else {
GlideApp.with(background).clear(background)
}
}
private fun moveToProgressState(state: State) {
this.state = state
visible = true
background.visible = true
loadingSpinner.visible = true
errorCircle.visible = false
errorBackground.visible = false
unavailableText.visible = false
errorText.visible = false
}
private fun moveToErrorState() {
state = State.ERROR
visible = true
background.visible = true
loadingSpinner.visible = false
errorCircle.visible = true
errorBackground.visible = true
unavailableText.visible = false
errorText.visible = true
if (NetworkConstraint.isMet(ApplicationDependencies.getApplication())) {
errorText.setText(R.string.StorySlateView__couldnt_load_content)
} else {
errorText.setText(R.string.StorySlateView__no_internet_connection)
}
}
private fun moveToNotFoundState(state: State, sender: Recipient?) {
this.state = state
visible = true
background.visible = true
loadingSpinner.visible = false
errorCircle.visible = false
errorBackground.visible = false
unavailableText.visible = true
errorText.visible = false
if (state == State.FAILED && sender != null) {
unavailableText.text = context.getString(R.string.StorySlateView__cant_download_story_s_will_need_to_share_it_again, sender.getShortDisplayName(context))
} else {
unavailableText.setText(R.string.StorySlateView__this_story_is_no_longer_available)
}
}
private fun moveToHiddenState() {
state = State.HIDDEN
visible = false
}
override fun onSaveInstanceState(): Parcelable {
val rootState = super.onSaveInstanceState()
return Bundle().apply {
putParcelable("ROOT", rootState)
putInt("STATE", state.code)
putLong("ID", postId)
}
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state is Bundle) {
val rootState: Parcelable? = state.getParcelableCompat("ROOT", Parcelable::class.java)
this.state = State.fromCode(state.getInt("STATE", State.HIDDEN.code))
this.postId = state.getLong("ID")
super.onRestoreInstanceState(rootState)
} else {
super.onRestoreInstanceState(state)
}
}
init {
errorCircle.setOnClickListener { moveToState(State.RETRY, postId) }
}
interface Callback {
fun onStateChanged(state: State, postId: Long)
}
enum class State(val code: Int, val hasClickableContent: Boolean) {
LOADING(0, false),
ERROR(1, true),
RETRY(2, true),
NOT_FOUND(3, false),
HIDDEN(4, false),
FAILED(5, false);
companion object {
fun fromCode(code: Int): State {
return values().firstOrNull {
it.code == code
} ?: HIDDEN
}
}
}
}