Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SES-2021] Optimise XML loading #1512

Merged
merged 3 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
private static final String TAG = BaseActionBarActivity.class.getSimpleName();
public ThemeState currentThemeState;

private Resources.Theme modifiedTheme;

private TextSecurePreferences getPreferences() {
ApplicationContext appContext = (ApplicationContext) getApplicationContext();
return appContext.textSecurePreferences;
}

@StyleRes
public int getDesiredTheme() {
private int getDesiredTheme() {
ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences());
int userSelectedTheme = themeState.getTheme();

Expand All @@ -58,16 +60,20 @@ public int getDesiredTheme() {
}

@StyleRes @Nullable
public Integer getAccentTheme() {
private Integer getAccentTheme() {
if (!getPreferences().hasPreference(SELECTED_ACCENT_COLOR)) return null;
ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences());
return themeState.getAccentStyle();
}

@Override
public Resources.Theme getTheme() {
if (modifiedTheme != null) {
return modifiedTheme;
}

// New themes
Resources.Theme modifiedTheme = super.getTheme();
modifiedTheme = super.getTheme();
modifiedTheme.applyStyle(getDesiredTheme(), true);
Integer accentTheme = getAccentTheme();
if (accentTheme != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityConversationV2Binding
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import network.loki.messenger.libsession_util.util.ExpiryMode
import nl.komponents.kovenant.ui.successUi
import org.session.libsession.messaging.MessagingModuleConfiguration
Expand Down Expand Up @@ -1558,8 +1557,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe

if (indexInAdapter < 0 || indexInAdapter >= adapter.itemCount) { return }
val viewHolder = binding?.conversationRecyclerView?.findViewHolderForAdapterPosition(indexInAdapter) as? ConversationAdapter.VisibleMessageViewHolder ?: return
val visibleMessageView = ViewVisibleMessageBinding.bind(viewHolder.view).visibleMessageView
visibleMessageView.playVoiceMessage()
viewHolder.view.playVoiceMessage()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested this? The audio message plays without using that existing binding that was removed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I have tested.

The binding has been moved into the custom view itself

}

override fun sendMessage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import android.content.Intent
import android.database.Cursor
import android.util.SparseArray
import android.util.SparseBooleanArray
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.annotation.WorkerThread
import androidx.core.util.getOrDefault
Expand All @@ -20,14 +18,11 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
import org.thoughtcrime.securesms.database.MmsSmsColumns
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.GlideRequests
Expand Down Expand Up @@ -90,7 +85,7 @@ class ConversationAdapter(
}
}

class VisibleMessageViewHolder(val view: View) : ViewHolder(view)
class VisibleMessageViewHolder(val view: VisibleMessageView) : ViewHolder(view)
class ControlMessageViewHolder(val view: ControlMessageView) : ViewHolder(view)

override fun getItemViewType(cursor: Cursor): Int {
Expand All @@ -103,7 +98,7 @@ class ConversationAdapter(
@Suppress("NAME_SHADOWING")
val viewType = ViewType.allValues[viewType]
return when (viewType) {
ViewType.Visible -> VisibleMessageViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_visible_message, parent, false))
ViewType.Visible -> VisibleMessageViewHolder(VisibleMessageView(context))
ViewType.Control -> ControlMessageViewHolder(ControlMessageView(context))
else -> throw IllegalStateException("Unexpected view type: $viewType.")
}
Expand All @@ -115,7 +110,7 @@ class ConversationAdapter(
val messageBefore = getMessageBefore(position, cursor)
when (viewHolder) {
is VisibleMessageViewHolder -> {
val visibleMessageView = ViewVisibleMessageBinding.bind(viewHolder.view).visibleMessageView
val visibleMessageView = viewHolder.view
val isSelected = selectedItems.contains(message)
visibleMessageView.snIsSelected = isSelected
visibleMessageView.indexInAdapter = position
Expand Down Expand Up @@ -181,7 +176,7 @@ class ConversationAdapter(

override fun onItemViewRecycled(viewHolder: ViewHolder?) {
when (viewHolder) {
is VisibleMessageViewHolder -> viewHolder.view.findViewById<VisibleMessageView>(R.id.visibleMessageView).recycle()
is VisibleMessageViewHolder -> viewHolder.view.recycle()
is ControlMessageViewHolder -> viewHolder.view.recycle()
}
super.onItemViewRecycled(viewHolder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ class ControlMessageView : LinearLayout {

private val TAG = "ControlMessageView"

private lateinit var binding: ViewControlMessageBinding
private val binding = ViewControlMessageBinding.inflate(LayoutInflater.from(context), this, true)

constructor(context: Context) : super(context) { initialize() }
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

@Inject lateinit var disappearingMessages: DisappearingMessages

private fun initialize() {
binding = ViewControlMessageBinding.inflate(LayoutInflater.from(context), this, true)
init {
layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import android.os.Looper
import android.util.AttributeSet
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.annotation.ColorInt
Expand All @@ -26,17 +28,17 @@ import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewEmojiReactionsBinding
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import network.loki.messenger.databinding.ViewstubVisibleMessageMarkerContainerBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.contacts.Contact.ContactContext
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.getColorFromAttr
import org.session.libsession.utilities.modifyLayoutParams
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.database.LastSentTimestampCache
import org.thoughtcrime.securesms.database.LokiAPIDatabase
Expand Down Expand Up @@ -65,7 +67,7 @@ import kotlin.math.sqrt
private const val TAG = "VisibleMessageView"

@AndroidEntryPoint
class VisibleMessageView : LinearLayout {
class VisibleMessageView : FrameLayout {
private var replyDisabled: Boolean = false
@Inject lateinit var threadDb: ThreadDatabase
@Inject lateinit var lokiThreadDb: LokiThreadDatabase
Expand All @@ -75,7 +77,16 @@ class VisibleMessageView : LinearLayout {
@Inject lateinit var mmsDb: MmsDatabase
@Inject lateinit var lastSentTimestampCache: LastSentTimestampCache

private val binding by lazy { ViewVisibleMessageBinding.bind(this) }
private val binding = ViewVisibleMessageBinding.inflate(LayoutInflater.from(context), this, true)

private val markerContainerBinding = lazy(LazyThreadSafetyMode.NONE) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you have to add the LazyThreadSafetyMode.NONE to those two bindings?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it wasteful to have a thread safe lazy for UI components where you only access through main thread.

ViewstubVisibleMessageMarkerContainerBinding.bind(binding.unreadMarkerContainerStub.inflate())
}

private val emojiReactionsBinding = lazy(LazyThreadSafetyMode.NONE) {
ViewEmojiReactionsBinding.bind(binding.emojiReactionsView.inflate())
}

private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate()
private val swipeToReplyIconRect = Rect()
private var dx = 0.0f
Expand All @@ -94,7 +105,7 @@ class VisibleMessageView : LinearLayout {
var onPress: ((event: MotionEvent) -> Unit)? = null
var onSwipeToReply: (() -> Unit)? = null
var onLongPress: (() -> Unit)? = null
val messageContentView: VisibleMessageContentView by lazy { binding.messageContentView.root }
val messageContentView: VisibleMessageContentView get() = binding.messageContentView.root

companion object {
const val swipeToReplyThreshold = 64.0f // dp
Expand All @@ -108,20 +119,19 @@ class VisibleMessageView : LinearLayout {
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

override fun onFinishInflate() {
super.onFinishInflate()
initialize()
}

private fun initialize() {
init {
isHapticFeedbackEnabled = true
setWillNotDraw(false)
binding.root.disableClipping()
binding.mainContainer.disableClipping()
binding.messageInnerContainer.disableClipping()
binding.messageInnerLayout.disableClipping()
binding.messageContentView.root.disableClipping()

// Default layout params
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}

// endregion

// region Updating
Expand Down Expand Up @@ -203,7 +213,13 @@ class VisibleMessageView : LinearLayout {
binding.senderNameTextView.text = contact?.displayName(contactContext) ?: senderSessionID

// Unread marker
binding.unreadMarkerContainer.isVisible = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing
val shouldShowUnreadMarker = lastSeen != -1L && message.timestamp > lastSeen && (previous == null || previous.timestamp <= lastSeen) && !message.isOutgoing
if (shouldShowUnreadMarker) {
markerContainerBinding.value.root.isVisible = true
} else if (markerContainerBinding.isInitialized()) {
// Only need to hide the binding when the binding is inflated. (default is gone)
markerContainerBinding.value.root.isVisible = false
}

// Date break
val showDateBreak = isStartOfMessageCluster || snIsSelected
Expand All @@ -214,21 +230,22 @@ class VisibleMessageView : LinearLayout {
showStatusMessage(message)

// Emoji Reactions
val emojiLayoutParams = binding.emojiReactionsView.root.layoutParams as ConstraintLayout.LayoutParams
emojiLayoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
binding.emojiReactionsView.root.layoutParams = emojiLayoutParams

if (message.reactions.isNotEmpty()) {
val capabilities = lokiThreadDb.getOpenGroupChat(threadID)?.server?.let { lokiApiDb.getServerCapabilities(it) }
if (capabilities.isNullOrEmpty() || capabilities.contains(OpenGroupApi.Capability.REACTIONS.name.lowercase())) {
binding.emojiReactionsView.root.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
binding.emojiReactionsView.root.isVisible = true
} else {
binding.emojiReactionsView.root.isVisible = false
emojiReactionsBinding.value.root.let { root ->
root.setReactions(message.id, message.reactions, message.isOutgoing, delegate)
root.isVisible = true
(root.layoutParams as ConstraintLayout.LayoutParams).apply {
horizontalBias = if (message.isOutgoing) 1f else 0f
}
}
} else if (emojiReactionsBinding.isInitialized()) {
emojiReactionsBinding.value.root.isVisible = false
}
}
else {
binding.emojiReactionsView.root.isVisible = false
else if (emojiReactionsBinding.isInitialized()) {
emojiReactionsBinding.value.root.isVisible = false
}

// Populate content view
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ abstract class AppModule {

@Binds
abstract fun bindConversationRepository(repository: DefaultConversationRepository): ConversationRepository

}

@EntryPoint
@InstallIn(SingletonComponent::class)
interface AppComponent {
fun getPrefs(): TextSecurePreferences

}
48 changes: 8 additions & 40 deletions app/src/main/res/layout/view_visible_message.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
Expand All @@ -8,45 +8,11 @@
android:layout_height="wrap_content"
android:orientation="vertical">

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/unreadMarkerContainer"
<ViewStub
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/small_spacing"
android:visibility="gone"
tools:visibility="visible">
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="@dimen/medium_spacing"
android:layout_marginEnd="@dimen/small_spacing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/unreadMarker"
android:background="?android:colorAccent" />
<TextView
android:id="@+id/unreadMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/unread_marker"
android:gravity="center"
android:textColor="?android:colorAccent"
android:textSize="@dimen/small_font_size"
android:textStyle="bold" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="@dimen/small_spacing"
android:layout_marginEnd="@dimen/medium_spacing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/unreadMarker"
app:layout_constraintEnd_toEndOf="parent"
android:background="?android:colorAccent" />
</androidx.constraintlayout.widget.ConstraintLayout>
android:id="@+id/unreadMarkerContainerStub"
android:layout="@layout/viewstub_visible_message_marker_container" />

<TextView
android:id="@+id/dateBreakTextView"
Expand Down Expand Up @@ -129,8 +95,10 @@
</LinearLayout>
</FrameLayout>

<include layout="@layout/view_emoji_reactions"
<ViewStub
android:layout="@layout/view_emoji_reactions"
android:id="@+id/emojiReactionsView"
android:inflatedId="@+id/emojiReactionsView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
Expand Down Expand Up @@ -176,4 +144,4 @@

</androidx.constraintlayout.widget.ConstraintLayout>

</org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView>
</LinearLayout>
Loading