Migrate to ViewBindings (#1072) - WIP

This commit is contained in:
Benoit Marty 2020-12-16 03:38:07 +01:00
parent 7de2494af2
commit 4d3c4b5afc
8 changed files with 78 additions and 63 deletions

View File

@ -23,7 +23,7 @@ import android.widget.LinearLayout
import androidx.core.content.withStyledAttributes
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.databinding.ItemTimelineEventPollResultItemBinding
class PollResultLineView @JvmOverloads constructor(
context: Context,
@ -31,34 +31,37 @@ class PollResultLineView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private val views: ItemTimelineEventPollResultItemBinding
var label: String? = null
set(value) {
field = value
pollResultItemLabel.setTextOrHide(value)
views.pollResultItemLabel.setTextOrHide(value)
}
var percent: String? = null
set(value) {
field = value
pollResultItemPercent.setTextOrHide(value)
views.pollResultItemPercent.setTextOrHide(value)
}
var optionSelected: Boolean = false
set(value) {
field = value
pollResultItemSelectedIcon.visibility = if (value) View.VISIBLE else View.INVISIBLE
views.pollResultItemSelectedIcon.visibility = if (value) View.VISIBLE else View.INVISIBLE
}
var isWinner: Boolean = false
set(value) {
field = value
// Text in main color
pollResultItemLabel.setTypeface(pollResultItemLabel.typeface, if (value) Typeface.BOLD else Typeface.NORMAL)
pollResultItemPercent.setTypeface(pollResultItemPercent.typeface, if (value) Typeface.BOLD else Typeface.NORMAL)
views.pollResultItemLabel.setTypeface(views.pollResultItemLabel.typeface, if (value) Typeface.BOLD else Typeface.NORMAL)
views.pollResultItemPercent.setTypeface(views.pollResultItemPercent.typeface, if (value) Typeface.BOLD else Typeface.NORMAL)
}
init {
inflate(context, R.layout.item_timeline_event_poll_result_item, this)
views = ItemTimelineEventPollResultItemBinding.bind(this)
orientation = HORIZONTAL
context.withStyledAttributes(attrs, R.styleable.PollResultLineView) {

View File

@ -23,6 +23,7 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.databinding.UrlPreviewBinding
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.media.ImageContentRenderer
@ -38,10 +39,13 @@ class PreviewUrlView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
private val views: UrlPreviewBinding
var delegate: TimelineEventController.PreviewUrlCallback? = null
init {
setupView()
views = UrlPreviewBinding.bind(this)
}
private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown
@ -90,7 +94,7 @@ class PreviewUrlView @JvmOverloads constructor(
inflate(context, R.layout.url_preview, this)
setOnClickListener(this)
url_preview_close.setOnClickListener { onCloseClick() }
views.urlPreviewClose.setOnClickListener { onCloseClick() }
}
private fun renderHidden() {
@ -104,19 +108,19 @@ class PreviewUrlView @JvmOverloads constructor(
private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) {
isVisible = true
url_preview_title.setTextOrHide(previewUrlData.title)
url_preview_image.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, url_preview_image) }.orFalse()
url_preview_description.setTextOrHide(previewUrlData.description)
url_preview_site.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title })
views.urlPreviewTitle.setTextOrHide(previewUrlData.title)
views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse()
views.urlPreviewDescription.setTextOrHide(previewUrlData.description)
views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title })
}
/**
* Hide all views that are not visible in all state
*/
private fun hideAll() {
url_preview_title.isVisible = false
url_preview_image.isVisible = false
url_preview_description.isVisible = false
url_preview_site.isVisible = false
views.urlPreviewTitle.isVisible = false
views.urlPreviewImage.isVisible = false
views.urlPreviewDescription.isVisible = false
views.urlPreviewSite.isVisible = false
}
}

View File

@ -21,6 +21,7 @@ import android.util.AttributeSet
import android.view.View
import android.widget.RelativeLayout
import im.vector.app.R
import im.vector.app.databinding.ViewRoomWidgetsBannerBinding
import org.matrix.android.sdk.api.session.widgets.model.Widget
@ -34,10 +35,13 @@ class RoomWidgetsBannerView @JvmOverloads constructor(
fun onViewWidgetsClicked()
}
private val views: ViewRoomWidgetsBannerBinding
var callback: Callback? = null
init {
setupView()
views = ViewRoomWidgetsBannerBinding.bind(this)
}
private fun setupView() {
@ -53,7 +57,7 @@ class RoomWidgetsBannerView @JvmOverloads constructor(
visibility = View.GONE
} else {
visibility = View.VISIBLE
activeWidgetsLabel.text = context.resources.getQuantityString(R.plurals.active_widgets, widgets.size, widgets.size)
views.activeWidgetsLabel.text = context.resources.getQuantityString(R.plurals.active_widgets, widgets.size, widgets.size)
}
}
}

View File

@ -119,7 +119,7 @@ class RoomListFragment @Inject constructor(
}.exhaustive
}
createChatFabMenu.listener = this
views.createChatFabMenu.listener = this
sharedActionViewModel
.observe()
@ -134,10 +134,10 @@ class RoomListFragment @Inject constructor(
override fun onDestroyView() {
roomController.removeModelBuildListener(modelBuildListener)
modelBuildListener = null
roomListView.cleanup()
views.roomListView.cleanup()
roomController.listener = null
stateRestorer.clear()
createChatFabMenu.listener = null
views.createChatFabMenu.listener = null
super.onDestroyView()
}
@ -147,35 +147,35 @@ class RoomListFragment @Inject constructor(
private fun setupCreateRoomButton() {
when (roomListParams.displayMode) {
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true
RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true
else -> Unit // No button in this mode
}
createChatRoomButton.debouncedClicks {
views.createChatRoomButton.debouncedClicks {
createDirectChat()
}
createGroupRoomButton.debouncedClicks {
views.createGroupRoomButton.debouncedClicks {
openRoomDirectory()
}
// Hide FAB when list is scrolling
roomListView.addOnScrollListener(
views.roomListView.addOnScrollListener(
object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
createChatFabMenu.removeCallbacks(showFabRunnable)
views.createChatFabMenu.removeCallbacks(showFabRunnable)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
createChatFabMenu.postDelayed(showFabRunnable, 250)
views.createChatFabMenu.postDelayed(showFabRunnable, 250)
}
RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> {
when (roomListParams.displayMode) {
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide()
RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide()
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.hide()
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.hide()
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.hide()
else -> Unit
}
}
@ -186,7 +186,7 @@ class RoomListFragment @Inject constructor(
fun filterRoomsWith(filter: String) {
// Scroll the list to top
roomListView.scrollToPosition(0)
views.roomListView.scrollToPosition(0)
roomListViewModel.handle(RoomListAction.FilterWith(filter))
}
@ -202,23 +202,23 @@ class RoomListFragment @Inject constructor(
private fun setupRecyclerView() {
val layoutManager = LinearLayoutManager(context)
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
roomListView.layoutManager = layoutManager
roomListView.itemAnimator = RoomListAnimator()
roomListView.setRecycledViewPool(sharedViewPool)
views.roomListView.layoutManager = layoutManager
views.roomListView.itemAnimator = RoomListAnimator()
views.roomListView.setRecycledViewPool(sharedViewPool)
layoutManager.recycleChildrenOnDetach = true
roomController.listener = this
modelBuildListener = OnModelBuildFinishedListener { it.dispatchTo(stateRestorer) }
roomController.addModelBuildListener(modelBuildListener)
roomListView.adapter = roomController.adapter
stateView.contentView = roomListView
views.roomListView.adapter = roomController.adapter
views.stateView.contentView = views.roomListView
}
private val showFabRunnable = Runnable {
if (isAdded) {
when (roomListParams.displayMode) {
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show()
RoomListDisplayMode.PEOPLE -> createChatRoomButton.show()
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.show()
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.show()
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.show()
else -> Unit
}
}
@ -289,7 +289,7 @@ class RoomListFragment @Inject constructor(
if (filteredRooms.isNullOrEmpty()) {
renderEmptyState(allRooms)
} else {
stateView.state = StateView.State.Content
views.stateView.state = StateView.State.Content
}
}
@ -332,11 +332,11 @@ class RoomListFragment @Inject constructor(
// Always display the content in this mode, because if the footer
StateView.State.Content
}
stateView.state = emptyState
views.stateView.state = emptyState
}
private fun renderLoading() {
stateView.state = StateView.State.Loading
views.stateView.state = StateView.State.Loading
}
private fun renderFailure(error: Throwable) {
@ -344,11 +344,11 @@ class RoomListFragment @Inject constructor(
is Failure.NetworkConnection -> getString(R.string.network_error_please_check_and_retry)
else -> getString(R.string.unknown_error)
}
stateView.state = StateView.State.Error(message)
views.stateView.state = StateView.State.Error(message)
}
override fun onBackPressed(toolbarButton: Boolean): Boolean {
if (createChatFabMenu.onBackPressed()) {
if (views.createChatFabMenu.onBackPressed()) {
return true
}
return false

View File

@ -75,12 +75,12 @@ class RoomListQuickActionsBottomSheet :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
views.views.bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
roomListActionsEpoxyController.listener = this
}
override fun onDestroyView() {
views.views.bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
roomListActionsEpoxyController.listener = null
super.onDestroyView()
}

View File

@ -22,28 +22,31 @@ import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.isVisible
import com.google.android.material.floatingactionbutton.FloatingActionButton
import im.vector.app.R
import im.vector.app.databinding.MotionNotifsFabMenuMergeBinding
class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) {
private val views: MotionNotifsFabMenuMergeBinding
var listener: Listener? = null
init {
inflate(context, R.layout.motion_notifs_fab_menu_merge, this)
views = MotionNotifsFabMenuMergeBinding.bind(this)
}
override fun onFinishInflate() {
super.onFinishInflate()
listOf(createRoomItemChat, createRoomItemChatLabel)
listOf(views.createRoomItemChat, views.createRoomItemChatLabel)
.forEach {
it.setOnClickListener {
closeFabMenu()
listener?.createDirectChat()
}
}
listOf(createRoomItemGroup, createRoomItemGroupLabel)
listOf(views.createRoomItemGroup, views.createRoomItemGroupLabel)
.forEach {
it.setOnClickListener {
closeFabMenu()
@ -51,7 +54,7 @@ class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: Attri
}
}
createRoomTouchGuard.setOnClickListener {
views.createRoomTouchGuard.setOnClickListener {
closeFabMenu()
}
}
@ -59,22 +62,22 @@ class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: Attri
override fun transitionToEnd() {
super.transitionToEnd()
createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close)
views.createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_close)
}
override fun transitionToStart() {
super.transitionToStart()
createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open)
views.createRoomButton.contentDescription = context.getString(R.string.a11y_create_menu_open)
}
fun show() {
isVisible = true
createRoomButton.show()
views.createRoomButton.show()
}
fun hide() {
createRoomButton.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
views.createRoomButton.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
isVisible = false

View File

@ -22,6 +22,7 @@ import android.content.Intent
import android.view.View
import android.view.Window
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityOptionsCompat
import androidx.core.app.TaskStackBuilder
import androidx.core.util.Pair
@ -99,7 +100,7 @@ class DefaultNavigator @Inject constructor(
val tx = session.cryptoService().verificationService().getExistingTransaction(otherUserId, sasTransactionId)
?: return
(tx as? IncomingSasVerificationTransaction)?.performAccept()
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
VerificationBottomSheet.withArgs(
roomId = null,
otherUserId = otherUserId,
@ -115,7 +116,7 @@ class DefaultNavigator @Inject constructor(
session.myUserId,
listOf(otherSessionId)
)
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
VerificationBottomSheet.withArgs(
roomId = null,
otherUserId = session.myUserId,
@ -130,7 +131,7 @@ class DefaultNavigator @Inject constructor(
.getCryptoDeviceInfo(session.myUserId)
.filter { it.deviceId != session.sessionParams.deviceId }
.map { it.deviceId }
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
if (otherSessions.isNotEmpty()) {
val pr = session.cryptoService().verificationService().requestKeyVerification(
supportedVerificationMethodsProvider.provide(),
@ -147,14 +148,14 @@ class DefaultNavigator @Inject constructor(
override fun waitSessionVerification(context: Context) {
val session = sessionHolder.getSafeActiveSession() ?: return
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
VerificationBottomSheet.forSelfVerification(session)
.show(context.supportFragmentManager, VerificationBottomSheet.WAITING_SELF_VERIF_TAG)
}
}
override fun upgradeSessionSecurity(context: Context, initCrossSigningOnly: Boolean) {
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
BootstrapBottomSheet.show(
context.supportFragmentManager,
if (initCrossSigningOnly) SetupMode.CROSS_SIGNING_ONLY else SetupMode.NORMAL
@ -163,7 +164,7 @@ class DefaultNavigator @Inject constructor(
}
override fun openGroupDetail(groupId: String, context: Context, buildTask: Boolean) {
if (context is VectorBaseActivity) {
if (context is VectorBaseActivity<*>) {
context.notImplemented("Open group detail")
} else {
context.toast(R.string.not_implemented)
@ -230,7 +231,7 @@ class DefaultNavigator @Inject constructor(
override fun openKeysBackupSetup(context: Context, showManualExport: Boolean) {
// if cross signing is enabled we should propose full 4S
sessionHolder.getSafeActiveSession()?.let { session ->
if (session.cryptoService().crossSigningService().canCrossSign() && context is VectorBaseActivity) {
if (session.cryptoService().crossSigningService().canCrossSign() && context is AppCompatActivity) {
BootstrapBottomSheet.show(context.supportFragmentManager, SetupMode.NORMAL)
} else {
context.startActivity(KeysBackupSetupActivity.intent(context, showManualExport))
@ -239,7 +240,7 @@ class DefaultNavigator @Inject constructor(
}
override fun open4SSetup(context: Context, setupMode: SetupMode) {
if (context is VectorBaseActivity) {
if (context is AppCompatActivity) {
BootstrapBottomSheet.show(context.supportFragmentManager, setupMode)
}
}

View File

@ -272,7 +272,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
private fun shouldBeDisplayedIn(alert: VectorAlert?, activity: Activity): Boolean {
return alert != null
&& activity !is PinActivity
&& activity is VectorBaseActivity
&& activity is VectorBaseActivity<*>
&& alert.shouldBeDisplayedIn.invoke(activity)
}
}