Migrate to ViewBindings (#1072) - WIP

This commit is contained in:
Benoit Marty 2020-12-16 02:33:52 +01:00
parent dba65dcd22
commit a8c6b1cdf7
15 changed files with 136 additions and 340 deletions

View File

@ -19,17 +19,17 @@ package im.vector.lib.attachmentviewer
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import im.vector.lib.attachmentviewer.databinding.ItemAnimatedImageAttachmentBinding
class AnimatedImageViewHolder constructor(itemView: View) : class AnimatedImageViewHolder constructor(itemView: View) :
BaseViewHolder(itemView) { BaseViewHolder(itemView) {
val touchImageView: ImageView = itemView.findViewById(R.id.imageView) val views = ItemAnimatedImageAttachmentBinding.bind(itemView)
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
internal val target = DefaultImageLoaderTarget(this, this.touchImageView) internal val target = DefaultImageLoaderTarget(this, views.imageView)
override fun onRecycled() { override fun onRecycled() {
super.onRecycled() super.onRecycled()
touchImageView.setImageDrawable(null) views.imageView.setImageDrawable(null)
} }
} }

View File

@ -104,7 +104,6 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
attachmentsAdapter = AttachmentsAdapter() attachmentsAdapter = AttachmentsAdapter()
views.attachmentPager.adapter = attachmentsAdapter views.attachmentPager.adapter = attachmentsAdapter
imageTransitionView = views.transitionImageView imageTransitionView = views.transitionImageView
transitionImageContainer = findViewById(R.id.transitionImageContainer)
pager2 = views.attachmentPager pager2 = views.attachmentPager
directionDetector = createSwipeDirectionDetector() directionDetector = createSwipeDirectionDetector()
gestureDetector = createGestureDetector() gestureDetector = createGestureDetector()

View File

@ -23,6 +23,7 @@ import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import android.widget.VideoView import android.widget.VideoView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import im.vector.lib.attachmentviewer.databinding.ItemVideoAttachmentBinding
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
@ -44,13 +45,9 @@ class VideoViewHolder constructor(itemView: View) :
var eventListener: WeakReference<AttachmentEventListener>? = null var eventListener: WeakReference<AttachmentEventListener>? = null
val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage) val views = ItemVideoAttachmentBinding.bind(itemView)
val videoView: VideoView = itemView.findViewById(R.id.videoView)
val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress)
val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon)
val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView)
internal val target = DefaultVideoLoaderTarget(this, thumbnailImage) internal val target = DefaultVideoLoaderTarget(this, views.videoThumbnailImage)
override fun onRecycled() { override fun onRecycled() {
super.onRecycled() super.onRecycled()
@ -77,12 +74,12 @@ class VideoViewHolder constructor(itemView: View) :
} }
override fun entersBackground() { override fun entersBackground() {
if (videoView.isPlaying) { if (views.videoView.isPlaying) {
progress = videoView.currentPosition progress = views.videoView.currentPosition
progressDisposable?.dispose() progressDisposable?.dispose()
progressDisposable = null progressDisposable = null
videoView.stopPlayback() views.videoView.stopPlayback()
videoView.pause() views.videoView.pause()
} }
} }
@ -92,9 +89,9 @@ class VideoViewHolder constructor(itemView: View) :
override fun onSelected(selected: Boolean) { override fun onSelected(selected: Boolean) {
if (!selected) { if (!selected) {
if (videoView.isPlaying) { if (views.videoView.isPlaying) {
progress = videoView.currentPosition progress = views.videoView.currentPosition
videoView.stopPlayback() views.videoView.stopPlayback()
} else { } else {
progress = 0 progress = 0
} }
@ -109,34 +106,34 @@ class VideoViewHolder constructor(itemView: View) :
} }
private fun startPlaying() { private fun startPlaying() {
thumbnailImage.isVisible = false views.videoThumbnailImage.isVisible = false
loaderProgressBar.isVisible = false views.videoLoaderProgress.isVisible = false
videoView.isVisible = true views.videoView.isVisible = true
videoView.setOnPreparedListener { views.videoView.setOnPreparedListener {
progressDisposable?.dispose() progressDisposable?.dispose()
progressDisposable = Observable.interval(100, TimeUnit.MILLISECONDS) progressDisposable = Observable.interval(100, TimeUnit.MILLISECONDS)
.timeInterval() .timeInterval()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
val duration = videoView.duration val duration = views.videoView.duration
val progress = videoView.currentPosition val progress = views.videoView.currentPosition
val isPlaying = videoView.isPlaying val isPlaying = views.videoView.isPlaying
// Log.v("FOO", "isPlaying $isPlaying $progress/$duration") // Log.v("FOO", "isPlaying $isPlaying $progress/$duration")
eventListener?.get()?.onEvent(AttachmentEvents.VideoEvent(isPlaying, progress, duration)) eventListener?.get()?.onEvent(AttachmentEvents.VideoEvent(isPlaying, progress, duration))
} }
} }
try { try {
videoView.setVideoPath(mVideoPath) views.videoView.setVideoPath(mVideoPath)
} catch (failure: Throwable) { } catch (failure: Throwable) {
// Couldn't open // Couldn't open
Log.v(VideoViewHolder::class.java.name, "Failed to start video") Log.v(VideoViewHolder::class.java.name, "Failed to start video")
} }
if (!wasPaused) { if (!wasPaused) {
videoView.start() views.videoView.start()
if (progress > 0) { if (progress > 0) {
videoView.seekTo(progress) views.videoView.seekTo(progress)
} }
} }
} }
@ -146,17 +143,17 @@ class VideoViewHolder constructor(itemView: View) :
when (commands) { when (commands) {
AttachmentCommands.StartVideo -> { AttachmentCommands.StartVideo -> {
wasPaused = false wasPaused = false
videoView.start() views.videoView.start()
} }
AttachmentCommands.PauseVideo -> { AttachmentCommands.PauseVideo -> {
wasPaused = true wasPaused = true
videoView.pause() views.videoView.pause()
} }
is AttachmentCommands.SeekTo -> { is AttachmentCommands.SeekTo -> {
val duration = videoView.duration val duration = views.videoView.duration
if (duration > 0) { if (duration > 0) {
val seekDuration = duration * (commands.percentProgress / 100f) val seekDuration = duration * (commands.percentProgress / 100f)
videoView.seekTo(seekDuration.toInt()) views.videoView.seekTo(seekDuration.toInt())
} }
} }
} }

View File

@ -19,29 +19,29 @@ package im.vector.lib.attachmentviewer
import android.view.View import android.view.View
import android.widget.ProgressBar import android.widget.ProgressBar
import com.github.chrisbanes.photoview.PhotoView import com.github.chrisbanes.photoview.PhotoView
import im.vector.lib.attachmentviewer.databinding.ItemImageAttachmentBinding
class ZoomableImageViewHolder constructor(itemView: View) : class ZoomableImageViewHolder constructor(itemView: View) :
BaseViewHolder(itemView) { BaseViewHolder(itemView) {
val touchImageView: PhotoView = itemView.findViewById(R.id.touchImageView) val views = ItemImageAttachmentBinding.bind(itemView)
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
init { init {
touchImageView.setAllowParentInterceptOnEdge(false) views.touchImageView.setAllowParentInterceptOnEdge(false)
touchImageView.setOnScaleChangeListener { scaleFactor, _, _ -> views.touchImageView.setOnScaleChangeListener { scaleFactor, _, _ ->
// Log.v("ATTACHEMENTS", "scaleFactor $scaleFactor") // Log.v("ATTACHEMENTS", "scaleFactor $scaleFactor")
// It's a bit annoying but when you pitch down the scaling // It's a bit annoying but when you pitch down the scaling
// is not exactly one :/ // is not exactly one :/
touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f) views.touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f)
} }
touchImageView.setScale(1.0f, true) views.touchImageView.setScale(1.0f, true)
touchImageView.setAllowParentInterceptOnEdge(true) views.touchImageView.setAllowParentInterceptOnEdge(true)
} }
internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView) internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, views.touchImageView)
override fun onRecycled() { override fun onRecycled() {
super.onRecycled() super.onRecycled()
touchImageView.setImageDrawable(null) views.touchImageView.setImageDrawable(null)
} }
} }

View File

@ -61,12 +61,11 @@ class ExportKeysDialog {
views.exportDialogEt.addTextChangedListener(textWatcher) views.exportDialogEt.addTextChangedListener(textWatcher)
views.exportDialogEtConfirm.addTextChangedListener(textWatcher) views.exportDialogEtConfirm.addTextChangedListener(textWatcher)
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword) views.exportDialogShowPassword.setOnClickListener {
showPassword.setOnClickListener {
passwordVisible = !passwordVisible passwordVisible = !passwordVisible
views.exportDialogEt.showPassword(passwordVisible) views.exportDialogEt.showPassword(passwordVisible)
views.exportDialogEtConfirm.showPassword(passwordVisible) views.exportDialogEtConfirm.showPassword(passwordVisible)
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.exportDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
} }
val exportDialog = builder.show() val exportDialog = builder.show()

View File

@ -44,11 +44,10 @@ class PromptPasswordDialog {
} }
views.promptPassword.addTextChangedListener(textWatcher) views.promptPassword.addTextChangedListener(textWatcher)
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal) views.promptPasswordPasswordReveal.setOnClickListener {
showPassword.setOnClickListener {
passwordVisible = !passwordVisible passwordVisible = !passwordVisible
views.promptPassword.showPassword(passwordVisible) views.promptPassword.showPassword(passwordVisible)
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye) views.promptPasswordPasswordReveal.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
} }
AlertDialog.Builder(activity) AlertDialog.Builder(activity)

View File

@ -22,6 +22,7 @@ import androidx.appcompat.app.AlertDialog
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.databinding.DialogSslFingerprintBinding
import org.matrix.android.sdk.internal.network.ssl.Fingerprint import org.matrix.android.sdk.internal.network.ssl.Fingerprint
import timber.log.Timber import timber.log.Timber
import java.util.HashMap import java.util.HashMap
@ -95,30 +96,27 @@ class UnrecognizedCertificateDialog @Inject constructor(
val builder = AlertDialog.Builder(activity) val builder = AlertDialog.Builder(activity)
val inflater = activity.layoutInflater val inflater = activity.layoutInflater
val layout: View = inflater.inflate(R.layout.dialog_ssl_fingerprint, null) val layout = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
val sslFingerprintTitle = layout.findViewById<TextView>(R.id.ssl_fingerprint_title) val views = DialogSslFingerprintBinding.bind(layout)
sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString()) views.sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
val sslFingerprint = layout.findViewById<TextView>(R.id.ssl_fingerprint) views.sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
val sslUserId = layout.findViewById<TextView>(R.id.ssl_user_id)
if (userId != null) { if (userId != null) {
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value, views.sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
stringProvider.getString(R.string.username), stringProvider.getString(R.string.username),
userId) userId)
} else { } else {
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value, views.sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
stringProvider.getString(R.string.hs_url), stringProvider.getString(R.string.hs_url),
homeServerUrl) homeServerUrl)
} }
val sslExpl = layout.findViewById<TextView>(R.id.ssl_explanation)
if (existing) { if (existing) {
if (homeServerConnectionConfigHasFingerprints) { if (homeServerConnectionConfigHasFingerprints) {
sslExpl.text = stringProvider.getString(R.string.ssl_expected_existing_expl) views.sslExplanation.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
} else { } else {
sslExpl.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl) views.sslExplanation.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
} }
} else { } else {
sslExpl.text = stringProvider.getString(R.string.ssl_cert_new_account_expl) views.sslExplanation.text = stringProvider.getString(R.string.ssl_cert_new_account_expl)
} }
builder.setView(layout) builder.setView(layout)
builder.setTitle(R.string.ssl_could_not_verify) builder.setTitle(R.string.ssl_could_not_verify)

View File

@ -1,69 +0,0 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.preference
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import androidx.preference.PreferenceViewHolder
import im.vector.app.R
/**
* Preference used in Room setting for Room aliases
*/
class AddressPreference : VectorPreference {
// members
private var mMainAddressIconView: ImageView? = null
private var mIsMainIconVisible = false
/**
* @return the main icon view.
*/
val mainIconView: View?
get() = mMainAddressIconView
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
init {
widgetLayoutResource = R.layout.vector_settings_address_preference
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val view = holder.itemView
mMainAddressIconView = view.findViewById(R.id.main_address_icon_view)
mMainAddressIconView!!.visibility = if (mIsMainIconVisible) View.VISIBLE else View.GONE
}
/**
* Set the main address icon visibility.
*
* @param isVisible true to display the main icon
*/
fun setMainIconVisible(isVisible: Boolean) {
mIsMainIconVisible = isVisible
mMainAddressIconView?.visibility = if (mIsMainIconVisible) View.VISIBLE else View.GONE
}
}

View File

@ -1,103 +0,0 @@
/*
* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.preference
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.preference.PreferenceViewHolder
import androidx.preference.SwitchPreference
import im.vector.app.R
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.group.Group
class VectorGroupPreference : SwitchPreference {
private var mAvatarView: ImageView? = null
private var mGroup: Group? = null
private var mSession: Session? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val createdView = holder.itemView
if (mAvatarView == null) {
try {
// insert the group avatar to the left
val iconView = createdView.findViewById<ImageView>(android.R.id.icon)
var iconViewParent = iconView.parent
while (null != iconViewParent.parent) {
iconViewParent = iconViewParent.parent
}
val inflater = LayoutInflater.from(context)
val layout = inflater.inflate(R.layout.vector_settings_round_group_avatar, (iconViewParent as LinearLayout), false) as FrameLayout
mAvatarView = layout.findViewById(R.id.settings_round_group_avatar)
val params = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
params.gravity = Gravity.CENTER
layout.layoutParams = params
iconViewParent.addView(layout, 0)
} catch (e: Exception) {
mAvatarView = null
}
}
refreshAvatar()
}
/**
* Init the group information
*
* @param group the group
* @param session the session
*/
fun setGroup(group: Group, session: Session) {
mGroup = group
mSession = session
refreshAvatar()
}
/**
* Refresh the avatar
*/
private fun refreshAvatar() {
if (null != mAvatarView && null != mSession && null != mGroup) {
// TODO
// VectorUtils.loadGroupAvatar(context, session, mAvatarView, mGroup)
}
}
}

View File

@ -27,6 +27,7 @@ import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.utils.tappableMatchingText import im.vector.app.core.utils.tappableMatchingText
import im.vector.app.databinding.ViewActiveConferenceViewBinding
import im.vector.app.features.home.room.detail.RoomDetailViewState import im.vector.app.features.home.room.detail.RoomDetailViewState
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
@ -48,12 +49,15 @@ class ActiveConferenceView @JvmOverloads constructor(
var callback: Callback? = null var callback: Callback? = null
var jitsiWidget: Widget? = null var jitsiWidget: Widget? = null
private lateinit var views: ViewActiveConferenceViewBinding
init { init {
setupView() setupView()
} }
private fun setupView() { private fun setupView() {
inflate(context, R.layout.view_active_conference_view, this) inflate(context, R.layout.view_active_conference_view, this)
views = ViewActiveConferenceViewBinding.bind(this)
setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary)) setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
// "voice" and "video" texts are underlined and clickable // "voice" and "video" texts are underlined and clickable
@ -78,12 +82,12 @@ class ActiveConferenceView @JvmOverloads constructor(
} }
}) })
findViewById<TextView>(R.id.activeConferenceInfo).apply { views.activeConferenceInfo.apply {
text = styledText text = styledText
movementMethod = LinkMovementMethod.getInstance() movementMethod = LinkMovementMethod.getInstance()
} }
findViewById<TextView>(R.id.deleteWidgetButton).setOnClickListener { views.deleteWidgetButton.setOnClickListener {
jitsiWidget?.let { callback?.onDelete(it) } jitsiWidget?.let { callback?.onDelete(it) }
} }
} }
@ -105,7 +109,7 @@ class ActiveConferenceView @JvmOverloads constructor(
jitsiWidget = activeConf jitsiWidget = activeConf
} }
// if sent by me or if i can moderate? // if sent by me or if i can moderate?
findViewById<TextView>(R.id.deleteWidgetButton).isVisible = state.isAllowedToManageWidgets views.deleteWidgetButton.isVisible = state.isAllowedToManageWidgets
} else { } else {
isVisible = false isVisible = false
} }

View File

@ -31,6 +31,7 @@ import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.databinding.ItemVerificationActionBinding
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
class BottomSheetActionButton @JvmOverloads constructor( class BottomSheetActionButton @JvmOverloads constructor(
@ -38,23 +39,18 @@ class BottomSheetActionButton @JvmOverloads constructor(
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) { ) : FrameLayout(context, attrs, defStyleAttr) {
private val views : ItemVerificationActionBinding
private val actionTextView: TextView
private val descriptionTextView: TextView
private val leftIconImageView: ImageView
private val rightIconImageView: ImageView
private val clickableView: View
var title: String? = null var title: String? = null
set(value) { set(value) {
field = value field = value
actionTextView.setTextOrHide(value) views.itemVerificationActionTitle.setTextOrHide(value)
} }
var subTitle: String? = null var subTitle: String? = null
set(value) { set(value) {
field = value field = value
descriptionTextView.setTextOrHide(value) views.itemVerificationActionSubTitle.setTextOrHide(value)
} }
var forceStartPadding: Boolean? = null var forceStartPadding: Boolean? = null
@ -62,9 +58,9 @@ class BottomSheetActionButton @JvmOverloads constructor(
field = value field = value
if (leftIcon == null) { if (leftIcon == null) {
if (forceStartPadding == true) { if (forceStartPadding == true) {
leftIconImageView.isInvisible = true views.itemVerificationLeftIcon.isInvisible = true
} else { } else {
leftIconImageView.isGone = true views.itemVerificationLeftIcon.isGone = true
} }
} }
} }
@ -74,43 +70,38 @@ class BottomSheetActionButton @JvmOverloads constructor(
field = value field = value
if (value == null) { if (value == null) {
if (forceStartPadding == true) { if (forceStartPadding == true) {
leftIconImageView.isInvisible = true views.itemVerificationLeftIcon.isInvisible = true
} else { } else {
leftIconImageView.isGone = true views.itemVerificationLeftIcon.isGone = true
} }
leftIconImageView.setImageDrawable(null) views.itemVerificationLeftIcon.setImageDrawable(null)
} else { } else {
leftIconImageView.isVisible = true views.itemVerificationLeftIcon.isVisible = true
leftIconImageView.setImageDrawable(value) views.itemVerificationLeftIcon.setImageDrawable(value)
} }
} }
var rightIcon: Drawable? = null var rightIcon: Drawable? = null
set(value) { set(value) {
field = value field = value
rightIconImageView.setImageDrawable(value) views.itemVerificationActionIcon.setImageDrawable(value)
} }
var tint: Int? = null var tint: Int? = null
set(value) { set(value) {
field = value field = value
leftIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) } views.itemVerificationLeftIcon.imageTintList = value?.let { ColorStateList.valueOf(value) }
} }
var titleTextColor: Int? = null var titleTextColor: Int? = null
set(value) { set(value) {
field = value field = value
value?.let { actionTextView.setTextColor(it) } value?.let { views.itemVerificationActionTitle.setTextColor(it) }
} }
init { init {
inflate(context, R.layout.item_verification_action, this) inflate(context, R.layout.item_verification_action, this)
views = ItemVerificationActionBinding.bind(this)
actionTextView = findViewById(R.id.itemVerificationActionTitle)
descriptionTextView = findViewById(R.id.itemVerificationActionSubTitle)
leftIconImageView = findViewById(R.id.itemVerificationLeftIcon)
rightIconImageView = findViewById(R.id.itemVerificationActionIcon)
clickableView = findViewById(R.id.itemVerificationClickableZone)
context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) { context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) {
title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: "" title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: ""

View File

@ -42,6 +42,7 @@ import im.vector.app.core.extensions.getMeasurements
import im.vector.app.core.utils.PERMISSIONS_EMPTY import im.vector.app.core.utils.PERMISSIONS_EMPTY
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
import kotlin.math.max import kotlin.math.max
@ -62,24 +63,20 @@ class AttachmentTypeSelectorView(context: Context,
private val iconColorGenerator = ColorGenerator.MATERIAL private val iconColorGenerator = ColorGenerator.MATERIAL
private var galleryButton: ImageButton private val views: ViewAttachmentTypeSelectorBinding
private var cameraButton: ImageButton
private var fileButton: ImageButton
private var stickersButton: ImageButton
private var audioButton: ImageButton
private var contactButton: ImageButton
private var anchor: View? = null private var anchor: View? = null
init { init {
val root = FrameLayout(context) val root = FrameLayout(context)
val layout = inflater.inflate(R.layout.view_attachment_type_selector, root, true) val layout = inflater.inflate(R.layout.view_attachment_type_selector, root, true)
galleryButton = layout.findViewById<ImageButton>(R.id.attachmentGalleryButton).configure(Type.GALLERY) views = ViewAttachmentTypeSelectorBinding.bind(layout)
cameraButton = layout.findViewById<ImageButton>(R.id.attachmentCameraButton).configure(Type.CAMERA) views.attachmentGalleryButton.configure(Type.GALLERY)
fileButton = layout.findViewById<ImageButton>(R.id.attachmentFileButton).configure(Type.FILE) views.attachmentCameraButton.configure(Type.CAMERA)
stickersButton = layout.findViewById<ImageButton>(R.id.attachmentStickersButton).configure(Type.STICKER) views.attachmentFileButton.configure(Type.FILE)
audioButton = layout.findViewById<ImageButton>(R.id.attachmentAudioButton).configure(Type.AUDIO) views.attachmentStickersButton.configure(Type.STICKER)
contactButton = layout.findViewById<ImageButton>(R.id.attachmentContactButton).configure(Type.CONTACT) views.attachmentAudioButton.configure(Type.AUDIO)
views.attachmentContactButton.configure(Type.CONTACT)
contentView = root contentView = root
width = LinearLayout.LayoutParams.MATCH_PARENT width = LinearLayout.LayoutParams.MATCH_PARENT
height = LinearLayout.LayoutParams.WRAP_CONTENT height = LinearLayout.LayoutParams.WRAP_CONTENT
@ -108,12 +105,12 @@ class AttachmentTypeSelectorView(context: Context,
contentView.doOnNextLayout { contentView.doOnNextLayout {
animateWindowInCircular(anchor, contentView) animateWindowInCircular(anchor, contentView)
} }
animateButtonIn(galleryButton, ANIMATION_DURATION / 2) animateButtonIn(views.attachmentGalleryButton, ANIMATION_DURATION / 2)
animateButtonIn(cameraButton, ANIMATION_DURATION / 2) animateButtonIn(views.attachmentCameraButton, ANIMATION_DURATION / 2)
animateButtonIn(fileButton, ANIMATION_DURATION / 4) animateButtonIn(views.attachmentFileButton, ANIMATION_DURATION / 4)
animateButtonIn(audioButton, ANIMATION_DURATION / 2) animateButtonIn(views.attachmentAudioButton, ANIMATION_DURATION / 2)
animateButtonIn(contactButton, ANIMATION_DURATION / 4) animateButtonIn(views.attachmentContactButton, ANIMATION_DURATION / 4)
animateButtonIn(stickersButton, 0) animateButtonIn(views.attachmentStickersButton, 0)
} }
override fun dismiss() { override fun dismiss() {

View File

@ -24,6 +24,7 @@ import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import im.vector.app.R import im.vector.app.R
import im.vector.app.databinding.ViewCallControlsBinding
import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.CallState
import org.webrtc.PeerConnection import org.webrtc.PeerConnection
@ -32,40 +33,22 @@ class CallControlsView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) { ) : LinearLayout(context, attrs, defStyleAttr) {
private var ringingControls: View private val views: ViewCallControlsBinding
private var connectedControls: View
private val ringingControlAccept: View
private var ringingControlDecline: View
private var iv_end_call: View
private var muteIcon: ImageView
private var videoToggleIcon: ImageView
private var iv_leftMiniControl: View
private var iv_more: View
var interactionListener: InteractionListener? = null var interactionListener: InteractionListener? = null
init { init {
View.inflate(context, R.layout.view_call_controls, this) View.inflate(context, R.layout.view_call_controls, this)
// layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) // layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
views = ViewCallControlsBinding.bind(this)
ringingControlAccept = findViewById<View>(R.id.ringingControlAccept) views.ringingControlAccept.setOnClickListener { acceptIncomingCall() }
.also { it.setOnClickListener { acceptIncomingCall() } } views.ringingControlDecline.setOnClickListener { declineIncomingCall() }
ringingControlDecline = findViewById<View>(R.id.ringingControlDecline) views.ivEndCall.setOnClickListener { endOngoingCall() }
.also { it.setOnClickListener { declineIncomingCall() } } views.muteIcon.setOnClickListener { toggleMute() }
iv_end_call = findViewById<View>(R.id.iv_end_call) views.videoToggleIcon.setOnClickListener { toggleVideo() }
.also { it.setOnClickListener { endOngoingCall() } } views.ivLeftMiniControl.setOnClickListener { returnToChat() }
muteIcon = findViewById<ImageView>(R.id.muteIcon) views.ivMore.setOnClickListener { moreControlOption() }
.also { it.setOnClickListener { toggleMute() } }
videoToggleIcon = findViewById<ImageView>(R.id.videoToggleIcon)
.also { it.setOnClickListener { toggleVideo() } }
iv_leftMiniControl = findViewById<View>(R.id.iv_leftMiniControl)
.also { it.setOnClickListener { returnToChat() } }
iv_more = findViewById<View>(R.id.iv_more)
.also { it.setOnClickListener { moreControlOption() } }
ringingControls = findViewById(R.id.ringingControls)
connectedControls = findViewById(R.id.connectedControls)
} }
private fun acceptIncomingCall() { private fun acceptIncomingCall() {
@ -99,51 +82,51 @@ class CallControlsView @JvmOverloads constructor(
fun updateForState(state: VectorCallViewState) { fun updateForState(state: VectorCallViewState) {
val callState = state.callState.invoke() val callState = state.callState.invoke()
if (state.isAudioMuted) { if (state.isAudioMuted) {
muteIcon.setImageResource(R.drawable.ic_microphone_off) views.muteIcon.setImageResource(R.drawable.ic_microphone_off)
muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone) views.muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone)
} else { } else {
muteIcon.setImageResource(R.drawable.ic_microphone_on) views.muteIcon.setImageResource(R.drawable.ic_microphone_on)
muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone) views.muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone)
} }
if (state.isVideoEnabled) { if (state.isVideoEnabled) {
videoToggleIcon.setImageResource(R.drawable.ic_video) views.videoToggleIcon.setImageResource(R.drawable.ic_video)
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera) views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera)
} else { } else {
videoToggleIcon.setImageResource(R.drawable.ic_video_off) views. videoToggleIcon.setImageResource(R.drawable.ic_video_off)
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera) views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera)
} }
when (callState) { when (callState) {
is CallState.Idle, is CallState.Idle,
is CallState.Dialing, is CallState.Dialing,
is CallState.Answering -> { is CallState.Answering -> {
ringingControls.isVisible = true views.ringingControls.isVisible = true
ringingControlAccept.isVisible = false views.ringingControlAccept.isVisible = false
ringingControlDecline.isVisible = true views.ringingControlDecline.isVisible = true
connectedControls.isVisible = false views.connectedControls.isVisible = false
} }
is CallState.LocalRinging -> { is CallState.LocalRinging -> {
ringingControls.isVisible = true views.ringingControls.isVisible = true
ringingControlAccept.isVisible = true views.ringingControlAccept.isVisible = true
ringingControlDecline.isVisible = true views.ringingControlDecline.isVisible = true
connectedControls.isVisible = false views.connectedControls.isVisible = false
} }
is CallState.Connected -> { is CallState.Connected -> {
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) { if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
ringingControls.isVisible = false views.ringingControls.isVisible = false
connectedControls.isVisible = true views.connectedControls.isVisible = true
videoToggleIcon.isVisible = state.isVideoCall views.videoToggleIcon.isVisible = state.isVideoCall
} else { } else {
ringingControls.isVisible = true views.ringingControls.isVisible = true
ringingControlAccept.isVisible = false views.ringingControlAccept.isVisible = false
ringingControlDecline.isVisible = true views.ringingControlDecline.isVisible = true
connectedControls.isVisible = false views.connectedControls.isVisible = false
} }
} }
is CallState.Terminated, is CallState.Terminated,
null -> { null -> {
ringingControls.isVisible = false views.ringingControls.isVisible = false
connectedControls.isVisible = false views.connectedControls.isVisible = false
} }
} }
} }

View File

@ -86,13 +86,13 @@ class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMee
when (viewState.widget) { when (viewState.widget) {
is Fail -> finish() is Fail -> finish()
is Success -> { is Success -> {
findViewById<View>(R.id.jitsi_progress_layout).isVisible = false views.jitsiProgressLayout.isVisible = false
jitsiMeetView?.isVisible = true jitsiMeetView?.isVisible = true
configureJitsiView(viewState) configureJitsiView(viewState)
} }
else -> { else -> {
jitsiMeetView?.isVisible = false jitsiMeetView?.isVisible = false
findViewById<View>(R.id.jitsi_progress_layout).isVisible = true views.jitsiProgressLayout.isVisible = true
} }
} }
} }

View File

@ -35,6 +35,7 @@ import im.vector.app.core.utils.LiveEvent
import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.selectTxtFileToWrite import im.vector.app.core.utils.selectTxtFileToWrite
import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.BottomSheetSaveRecoveryKeyBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
@ -65,10 +66,10 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
viewModel.passphrase.observe(viewLifecycleOwner, Observer { viewModel.passphrase.observe(viewLifecycleOwner, Observer {
if (it.isNullOrBlank()) { if (it.isNullOrBlank()) {
// Recovery was generated, so show key and options to save // Recovery was generated, so show key and options to save
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase) views.mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)
mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title_no_passphrase) views.mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title_no_passphrase)
keys_backup_recovery_key_text.text = viewModel.recoveryKey.value!! views.keysBackupRecoveryKeyText.text = viewModel.recoveryKey.value!!
.replace(" ", "") .replace(" ", "")
.chunked(16) .chunked(16)
.joinToString("\n") { .joinToString("\n") {
@ -76,11 +77,11 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
.chunked(4) .chunked(4)
.joinToString(" ") .joinToString(" ")
} }
keys_backup_recovery_key_text.isVisible = true views.keysBackupRecoveryKeyText.isVisible = true
} else { } else {
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2) views.mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2)
mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title) views.mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
keys_backup_recovery_key_text.isVisible = false views.keysBackupRecoveryKeyText.isVisible = false
} }
}) })
@ -88,9 +89,9 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
} }
private fun setupViews() { private fun setupViews() {
mFinishButton.setOnClickListener { onFinishButtonClicked() } views.mFinishButton.setOnClickListener { onFinishButtonClicked() }
keys_backup_setup_step3_copy_button.setOnClickListener { onCopyButtonClicked() } views.keysBackupSetupStep3CopyButton.setOnClickListener { onCopyButtonClicked() }
keys_backup_recovery_key_text.setOnClickListener { onRecoveryKeyClicked() } views.keysBackupRecoveryKeyText.setOnClickListener { onRecoveryKeyClicked() }
} }
private fun onFinishButtonClicked() { private fun onFinishButtonClicked() {