Optimise XML

This commit is contained in:
fanchao 2024-06-06 13:59:30 +10:00
parent 9b6fa0db01
commit 54bb84541a
11 changed files with 167 additions and 84 deletions

View File

@ -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();
@ -58,7 +60,7 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
}
@StyleRes @Nullable
public Integer getAccentTheme() {
private Integer getAccentTheme() {
if (!getPreferences().hasPreference(SELECTED_ACCENT_COLOR)) return null;
ThemeState themeState = ActivityUtilitiesKt.themeState(getPreferences());
return themeState.getAccentStyle();
@ -66,8 +68,12 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
@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) {

View File

@ -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
@ -146,6 +145,7 @@ import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.dependencies.ConversationViewPool
import org.thoughtcrime.securesms.giph.ui.GiphyActivity
import org.thoughtcrime.securesms.groups.OpenGroupManager
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
@ -216,6 +216,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
@Inject lateinit var storage: Storage
@Inject lateinit var reactionDb: ReactionDatabase
@Inject lateinit var viewModelFactory: ConversationViewModel.AssistedFactory
@Inject @ConversationViewPool lateinit var viewPool: RecyclerView.RecycledViewPool
private val screenshotObserver by lazy {
ScreenshotObserver(this, Handler(Looper.getMainLooper())) {
@ -568,6 +569,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
// called from onCreate
private fun setUpRecyclerView() {
binding!!.conversationRecyclerView.adapter = adapter
binding!!.conversationRecyclerView.setRecycledViewPool(viewPool)
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, reverseMessageList)
binding!!.conversationRecyclerView.layoutManager = layoutManager
// Workaround for the fact that CursorRecyclerViewAdapter doesn't auto-update automatically (even though it says it will)
@ -1558,8 +1560,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()
}
override fun sendMessage() {

View File

@ -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
@ -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
@ -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 {
@ -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.")
}
@ -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
@ -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)

View File

@ -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)
}

View File

@ -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
@ -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
@ -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
@ -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) {
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
@ -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
@ -108,12 +119,7 @@ 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()
@ -121,7 +127,11 @@ class VisibleMessageView : LinearLayout {
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
@ -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
@ -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 {
binding.emojiReactionsView.root.isVisible = false
} else if (emojiReactionsBinding.isInitialized()) {
emojiReactionsBinding.value.root.isVisible = false
}
}
else if (emojiReactionsBinding.isInitialized()) {
emojiReactionsBinding.value.root.isVisible = false
}
// Populate content view

View File

@ -19,11 +19,11 @@ abstract class AppModule {
@Binds
abstract fun bindConversationRepository(repository: DefaultConversationRepository): ConversationRepository
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface AppComponent {
fun getPrefs(): TextSecurePreferences
}

View File

@ -0,0 +1,19 @@
package org.thoughtcrime.securesms.dependencies
import androidx.recyclerview.widget.RecyclerView
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class UiModule {
@Singleton
@Provides
@ConversationViewPool
fun provideConversationRecycledViewPool(): RecyclerView.RecycledViewPool {
return RecyclerView.RecycledViewPool()
}
}

View File

@ -0,0 +1,7 @@
package org.thoughtcrime.securesms.dependencies
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.SOURCE)
annotation class ConversationViewPool

View File

@ -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"
@ -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"
@ -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"
@ -176,4 +144,4 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView>
</LinearLayout>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/unreadMarkerContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/small_spacing"
android:gravity="center"
android:orientation="horizontal"
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"
android:layout_weight="1"
android:background="?android:colorAccent" />
<TextView
android:id="@+id/unreadMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/unread_marker"
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"
android:layout_weight="1"
android:background="?android:colorAccent" />
</LinearLayout>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/statusContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:baselineAligned="true"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="@+id/messageStatusTextView"
android:contentDescription="@string/AccessibilityId_message_sent_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="2dp"
android:layout_gravity="center"
android:textSize="@dimen/very_small_font_size"
tools:text="Sent" />
<ImageView
android:id="@+id/messageStatusImageView"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center"
android:src="@drawable/ic_delivery_status_sent" />
<org.thoughtcrime.securesms.conversation.v2.components.ExpirationTimerView
android:id="@+id/expirationTimerView"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center"
android:tint="?message_status_color" />
</LinearLayout>