diff --git a/CHANGES.md b/CHANGES.md index 9996d8d20c..0fb7d72c13 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,7 +23,7 @@ Test: - Other changes: - - + - Migrate to ViewBindings (#1072) Changes in Element 1.0.13 (2020-12-18) =================================================== diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 59ba6c4500..d8cd7d0c98 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -16,7 +16,6 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' buildscript { repositories { @@ -55,6 +54,10 @@ android { kotlinOptions { jvmTarget = '1.8' } + + buildFeatures { + viewBinding true + } } dependencies { diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AnimatedImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AnimatedImageViewHolder.kt index 96e6c92467..0d9eaf59b7 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AnimatedImageViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AnimatedImageViewHolder.kt @@ -17,19 +17,17 @@ package im.vector.lib.attachmentviewer import android.view.View -import android.widget.ImageView -import android.widget.ProgressBar +import im.vector.lib.attachmentviewer.databinding.ItemAnimatedImageAttachmentBinding class AnimatedImageViewHolder constructor(itemView: View) : BaseViewHolder(itemView) { - val touchImageView: ImageView = itemView.findViewById(R.id.imageView) - val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress) + val views = ItemAnimatedImageAttachmentBinding.bind(itemView) - internal val target = DefaultImageLoaderTarget(this, this.touchImageView) + internal val target = DefaultImageLoaderTarget(this, views.imageView) override fun onRecycled() { super.onRecycled() - touchImageView.setImageDrawable(null) + views.imageView.setImageDrawable(null) } } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 71ce436cf2..ae095be41a 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -33,7 +33,8 @@ import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.transition.TransitionManager import androidx.viewpager2.widget.ViewPager2 -import kotlinx.android.synthetic.main.activity_attachment_viewer.* +import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding + import java.lang.ref.WeakReference import kotlin.math.abs @@ -50,12 +51,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private var overlayView: View? = null set(value) { if (value == overlayView) return - overlayView?.let { rootContainer.removeView(it) } - rootContainer.addView(value) + overlayView?.let { views.rootContainer.removeView(it) } + views.rootContainer.addView(value) value?.updatePadding(top = topInset, bottom = bottomInset) field = value } + private lateinit var views: ActivityAttachmentViewerBinding + private lateinit var swipeDismissHandler: SwipeToDismissHandler private lateinit var directionDetector: SwipeDirectionDetector private lateinit var scaleDetector: ScaleGestureDetector @@ -95,17 +98,17 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - setContentView(R.layout.activity_attachment_viewer) - attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL + views = ActivityAttachmentViewerBinding.inflate(layoutInflater) + setContentView(views.root) + views.attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL attachmentsAdapter = AttachmentsAdapter() - attachmentPager.adapter = attachmentsAdapter - imageTransitionView = transitionImageView - transitionImageContainer = findViewById(R.id.transitionImageContainer) - pager2 = attachmentPager + views.attachmentPager.adapter = attachmentsAdapter + imageTransitionView = views.transitionImageView + pager2 = views.attachmentPager directionDetector = createSwipeDirectionDetector() gestureDetector = createGestureDetector() - attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + views.attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageScrollStateChanged(state: Int) { isImagePagerIdle = state == ViewPager2.SCROLL_STATE_IDLE } @@ -116,12 +119,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi }) swipeDismissHandler = createSwipeToDismissHandler() - rootContainer.setOnTouchListener(swipeDismissHandler) - rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = dismissContainer.height / 4 } + views.rootContainer.setOnTouchListener(swipeDismissHandler) + views.rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = views.dismissContainer.height / 4 } scaleDetector = createScaleGestureDetector() - ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { _, insets -> + ViewCompat.setOnApplyWindowInsetsListener(views.rootContainer) { _, insets -> overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom) topInset = insets.systemWindowInsetTop bottomInset = insets.systemWindowInsetBottom @@ -170,7 +173,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi if (swipeDirection == null && (scaleDetector.isInProgress || ev.pointerCount > 1 || wasScaled)) { wasScaled = true // Log.v("ATTACHEMENTS", "dispatch to pager") - return attachmentPager.dispatchTouchEvent(ev) + return views.attachmentPager.dispatchTouchEvent(ev) } // Log.v("ATTACHEMENTS", "is current item scaled ${isScaled()}") @@ -196,16 +199,16 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun handleEventActionDown(event: MotionEvent) { swipeDirection = null wasScaled = false - attachmentPager.dispatchTouchEvent(event) + views.attachmentPager.dispatchTouchEvent(event) - swipeDismissHandler.onTouch(rootContainer, event) + swipeDismissHandler.onTouch(views.rootContainer, event) isOverlayWasClicked = dispatchOverlayTouch(event) } private fun handleEventActionUp(event: MotionEvent) { // wasDoubleTapped = false - swipeDismissHandler.onTouch(rootContainer, event) - attachmentPager.dispatchTouchEvent(event) + swipeDismissHandler.onTouch(views.rootContainer, event) + views.attachmentPager.dispatchTouchEvent(event) isOverlayWasClicked = dispatchOverlayTouch(event) } @@ -220,12 +223,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun toggleOverlayViewVisibility() { if (systemUiVisibility) { // we hide - TransitionManager.beginDelayedTransition(rootContainer) + TransitionManager.beginDelayedTransition(views.rootContainer) hideSystemUI() overlayView?.isVisible = false } else { // we show - TransitionManager.beginDelayedTransition(rootContainer) + TransitionManager.beginDelayedTransition(views.rootContainer) showSystemUI() overlayView?.isVisible = true } @@ -238,11 +241,11 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi return when (swipeDirection) { SwipeDirection.Up, SwipeDirection.Down -> { if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) { - swipeDismissHandler.onTouch(rootContainer, event) + swipeDismissHandler.onTouch(views.rootContainer, event) } else true } SwipeDirection.Left, SwipeDirection.Right -> { - attachmentPager.dispatchTouchEvent(event) + views.attachmentPager.dispatchTouchEvent(event) } else -> true } @@ -250,8 +253,8 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun handleSwipeViewMove(translationY: Float, translationLimit: Int) { val alpha = calculateTranslationAlpha(translationY, translationLimit) - backgroundView.alpha = alpha - dismissContainer.alpha = alpha + views.backgroundView.alpha = alpha + views.dismissContainer.alpha = alpha overlayView?.alpha = alpha } @@ -265,7 +268,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi private fun createSwipeToDismissHandler() : SwipeToDismissHandler = SwipeToDismissHandler( - swipeView = dismissContainer, + swipeView = views.dismissContainer, shouldAnimateDismiss = { shouldAnimateDismiss() }, onDismiss = { animateClose() }, onSwipeViewMove = ::handleSwipeViewMove) diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt index 99c7777220..4805a1186b 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentsAdapter.kt @@ -98,7 +98,7 @@ class AttachmentsAdapter : RecyclerView.Adapter() { fun isScaled(position: Int): Boolean { val holder = recyclerView?.findViewHolderForAdapterPosition(position) if (holder is ZoomableImageViewHolder) { - return holder.touchImageView.attacher.scale > 1f + return holder.views.touchImageView.attacher.scale > 1f } return false } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ImageLoaderTarget.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ImageLoaderTarget.kt index 9166c2ce4f..531e8171e1 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ImageLoaderTarget.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ImageLoaderTarget.kt @@ -44,29 +44,29 @@ internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, pri override fun onResourceLoading(uid: String, placeholder: Drawable?) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = true + holder.views.imageLoaderProgress.isVisible = true } override fun onLoadFailed(uid: String, errorDrawable: Drawable?) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = false - holder.touchImageView.setImageDrawable(errorDrawable) + holder.views.imageLoaderProgress.isVisible = false + holder.views.imageView.setImageDrawable(errorDrawable) } override fun onResourceCleared(uid: String, placeholder: Drawable?) { if (holder.boundResourceUid != uid) return - holder.touchImageView.setImageDrawable(placeholder) + holder.views.imageView.setImageDrawable(placeholder) } override fun onResourceReady(uid: String, resource: Drawable) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = false + holder.views.imageLoaderProgress.isVisible = false // Glide mess up the view size :/ - holder.touchImageView.updateLayoutParams { + holder.views.imageView.updateLayoutParams { width = LinearLayout.LayoutParams.MATCH_PARENT height = LinearLayout.LayoutParams.MATCH_PARENT } - holder.touchImageView.setImageDrawable(resource) + holder.views.imageView.setImageDrawable(resource) if (resource is Animatable) { resource.start() } @@ -77,30 +77,30 @@ internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, pri override fun onResourceLoading(uid: String, placeholder: Drawable?) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = true - holder.touchImageView.setImageDrawable(placeholder) + holder.views.imageLoaderProgress.isVisible = true + holder.views.touchImageView.setImageDrawable(placeholder) } override fun onLoadFailed(uid: String, errorDrawable: Drawable?) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = false - holder.touchImageView.setImageDrawable(errorDrawable) + holder.views.imageLoaderProgress.isVisible = false + holder.views.touchImageView.setImageDrawable(errorDrawable) } override fun onResourceCleared(uid: String, placeholder: Drawable?) { if (holder.boundResourceUid != uid) return - holder.touchImageView.setImageDrawable(placeholder) + holder.views.touchImageView.setImageDrawable(placeholder) } override fun onResourceReady(uid: String, resource: Drawable) { if (holder.boundResourceUid != uid) return - holder.imageLoaderProgress.isVisible = false + holder.views.imageLoaderProgress.isVisible = false // Glide mess up the view size :/ - holder.touchImageView.updateLayoutParams { + holder.views.touchImageView.updateLayoutParams { width = LinearLayout.LayoutParams.MATCH_PARENT height = LinearLayout.LayoutParams.MATCH_PARENT } - holder.touchImageView.setImageDrawable(resource) + holder.views.touchImageView.setImageDrawable(resource) } } } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoLoaderTarget.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoLoaderTarget.kt index d88faba110..078edfc548 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoLoaderTarget.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoLoaderTarget.kt @@ -49,19 +49,19 @@ internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val override fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?) { if (holder.boundResourceUid != uid) return - holder.thumbnailImage.setImageDrawable(placeholder) + holder.views.videoThumbnailImage.setImageDrawable(placeholder) } override fun onThumbnailResourceReady(uid: String, resource: Drawable) { if (holder.boundResourceUid != uid) return - holder.thumbnailImage.setImageDrawable(resource) + holder.views.videoThumbnailImage.setImageDrawable(resource) } override fun onVideoFileLoading(uid: String) { if (holder.boundResourceUid != uid) return - holder.thumbnailImage.isVisible = true - holder.loaderProgressBar.isVisible = true - holder.videoView.isVisible = false + holder.views.videoThumbnailImage.isVisible = true + holder.views.videoLoaderProgress.isVisible = true + holder.views.videoView.isVisible = false } override fun onVideoFileLoadFailed(uid: String) { @@ -82,8 +82,8 @@ internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val } private fun arrangeForVideoReady() { - holder.thumbnailImage.isVisible = false - holder.loaderProgressBar.isVisible = false - holder.videoView.isVisible = true + holder.views.videoThumbnailImage.isVisible = false + holder.views.videoLoaderProgress.isVisible = false + holder.views.videoView.isVisible = true } } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt index 4d8be6468b..0b72ef36f0 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/VideoViewHolder.kt @@ -18,11 +18,8 @@ package im.vector.lib.attachmentviewer import android.util.Log import android.view.View -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.TextView -import android.widget.VideoView import androidx.core.view.isVisible +import im.vector.lib.attachmentviewer.databinding.ItemVideoAttachmentBinding import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -44,13 +41,9 @@ class VideoViewHolder constructor(itemView: View) : var eventListener: WeakReference? = null - val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage) - 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) + val views = ItemVideoAttachmentBinding.bind(itemView) - internal val target = DefaultVideoLoaderTarget(this, thumbnailImage) + internal val target = DefaultVideoLoaderTarget(this, views.videoThumbnailImage) override fun onRecycled() { super.onRecycled() @@ -77,12 +70,12 @@ class VideoViewHolder constructor(itemView: View) : } override fun entersBackground() { - if (videoView.isPlaying) { - progress = videoView.currentPosition + if (views.videoView.isPlaying) { + progress = views.videoView.currentPosition progressDisposable?.dispose() progressDisposable = null - videoView.stopPlayback() - videoView.pause() + views.videoView.stopPlayback() + views.videoView.pause() } } @@ -92,9 +85,9 @@ class VideoViewHolder constructor(itemView: View) : override fun onSelected(selected: Boolean) { if (!selected) { - if (videoView.isPlaying) { - progress = videoView.currentPosition - videoView.stopPlayback() + if (views.videoView.isPlaying) { + progress = views.videoView.currentPosition + views.videoView.stopPlayback() } else { progress = 0 } @@ -109,34 +102,34 @@ class VideoViewHolder constructor(itemView: View) : } private fun startPlaying() { - thumbnailImage.isVisible = false - loaderProgressBar.isVisible = false - videoView.isVisible = true + views.videoThumbnailImage.isVisible = false + views.videoLoaderProgress.isVisible = false + views.videoView.isVisible = true - videoView.setOnPreparedListener { + views.videoView.setOnPreparedListener { progressDisposable?.dispose() progressDisposable = Observable.interval(100, TimeUnit.MILLISECONDS) .timeInterval() .observeOn(AndroidSchedulers.mainThread()) .subscribe { - val duration = videoView.duration - val progress = videoView.currentPosition - val isPlaying = videoView.isPlaying + val duration = views.videoView.duration + val progress = views.videoView.currentPosition + val isPlaying = views.videoView.isPlaying // Log.v("FOO", "isPlaying $isPlaying $progress/$duration") eventListener?.get()?.onEvent(AttachmentEvents.VideoEvent(isPlaying, progress, duration)) } } try { - videoView.setVideoPath(mVideoPath) + views.videoView.setVideoPath(mVideoPath) } catch (failure: Throwable) { // Couldn't open Log.v(VideoViewHolder::class.java.name, "Failed to start video") } if (!wasPaused) { - videoView.start() + views.videoView.start() if (progress > 0) { - videoView.seekTo(progress) + views.videoView.seekTo(progress) } } } @@ -146,17 +139,17 @@ class VideoViewHolder constructor(itemView: View) : when (commands) { AttachmentCommands.StartVideo -> { wasPaused = false - videoView.start() + views.videoView.start() } AttachmentCommands.PauseVideo -> { wasPaused = true - videoView.pause() + views.videoView.pause() } is AttachmentCommands.SeekTo -> { - val duration = videoView.duration + val duration = views.videoView.duration if (duration > 0) { val seekDuration = duration * (commands.percentProgress / 100f) - videoView.seekTo(seekDuration.toInt()) + views.videoView.seekTo(seekDuration.toInt()) } } } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ZoomableImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ZoomableImageViewHolder.kt index 49378631e8..2a212c16a6 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ZoomableImageViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/ZoomableImageViewHolder.kt @@ -17,31 +17,29 @@ package im.vector.lib.attachmentviewer import android.view.View -import android.widget.ProgressBar -import com.github.chrisbanes.photoview.PhotoView +import im.vector.lib.attachmentviewer.databinding.ItemImageAttachmentBinding class ZoomableImageViewHolder constructor(itemView: View) : BaseViewHolder(itemView) { - val touchImageView: PhotoView = itemView.findViewById(R.id.touchImageView) - val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress) + val views = ItemImageAttachmentBinding.bind(itemView) init { - touchImageView.setAllowParentInterceptOnEdge(false) - touchImageView.setOnScaleChangeListener { scaleFactor, _, _ -> + views.touchImageView.setAllowParentInterceptOnEdge(false) + views.touchImageView.setOnScaleChangeListener { scaleFactor, _, _ -> // Log.v("ATTACHEMENTS", "scaleFactor $scaleFactor") // It's a bit annoying but when you pitch down the scaling // is not exactly one :/ - touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f) + views.touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f) } - touchImageView.setScale(1.0f, true) - touchImageView.setAllowParentInterceptOnEdge(true) + views.touchImageView.setScale(1.0f, true) + views.touchImageView.setAllowParentInterceptOnEdge(true) } - internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView) + internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, views.touchImageView) override fun onRecycled() { super.onRecycled() - touchImageView.setImageDrawable(null) + views.touchImageView.setImageDrawable(null) } } diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 519b8439c9..d72e5bda41 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'realm-android' buildscript { @@ -13,10 +13,6 @@ buildscript { } } -androidExtensions { - experimental = true -} - android { compileSdkVersion 29 testOptions.unitTests.includeAndroidResources = true diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt index d89607843f..6759c59237 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/data/SsoIdentityProvider.kt @@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth.data import android.os.Parcelable import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize @JsonClass(generateAdapter = true) @Parcelize diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt index 4164b84ecd..98a84b8b66 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt @@ -20,7 +20,7 @@ import android.net.Uri import android.os.Parcelable import androidx.exifinterface.media.ExifInterface import com.squareup.moshi.JsonClass -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType @Parcelize diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt index 1e18887008..5d119bb617 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/LocalizedFlowDataLoginTerms.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.auth.registration import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize /** * This class represent a localized privacy policy for registration Flow. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt index b77006aa3a..c071384df4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/ElementToDecrypt.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.attachments import android.os.Parcelable import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? { // Check the validity of some fields diff --git a/multipicker/build.gradle b/multipicker/build.gradle index 7c29a5539f..c58c4586b2 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' android { compileSdkVersion 29 diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index fc510e585c..b9929dfebe 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -109,9 +109,6 @@ import retrofit2\.adapter\.rxjava\.HttpException ### This is generally not necessary, no need to reset the padding if there is no drawable setCompoundDrawablePadding\(0\) -### Deprecated use class form SDK API 26 -ButterKnife\.findById\( - # Change thread with Rx # DISABLED #runOnUiThread @@ -175,3 +172,6 @@ getSystemService\(Context ### Use DefaultSharedPreferences.getInstance() instead for better performance PreferenceManager\.getDefaultSharedPreferences==2 + +### Use ViewBindings +# findViewById diff --git a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl index 7e6eac65c8..38f8132d24 100644 --- a/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl +++ b/tools/templates/ElementFeature/root/src/app_package/Fragment.kt.ftl @@ -3,7 +3,7 @@ package ${escapeKotlinIdentifiers(packageName)} import android.os.Bundle <#if createFragmentArgs> import android.os.Parcelable -import kotlinx.android.parcel.Parcelize +import kotlinx.parcelize.Parcelize import com.airbnb.mvrx.args import android.view.View @@ -36,8 +36,8 @@ class ${fragmentClass} @Inject constructor( } override fun onDestroyView() { - super.onDestroyView() // Clear your view, unsubscribe... + super.onDestroyView() } override fun invalidate() = withState(viewModel) { state -> diff --git a/vector/build.gradle b/vector/build.gradle index 8ab80e6964..f6ba5d6e27 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -3,17 +3,13 @@ import com.android.build.OutputFile apply plugin: 'com.android.application' apply plugin: 'com.google.android.gms.oss-licenses-plugin' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-kapt' kapt { correctErrorTypes = true } -androidExtensions { - experimental = true -} - // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 0 @@ -280,6 +276,10 @@ android { java.srcDirs += "src/sharedTest/java" } } + + buildFeatures { + viewBinding true + } } dependencies { @@ -386,10 +386,6 @@ dependencies { implementation 'com.otaliastudios:autocomplete:1.1.0' - // Butterknife - implementation 'com.jakewharton:butterknife:10.2.0' - kapt 'com.jakewharton:butterknife-compiler:10.2.0' - // Shake detection implementation 'com.squareup:seismic:1.0.2' diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt index 6b30700116..cc4724e8f3 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt @@ -76,7 +76,9 @@ class UiAllScreensSanityTest { private val uiTestBase = UiTestBase() - // Last passing: 2020-11-09 + // Last passing: + // 2020-11-09 + // 2020-12-16 After ViewBinding huge change @Test fun allScreensTest() { // Create an account diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt index 6c4bb925dd..8df1feab1e 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMaterialThemeActivity.kt @@ -24,26 +24,27 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.snackbar.Snackbar import im.vector.app.R import im.vector.app.core.utils.toast -import kotlinx.android.synthetic.debug.activity_test_material_theme.* +import im.vector.app.databinding.ActivityTestMaterialThemeBinding // Rendering is not the same with VectorBaseActivity abstract class DebugMaterialThemeActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test_material_theme) + val views = ActivityTestMaterialThemeBinding.inflate(layoutInflater) + setContentView(views.root) - debugShowSnackbar.setOnClickListener { - Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT) + views.debugShowSnackbar.setOnClickListener { + Snackbar.make(views.coordinatorLayout, "Snackbar!", Snackbar.LENGTH_SHORT) .setAction("Action") { } .show() } - debugShowToast.setOnClickListener { + views.debugShowToast.setOnClickListener { toast("Toast") } - debugShowDialog.setOnClickListener { + views.debugShowDialog.setOnClickListener { AlertDialog.Builder(this) .setMessage("Dialog content") .setIcon(R.drawable.ic_settings_x) @@ -53,7 +54,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() { .show() } - debugShowBottomSheet.setOnClickListener { + views.debugShowBottomSheet.setOnClickListener { BottomSheetDialogFragment().show(supportFragmentManager, "TAG") } } diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 9cca462d1a..8699b238ec 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -24,7 +24,6 @@ import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.Person import androidx.core.content.getSystemService -import butterknife.OnClick import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent @@ -35,16 +34,17 @@ import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.toast +import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.qrcode.QrCodeScannerActivity import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData -import kotlinx.android.synthetic.debug.activity_debug_menu.* + import timber.log.Timber import javax.inject.Inject -class DebugMenuActivity : VectorBaseActivity() { +class DebugMenuActivity : VectorBaseActivity() { - override fun getLayoutRes() = R.layout.activity_debug_menu + override fun getBinding() = ActivityDebugMenuBinding.inflate(layoutInflater) @Inject lateinit var activeSessionHolder: ActiveSessionHolder @@ -66,24 +66,32 @@ class DebugMenuActivity : VectorBaseActivity() { val string = buffer.toString(Charsets.ISO_8859_1) renderQrCode(string) + setupViews() + } + + private fun setupViews() { + views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } + views.debugShowSasEmoji.setOnClickListener { showSasEmoji() } + views.debugTestNotification.setOnClickListener { testNotification() } + views.debugTestMaterialThemeLight.setOnClickListener { testMaterialThemeLight() } + views.debugTestMaterialThemeDark.setOnClickListener { testMaterialThemeDark() } + views.debugTestCrash.setOnClickListener { testCrash() } + views.debugScanQrCode.setOnClickListener { scanQRCode() } } private fun renderQrCode(text: String) { - debug_qr_code.setData(text) + views.debugQrCode.setData(text) } - @OnClick(R.id.debug_test_text_view_link) - fun testTextViewLink() { + private fun testTextViewLink() { startActivity(Intent(this, TestLinkifyActivity::class.java)) } - @OnClick(R.id.debug_show_sas_emoji) - fun showSasEmoji() { + private fun showSasEmoji() { startActivity(Intent(this, DebugSasEmojiActivity::class.java)) } - @OnClick(R.id.debug_test_notification) - fun testNotification() { + private fun testNotification() { val notificationManager = getSystemService()!! // Create channel first @@ -166,23 +174,19 @@ class DebugMenuActivity : VectorBaseActivity() { ) } - @OnClick(R.id.debug_test_material_theme_light) - fun testMaterialThemeLight() { + private fun testMaterialThemeLight() { startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java)) } - @OnClick(R.id.debug_test_material_theme_dark) - fun testMaterialThemeDark() { + private fun testMaterialThemeDark() { startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java)) } - @OnClick(R.id.debug_test_crash) - fun testCrash() { + private fun testCrash() { throw RuntimeException("Application crashed from user demand") } - @OnClick(R.id.debug_scan_qr_code) - fun scanQRCode() { + private fun scanQRCode() { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { doScanQRCode() } diff --git a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt index fd28aabd49..88e55d6760 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/TestLinkifyActivity.kt @@ -19,28 +19,18 @@ package im.vector.app.features.debug import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.TextView import androidx.appcompat.app.AppCompatActivity -import androidx.coordinatorlayout.widget.CoordinatorLayout -import butterknife.BindView -import butterknife.ButterKnife import im.vector.app.R +import im.vector.app.databinding.ActivityTestLinkifyBinding +import im.vector.app.databinding.ItemTestLinkifyBinding class TestLinkifyActivity : AppCompatActivity() { - @BindView(R.id.test_linkify_content_view) - lateinit var scrollContent: LinearLayout - - @BindView(R.id.test_linkify_coordinator) - lateinit var coordinatorLayout: CoordinatorLayout - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_test_linkify) - ButterKnife.bind(this) - - scrollContent.removeAllViews() + val views = ActivityTestLinkifyBinding.inflate(layoutInflater) + setContentView(views.root) + views.testLinkifyContentView.removeAllViews() listOf( "https://www.html5rocks.com/en/tutorials/webrtc/basics/ |", @@ -89,43 +79,42 @@ class TestLinkifyActivity : AppCompatActivity() { ) .forEach { textContent -> val item = LayoutInflater.from(this) - .inflate(R.layout.item_test_linkify, scrollContent, false) - - item.findViewById(R.id.test_linkify_auto_text) - ?.apply { - text = textContent - /* TODO Use BetterLinkMovementMethod when the other PR is merged - movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { - override fun onURLClick(uri: Uri?) { - Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) - .setAction("open") { - openUrlInExternalBrowser(this@TestLinkifyActivity, uri) - } - .show() - } - }) - */ + .inflate(R.layout.item_test_linkify, views.testLinkifyContentView, false) + val subViews = ItemTestLinkifyBinding.bind(item) + subViews.testLinkifyAutoText.apply { + text = textContent + /* TODO Use BetterLinkMovementMethod when the other PR is merged + movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { + override fun onURLClick(uri: Uri?) { + Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) + .setAction("open") { + openUrlInExternalBrowser(this@TestLinkifyActivity, uri) + } + .show() } + }) + */ + } - item.findViewById(R.id.test_linkify_custom_text) - ?.apply { - text = textContent - /* TODO Use BetterLinkMovementMethod when the other PR is merged - movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { - override fun onURLClick(uri: Uri?) { - Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) - .setAction("open") { - openUrlInExternalBrowser(this@TestLinkifyActivity, uri) - } - .show() - } - }) - */ - - // TODO Call VectorLinkify.addLinks(text) + subViews.testLinkifyCustomText.apply { + text = textContent + /* TODO Use BetterLinkMovementMethod when the other PR is merged + movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() { + override fun onURLClick(uri: Uri?) { + Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG) + .setAction("open") { + openUrlInExternalBrowser(this@TestLinkifyActivity, uri) + } + .show() } + }) + */ - scrollContent.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + // TODO Call VectorLinkify.addLinks(text) + } + + views.testLinkifyContentView + .addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) } } } diff --git a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt index 869058eff6..4d7005aca8 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/sas/DebugSasEmojiActivity.kt @@ -18,24 +18,26 @@ package im.vector.app.features.debug.sas import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith +import im.vector.app.databinding.FragmentGenericRecyclerBinding import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis -import kotlinx.android.synthetic.main.fragment_generic_recycler.* class DebugSasEmojiActivity : AppCompatActivity() { + private lateinit var views: FragmentGenericRecyclerBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.fragment_generic_recycler) + views = FragmentGenericRecyclerBinding.inflate(layoutInflater) + setContentView(views.root) val controller = SasEmojiController() - genericRecyclerView.configureWith(controller) + views.genericRecyclerView.configureWith(controller) controller.setData(SasState(getAllVerificationEmojis())) } override fun onDestroy() { - genericRecyclerView.cleanup() + views.genericRecyclerView.cleanup() super.onDestroy() } } diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index 9a95085a07..6a41488987 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -1,6 +1,7 @@ Copyright (c) 2017 -
  • - Butterknife -
    - Copyright 2013 Jake Wharton -
  • seismic
    diff --git a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt index 0d9fb9d93d..ed429b30c6 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/ConfirmationDialogBuilder.kt @@ -21,7 +21,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import im.vector.app.R -import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.* +import im.vector.app.databinding.DialogConfirmationWithReasonBinding object ConfirmationDialogBuilder { @@ -33,25 +33,26 @@ object ConfirmationDialogBuilder { @StringRes reasonHintRes: Int, confirmation: (String?) -> Unit) { val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null) - layout.dialogConfirmationText.setText(confirmationRes) + val views = DialogConfirmationWithReasonBinding.bind(layout) + views.dialogConfirmationText.setText(confirmationRes) - layout.dialogReasonCheck.isVisible = askForReason - layout.dialogReasonTextInputLayout.isVisible = askForReason + views.dialogReasonCheck.isVisible = askForReason + views.dialogReasonTextInputLayout.isVisible = askForReason - layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked -> - layout.dialogReasonTextInputLayout.isEnabled = isChecked + views.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked -> + views.dialogReasonTextInputLayout.isEnabled = isChecked } if (askForReason && reasonHintRes != 0) { - layout.dialogReasonInput.setHint(reasonHintRes) + views.dialogReasonInput.setHint(reasonHintRes) } AlertDialog.Builder(activity) .setTitle(titleRes) .setView(layout) .setPositiveButton(positiveRes) { _, _ -> - val reason = layout.dialogReasonInput.text.toString() + val reason = views.dialogReasonInput.text.toString() .takeIf { askForReason } - ?.takeIf { layout.dialogReasonCheck.isChecked } + ?.takeIf { views.dialogReasonCheck.isChecked } ?.takeIf { it.isNotBlank() } confirmation(reason) } diff --git a/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt b/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt index b4087d5ce1..e137eb1b70 100644 --- a/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt +++ b/vector/src/main/java/im/vector/app/core/dialogs/ExportKeysDialog.kt @@ -18,14 +18,11 @@ package im.vector.app.core.dialogs import android.app.Activity import android.text.Editable -import android.widget.Button -import android.widget.ImageView import androidx.appcompat.app.AlertDialog -import com.google.android.material.textfield.TextInputEditText -import com.google.android.material.textfield.TextInputLayout import im.vector.app.R import im.vector.app.core.extensions.showPassword import im.vector.app.core.platform.SimpleTextWatcher +import im.vector.app.databinding.DialogExportE2eKeysBinding class ExportKeysDialog { @@ -33,48 +30,44 @@ class ExportKeysDialog { fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) { val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null) + val views = DialogExportE2eKeysBinding.bind(dialogLayout) val builder = AlertDialog.Builder(activity) .setTitle(R.string.encryption_export_room_keys) .setView(dialogLayout) - val passPhrase1EditText = dialogLayout.findViewById(R.id.exportDialogEt) - val passPhrase2EditText = dialogLayout.findViewById(R.id.exportDialogEtConfirm) - val passPhrase2Til = dialogLayout.findViewById(R.id.exportDialogTilConfirm) - val exportButton = dialogLayout.findViewById