mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Merge pull request #2542 from vector-im/feature/bma/view_bindings
View bindings
This commit is contained in:
commit
2b780a8b76
274 changed files with 3820 additions and 3648 deletions
|
@ -23,7 +23,7 @@ Test:
|
|||
-
|
||||
|
||||
Other changes:
|
||||
-
|
||||
- Migrate to ViewBindings (#1072)
|
||||
|
||||
Changes in Element 1.0.13 (2020-12-18)
|
||||
===================================================
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -98,7 +98,7 @@ class AttachmentsAdapter : RecyclerView.Adapter<BaseViewHolder>() {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AttachmentEventListener>? = 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
</#if>
|
||||
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 ->
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ActivityDebugMenuBinding>() {
|
||||
|
||||
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<NotificationManager>()!!
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
|
|
@ -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<TextView>(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<TextView>(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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".features.debug.DebugMenuActivity"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/test_linkify_coordinator"
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#7F70808D"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/debugMaterialCoordinator"
|
||||
android:id="@+id/coordinatorLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
|
|
@ -312,11 +312,6 @@ SOFTWARE.
|
|||
<br/>
|
||||
Copyright (c) 2017
|
||||
</li>
|
||||
<li>
|
||||
<b>Butterknife</b>
|
||||
<br/>
|
||||
Copyright 2013 Jake Wharton
|
||||
</li>
|
||||
<li>
|
||||
<b>seismic</b>
|
||||
<br/>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<TextInputEditText>(R.id.exportDialogEt)
|
||||
val passPhrase2EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEtConfirm)
|
||||
val passPhrase2Til = dialogLayout.findViewById<TextInputLayout>(R.id.exportDialogTilConfirm)
|
||||
val exportButton = dialogLayout.findViewById<Button>(R.id.exportDialogSubmit)
|
||||
val textWatcher = object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
when {
|
||||
passPhrase1EditText.text.isNullOrEmpty() -> {
|
||||
exportButton.isEnabled = false
|
||||
passPhrase2Til.error = null
|
||||
views.exportDialogEt.text.isNullOrEmpty() -> {
|
||||
views.exportDialogSubmit.isEnabled = false
|
||||
views.exportDialogTilConfirm.error = null
|
||||
}
|
||||
passPhrase1EditText.text.toString() == passPhrase2EditText.text.toString() -> {
|
||||
exportButton.isEnabled = true
|
||||
passPhrase2Til.error = null
|
||||
views.exportDialogEt.text.toString() == views.exportDialogEtConfirm.text.toString() -> {
|
||||
views.exportDialogSubmit.isEnabled = true
|
||||
views.exportDialogTilConfirm.error = null
|
||||
}
|
||||
else -> {
|
||||
exportButton.isEnabled = false
|
||||
passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
||||
views.exportDialogSubmit.isEnabled = false
|
||||
views.exportDialogTilConfirm.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
passPhrase1EditText.addTextChangedListener(textWatcher)
|
||||
passPhrase2EditText.addTextChangedListener(textWatcher)
|
||||
views.exportDialogEt.addTextChangedListener(textWatcher)
|
||||
views.exportDialogEtConfirm.addTextChangedListener(textWatcher)
|
||||
|
||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
||||
showPassword.setOnClickListener {
|
||||
views.exportDialogShowPassword.setOnClickListener {
|
||||
passwordVisible = !passwordVisible
|
||||
passPhrase1EditText.showPassword(passwordVisible)
|
||||
passPhrase2EditText.showPassword(passwordVisible)
|
||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.exportDialogEt.showPassword(passwordVisible)
|
||||
views.exportDialogEtConfirm.showPassword(passwordVisible)
|
||||
views.exportDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
|
||||
val exportDialog = builder.show()
|
||||
|
||||
exportButton.setOnClickListener {
|
||||
exportKeyDialogListener.onPassphrase(passPhrase1EditText.text.toString())
|
||||
views.exportDialogSubmit.setOnClickListener {
|
||||
exportKeyDialogListener.onPassphrase(views.exportDialogEt.text.toString())
|
||||
|
||||
exportDialog.dismiss()
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
package im.vector.app.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.DialogDeviceVerifyBinding
|
||||
import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
|
||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||
|
||||
|
@ -27,6 +27,7 @@ object ManuallyVerifyDialog {
|
|||
|
||||
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
||||
val views = DialogDeviceVerifyBinding.bind(dialogLayout)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.cross_signing_verify_by_text)
|
||||
.setView(dialogLayout)
|
||||
|
@ -35,17 +36,9 @@ object ManuallyVerifyDialog {
|
|||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_name)?.let {
|
||||
it.text = cryptoDeviceInfo.displayName()
|
||||
}
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_id)?.let {
|
||||
it.text = cryptoDeviceInfo.deviceId
|
||||
}
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_key)?.let {
|
||||
it.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
||||
}
|
||||
views.encryptedDeviceInfoDeviceName.text = cryptoDeviceInfo.displayName()
|
||||
views.encryptedDeviceInfoDeviceId.text = cryptoDeviceInfo.deviceId
|
||||
views.encryptedDeviceInfoDeviceKey.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
||||
|
||||
builder.show()
|
||||
}
|
||||
|
|
|
@ -20,14 +20,12 @@ import android.app.Activity
|
|||
import android.content.DialogInterface
|
||||
import android.text.Editable
|
||||
import android.view.KeyEvent
|
||||
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.hideKeyboard
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.SimpleTextWatcher
|
||||
import im.vector.app.databinding.DialogPromptPasswordBinding
|
||||
|
||||
class PromptPasswordDialog {
|
||||
|
||||
|
@ -35,21 +33,18 @@ class PromptPasswordDialog {
|
|||
|
||||
fun show(activity: Activity, listener: (String) -> Unit) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
||||
|
||||
val passwordTil = dialogLayout.findViewById<TextInputLayout>(R.id.promptPasswordTil)
|
||||
val passwordEditText = dialogLayout.findViewById<TextInputEditText>(R.id.promptPassword)
|
||||
val views = DialogPromptPasswordBinding.bind(dialogLayout)
|
||||
val textWatcher = object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
passwordTil.error = null
|
||||
views.promptPasswordTil.error = null
|
||||
}
|
||||
}
|
||||
passwordEditText.addTextChangedListener(textWatcher)
|
||||
views.promptPassword.addTextChangedListener(textWatcher)
|
||||
|
||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal)
|
||||
showPassword.setOnClickListener {
|
||||
views.promptPasswordPasswordReveal.setOnClickListener {
|
||||
passwordVisible = !passwordVisible
|
||||
passwordEditText.showPassword(passwordVisible)
|
||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.promptPassword.showPassword(passwordVisible)
|
||||
views.promptPasswordPasswordReveal.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
|
@ -73,10 +68,10 @@ class PromptPasswordDialog {
|
|||
setOnShowListener {
|
||||
getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
.setOnClickListener {
|
||||
if (passwordEditText.text.toString().isEmpty()) {
|
||||
passwordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||
if (views.promptPassword.text.toString().isEmpty()) {
|
||||
views.promptPasswordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||
} else {
|
||||
listener.invoke(passwordEditText.text.toString())
|
||||
listener.invoke(views.promptPassword.text.toString())
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
package im.vector.app.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.databinding.DialogSslFingerprintBinding
|
||||
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
||||
import timber.log.Timber
|
||||
import java.util.HashMap
|
||||
|
@ -95,30 +94,27 @@ class UnrecognizedCertificateDialog @Inject constructor(
|
|||
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
val layout: View = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
|
||||
val sslFingerprintTitle = layout.findViewById<TextView>(R.id.ssl_fingerprint_title)
|
||||
sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
|
||||
val sslFingerprint = layout.findViewById<TextView>(R.id.ssl_fingerprint)
|
||||
sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
|
||||
val sslUserId = layout.findViewById<TextView>(R.id.ssl_user_id)
|
||||
val layout = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
|
||||
val views = DialogSslFingerprintBinding.bind(layout)
|
||||
views.sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
|
||||
views.sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
|
||||
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),
|
||||
userId)
|
||||
} 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),
|
||||
homeServerUrl)
|
||||
}
|
||||
val sslExpl = layout.findViewById<TextView>(R.id.ssl_explanation)
|
||||
if (existing) {
|
||||
if (homeServerConnectionConfigHasFingerprints) {
|
||||
sslExpl.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
|
||||
views.sslExplanation.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
|
||||
} else {
|
||||
sslExpl.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
|
||||
views.sslExplanation.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
|
||||
}
|
||||
} 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.setTitle(R.string.ssl_could_not_verify)
|
||||
|
|
|
@ -23,15 +23,15 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
|
||||
fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher<Intent> {
|
||||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.addFragment(
|
||||
fun AppCompatActivity.addFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
allowStateLoss: Boolean = false
|
||||
|
@ -39,7 +39,7 @@ fun VectorBaseActivity.addFragment(
|
|||
supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.addFragment(
|
||||
fun <T : Fragment> AppCompatActivity.addFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -51,7 +51,7 @@ fun <T : Fragment> VectorBaseActivity.addFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.replaceFragment(
|
||||
fun AppCompatActivity.replaceFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -60,7 +60,7 @@ fun VectorBaseActivity.replaceFragment(
|
|||
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.replaceFragment(
|
||||
fun <T : Fragment> AppCompatActivity.replaceFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -72,7 +72,7 @@ fun <T : Fragment> VectorBaseActivity.replaceFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.addFragmentToBackstack(
|
||||
fun AppCompatActivity.addFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -81,19 +81,20 @@ fun VectorBaseActivity.addFragmentToBackstack(
|
|||
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
tag: String? = null,
|
||||
allowStateLoss: Boolean = false,
|
||||
option: ((FragmentTransaction) -> Unit)? = null) {
|
||||
fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
tag: String? = null,
|
||||
allowStateLoss: Boolean = false,
|
||||
option: ((FragmentTransaction) -> Unit)? = null) {
|
||||
supportFragmentManager.commitTransaction(allowStateLoss) {
|
||||
option?.invoke(this)
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.hideKeyboard() {
|
||||
fun AppCompatActivity.hideKeyboard() {
|
||||
currentFocus?.hideKeyboard()
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import androidx.activity.result.ActivityResultLauncher
|
|||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.selectTxtFileToWrite
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
@ -34,7 +33,7 @@ fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit):
|
|||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addFragment(
|
||||
fun Fragment.addFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
allowStateLoss: Boolean = false
|
||||
|
@ -42,7 +41,7 @@ fun VectorBaseFragment.addFragment(
|
|||
parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addFragment(
|
||||
fun <T : Fragment> Fragment.addFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -54,7 +53,7 @@ fun <T : Fragment> VectorBaseFragment.addFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.replaceFragment(
|
||||
fun Fragment.replaceFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
allowStateLoss: Boolean = false
|
||||
|
@ -62,7 +61,7 @@ fun VectorBaseFragment.replaceFragment(
|
|||
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.replaceFragment(
|
||||
fun <T : Fragment> Fragment.replaceFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -74,7 +73,7 @@ fun <T : Fragment> VectorBaseFragment.replaceFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addFragmentToBackstack(
|
||||
fun Fragment.addFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -83,7 +82,7 @@ fun VectorBaseFragment.addFragmentToBackstack(
|
|||
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
|
||||
fun <T : Fragment> Fragment.addFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -95,7 +94,7 @@ fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addChildFragment(
|
||||
fun Fragment.addChildFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -104,7 +103,7 @@ fun VectorBaseFragment.addChildFragment(
|
|||
childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addChildFragment(
|
||||
fun <T : Fragment> Fragment.addChildFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -116,7 +115,7 @@ fun <T : Fragment> VectorBaseFragment.addChildFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.replaceChildFragment(
|
||||
fun Fragment.replaceChildFragment(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -125,7 +124,7 @@ fun VectorBaseFragment.replaceChildFragment(
|
|||
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
|
||||
fun <T : Fragment> Fragment.replaceChildFragment(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
@ -137,7 +136,7 @@ fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
|
|||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addChildFragmentToBackstack(
|
||||
fun Fragment.addChildFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragment: Fragment,
|
||||
tag: String? = null,
|
||||
|
@ -146,7 +145,7 @@ fun VectorBaseFragment.addChildFragmentToBackstack(
|
|||
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(
|
||||
fun <T : Fragment> Fragment.addChildFragmentToBackstack(
|
||||
frameId: Int,
|
||||
fragmentClass: Class<T>,
|
||||
params: Parcelable? = null,
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.extensions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import com.airbnb.mvrx.MvRx
|
||||
|
||||
fun Parcelable?.toMvRxBundle(): Bundle? {
|
||||
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
|
||||
}
|
|
@ -18,14 +18,13 @@ package im.vector.app.core.platform
|
|||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import kotlinx.android.synthetic.main.view_button_state.view.*
|
||||
import im.vector.app.databinding.ViewButtonStateBinding
|
||||
|
||||
class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: FrameLayout(context, attrs, defStyle) {
|
||||
|
@ -47,11 +46,15 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||
// Big or Flat button
|
||||
var button: Button
|
||||
|
||||
private val views: ViewButtonStateBinding
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.view_button_state, this)
|
||||
inflate(context, R.layout.view_button_state, this)
|
||||
views = ViewButtonStateBinding.bind(this)
|
||||
|
||||
layoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
||||
buttonStateRetry.setOnClickListener {
|
||||
views.buttonStateRetry.setOnClickListener {
|
||||
callback?.onRetryClicked()
|
||||
}
|
||||
|
||||
|
@ -63,15 +66,15 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||
.apply {
|
||||
try {
|
||||
if (getBoolean(R.styleable.ButtonStateView_bsv_use_flat_button, true)) {
|
||||
button = buttonStateButtonFlat
|
||||
buttonStateButtonBig.isVisible = false
|
||||
button = views.buttonStateButtonFlat
|
||||
views.buttonStateButtonBig.isVisible = false
|
||||
} else {
|
||||
button = buttonStateButtonBig
|
||||
buttonStateButtonFlat.isVisible = false
|
||||
button = views.buttonStateButtonBig
|
||||
views.buttonStateButtonFlat.isVisible = false
|
||||
}
|
||||
|
||||
button.text = getString(R.styleable.ButtonStateView_bsv_button_text)
|
||||
buttonStateLoaded.setImageDrawable(getDrawable(R.styleable.ButtonStateView_bsv_loaded_image_src))
|
||||
views.buttonStateLoaded.setImageDrawable(getDrawable(R.styleable.ButtonStateView_bsv_loaded_image_src))
|
||||
} finally {
|
||||
recycle()
|
||||
}
|
||||
|
@ -90,8 +93,8 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||
button.isInvisible = true
|
||||
}
|
||||
|
||||
buttonStateLoading.isVisible = newState == State.Loading
|
||||
buttonStateLoaded.isVisible = newState == State.Loaded
|
||||
buttonStateRetry.isVisible = newState == State.Error
|
||||
views.buttonStateLoading.isVisible = newState == State.Loading
|
||||
views.buttonStateLoaded.isVisible = newState == State.Loaded
|
||||
views.buttonStateRetry.isVisible = newState == State.Error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,37 +15,25 @@
|
|||
*/
|
||||
package im.vector.app.core.platform
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
import im.vector.app.databinding.ActivityBinding
|
||||
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Simple activity with a toolbar, a waiting overlay, and a fragment container and a session.
|
||||
*/
|
||||
abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
||||
abstract class SimpleFragmentActivity : VectorBaseActivity<ActivityBinding>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity
|
||||
final override fun getBinding() = ActivityBinding.inflate(layoutInflater)
|
||||
|
||||
@BindView(R.id.waiting_view_status_circular_progress)
|
||||
lateinit var waitingCircularProgress: View
|
||||
final override fun getCoordinatorLayout() = views.coordinatorLayout
|
||||
|
||||
@BindView(R.id.waiting_view_status_text)
|
||||
lateinit var waitingStatusText: TextView
|
||||
|
||||
@BindView(R.id.waiting_view_status_horizontal_progress)
|
||||
lateinit var waitingHorizontalProgress: ProgressBar
|
||||
|
||||
@Inject lateinit var session: Session
|
||||
lateinit var session: Session
|
||||
|
||||
@CallSuper
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
|
@ -53,8 +41,8 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
configureToolbar(toolbar)
|
||||
waitingView = findViewById(R.id.waiting_view)
|
||||
configureToolbar(views.toolbar)
|
||||
waitingView = views.waitingView.waitingView
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,21 +51,21 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||
*/
|
||||
fun updateWaitingView(data: WaitingViewData?) {
|
||||
data?.let {
|
||||
waitingStatusText.text = data.message
|
||||
views.waitingView.waitingStatusText.text = data.message
|
||||
|
||||
if (data.progress != null && data.progressTotal != null) {
|
||||
waitingHorizontalProgress.isIndeterminate = false
|
||||
waitingHorizontalProgress.progress = data.progress
|
||||
waitingHorizontalProgress.max = data.progressTotal
|
||||
waitingHorizontalProgress.isVisible = true
|
||||
waitingCircularProgress.isVisible = false
|
||||
views.waitingView.waitingHorizontalProgress.isIndeterminate = false
|
||||
views.waitingView.waitingHorizontalProgress.progress = data.progress
|
||||
views.waitingView.waitingHorizontalProgress.max = data.progressTotal
|
||||
views.waitingView.waitingHorizontalProgress.isVisible = true
|
||||
views.waitingView.waitingCircularProgress.isVisible = false
|
||||
} else if (data.isIndeterminate) {
|
||||
waitingHorizontalProgress.isIndeterminate = true
|
||||
waitingHorizontalProgress.isVisible = true
|
||||
waitingCircularProgress.isVisible = false
|
||||
views.waitingView.waitingHorizontalProgress.isIndeterminate = true
|
||||
views.waitingView.waitingHorizontalProgress.isVisible = true
|
||||
views.waitingView.waitingCircularProgress.isVisible = false
|
||||
} else {
|
||||
waitingHorizontalProgress.isVisible = false
|
||||
waitingCircularProgress.isVisible = true
|
||||
views.waitingView.waitingHorizontalProgress.isVisible = false
|
||||
views.waitingView.waitingCircularProgress.isVisible = true
|
||||
}
|
||||
|
||||
showWaitingView()
|
||||
|
@ -86,17 +74,17 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun showWaitingView() {
|
||||
override fun showWaitingView(text: String?) {
|
||||
hideKeyboard()
|
||||
waitingStatusText.isGone = waitingStatusText.text.isNullOrBlank()
|
||||
super.showWaitingView()
|
||||
views.waitingView.waitingStatusText.isGone = views.waitingView.waitingStatusText.text.isNullOrBlank()
|
||||
super.showWaitingView(text)
|
||||
}
|
||||
|
||||
override fun hideWaitingView() {
|
||||
waitingStatusText.text = null
|
||||
waitingStatusText.isGone = true
|
||||
waitingHorizontalProgress.progress = 0
|
||||
waitingHorizontalProgress.isVisible = false
|
||||
views.waitingView.waitingStatusText.text = null
|
||||
views.waitingView.waitingStatusText.isGone = true
|
||||
views.waitingView.waitingHorizontalProgress.progress = 0
|
||||
views.waitingView.waitingHorizontalProgress.isVisible = false
|
||||
super.hideWaitingView()
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import android.widget.FrameLayout
|
|||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.updateConstraintSet
|
||||
import kotlinx.android.synthetic.main.view_state.view.*
|
||||
import im.vector.app.databinding.ViewStateBinding
|
||||
|
||||
class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: FrameLayout(context, attrs, defStyle) {
|
||||
|
@ -42,6 +42,8 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||
data class Error(val message: CharSequence? = null) : State()
|
||||
}
|
||||
|
||||
private val views: ViewStateBinding
|
||||
|
||||
var eventCallback: EventCallback? = null
|
||||
|
||||
var contentView: View? = null
|
||||
|
@ -58,33 +60,34 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||
}
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.view_state, this)
|
||||
inflate(context, R.layout.view_state, this)
|
||||
views = ViewStateBinding.bind(this)
|
||||
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
errorRetryView.setOnClickListener {
|
||||
views.errorRetryView.setOnClickListener {
|
||||
eventCallback?.onRetryClicked()
|
||||
}
|
||||
state = State.Content
|
||||
}
|
||||
|
||||
private fun update(newState: State) {
|
||||
progressBar.isVisible = newState is State.Loading
|
||||
errorView.isVisible = newState is State.Error
|
||||
emptyView.isVisible = newState is State.Empty
|
||||
views.progressBar.isVisible = newState is State.Loading
|
||||
views.errorView.isVisible = newState is State.Error
|
||||
views.emptyView.isVisible = newState is State.Empty
|
||||
contentView?.isVisible = newState is State.Content
|
||||
|
||||
when (newState) {
|
||||
is State.Content -> Unit
|
||||
is State.Loading -> Unit
|
||||
is State.Empty -> {
|
||||
emptyImageView.setImageDrawable(newState.image)
|
||||
emptyView.updateConstraintSet {
|
||||
views.emptyImageView.setImageDrawable(newState.image)
|
||||
views.emptyView.updateConstraintSet {
|
||||
it.constrainPercentHeight(R.id.emptyImageView, if (newState.isBigImage) 0.5f else 0.1f)
|
||||
}
|
||||
emptyMessageView.text = newState.message
|
||||
emptyTitleView.text = newState.title
|
||||
views.emptyMessageView.text = newState.message
|
||||
views.emptyTitleView.text = newState.title
|
||||
}
|
||||
is State.Error -> {
|
||||
errorMessageView.text = newState.message
|
||||
views.errorMessageView.text = newState.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,16 +20,15 @@ import android.app.Activity
|
|||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.annotation.Nullable
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
|
@ -40,10 +39,7 @@ import androidx.fragment.app.FragmentFactory
|
|||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.Unbinder
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.bumptech.glide.util.Util
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import im.vector.app.BuildConfig
|
||||
|
@ -61,6 +57,7 @@ import im.vector.app.core.extensions.observeEvent
|
|||
import im.vector.app.core.extensions.observeNotNull
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.restart
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.extensions.vectorComponent
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.MainActivity
|
||||
|
@ -83,20 +80,18 @@ import im.vector.app.receivers.DebugReceiver
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.failure.GlobalError
|
||||
import timber.log.Timber
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||
abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScreenInjector {
|
||||
/* ==========================================================================================
|
||||
* UI
|
||||
* View
|
||||
* ========================================================================================== */
|
||||
|
||||
@Nullable
|
||||
@JvmField
|
||||
@BindView(R.id.vector_coordinator_layout)
|
||||
var coordinatorLayout: CoordinatorLayout? = null
|
||||
protected lateinit var views: VB
|
||||
|
||||
/* ==========================================================================================
|
||||
* View model
|
||||
|
@ -138,8 +133,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
// Filter for multiple invalid token error
|
||||
private var mainActivityStarted = false
|
||||
|
||||
private var unBinder: Unbinder? = null
|
||||
|
||||
private var savedInstanceState: Bundle? = null
|
||||
|
||||
// For debug only
|
||||
|
@ -176,6 +169,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
uiDisposables.add(this)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Timber.i("onCreate Activity ${javaClass.simpleName}")
|
||||
val vectorComponent = getVectorComponent()
|
||||
|
@ -223,11 +217,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
// Hack for font size
|
||||
applyFontSize()
|
||||
|
||||
if (getLayoutRes() != -1) {
|
||||
setContentView(getLayoutRes())
|
||||
}
|
||||
|
||||
unBinder = ButterKnife.bind(this)
|
||||
views = getBinding()
|
||||
setContentView(views.root)
|
||||
|
||||
this.savedInstanceState = savedInstanceState
|
||||
|
||||
|
@ -306,8 +297,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Timber.i("onDestroy Activity ${javaClass.simpleName}")
|
||||
unBinder?.unbind()
|
||||
unBinder = null
|
||||
|
||||
uiDisposables.dispose()
|
||||
}
|
||||
|
@ -467,7 +456,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
}
|
||||
|
||||
private fun recursivelyDispatchOnBackPressed(fm: FragmentManager, fromToolbar: Boolean): Boolean {
|
||||
val reverseOrder = fm.fragments.filterIsInstance<VectorBaseFragment>().reversed()
|
||||
val reverseOrder = fm.fragments.filterIsInstance<VectorBaseFragment<*>>().reversed()
|
||||
for (f in reverseOrder) {
|
||||
val handledByChildFragments = recursivelyDispatchOnBackPressed(f.childFragmentManager, fromToolbar)
|
||||
if (handledByChildFragments) {
|
||||
|
@ -513,10 +502,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
}
|
||||
}
|
||||
|
||||
fun Parcelable?.toMvRxBundle(): Bundle? {
|
||||
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
|
||||
}
|
||||
|
||||
// ==============================================================================================
|
||||
// Handle loading view (also called waiting view or spinner view)
|
||||
// ==============================================================================================
|
||||
|
@ -537,10 +522,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
fun isWaitingViewVisible() = waitingView?.isVisible == true
|
||||
|
||||
/**
|
||||
* Show the waiting view
|
||||
* Show the waiting view, and set text if not null.
|
||||
*/
|
||||
open fun showWaitingView() {
|
||||
open fun showWaitingView(text: String? = null) {
|
||||
waitingView?.isVisible = true
|
||||
if (text != null) {
|
||||
waitingView?.findViewById<TextView>(R.id.waitingStatusText)?.setTextOrHide(text)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,8 +542,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
* OPEN METHODS
|
||||
* ========================================================================================== */
|
||||
|
||||
@LayoutRes
|
||||
open fun getLayoutRes() = -1
|
||||
abstract fun getBinding(): VB
|
||||
|
||||
open fun displayInFullscreen() = false
|
||||
|
||||
|
@ -582,13 +569,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
* ========================================================================================== */
|
||||
|
||||
fun showSnackbar(message: String) {
|
||||
coordinatorLayout?.let {
|
||||
getCoordinatorLayout()?.let {
|
||||
Snackbar.make(it, message, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) {
|
||||
coordinatorLayout?.let {
|
||||
getCoordinatorLayout()?.let {
|
||||
Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply {
|
||||
withActionTitle?.let {
|
||||
setAction(withActionTitle, { action?.invoke() })
|
||||
|
@ -597,6 +584,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
}
|
||||
}
|
||||
|
||||
open fun getCoordinatorLayout(): CoordinatorLayout? = null
|
||||
|
||||
/* ==========================================================================================
|
||||
* User Consent
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -25,10 +25,8 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.Unbinder
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.MvRxView
|
||||
import com.airbnb.mvrx.MvRxViewId
|
||||
|
@ -48,7 +46,7 @@ import java.util.concurrent.TimeUnit
|
|||
/**
|
||||
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
||||
*/
|
||||
abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView {
|
||||
abstract class VectorBaseBottomSheetDialogFragment<VB: ViewBinding> : BottomSheetDialogFragment(), MvRxView {
|
||||
|
||||
private val mvrxViewIdProperty = MvRxViewId()
|
||||
final override val mvrxViewId: String by mvrxViewIdProperty
|
||||
|
@ -58,10 +56,13 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
* View
|
||||
* ========================================================================================== */
|
||||
|
||||
@LayoutRes
|
||||
abstract fun getLayoutResId(): Int
|
||||
private var _binding: VB? = null
|
||||
|
||||
private var unBinder: Unbinder? = null
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
protected val views: VB
|
||||
get() = _binding!!
|
||||
|
||||
abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB
|
||||
|
||||
/* ==========================================================================================
|
||||
* View model
|
||||
|
@ -81,8 +82,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
|
||||
private var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>? = null
|
||||
|
||||
val vectorBaseActivity: VectorBaseActivity by lazy {
|
||||
activity as VectorBaseActivity
|
||||
val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||
activity as VectorBaseActivity<*>
|
||||
}
|
||||
|
||||
open val showExpanded = false
|
||||
|
@ -106,17 +107,14 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(getLayoutResId(), container, false)
|
||||
unBinder = ButterKnife.bind(this, view)
|
||||
return view
|
||||
_binding = getBinding(inflater, container)
|
||||
return views.root
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
unBinder?.unbind()
|
||||
unBinder = null
|
||||
uiDisposables.clear()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
|
|
@ -28,15 +28,12 @@ import android.view.MenuInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.Unbinder
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.airbnb.mvrx.BaseMvRxFragment
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.bumptech.glide.util.Util.assertMainThread
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.jakewharton.rxbinding3.view.clicks
|
||||
|
@ -46,20 +43,19 @@ import im.vector.app.core.di.HasScreenInjector
|
|||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
||||
abstract class VectorBaseFragment<VB: ViewBinding> : BaseMvRxFragment(), HasScreenInjector {
|
||||
|
||||
// Butterknife unbinder
|
||||
private var mUnBinder: Unbinder? = null
|
||||
|
||||
protected val vectorBaseActivity: VectorBaseActivity by lazy {
|
||||
activity as VectorBaseActivity
|
||||
protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||
activity as VectorBaseActivity<*>
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
|
@ -86,6 +82,16 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
protected val fragmentViewModelProvider
|
||||
get() = ViewModelProvider(this, viewModelFactory)
|
||||
|
||||
/* ==========================================================================================
|
||||
* Views
|
||||
* ========================================================================================== */
|
||||
|
||||
private var _binding: VB? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
protected val views: VB
|
||||
get() = _binding!!
|
||||
|
||||
/* ==========================================================================================
|
||||
* Life cycle
|
||||
* ========================================================================================== */
|
||||
|
@ -110,11 +116,11 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
|
||||
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
Timber.i("onCreateView Fragment ${javaClass.simpleName}")
|
||||
return inflater.inflate(getLayoutResId(), container, false)
|
||||
_binding = getBinding(inflater, container)
|
||||
return views.root
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
abstract fun getLayoutResId(): Int
|
||||
abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB
|
||||
|
||||
@CallSuper
|
||||
override fun onResume() {
|
||||
|
@ -125,7 +131,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
@CallSuper
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mUnBinder = ButterKnife.bind(this, view)
|
||||
Timber.i("onViewCreated Fragment ${javaClass.simpleName}")
|
||||
}
|
||||
|
||||
open fun showLoading(message: CharSequence?) {
|
||||
|
@ -138,11 +144,10 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
|
||||
@CallSuper
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
|
||||
mUnBinder?.unbind()
|
||||
mUnBinder = null
|
||||
uiDisposables.clear()
|
||||
_binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -180,10 +185,6 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
arguments = args.toMvRxBundle()
|
||||
}
|
||||
|
||||
fun Parcelable?.toMvRxBundle(): Bundle? {
|
||||
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
|
||||
}
|
||||
|
||||
@MainThread
|
||||
protected fun <T : Restorable> T.register(): T {
|
||||
assertMainThread()
|
||||
|
@ -192,7 +193,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
}
|
||||
|
||||
protected fun showErrorInSnackbar(throwable: Throwable) {
|
||||
vectorBaseActivity.coordinatorLayout?.let {
|
||||
vectorBaseActivity.getCoordinatorLayout()?.let {
|
||||
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,44 +17,45 @@
|
|||
package im.vector.app.core.ui.bottomsheet
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.databinding.BottomSheetGenericListBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Generic Bottom sheet with actions
|
||||
*/
|
||||
abstract class BottomSheetGeneric<STATE : BottomSheetGenericState, ACTION : BottomSheetGenericAction> :
|
||||
VectorBaseBottomSheetDialogFragment(),
|
||||
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
|
||||
BottomSheetGenericController.Listener<ACTION> {
|
||||
|
||||
@Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
|
||||
|
||||
@BindView(R.id.bottomSheetRecyclerView)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
final override val showExpanded = true
|
||||
|
||||
final override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
|
||||
final override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
|
||||
return BottomSheetGenericListBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
abstract fun getController(): BottomSheetGenericController<STATE, ACTION>
|
||||
|
||||
@CallSuper
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
recyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetRecyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
|
||||
getController().listener = this
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onDestroyView() {
|
||||
recyclerView.cleanup()
|
||||
views.bottomSheetRecyclerView.cleanup()
|
||||
getController().listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import android.text.style.ClickableSpan
|
|||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
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.themes.ThemeUtils
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
|
@ -48,12 +48,15 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||
var callback: Callback? = null
|
||||
var jitsiWidget: Widget? = null
|
||||
|
||||
private lateinit var views: ViewActiveConferenceViewBinding
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_active_conference_view, this)
|
||||
views = ViewActiveConferenceViewBinding.bind(this)
|
||||
setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
|
||||
|
||||
// "voice" and "video" texts are underlined and clickable
|
||||
|
@ -78,12 +81,12 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||
}
|
||||
})
|
||||
|
||||
findViewById<TextView>(R.id.activeConferenceInfo).apply {
|
||||
views.activeConferenceInfo.apply {
|
||||
text = styledText
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
|
||||
findViewById<TextView>(R.id.deleteWidgetButton).setOnClickListener {
|
||||
views.deleteWidgetButton.setOnClickListener {
|
||||
jitsiWidget?.let { callback?.onDelete(it) }
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +108,7 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||
jitsiWidget = activeConf
|
||||
}
|
||||
// if sent by me or if i can moderate?
|
||||
findViewById<TextView>(R.id.deleteWidgetButton).isVisible = state.isAllowedToManageWidgets
|
||||
views.deleteWidgetButton.isVisible = state.isAllowedToManageWidgets
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
|
|
|
@ -20,19 +20,15 @@ import android.content.Context
|
|||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.databinding.ItemVerificationActionBinding
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
|
||||
class BottomSheetActionButton @JvmOverloads constructor(
|
||||
|
@ -40,32 +36,18 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
@BindView(R.id.itemVerificationActionTitle)
|
||||
lateinit var actionTextView: TextView
|
||||
|
||||
@BindView(R.id.itemVerificationActionSubTitle)
|
||||
lateinit var descriptionTextView: TextView
|
||||
|
||||
@BindView(R.id.itemVerificationLeftIcon)
|
||||
lateinit var leftIconImageView: ImageView
|
||||
|
||||
@BindView(R.id.itemVerificationActionIcon)
|
||||
lateinit var rightIconImageView: ImageView
|
||||
|
||||
@BindView(R.id.itemVerificationClickableZone)
|
||||
lateinit var clickableView: View
|
||||
val views : ItemVerificationActionBinding
|
||||
|
||||
var title: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
actionTextView.setTextOrHide(value)
|
||||
views.itemVerificationActionTitle.setTextOrHide(value)
|
||||
}
|
||||
|
||||
var subTitle: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
descriptionTextView.setTextOrHide(value)
|
||||
views.itemVerificationActionSubTitle.setTextOrHide(value)
|
||||
}
|
||||
|
||||
var forceStartPadding: Boolean? = null
|
||||
|
@ -73,9 +55,9 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||
field = value
|
||||
if (leftIcon == null) {
|
||||
if (forceStartPadding == true) {
|
||||
leftIconImageView.isInvisible = true
|
||||
views.itemVerificationLeftIcon.isInvisible = true
|
||||
} else {
|
||||
leftIconImageView.isGone = true
|
||||
views.itemVerificationLeftIcon.isGone = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,38 +67,38 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||
field = value
|
||||
if (value == null) {
|
||||
if (forceStartPadding == true) {
|
||||
leftIconImageView.isInvisible = true
|
||||
views.itemVerificationLeftIcon.isInvisible = true
|
||||
} else {
|
||||
leftIconImageView.isGone = true
|
||||
views.itemVerificationLeftIcon.isGone = true
|
||||
}
|
||||
leftIconImageView.setImageDrawable(null)
|
||||
views.itemVerificationLeftIcon.setImageDrawable(null)
|
||||
} else {
|
||||
leftIconImageView.isVisible = true
|
||||
leftIconImageView.setImageDrawable(value)
|
||||
views.itemVerificationLeftIcon.isVisible = true
|
||||
views.itemVerificationLeftIcon.setImageDrawable(value)
|
||||
}
|
||||
}
|
||||
|
||||
var rightIcon: Drawable? = null
|
||||
set(value) {
|
||||
field = value
|
||||
rightIconImageView.setImageDrawable(value)
|
||||
views.itemVerificationActionIcon.setImageDrawable(value)
|
||||
}
|
||||
|
||||
var tint: Int? = null
|
||||
set(value) {
|
||||
field = value
|
||||
leftIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
||||
views.itemVerificationLeftIcon.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
||||
}
|
||||
|
||||
var titleTextColor: Int? = null
|
||||
set(value) {
|
||||
field = value
|
||||
value?.let { actionTextView.setTextColor(it) }
|
||||
value?.let { views.itemVerificationActionTitle.setTextColor(it) }
|
||||
}
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.item_verification_action, this)
|
||||
ButterKnife.bind(this)
|
||||
views = ItemVerificationActionBinding.bind(this)
|
||||
|
||||
context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) {
|
||||
title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: ""
|
||||
|
|
|
@ -22,7 +22,7 @@ import android.view.View
|
|||
import android.widget.RelativeLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.app.R
|
||||
import kotlinx.android.synthetic.main.view_jump_to_read_marker.view.*
|
||||
import im.vector.app.databinding.ViewJumpToReadMarkerBinding
|
||||
|
||||
class JumpToReadMarkerView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -43,11 +43,12 @@ class JumpToReadMarkerView @JvmOverloads constructor(
|
|||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_jump_to_read_marker, this)
|
||||
val views = ViewJumpToReadMarkerBinding.bind(this)
|
||||
setBackgroundColor(ContextCompat.getColor(context, R.color.notification_accent_color))
|
||||
jumpToReadMarkerLabelView.setOnClickListener {
|
||||
views.jumpToReadMarkerLabelView.setOnClickListener {
|
||||
callback?.onJumpToReadMarkerClicked()
|
||||
}
|
||||
closeJumpToReadMarkerView.setOnClickListener {
|
||||
views.closeJumpToReadMarkerView.setOnClickListener {
|
||||
visibility = View.INVISIBLE
|
||||
callback?.onClearReadMarkerClicked()
|
||||
}
|
||||
|
|
|
@ -19,15 +19,13 @@ package im.vector.app.core.ui.views
|
|||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.DefaultSharedPreferences
|
||||
import im.vector.app.databinding.ViewKeysBackupBannerBinding
|
||||
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
|
@ -40,21 +38,11 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
|
||||
|
||||
@BindView(R.id.view_keys_backup_banner_text_1)
|
||||
lateinit var textView1: TextView
|
||||
|
||||
@BindView(R.id.view_keys_backup_banner_text_2)
|
||||
lateinit var textView2: TextView
|
||||
|
||||
@BindView(R.id.view_keys_backup_banner_close_group)
|
||||
lateinit var close: View
|
||||
|
||||
@BindView(R.id.view_keys_backup_banner_loading)
|
||||
lateinit var loading: View
|
||||
|
||||
var delegate: Delegate? = null
|
||||
private var state: State = State.Initial
|
||||
|
||||
private lateinit var views: ViewKeysBackupBannerBinding
|
||||
|
||||
init {
|
||||
setupView()
|
||||
DefaultSharedPreferences.getInstance(context).edit {
|
||||
|
@ -100,8 +88,7 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.view_keys_backup_banner_close)
|
||||
internal fun onCloseClicked() {
|
||||
private fun onCloseClicked() {
|
||||
state.let {
|
||||
when (it) {
|
||||
is State.Setup -> {
|
||||
|
@ -133,11 +120,12 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_keys_backup_banner, this)
|
||||
ButterKnife.bind(this)
|
||||
|
||||
setOnClickListener(this)
|
||||
textView1.setOnClickListener(this)
|
||||
textView2.setOnClickListener(this)
|
||||
views = ViewKeysBackupBannerBinding.bind(this)
|
||||
views.viewKeysBackupBannerText1.setOnClickListener(this)
|
||||
views.viewKeysBackupBannerText2.setOnClickListener(this)
|
||||
views.viewKeysBackupBannerClose.setOnClickListener { onCloseClicked() }
|
||||
}
|
||||
|
||||
private fun renderInitial() {
|
||||
|
@ -156,10 +144,10 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
} else {
|
||||
isVisible = true
|
||||
|
||||
textView1.setText(R.string.secure_backup_banner_setup_line1)
|
||||
textView2.isVisible = true
|
||||
textView2.setText(R.string.secure_backup_banner_setup_line2)
|
||||
close.isVisible = true
|
||||
views.viewKeysBackupBannerText1.setText(R.string.secure_backup_banner_setup_line1)
|
||||
views.viewKeysBackupBannerText2.isVisible = true
|
||||
views.viewKeysBackupBannerText2.setText(R.string.secure_backup_banner_setup_line2)
|
||||
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,10 +157,10 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
} else {
|
||||
isVisible = true
|
||||
|
||||
textView1.setText(R.string.keys_backup_banner_recover_line1)
|
||||
textView2.isVisible = true
|
||||
textView2.setText(R.string.keys_backup_banner_recover_line2)
|
||||
close.isVisible = true
|
||||
views.viewKeysBackupBannerText1.setText(R.string.keys_backup_banner_recover_line1)
|
||||
views.viewKeysBackupBannerText2.isVisible = true
|
||||
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_recover_line2)
|
||||
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,28 +170,28 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||
} else {
|
||||
isVisible = true
|
||||
|
||||
textView1.setText(R.string.keys_backup_banner_update_line1)
|
||||
textView2.isVisible = true
|
||||
textView2.setText(R.string.keys_backup_banner_update_line2)
|
||||
close.isVisible = true
|
||||
views.viewKeysBackupBannerText1.setText(R.string.keys_backup_banner_update_line1)
|
||||
views.viewKeysBackupBannerText2.isVisible = true
|
||||
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_update_line2)
|
||||
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderBackingUp() {
|
||||
isVisible = true
|
||||
textView1.setText(R.string.secure_backup_banner_setup_line1)
|
||||
textView2.isVisible = true
|
||||
textView2.setText(R.string.keys_backup_banner_in_progress)
|
||||
loading.isVisible = true
|
||||
views.viewKeysBackupBannerText1.setText(R.string.secure_backup_banner_setup_line1)
|
||||
views.viewKeysBackupBannerText2.isVisible = true
|
||||
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_in_progress)
|
||||
views.viewKeysBackupBannerLoading.isVisible = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all views that are not visible in all state
|
||||
*/
|
||||
private fun hideAll() {
|
||||
textView2.isVisible = false
|
||||
close.isVisible = false
|
||||
loading.isVisible = false
|
||||
views.viewKeysBackupBannerText2.isVisible = false
|
||||
views.viewKeysBackupBannerCloseGroup.isVisible = false
|
||||
views.viewKeysBackupBannerLoading.isVisible = false
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,8 +27,9 @@ import androidx.core.text.italic
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.error.ResourceLimitErrorFormatter
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.databinding.ViewNotificationAreaBinding
|
||||
import im.vector.app.features.themes.ThemeUtils
|
||||
import kotlinx.android.synthetic.main.view_notification_area.view.*
|
||||
|
||||
import me.gujun.android.span.span
|
||||
import me.saket.bettermovementmethod.BetterLinkMovementMethod
|
||||
import org.matrix.android.sdk.api.failure.MatrixError
|
||||
|
@ -48,6 +49,8 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
var delegate: Delegate? = null
|
||||
private var state: State = State.Initial
|
||||
|
||||
private lateinit var views : ViewNotificationAreaBinding
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
@ -78,27 +81,28 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
|
||||
private fun setupView() {
|
||||
inflate(context, R.layout.view_notification_area, this)
|
||||
views = ViewNotificationAreaBinding.bind(this)
|
||||
minimumHeight = DimensionConverter(resources).dpToPx(48)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
roomNotificationMessage.setOnClickListener(null)
|
||||
roomNotificationIcon.setOnClickListener(null)
|
||||
views.roomNotificationMessage.setOnClickListener(null)
|
||||
views.roomNotificationIcon.setOnClickListener(null)
|
||||
setBackgroundColor(Color.TRANSPARENT)
|
||||
roomNotificationMessage.text = null
|
||||
roomNotificationIcon.setImageResource(0)
|
||||
views.roomNotificationMessage.text = null
|
||||
views.roomNotificationIcon.setImageResource(0)
|
||||
}
|
||||
|
||||
private fun renderNoPermissionToPost() {
|
||||
visibility = View.VISIBLE
|
||||
roomNotificationIcon.setImageDrawable(null)
|
||||
views.roomNotificationIcon.setImageDrawable(null)
|
||||
val message = span {
|
||||
italic {
|
||||
+resources.getString(R.string.room_do_not_have_permission_to_post)
|
||||
}
|
||||
}
|
||||
roomNotificationMessage.text = message
|
||||
roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||
views.roomNotificationMessage.text = message
|
||||
views.roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||
}
|
||||
|
||||
private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) {
|
||||
|
@ -114,16 +118,16 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
formatterMode = ResourceLimitErrorFormatter.Mode.Hard
|
||||
}
|
||||
val message = resourceLimitErrorFormatter.format(state.matrixError, formatterMode, clickable = true)
|
||||
roomNotificationMessage.setTextColor(Color.WHITE)
|
||||
roomNotificationMessage.text = message
|
||||
roomNotificationMessage.movementMethod = LinkMovementMethod.getInstance()
|
||||
roomNotificationMessage.setLinkTextColor(Color.WHITE)
|
||||
views.roomNotificationMessage.setTextColor(Color.WHITE)
|
||||
views.roomNotificationMessage.text = message
|
||||
views.roomNotificationMessage.movementMethod = LinkMovementMethod.getInstance()
|
||||
views.roomNotificationMessage.setLinkTextColor(Color.WHITE)
|
||||
setBackgroundColor(ContextCompat.getColor(context, backgroundColor))
|
||||
}
|
||||
|
||||
private fun renderTombstone(state: State.Tombstone) {
|
||||
visibility = View.VISIBLE
|
||||
roomNotificationIcon.setImageResource(R.drawable.error)
|
||||
views.roomNotificationIcon.setImageResource(R.drawable.error)
|
||||
val message = span {
|
||||
+resources.getString(R.string.room_tombstone_versioned_description)
|
||||
+"\n"
|
||||
|
@ -132,8 +136,8 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||
onClick = { delegate?.onTombstoneEventClicked(state.tombstoneEvent) }
|
||||
}
|
||||
}
|
||||
roomNotificationMessage.movementMethod = BetterLinkMovementMethod.getInstance()
|
||||
roomNotificationMessage.text = message
|
||||
views.roomNotificationMessage.movementMethod = BetterLinkMovementMethod.getInstance()
|
||||
views.roomNotificationMessage.text = message
|
||||
}
|
||||
|
||||
private fun renderDefault() {
|
||||
|
|
|
@ -17,14 +17,11 @@ package im.vector.app.core.ui.views
|
|||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.IntRange
|
||||
import butterknife.BindColor
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.ViewPasswordStrengthBarBinding
|
||||
|
||||
/**
|
||||
* A password strength bar custom widget
|
||||
|
@ -41,37 +38,13 @@ class PasswordStrengthBar @JvmOverloads constructor(
|
|||
defStyleAttr: Int = 0)
|
||||
: LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
@BindView(R.id.password_strength_bar_1)
|
||||
lateinit var bar1: View
|
||||
private val views: ViewPasswordStrengthBarBinding
|
||||
|
||||
@BindView(R.id.password_strength_bar_2)
|
||||
lateinit var bar2: View
|
||||
|
||||
@BindView(R.id.password_strength_bar_3)
|
||||
lateinit var bar3: View
|
||||
|
||||
@BindView(R.id.password_strength_bar_4)
|
||||
lateinit var bar4: View
|
||||
|
||||
@BindColor(R.color.password_strength_bar_undefined)
|
||||
@JvmField
|
||||
var colorBackground: Int = 0
|
||||
|
||||
@BindColor(R.color.password_strength_bar_weak)
|
||||
@JvmField
|
||||
var colorWeak: Int = 0
|
||||
|
||||
@BindColor(R.color.password_strength_bar_low)
|
||||
@JvmField
|
||||
var colorLow: Int = 0
|
||||
|
||||
@BindColor(R.color.password_strength_bar_ok)
|
||||
@JvmField
|
||||
var colorOk: Int = 0
|
||||
|
||||
@BindColor(R.color.password_strength_bar_strong)
|
||||
@JvmField
|
||||
var colorStrong: Int = 0
|
||||
private val colorBackground = ContextCompat.getColor(context, R.color.password_strength_bar_undefined)
|
||||
private val colorWeak = ContextCompat.getColor(context, R.color.password_strength_bar_weak)
|
||||
private val colorLow = ContextCompat.getColor(context, R.color.password_strength_bar_low)
|
||||
private val colorOk = ContextCompat.getColor(context, R.color.password_strength_bar_ok)
|
||||
private val colorStrong = ContextCompat.getColor(context, R.color.password_strength_bar_strong)
|
||||
|
||||
@IntRange(from = 0, to = 4)
|
||||
var strength = 0
|
||||
|
@ -80,43 +53,42 @@ class PasswordStrengthBar @JvmOverloads constructor(
|
|||
|
||||
when (newValue) {
|
||||
0 -> {
|
||||
bar1.setBackgroundColor(colorBackground)
|
||||
bar2.setBackgroundColor(colorBackground)
|
||||
bar3.setBackgroundColor(colorBackground)
|
||||
bar4.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar1.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar2.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||
}
|
||||
1 -> {
|
||||
bar1.setBackgroundColor(colorWeak)
|
||||
bar2.setBackgroundColor(colorBackground)
|
||||
bar3.setBackgroundColor(colorBackground)
|
||||
bar4.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar1.setBackgroundColor(colorWeak)
|
||||
views.passwordStrengthBar2.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||
}
|
||||
2 -> {
|
||||
bar1.setBackgroundColor(colorLow)
|
||||
bar2.setBackgroundColor(colorLow)
|
||||
bar3.setBackgroundColor(colorBackground)
|
||||
bar4.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar1.setBackgroundColor(colorLow)
|
||||
views.passwordStrengthBar2.setBackgroundColor(colorLow)
|
||||
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||
}
|
||||
3 -> {
|
||||
bar1.setBackgroundColor(colorOk)
|
||||
bar2.setBackgroundColor(colorOk)
|
||||
bar3.setBackgroundColor(colorOk)
|
||||
bar4.setBackgroundColor(colorBackground)
|
||||
views.passwordStrengthBar1.setBackgroundColor(colorOk)
|
||||
views.passwordStrengthBar2.setBackgroundColor(colorOk)
|
||||
views.passwordStrengthBar3.setBackgroundColor(colorOk)
|
||||
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||
}
|
||||
4 -> {
|
||||
bar1.setBackgroundColor(colorStrong)
|
||||
bar2.setBackgroundColor(colorStrong)
|
||||
bar3.setBackgroundColor(colorStrong)
|
||||
bar4.setBackgroundColor(colorStrong)
|
||||
views.passwordStrengthBar1.setBackgroundColor(colorStrong)
|
||||
views.passwordStrengthBar2.setBackgroundColor(colorStrong)
|
||||
views.passwordStrengthBar3.setBackgroundColor(colorStrong)
|
||||
views.passwordStrengthBar4.setBackgroundColor(colorStrong)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.view_password_strength_bar, this, true)
|
||||
inflate(context, R.layout.view_password_strength_bar, this)
|
||||
views = ViewPasswordStrengthBarBinding.bind(this)
|
||||
orientation = HORIZONTAL
|
||||
ButterKnife.bind(this)
|
||||
strength = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import android.widget.ImageView
|
|||
import android.widget.LinearLayout
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.ViewReadReceiptsBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem
|
||||
import kotlinx.android.synthetic.main.view_read_receipts.view.*
|
||||
|
||||
private const val MAX_RECEIPT_DISPLAYED = 5
|
||||
private const val MAX_RECEIPT_DESCRIBED = 3
|
||||
|
@ -37,12 +37,21 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||
defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val receiptAvatars: List<ImageView> by lazy {
|
||||
listOf(receiptAvatar1, receiptAvatar2, receiptAvatar3, receiptAvatar4, receiptAvatar5)
|
||||
}
|
||||
private val views : ViewReadReceiptsBinding
|
||||
|
||||
init {
|
||||
setupView()
|
||||
views = ViewReadReceiptsBinding.bind(this)
|
||||
}
|
||||
|
||||
private val receiptAvatars: List<ImageView> by lazy {
|
||||
listOf(
|
||||
views.receiptAvatar1,
|
||||
views.receiptAvatar2,
|
||||
views.receiptAvatar3,
|
||||
views.receiptAvatar4,
|
||||
views.receiptAvatar5
|
||||
)
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
|
@ -69,12 +78,12 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||
.take(MAX_RECEIPT_DESCRIBED)
|
||||
|
||||
if (readReceipts.size > MAX_RECEIPT_DISPLAYED) {
|
||||
receiptMore.visibility = View.VISIBLE
|
||||
receiptMore.text = context.getString(
|
||||
views.receiptMore.visibility = View.VISIBLE
|
||||
views.receiptMore.text = context.getString(
|
||||
R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED
|
||||
)
|
||||
} else {
|
||||
receiptMore.visibility = View.GONE
|
||||
views.receiptMore.visibility = View.GONE
|
||||
}
|
||||
contentDescription = when (readReceipts.size) {
|
||||
1 ->
|
||||
|
|
|
@ -285,7 +285,7 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||
return isPermissionGranted
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) {
|
||||
fun VectorBaseActivity<*>.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) {
|
||||
showSnackbar(getString(rationaleMessage), R.string.settings) {
|
||||
openAppSettingsPage(this)
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.app.core.error.ErrorFormatter
|
|||
import im.vector.app.core.extensions.startSyncing
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.deleteAllFiles
|
||||
import im.vector.app.databinding.FragmentLoadingBinding
|
||||
import im.vector.app.features.home.HomeActivity
|
||||
import im.vector.app.features.home.ShortcutsHandler
|
||||
import im.vector.app.features.login.LoginActivity
|
||||
|
@ -42,7 +43,7 @@ import im.vector.app.features.settings.VectorPreferences
|
|||
import im.vector.app.features.signout.hard.SignedOutActivity
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -66,7 +67,7 @@ data class MainActivityArgs(
|
|||
* This Activity, when started with argument, is also doing some cleanup when user signs out,
|
||||
* clears cache, is logged out, or is soft logged out
|
||||
*/
|
||||
class MainActivity : VectorBaseActivity(), UnlockedActivity {
|
||||
class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActivity {
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_ARGS = "EXTRA_ARGS"
|
||||
|
@ -83,6 +84,8 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity {
|
|||
}
|
||||
}
|
||||
|
||||
override fun getBinding() = FragmentLoadingBinding.inflate(layoutInflater)
|
||||
|
||||
private lateinit var args: MainActivityArgs
|
||||
|
||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.view.animation.AnimationSet
|
|||
import android.view.animation.OvershootInterpolator
|
||||
import android.view.animation.ScaleAnimation
|
||||
import android.view.animation.TranslateAnimation
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
|
@ -42,6 +41,7 @@ import im.vector.app.core.extensions.getMeasurements
|
|||
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_TAKING_PHOTO
|
||||
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
|
||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
||||
import kotlin.math.max
|
||||
|
||||
|
@ -62,25 +62,19 @@ class AttachmentTypeSelectorView(context: Context,
|
|||
|
||||
private val iconColorGenerator = ColorGenerator.MATERIAL
|
||||
|
||||
private var galleryButton: ImageButton
|
||||
private var cameraButton: ImageButton
|
||||
private var fileButton: ImageButton
|
||||
private var stickersButton: ImageButton
|
||||
private var audioButton: ImageButton
|
||||
private var contactButton: ImageButton
|
||||
private val views: ViewAttachmentTypeSelectorBinding
|
||||
|
||||
private var anchor: View? = null
|
||||
|
||||
init {
|
||||
val root = FrameLayout(context)
|
||||
val layout = inflater.inflate(R.layout.view_attachment_type_selector, root, true)
|
||||
galleryButton = layout.findViewById<ImageButton>(R.id.attachmentGalleryButton).configure(Type.GALLERY)
|
||||
cameraButton = layout.findViewById<ImageButton>(R.id.attachmentCameraButton).configure(Type.CAMERA)
|
||||
fileButton = layout.findViewById<ImageButton>(R.id.attachmentFileButton).configure(Type.FILE)
|
||||
stickersButton = layout.findViewById<ImageButton>(R.id.attachmentStickersButton).configure(Type.STICKER)
|
||||
audioButton = layout.findViewById<ImageButton>(R.id.attachmentAudioButton).configure(Type.AUDIO)
|
||||
contactButton = layout.findViewById<ImageButton>(R.id.attachmentContactButton).configure(Type.CONTACT)
|
||||
contentView = root
|
||||
contentView = inflater.inflate(R.layout.view_attachment_type_selector, null, false)
|
||||
views = ViewAttachmentTypeSelectorBinding.bind(contentView)
|
||||
views.attachmentGalleryButton.configure(Type.GALLERY)
|
||||
views.attachmentCameraButton.configure(Type.CAMERA)
|
||||
views.attachmentFileButton.configure(Type.FILE)
|
||||
views.attachmentStickersButton.configure(Type.STICKER)
|
||||
views.attachmentAudioButton.configure(Type.AUDIO)
|
||||
views.attachmentContactButton.configure(Type.CONTACT)
|
||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||
height = LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
animationStyle = 0
|
||||
|
@ -108,12 +102,12 @@ class AttachmentTypeSelectorView(context: Context,
|
|||
contentView.doOnNextLayout {
|
||||
animateWindowInCircular(anchor, contentView)
|
||||
}
|
||||
animateButtonIn(galleryButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(cameraButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(fileButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(audioButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(contactButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(stickersButton, 0)
|
||||
animateButtonIn(views.attachmentGalleryButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(views.attachmentCameraButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(views.attachmentFileButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(views.attachmentAudioButton, ANIMATION_DURATION / 2)
|
||||
animateButtonIn(views.attachmentContactButton, ANIMATION_DURATION / 4)
|
||||
animateButtonIn(views.attachmentStickersButton, 0)
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
|
|
|
@ -24,10 +24,11 @@ import im.vector.app.R
|
|||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivitySimpleBinding
|
||||
import im.vector.app.features.themes.ActivityOtherThemes
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
|
||||
class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
||||
|
@ -51,7 +52,9 @@ class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
|
||||
override fun getOtherThemes() = ActivityOtherThemes.AttachmentsPreview
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_simple
|
||||
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
|
||||
|
||||
override fun getCoordinatorLayout() = views.coordinatorLayout
|
||||
|
||||
override fun initUiAndData() {
|
||||
if (isFirstCreation()) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.app.Activity.RESULT_CANCELED
|
|||
import android.app.Activity.RESULT_OK
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
@ -45,9 +46,9 @@ import im.vector.app.core.resources.ColorProvider
|
|||
import im.vector.app.core.utils.OnSnapPositionChangeListener
|
||||
import im.vector.app.core.utils.SnapOnScrollListener
|
||||
import im.vector.app.core.utils.attachSnapHelperWithListener
|
||||
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
|
||||
import im.vector.app.features.media.createUCropWithDefaultSettings
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import java.io.File
|
||||
|
@ -62,19 +63,21 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
|
||||
private val attachmentBigPreviewController: AttachmentBigPreviewController,
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback {
|
||||
) : VectorBaseFragment<FragmentAttachmentsPreviewBinding>(), AttachmentMiniaturePreviewController.Callback {
|
||||
|
||||
private val fragmentArgs: AttachmentsPreviewArgs by args()
|
||||
private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_attachments_preview
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentAttachmentsPreviewBinding {
|
||||
return FragmentAttachmentsPreviewBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
applyInsets()
|
||||
setupRecyclerViews()
|
||||
setupToolbar(attachmentPreviewerToolbar)
|
||||
attachmentPreviewerSendButton.setOnClickListener {
|
||||
setupToolbar(views.attachmentPreviewerToolbar)
|
||||
views.attachmentPreviewerSendButton.setOnClickListener {
|
||||
setResultAndFinish()
|
||||
}
|
||||
}
|
||||
|
@ -119,10 +122,10 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
override fun getMenuRes() = R.menu.vector_attachments_preview
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
attachmentPreviewerMiniatureList.cleanup()
|
||||
attachmentPreviewerBigList.cleanup()
|
||||
views.attachmentPreviewerMiniatureList.cleanup()
|
||||
views.attachmentPreviewerBigList.cleanup()
|
||||
attachmentMiniaturePreviewController.callback = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
|
@ -133,9 +136,9 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
} else {
|
||||
attachmentMiniaturePreviewController.setData(state)
|
||||
attachmentBigPreviewController.setData(state)
|
||||
attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
||||
attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
||||
attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
|
||||
views.attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
||||
views.attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
||||
views.attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,17 +149,17 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
private fun setResultAndFinish() = withState(viewModel) {
|
||||
(requireActivity() as? AttachmentsPreviewActivity)?.setResultAndFinish(
|
||||
it.attachments,
|
||||
attachmentPreviewerSendImageOriginalSize.isChecked
|
||||
views.attachmentPreviewerSendImageOriginalSize.isChecked
|
||||
)
|
||||
}
|
||||
|
||||
private fun applyInsets() {
|
||||
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerBottomContainer) { v, insets ->
|
||||
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets ->
|
||||
v.updatePadding(bottom = insets.systemWindowInsetBottom)
|
||||
insets
|
||||
}
|
||||
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerToolbar) { v, insets ->
|
||||
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerToolbar) { v, insets ->
|
||||
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = insets.systemWindowInsetTop
|
||||
}
|
||||
|
@ -180,13 +183,13 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
private fun setupRecyclerViews() {
|
||||
attachmentMiniaturePreviewController.callback = this
|
||||
|
||||
attachmentPreviewerMiniatureList.let {
|
||||
views.attachmentPreviewerMiniatureList.let {
|
||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
it.setHasFixedSize(true)
|
||||
it.adapter = attachmentMiniaturePreviewController.adapter
|
||||
}
|
||||
|
||||
attachmentPreviewerBigList.let {
|
||||
views.attachmentPreviewerBigList.let {
|
||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
it.attachSnapHelperWithListener(
|
||||
PagerSnapHelper(),
|
||||
|
|
|
@ -17,18 +17,23 @@
|
|||
package im.vector.app.features.call
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_call_controls.*
|
||||
import im.vector.app.databinding.BottomSheetCallControlsBinding
|
||||
|
||||
import me.gujun.android.span.span
|
||||
|
||||
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_call_controls
|
||||
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallControlsBinding {
|
||||
return BottomSheetCallControlsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val callViewModel: VectorCallViewModel by activityViewModel()
|
||||
|
||||
|
@ -39,16 +44,16 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
renderState(it)
|
||||
}
|
||||
|
||||
callControlsSoundDevice.clickableView.debouncedClicks {
|
||||
views.callControlsSoundDevice.views.itemVerificationClickableZone.debouncedClicks {
|
||||
callViewModel.handle(VectorCallViewActions.SwitchSoundDevice)
|
||||
}
|
||||
|
||||
callControlsSwitchCamera.clickableView.debouncedClicks {
|
||||
views.callControlsSwitchCamera.views.itemVerificationClickableZone.debouncedClicks {
|
||||
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
callControlsToggleSDHD.clickableView.debouncedClicks {
|
||||
views.callControlsToggleSDHD.views.itemVerificationClickableZone.debouncedClicks {
|
||||
callViewModel.handle(VectorCallViewActions.ToggleHDSD)
|
||||
dismiss()
|
||||
}
|
||||
|
@ -109,30 +114,30 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
private fun renderState(state: VectorCallViewState) {
|
||||
callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
|
||||
callControlsSoundDevice.subTitle = when (state.soundDevice) {
|
||||
views.callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
|
||||
views.callControlsSoundDevice.subTitle = when (state.soundDevice) {
|
||||
CallAudioManager.SoundDevice.PHONE -> getString(R.string.sound_device_phone)
|
||||
CallAudioManager.SoundDevice.SPEAKER -> getString(R.string.sound_device_speaker)
|
||||
CallAudioManager.SoundDevice.HEADSET -> getString(R.string.sound_device_headset)
|
||||
CallAudioManager.SoundDevice.WIRELESS_HEADSET -> getString(R.string.sound_device_wireless_headset)
|
||||
}
|
||||
|
||||
callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera
|
||||
callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
|
||||
views.callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera
|
||||
views.callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
|
||||
|
||||
if (state.isVideoCall) {
|
||||
callControlsToggleSDHD.isVisible = true
|
||||
views.callControlsToggleSDHD.isVisible = true
|
||||
if (state.isHD) {
|
||||
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
|
||||
callControlsToggleSDHD.subTitle = null
|
||||
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
|
||||
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
|
||||
views.callControlsToggleSDHD.subTitle = null
|
||||
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
|
||||
} else {
|
||||
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
|
||||
callControlsToggleSDHD.subTitle = null
|
||||
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
|
||||
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
|
||||
views.callControlsToggleSDHD.subTitle = null
|
||||
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
|
||||
}
|
||||
} else {
|
||||
callControlsToggleSDHD.isVisible = false
|
||||
views.callControlsToggleSDHD.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,16 +18,11 @@ package im.vector.app.features.call
|
|||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnClick
|
||||
import im.vector.app.R
|
||||
import kotlinx.android.synthetic.main.view_call_controls.view.*
|
||||
import im.vector.app.databinding.ViewCallControlsBinding
|
||||
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.webrtc.PeerConnection
|
||||
|
||||
|
@ -35,115 +30,100 @@ class CallControlsView @JvmOverloads constructor(
|
|||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val views: ViewCallControlsBinding
|
||||
|
||||
var interactionListener: InteractionListener? = null
|
||||
|
||||
@BindView(R.id.ringingControls)
|
||||
lateinit var ringingControls: ViewGroup
|
||||
|
||||
@BindView(R.id.iv_icr_accept_call)
|
||||
lateinit var ringingControlAccept: ImageView
|
||||
|
||||
@BindView(R.id.iv_icr_end_call)
|
||||
lateinit var ringingControlDecline: ImageView
|
||||
|
||||
@BindView(R.id.connectedControls)
|
||||
lateinit var connectedControls: ViewGroup
|
||||
|
||||
@BindView(R.id.iv_mute_toggle)
|
||||
lateinit var muteIcon: ImageView
|
||||
|
||||
@BindView(R.id.iv_video_toggle)
|
||||
lateinit var videoToggleIcon: ImageView
|
||||
|
||||
init {
|
||||
ConstraintLayout.inflate(context, R.layout.view_call_controls, this)
|
||||
inflate(context, R.layout.view_call_controls, this)
|
||||
// layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
ButterKnife.bind(this)
|
||||
views = ViewCallControlsBinding.bind(this)
|
||||
|
||||
views.ringingControlAccept.setOnClickListener { acceptIncomingCall() }
|
||||
views.ringingControlDecline.setOnClickListener { declineIncomingCall() }
|
||||
views.ivEndCall.setOnClickListener { endOngoingCall() }
|
||||
views.muteIcon.setOnClickListener { toggleMute() }
|
||||
views.videoToggleIcon.setOnClickListener { toggleVideo() }
|
||||
views.ivLeftMiniControl.setOnClickListener { returnToChat() }
|
||||
views.ivMore.setOnClickListener { moreControlOption() }
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_icr_accept_call)
|
||||
fun acceptIncomingCall() {
|
||||
private fun acceptIncomingCall() {
|
||||
interactionListener?.didAcceptIncomingCall()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_icr_end_call)
|
||||
fun declineIncomingCall() {
|
||||
private fun declineIncomingCall() {
|
||||
interactionListener?.didDeclineIncomingCall()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_end_call)
|
||||
fun endOngoingCall() {
|
||||
private fun endOngoingCall() {
|
||||
interactionListener?.didEndCall()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_mute_toggle)
|
||||
fun toggleMute() {
|
||||
private fun toggleMute() {
|
||||
interactionListener?.didTapToggleMute()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_video_toggle)
|
||||
fun toggleVideo() {
|
||||
private fun toggleVideo() {
|
||||
interactionListener?.didTapToggleVideo()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_leftMiniControl)
|
||||
fun returnToChat() {
|
||||
private fun returnToChat() {
|
||||
interactionListener?.returnToChat()
|
||||
}
|
||||
|
||||
@OnClick(R.id.iv_more)
|
||||
fun moreControlOption() {
|
||||
private fun moreControlOption() {
|
||||
interactionListener?.didTapMore()
|
||||
}
|
||||
|
||||
fun updateForState(state: VectorCallViewState) {
|
||||
val callState = state.callState.invoke()
|
||||
if (state.isAudioMuted) {
|
||||
muteIcon.setImageResource(R.drawable.ic_microphone_off)
|
||||
muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone)
|
||||
views.muteIcon.setImageResource(R.drawable.ic_microphone_off)
|
||||
views.muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone)
|
||||
} else {
|
||||
muteIcon.setImageResource(R.drawable.ic_microphone_on)
|
||||
muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone)
|
||||
views.muteIcon.setImageResource(R.drawable.ic_microphone_on)
|
||||
views.muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone)
|
||||
}
|
||||
if (state.isVideoEnabled) {
|
||||
videoToggleIcon.setImageResource(R.drawable.ic_video)
|
||||
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera)
|
||||
views.videoToggleIcon.setImageResource(R.drawable.ic_video)
|
||||
views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera)
|
||||
} else {
|
||||
videoToggleIcon.setImageResource(R.drawable.ic_video_off)
|
||||
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera)
|
||||
views.videoToggleIcon.setImageResource(R.drawable.ic_video_off)
|
||||
views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera)
|
||||
}
|
||||
|
||||
when (callState) {
|
||||
is CallState.Idle,
|
||||
is CallState.Dialing,
|
||||
is CallState.Answering -> {
|
||||
ringingControls.isVisible = true
|
||||
ringingControlAccept.isVisible = false
|
||||
ringingControlDecline.isVisible = true
|
||||
connectedControls.isVisible = false
|
||||
views.ringingControls.isVisible = true
|
||||
views.ringingControlAccept.isVisible = false
|
||||
views.ringingControlDecline.isVisible = true
|
||||
views.connectedControls.isVisible = false
|
||||
}
|
||||
is CallState.LocalRinging -> {
|
||||
ringingControls.isVisible = true
|
||||
ringingControlAccept.isVisible = true
|
||||
ringingControlDecline.isVisible = true
|
||||
connectedControls.isVisible = false
|
||||
views.ringingControls.isVisible = true
|
||||
views.ringingControlAccept.isVisible = true
|
||||
views.ringingControlDecline.isVisible = true
|
||||
views.connectedControls.isVisible = false
|
||||
}
|
||||
is CallState.Connected -> {
|
||||
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
||||
ringingControls.isVisible = false
|
||||
connectedControls.isVisible = true
|
||||
iv_video_toggle.isVisible = state.isVideoCall
|
||||
views.ringingControls.isVisible = false
|
||||
views.connectedControls.isVisible = true
|
||||
views.videoToggleIcon.isVisible = state.isVideoCall
|
||||
} else {
|
||||
ringingControls.isVisible = true
|
||||
ringingControlAccept.isVisible = false
|
||||
ringingControlDecline.isVisible = true
|
||||
connectedControls.isVisible = false
|
||||
views.ringingControls.isVisible = true
|
||||
views.ringingControlAccept.isVisible = false
|
||||
views.ringingControlDecline.isVisible = true
|
||||
views.connectedControls.isVisible = false
|
||||
}
|
||||
}
|
||||
is CallState.Terminated,
|
||||
null -> {
|
||||
ringingControls.isVisible = false
|
||||
connectedControls.isVisible = false
|
||||
views.ringingControls.isVisible = false
|
||||
views.connectedControls.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import androidx.core.view.ViewCompat
|
|||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
|
@ -45,12 +44,12 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
|
|||
import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.databinding.ActivityCallBinding
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_call.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.call.CallState
|
||||
import org.matrix.android.sdk.api.session.call.EglUtils
|
||||
import org.matrix.android.sdk.api.session.call.MxCallDetail
|
||||
|
@ -58,7 +57,6 @@ import org.matrix.android.sdk.api.session.call.TurnServerResponse
|
|||
import org.webrtc.EglBase
|
||||
import org.webrtc.PeerConnection
|
||||
import org.webrtc.RendererCommon
|
||||
import org.webrtc.SurfaceViewRenderer
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
@ -72,9 +70,9 @@ data class CallArgs(
|
|||
val isVideoCall: Boolean
|
||||
) : Parcelable
|
||||
|
||||
class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener {
|
||||
class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallControlsView.InteractionListener {
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_call
|
||||
override fun getBinding() = ActivityCallBinding.inflate(layoutInflater)
|
||||
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
|
@ -90,15 +88,6 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
|
||||
@Inject lateinit var viewModelFactory: VectorCallViewModel.Factory
|
||||
|
||||
@BindView(R.id.pip_video_view)
|
||||
lateinit var pipRenderer: SurfaceViewRenderer
|
||||
|
||||
@BindView(R.id.fullscreen_video_view)
|
||||
lateinit var fullscreenRenderer: SurfaceViewRenderer
|
||||
|
||||
@BindView(R.id.callControls)
|
||||
lateinit var callControlsView: CallControlsView
|
||||
|
||||
private var rootEglBase: EglBase? = null
|
||||
|
||||
var systemUiVisibility = false
|
||||
|
@ -158,7 +147,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
// This will need to be refined
|
||||
ViewCompat.setOnApplyWindowInsetsListener(constraintLayout) { v, insets ->
|
||||
ViewCompat.setOnApplyWindowInsetsListener(views.constraintLayout) { v, insets ->
|
||||
v.updatePadding(bottom = if (systemUiVisibility) insets.systemWindowInsetBottom else 0)
|
||||
insets
|
||||
}
|
||||
|
@ -178,7 +167,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
turnScreenOnAndKeyguardOff()
|
||||
}
|
||||
|
||||
constraintLayout.clicks()
|
||||
views.constraintLayout.clicks()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { toggleUiSystemVisibility() }
|
||||
|
@ -210,10 +199,10 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
peerConnectionManager.detachRenderers(listOf(pipRenderer, fullscreenRenderer))
|
||||
peerConnectionManager.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer))
|
||||
if (surfaceRenderersAreInitialized) {
|
||||
pipRenderer.release()
|
||||
fullscreenRenderer.release()
|
||||
views.pipRenderer.release()
|
||||
views.fullscreenRenderer.release()
|
||||
}
|
||||
turnScreenOffAndKeyguardOn()
|
||||
super.onDestroy()
|
||||
|
@ -228,54 +217,54 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
return
|
||||
}
|
||||
|
||||
callControlsView.updateForState(state)
|
||||
views.callControlsView.updateForState(state)
|
||||
val callState = state.callState.invoke()
|
||||
callConnectingProgress.isVisible = false
|
||||
views.callConnectingProgress.isVisible = false
|
||||
when (callState) {
|
||||
is CallState.Idle,
|
||||
is CallState.Dialing -> {
|
||||
callVideoGroup.isInvisible = true
|
||||
callInfoGroup.isVisible = true
|
||||
callStatusText.setText(R.string.call_ring)
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
views.callStatusText.setText(R.string.call_ring)
|
||||
configureCallInfo(state)
|
||||
}
|
||||
|
||||
is CallState.LocalRinging -> {
|
||||
callVideoGroup.isInvisible = true
|
||||
callInfoGroup.isVisible = true
|
||||
callStatusText.text = null
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
views.callStatusText.text = null
|
||||
configureCallInfo(state)
|
||||
}
|
||||
|
||||
is CallState.Answering -> {
|
||||
callVideoGroup.isInvisible = true
|
||||
callInfoGroup.isVisible = true
|
||||
callStatusText.setText(R.string.call_connecting)
|
||||
callConnectingProgress.isVisible = true
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
views.callStatusText.setText(R.string.call_connecting)
|
||||
views.callConnectingProgress.isVisible = true
|
||||
configureCallInfo(state)
|
||||
}
|
||||
is CallState.Connected -> {
|
||||
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
||||
if (callArgs.isVideoCall) {
|
||||
callVideoGroup.isVisible = true
|
||||
callInfoGroup.isVisible = false
|
||||
pip_video_view.isVisible = !state.isVideoCaptureInError
|
||||
views.callVideoGroup.isVisible = true
|
||||
views.callInfoGroup.isVisible = false
|
||||
views.pipRenderer.isVisible = !state.isVideoCaptureInError
|
||||
} else {
|
||||
callVideoGroup.isInvisible = true
|
||||
callInfoGroup.isVisible = true
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
configureCallInfo(state)
|
||||
callStatusText.text = null
|
||||
views.callStatusText.text = null
|
||||
}
|
||||
} else {
|
||||
// This state is not final, if you change network, new candidates will be sent
|
||||
callVideoGroup.isInvisible = true
|
||||
callInfoGroup.isVisible = true
|
||||
views.callVideoGroup.isInvisible = true
|
||||
views.callInfoGroup.isVisible = true
|
||||
configureCallInfo(state)
|
||||
callStatusText.setText(R.string.call_connecting)
|
||||
callConnectingProgress.isVisible = true
|
||||
views.callStatusText.setText(R.string.call_connecting)
|
||||
views.callConnectingProgress.isVisible = true
|
||||
}
|
||||
// ensure all attached?
|
||||
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer, null)
|
||||
peerConnectionManager.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, null)
|
||||
}
|
||||
is CallState.Terminated -> {
|
||||
finish()
|
||||
|
@ -287,14 +276,14 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
|
||||
private fun configureCallInfo(state: VectorCallViewState) {
|
||||
state.otherUserMatrixItem.invoke()?.let {
|
||||
avatarRenderer.render(it, otherMemberAvatar)
|
||||
participantNameText.text = it.getBestName()
|
||||
callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
|
||||
avatarRenderer.render(it, views.otherMemberAvatar)
|
||||
views.participantNameText.text = it.getBestName()
|
||||
views.callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureCallViews() {
|
||||
callControlsView.interactionListener = this
|
||||
views.callControlsView.interactionListener = this
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
|
@ -314,21 +303,24 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||
}
|
||||
|
||||
// Init Picture in Picture renderer
|
||||
pipRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
views.pipRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
views.pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
|
||||
// Init Full Screen renderer
|
||||
fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
views.fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||
views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||
|
||||
pipRenderer.setZOrderMediaOverlay(true)
|
||||
pipRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||
fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||
views.pipRenderer.setZOrderMediaOverlay(true)
|
||||
views.pipRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||
views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||
|
||||
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer,
|
||||
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() })
|
||||
peerConnectionManager.attachViewRenderers(
|
||||
views.pipRenderer,
|
||||
views.fullscreenRenderer,
|
||||
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() }
|
||||
)
|
||||
|
||||
pipRenderer.setOnClickListener {
|
||||
views.pipRenderer.setOnClickListener {
|
||||
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
||||
}
|
||||
surfaceRenderersAreInitialized = true
|
||||
|
|
|
@ -20,7 +20,6 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.Fail
|
||||
|
@ -28,11 +27,10 @@ import com.airbnb.mvrx.MvRx
|
|||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.facebook.react.modules.core.PermissionListener
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_jitsi.*
|
||||
import im.vector.app.databinding.ActivityJitsiBinding
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivityInterface
|
||||
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
|
||||
|
@ -42,7 +40,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
|||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
|
||||
class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener {
|
||||
class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMeetActivityInterface, JitsiMeetViewListener {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
|
@ -51,7 +49,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||
val enableVideo: Boolean
|
||||
) : Parcelable
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_jitsi
|
||||
override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater)
|
||||
|
||||
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
|
||||
|
||||
|
@ -76,7 +74,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||
super.initUiAndData()
|
||||
jitsiMeetView = JitsiMeetView(this)
|
||||
val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
||||
jitsi_layout.addView(jitsiMeetView, params)
|
||||
views.jitsiLayout.addView(jitsiMeetView, params)
|
||||
jitsiMeetView?.listener = this
|
||||
}
|
||||
|
||||
|
@ -84,13 +82,13 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||
when (viewState.widget) {
|
||||
is Fail -> finish()
|
||||
is Success -> {
|
||||
findViewById<View>(R.id.jitsi_progress_layout).isVisible = false
|
||||
views.jitsiProgressLayout.isVisible = false
|
||||
jitsiMeetView?.isVisible = true
|
||||
configureJitsiView(viewState)
|
||||
}
|
||||
else -> {
|
||||
jitsiMeetView?.isVisible = false
|
||||
findViewById<View>(R.id.jitsi_progress_layout).isVisible = true
|
||||
views.jitsiProgressLayout.isVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.contactsbook
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -29,12 +31,13 @@ import im.vector.app.core.extensions.cleanup
|
|||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentContactsBookBinding
|
||||
import im.vector.app.features.userdirectory.PendingInvitee
|
||||
import im.vector.app.features.userdirectory.UserListAction
|
||||
import im.vector.app.features.userdirectory.UserListSharedAction
|
||||
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
|
||||
import im.vector.app.features.userdirectory.UserListViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_contacts_book.*
|
||||
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -43,9 +46,12 @@ import javax.inject.Inject
|
|||
class ContactsBookFragment @Inject constructor(
|
||||
val contactsBookViewModelFactory: ContactsBookViewModel.Factory,
|
||||
private val contactsBookController: ContactsBookController
|
||||
) : VectorBaseFragment(), ContactsBookController.Callback {
|
||||
) : VectorBaseFragment<FragmentContactsBookBinding>(), ContactsBookController.Callback {
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentContactsBookBinding {
|
||||
return FragmentContactsBookBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_contacts_book
|
||||
private val viewModel: UserListViewModel by activityViewModel()
|
||||
|
||||
// Use activityViewModel to avoid loading several times the data
|
||||
|
@ -64,7 +70,7 @@ class ContactsBookFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun setupConsentView() {
|
||||
phoneBookSearchForMatrixContacts.setOnClickListener {
|
||||
views.phoneBookSearchForMatrixContacts.setOnClickListener {
|
||||
withState(contactsBookViewModel) { state ->
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.identity_server_consent_dialog_title)
|
||||
|
@ -79,7 +85,7 @@ class ContactsBookFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun setupOnlyBoundContactsView() {
|
||||
phoneBookOnlyBoundContacts.checkedChanges()
|
||||
views.phoneBookOnlyBoundContacts.checkedChanges()
|
||||
.subscribe {
|
||||
contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it))
|
||||
}
|
||||
|
@ -87,7 +93,7 @@ class ContactsBookFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun setupFilterView() {
|
||||
phoneBookFilter
|
||||
views.phoneBookFilter
|
||||
.textChanges()
|
||||
.skipInitialValue()
|
||||
.debounce(300, TimeUnit.MILLISECONDS)
|
||||
|
@ -98,25 +104,25 @@ class ContactsBookFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
phoneBookRecyclerView.cleanup()
|
||||
views.phoneBookRecyclerView.cleanup()
|
||||
contactsBookController.callback = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
contactsBookController.callback = this
|
||||
phoneBookRecyclerView.configureWith(contactsBookController)
|
||||
views.phoneBookRecyclerView.configureWith(contactsBookController)
|
||||
}
|
||||
|
||||
private fun setupCloseView() {
|
||||
phoneBookClose.debouncedClicks {
|
||||
views.phoneBookClose.debouncedClicks {
|
||||
sharedActionViewModel.post(UserListSharedAction.GoBack)
|
||||
}
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(contactsBookViewModel) { state ->
|
||||
phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
|
||||
phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
|
||||
views.phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
|
||||
views.phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
|
||||
contactsBookController.setData(state)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ import im.vector.app.features.userdirectory.UserListSharedAction
|
|||
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
|
||||
import im.vector.app.features.userdirectory.UserListViewModel
|
||||
import im.vector.app.features.userdirectory.UserListViewState
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
||||
import java.net.HttpURLConnection
|
||||
|
@ -77,7 +77,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
toolbar.visibility = View.GONE
|
||||
views.toolbar.visibility = View.GONE
|
||||
|
||||
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
||||
sharedActionViewModel
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package im.vector.app.features.createdirect
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.google.zxing.Result
|
||||
|
@ -26,19 +28,22 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.databinding.FragmentQrCodeScannerBinding
|
||||
import im.vector.app.features.userdirectory.PendingInvitee
|
||||
import kotlinx.android.synthetic.main.fragment_qr_code_scanner.*
|
||||
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler {
|
||||
class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment<FragmentQrCodeScannerBinding>(), ZXingScannerView.ResultHandler {
|
||||
|
||||
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_qr_code_scanner
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeScannerBinding {
|
||||
return FragmentQrCodeScannerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
|
@ -48,14 +53,14 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
|
|||
|
||||
private fun startCamera() {
|
||||
// Start camera on resume
|
||||
scannerView.startCamera()
|
||||
views.scannerView.startCamera()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
view?.hideKeyboard()
|
||||
// Register ourselves as a handler for scan results.
|
||||
scannerView.setResultHandler(this)
|
||||
views.scannerView.setResultHandler(this)
|
||||
// Start camera on resume
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
||||
startCamera()
|
||||
|
@ -65,9 +70,9 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
|
|||
override fun onPause() {
|
||||
super.onPause()
|
||||
// Unregister ourselves as a handler for scan results.
|
||||
scannerView.setResultHandler(null)
|
||||
views.scannerView.setResultHandler(null)
|
||||
// Stop camera on pause
|
||||
scannerView.stopCamera()
|
||||
views.scannerView.stopCamera()
|
||||
}
|
||||
|
||||
// Copied from https://github.com/markusfisch/BinaryEye/blob/
|
||||
|
|
|
@ -17,42 +17,37 @@ package im.vector.app.features.crypto.keysbackup.restore
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import butterknife.OnTextChanged
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
||||
: VectorBaseFragment() {
|
||||
: VectorBaseFragment<FragmentKeysBackupRestoreFromKeyBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_key
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromKeyBinding {
|
||||
return FragmentKeysBackupRestoreFromKeyBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel
|
||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||
|
||||
@BindView(R.id.keys_backup_key_enter_til)
|
||||
lateinit var mKeyInputLayout: TextInputLayout
|
||||
|
||||
@BindView(R.id.keys_restore_key_enter_edittext)
|
||||
lateinit var mKeyTextEdit: EditText
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java)
|
||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
mKeyTextEdit.setText(viewModel.recoveryCode.value)
|
||||
mKeyTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||
views.keyTextEdit.setText(viewModel.recoveryCode.value)
|
||||
views.keyTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
onRestoreFromKey()
|
||||
return@setOnEditorActionListener true
|
||||
|
@ -60,21 +55,23 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value
|
||||
views.keyInputLayout.error = viewModel.recoveryCodeErrorText.value
|
||||
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
||||
mKeyInputLayout.error = newValue
|
||||
views.keyInputLayout.error = newValue
|
||||
})
|
||||
|
||||
views.keysRestoreButton.setOnClickListener { onRestoreFromKey() }
|
||||
views.keysBackupImport.setOnClickListener { onImport() }
|
||||
views.keyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) }
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.keys_restore_key_enter_edittext)
|
||||
fun onRestoreKeyTextEditChange(s: Editable?) {
|
||||
private fun onRestoreKeyTextEditChange(s: CharSequence?) {
|
||||
s?.toString()?.let {
|
||||
viewModel.updateCode(it)
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_restore_button)
|
||||
fun onRestoreFromKey() {
|
||||
private fun onRestoreFromKey() {
|
||||
val value = viewModel.recoveryCode.value
|
||||
if (value.isNullOrBlank()) {
|
||||
viewModel.recoveryCodeErrorText.value = context?.getString(R.string.keys_backup_recovery_code_empty_error_message)
|
||||
|
@ -83,8 +80,7 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_import)
|
||||
fun onImport() {
|
||||
private fun onImport() {
|
||||
startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult)
|
||||
}
|
||||
|
||||
|
@ -98,8 +94,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||
?.bufferedReader()
|
||||
?.use { it.readText() }
|
||||
?.let {
|
||||
mKeyTextEdit.setText(it)
|
||||
mKeyTextEdit.setSelection(it.length)
|
||||
views.keyTextEdit.setText(it)
|
||||
views.keyTextEdit.setSelection(it.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,46 +16,32 @@
|
|||
package im.vector.app.features.crypto.keysbackup.restore
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.set
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import butterknife.OnTextChanged
|
||||
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.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupRestoreFromPassphraseBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_passphrase
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromPassphraseBinding {
|
||||
return FragmentKeysBackupRestoreFromPassphraseBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private lateinit var viewModel: KeysBackupRestoreFromPassphraseViewModel
|
||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_enter_til)
|
||||
lateinit var mPassphraseInputLayout: TextInputLayout
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_enter_edittext)
|
||||
lateinit var mPassphraseTextEdit: EditText
|
||||
|
||||
@BindView(R.id.keys_backup_view_show_password)
|
||||
lateinit var mPassphraseReveal: ImageView
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_help_with_link)
|
||||
lateinit var helperTextWithLink: TextView
|
||||
|
||||
@OnClick(R.id.keys_backup_view_show_password)
|
||||
fun toggleVisibilityMode() {
|
||||
private fun toggleVisibilityMode() {
|
||||
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
||||
}
|
||||
|
||||
|
@ -66,24 +52,29 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||
|
||||
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
||||
mPassphraseInputLayout.error = newValue
|
||||
views.keysBackupPassphraseEnterTil.error = newValue
|
||||
})
|
||||
|
||||
helperTextWithLink.text = spannableStringForHelperText()
|
||||
views.helperTextWithLink.text = spannableStringForHelperText()
|
||||
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||
val shouldBeVisible = it ?: false
|
||||
mPassphraseTextEdit.showPassword(shouldBeVisible)
|
||||
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||
views.keysBackupViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
})
|
||||
|
||||
mPassphraseTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||
views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
onRestoreBackup()
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
views.keysBackupViewShowPassword.setOnClickListener { toggleVisibilityMode() }
|
||||
views.helperTextWithLink.setOnClickListener { onUseRecoveryKey() }
|
||||
views.keysBackupRestoreWithPassphraseSubmit.setOnClickListener { onRestoreBackup() }
|
||||
views.keysBackupPassphraseEnterEdittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) }
|
||||
}
|
||||
|
||||
private fun spannableStringForHelperText(): SpannableString {
|
||||
|
@ -102,18 +93,15 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||
return spanString
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.keys_backup_passphrase_enter_edittext)
|
||||
fun onPassphraseTextEditChange(s: Editable?) {
|
||||
private fun onPassphraseTextEditChange(s: CharSequence?) {
|
||||
s?.toString()?.let { viewModel.updatePassphrase(it) }
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_passphrase_help_with_link)
|
||||
fun onUseRecoveryKey() {
|
||||
private fun onUseRecoveryKey() {
|
||||
sharedViewModel.moveToRecoverWithKey()
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_restore_with_passphrase_submit)
|
||||
fun onRestoreBackup() {
|
||||
private fun onRestoreBackup() {
|
||||
val value = viewModel.passphrase.value
|
||||
if (value.isNullOrBlank()) {
|
||||
viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message)
|
||||
|
|
|
@ -16,25 +16,22 @@
|
|||
package im.vector.app.features.crypto.keysbackup.restore
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.LiveEvent
|
||||
import im.vector.app.databinding.FragmentKeysBackupRestoreSuccessBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupRestoreSuccessBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_success
|
||||
|
||||
@BindView(R.id.keys_backup_restore_success)
|
||||
lateinit var mSuccessText: TextView
|
||||
|
||||
@BindView(R.id.keys_backup_restore_success_info)
|
||||
lateinit var mSuccessDetailsText: TextView
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreSuccessBinding {
|
||||
return FragmentKeysBackupRestoreSuccessBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||
|
||||
|
@ -48,18 +45,18 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen
|
|||
it.totalNumberOfKeys, it.totalNumberOfKeys)
|
||||
val part2 = resources.getQuantityString(R.plurals.keys_backup_restore_success_description_part2,
|
||||
it.successfullyNumberOfImportedKeys, it.successfullyNumberOfImportedKeys)
|
||||
mSuccessDetailsText.text = String.format("%s\n%s", part1, part2)
|
||||
views.successDetailsText.text = String.format("%s\n%s", part1, part2)
|
||||
}
|
||||
// We don't put emoji in string xml as it will crash on old devices
|
||||
mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉")
|
||||
views.successText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉")
|
||||
} else {
|
||||
mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
|
||||
mSuccessDetailsText.isVisible = false
|
||||
views.successText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
|
||||
views.successDetailsText.isVisible = false
|
||||
}
|
||||
views.keysBackupSetupDoneButton.setOnClickListener { onDone() }
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_done_button)
|
||||
fun onDone() {
|
||||
private fun onDone() {
|
||||
sharedViewModel.importRoomKeysFinishWithResult.value = LiveEvent(sharedViewModel.importKeyResult!!)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
package im.vector.app.features.crypto.keysbackup.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -24,28 +26,31 @@ import im.vector.app.R
|
|||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentKeysBackupSettingsBinding
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
||||
import kotlinx.android.synthetic.main.fragment_keys_backup_settings.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController)
|
||||
: VectorBaseFragment(),
|
||||
: VectorBaseFragment<FragmentKeysBackupSettingsBinding>(),
|
||||
KeysBackupSettingsRecyclerViewController.Listener {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_settings
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSettingsBinding {
|
||||
return FragmentKeysBackupSettingsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val viewModel: KeysBackupSettingsViewModel by activityViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
|
||||
views.keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
|
||||
keysBackupSettingsRecyclerViewController.listener = this
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
keysBackupSettingsRecyclerViewController.listener = null
|
||||
keysBackupSettingsRecyclerView.cleanup()
|
||||
views.keysBackupSettingsRecyclerView.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,29 +17,24 @@
|
|||
package im.vector.app.features.crypto.keysbackup.setup
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.Observer
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.LiveEvent
|
||||
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() {
|
||||
class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep1Binding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step1
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep1Binding {
|
||||
return FragmentKeysBackupSetupStep1Binding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||
|
||||
@BindView(R.id.keys_backup_setup_step1_advanced)
|
||||
lateinit var advancedOptionText: TextView
|
||||
|
||||
@BindView(R.id.keys_backup_setup_step1_manualExport)
|
||||
lateinit var manualExportButton: Button
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -48,18 +43,19 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment()
|
|||
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
|
||||
val showOption = it ?: false
|
||||
// Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated
|
||||
advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||
manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||
views.keysBackupSetupStep1AdvancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||
views.keysBackupSetupStep1ManualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||
})
|
||||
|
||||
views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() }
|
||||
views.keysBackupSetupStep1ManualExportButton.setOnClickListener { onManualExportClick() }
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step1_button)
|
||||
fun onButtonClick() {
|
||||
private fun onButtonClick() {
|
||||
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2)
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step1_manualExport)
|
||||
fun onManualExportClick() {
|
||||
private fun onManualExportClick() {
|
||||
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,64 +16,40 @@
|
|||
package im.vector.app.features.crypto.keysbackup.setup
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.transition.TransitionManager
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import butterknife.OnTextChanged
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.nulabinc.zxcvbn.Zxcvbn
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.ui.views.PasswordStrengthBar
|
||||
import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding
|
||||
import im.vector.app.features.settings.VectorLocale
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() {
|
||||
class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep2Binding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step2
|
||||
|
||||
@BindView(R.id.keys_backup_root)
|
||||
lateinit var rootGroup: ViewGroup
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_enter_edittext)
|
||||
lateinit var mPassphraseTextEdit: EditText
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_enter_til)
|
||||
lateinit var mPassphraseInputLayout: TextInputLayout
|
||||
|
||||
@BindView(R.id.keys_backup_view_show_password)
|
||||
lateinit var mPassphraseReveal: ImageView
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_confirm_edittext)
|
||||
lateinit var mPassphraseConfirmTextEdit: EditText
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_confirm_til)
|
||||
lateinit var mPassphraseConfirmInputLayout: TextInputLayout
|
||||
|
||||
@BindView(R.id.keys_backup_passphrase_security_progress)
|
||||
lateinit var mPassphraseProgressLevel: PasswordStrengthBar
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep2Binding {
|
||||
return FragmentKeysBackupSetupStep2Binding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val zxcvbn = Zxcvbn()
|
||||
|
||||
@OnTextChanged(R.id.keys_backup_passphrase_enter_edittext)
|
||||
fun onPassphraseChanged() {
|
||||
viewModel.passphrase.value = mPassphraseTextEdit.text.toString()
|
||||
private fun onPassphraseChanged() {
|
||||
viewModel.passphrase.value = views.keysBackupSetupStep2PassphraseEnterEdittext.text.toString()
|
||||
viewModel.confirmPassphraseError.value = null
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.keys_backup_passphrase_confirm_edittext)
|
||||
fun onConfirmPassphraseChanged() {
|
||||
viewModel.confirmPassphrase.value = mPassphraseConfirmTextEdit.text.toString()
|
||||
private fun onConfirmPassphraseChanged() {
|
||||
viewModel.confirmPassphrase.value = views.keysBackupSetupStep2PassphraseConfirmEditText.text.toString()
|
||||
}
|
||||
|
||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||
|
@ -85,6 +61,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
|
||||
viewModel.shouldPromptOnBack = true
|
||||
bindViewToViewModel()
|
||||
setupViews()
|
||||
}
|
||||
|
||||
/* ==========================================================================================
|
||||
|
@ -94,24 +71,24 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
private fun bindViewToViewModel() {
|
||||
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength ->
|
||||
if (strength == null) {
|
||||
mPassphraseProgressLevel.strength = 0
|
||||
mPassphraseInputLayout.error = null
|
||||
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = 0
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = null
|
||||
} else {
|
||||
val score = strength.score
|
||||
mPassphraseProgressLevel.strength = score
|
||||
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = score
|
||||
|
||||
if (score in 1..3) {
|
||||
val warning = strength.feedback?.getWarning(VectorLocale.applicationLocale)
|
||||
if (warning != null) {
|
||||
mPassphraseInputLayout.error = warning
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = warning
|
||||
}
|
||||
|
||||
val suggestions = strength.feedback?.getSuggestions(VectorLocale.applicationLocale)
|
||||
if (suggestions != null) {
|
||||
mPassphraseInputLayout.error = suggestions.firstOrNull()
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = suggestions.firstOrNull()
|
||||
}
|
||||
} else {
|
||||
mPassphraseInputLayout.error = null
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -129,28 +106,28 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
}
|
||||
})
|
||||
|
||||
mPassphraseTextEdit.setText(viewModel.passphrase.value)
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.setText(viewModel.passphrase.value)
|
||||
|
||||
viewModel.passphraseError.observe(viewLifecycleOwner, Observer {
|
||||
TransitionManager.beginDelayedTransition(rootGroup)
|
||||
mPassphraseInputLayout.error = it
|
||||
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
|
||||
views.keysBackupSetupStep2PassphraseEnterTil.error = it
|
||||
})
|
||||
|
||||
mPassphraseConfirmTextEdit.setText(viewModel.confirmPassphrase.value)
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value)
|
||||
|
||||
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||
val shouldBeVisible = it ?: false
|
||||
mPassphraseTextEdit.showPassword(shouldBeVisible)
|
||||
mPassphraseConfirmTextEdit.showPassword(shouldBeVisible)
|
||||
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.showPassword(shouldBeVisible)
|
||||
views.keysBackupSetupStep2ShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
})
|
||||
|
||||
viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer {
|
||||
TransitionManager.beginDelayedTransition(rootGroup)
|
||||
mPassphraseConfirmInputLayout.error = it
|
||||
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
|
||||
views.keysBackupSetupStep2PassphraseConfirmTil.error = it
|
||||
})
|
||||
|
||||
mPassphraseConfirmTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
doNext()
|
||||
return@setOnEditorActionListener true
|
||||
|
@ -159,13 +136,20 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_view_show_password)
|
||||
fun toggleVisibilityMode() {
|
||||
private fun setupViews() {
|
||||
views.keysBackupSetupStep2ShowPassword.setOnClickListener { toggleVisibilityMode() }
|
||||
views.keysBackupSetupStep2Button.setOnClickListener { doNext() }
|
||||
views.keysBackupSetupStep2SkipButton.setOnClickListener { skipPassphrase() }
|
||||
|
||||
views.keysBackupSetupStep2PassphraseEnterEdittext.doOnTextChanged { _, _, _, _ -> onPassphraseChanged() }
|
||||
views.keysBackupSetupStep2PassphraseConfirmEditText.doOnTextChanged { _, _, _, _ -> onConfirmPassphraseChanged() }
|
||||
}
|
||||
|
||||
private fun toggleVisibilityMode() {
|
||||
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step2_button)
|
||||
fun doNext() {
|
||||
private fun doNext() {
|
||||
when {
|
||||
viewModel.passphrase.value.isNullOrEmpty() -> {
|
||||
viewModel.passphraseError.value = context?.getString(R.string.passphrase_empty_error_message)
|
||||
|
@ -184,8 +168,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step2_skip_button)
|
||||
fun skipPassphrase() {
|
||||
private fun skipPassphrase() {
|
||||
when {
|
||||
viewModel.passphrase.value.isNullOrEmpty() -> {
|
||||
// Generate a recovery key for the user
|
||||
|
|
|
@ -18,16 +18,15 @@ package im.vector.app.features.crypto.keysbackup.setup
|
|||
import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import arrow.core.Try
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
|
@ -36,6 +35,8 @@ import im.vector.app.core.utils.LiveEvent
|
|||
import im.vector.app.core.utils.copyToClipboard
|
||||
import im.vector.app.core.utils.selectTxtFileToWrite
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -46,18 +47,11 @@ import java.util.Date
|
|||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
|
||||
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep3Binding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3
|
||||
|
||||
@BindView(R.id.keys_backup_setup_step3_button)
|
||||
lateinit var mFinishButton: Button
|
||||
|
||||
@BindView(R.id.keys_backup_recovery_key_text)
|
||||
lateinit var mRecoveryKeyTextView: TextView
|
||||
|
||||
@BindView(R.id.keys_backup_setup_step3_line2_text)
|
||||
lateinit var mRecoveryKeyLabel2TextView: TextView
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep3Binding {
|
||||
return FragmentKeysBackupSetupStep3Binding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||
|
||||
|
@ -70,10 +64,10 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
viewModel.passphrase.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNullOrBlank()) {
|
||||
// Recovery was generated, so show key and options to save
|
||||
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.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)
|
||||
views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title_no_passphrase)
|
||||
|
||||
mRecoveryKeyTextView.text = viewModel.recoveryKey.value!!
|
||||
views.keysBackupSetupStep3RecoveryKeyText.text = viewModel.recoveryKey.value!!
|
||||
.replace(" ", "")
|
||||
.chunked(16)
|
||||
.joinToString("\n") {
|
||||
|
@ -81,17 +75,24 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
.chunked(4)
|
||||
.joinToString(" ")
|
||||
}
|
||||
mRecoveryKeyTextView.isVisible = true
|
||||
views.keysBackupSetupStep3RecoveryKeyText.isVisible = true
|
||||
} else {
|
||||
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2)
|
||||
mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
|
||||
mRecoveryKeyTextView.isVisible = false
|
||||
views.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2)
|
||||
views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
|
||||
views.keysBackupSetupStep3RecoveryKeyText.isVisible = false
|
||||
}
|
||||
})
|
||||
|
||||
setupViews()
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step3_button)
|
||||
fun onFinishButtonClicked() {
|
||||
private fun setupViews() {
|
||||
views.keysBackupSetupStep3FinishButton.setOnClickListener { onFinishButtonClicked() }
|
||||
views.keysBackupSetupStep3CopyButton.setOnClickListener { onCopyButtonClicked() }
|
||||
views.keysBackupSetupStep3RecoveryKeyText.setOnClickListener { onRecoveryKeyClicked() }
|
||||
}
|
||||
|
||||
private fun onFinishButtonClicked() {
|
||||
if (viewModel.megolmBackupCreationInfo == null) {
|
||||
// nothing
|
||||
} else {
|
||||
|
@ -103,8 +104,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_setup_step3_copy_button)
|
||||
fun onCopyButtonClicked() {
|
||||
private fun onCopyButtonClicked() {
|
||||
val dialog = BottomSheetDialog(requireActivity())
|
||||
dialog.setContentView(R.layout.bottom_sheet_save_recovery_key)
|
||||
dialog.setCanceledOnTouchOutside(true)
|
||||
|
@ -155,8 +155,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||
dialog.show()
|
||||
}
|
||||
|
||||
@OnClick(R.id.keys_backup_recovery_key_text)
|
||||
fun onRecoveryKeyClicked() {
|
||||
private fun onRecoveryKeyClicked() {
|
||||
viewModel.recoveryKey.value?.let {
|
||||
viewModel.copyHasBeenMade = true
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ import im.vector.app.core.extensions.commitTransaction
|
|||
import im.vector.app.core.platform.SimpleFragmentActivity
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.features.crypto.recover.SetupMode
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
@ -65,7 +64,7 @@ class SharedSecureStorageActivity :
|
|||
super.onCreate(savedInstanceState)
|
||||
supportFragmentManager.addFragmentOnAttachListener(this)
|
||||
|
||||
toolbar.visibility = View.GONE
|
||||
views.toolbar.visibility = View.GONE
|
||||
|
||||
viewModel.observeViewEvents { observeViewEvents(it) }
|
||||
|
||||
|
@ -132,7 +131,7 @@ class SharedSecureStorageActivity :
|
|||
}
|
||||
|
||||
override fun onAttachFragment(fragmentManager: FragmentManager, fragment: Fragment) {
|
||||
if (fragment is VectorBaseBottomSheetDialogFragment) {
|
||||
if (fragment is VectorBaseBottomSheetDialogFragment<*>) {
|
||||
fragment.resultListener = this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ package im.vector.app.features.crypto.quads
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.jakewharton.rxbinding3.widget.editorActionEvents
|
||||
|
@ -27,23 +29,26 @@ import im.vector.app.R
|
|||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||
import im.vector.app.databinding.FragmentSsssAccessFromKeyBinding
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_ssss_access_from_key.*
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment<FragmentSsssAccessFromKeyBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_ssss_access_from_key
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromKeyBinding {
|
||||
return FragmentSsssAccessFromKeyBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
ssss_restore_with_key_text.text = getString(R.string.enter_secret_storage_input_key)
|
||||
views.ssssRestoreWithKeyText.text = getString(R.string.enter_secret_storage_input_key)
|
||||
|
||||
ssss_key_enter_edittext.editorActionEvents()
|
||||
views.ssssKeyEnterEdittext.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -53,35 +58,35 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_key_enter_edittext.textChanges()
|
||||
views.ssssKeyEnterEdittext.textChanges()
|
||||
.skipInitialValue()
|
||||
.subscribe {
|
||||
ssss_key_enter_til.error = null
|
||||
ssss_key_submit.isEnabled = it.isNotBlank()
|
||||
views.ssssKeyEnterTil.error = null
|
||||
views.ssssKeySubmit.isEnabled = it.isNotBlank()
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_key_use_file.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
views.ssssKeyUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
|
||||
ssss_key_reset.clickableView.debouncedClicks {
|
||||
views.ssssKeyReset.views.itemVerificationClickableZone.debouncedClicks {
|
||||
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
|
||||
}
|
||||
|
||||
sharedViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is SharedSecureStorageViewEvent.KeyInlineError -> {
|
||||
ssss_key_enter_til.error = it.message
|
||||
views.ssssKeyEnterTil.error = it.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssss_key_submit.debouncedClicks { submit() }
|
||||
views.ssssKeySubmit.debouncedClicks { submit() }
|
||||
}
|
||||
|
||||
fun submit() {
|
||||
val text = ssss_key_enter_edittext.text.toString()
|
||||
val text = views.ssssKeyEnterEdittext.text.toString()
|
||||
if (text.isBlank()) return // Should not reach this point as button disabled
|
||||
ssss_key_submit.isEnabled = false
|
||||
views.ssssKeySubmit.isEnabled = false
|
||||
sharedViewModel.handle(SharedSecureStorageAction.SubmitKey(text))
|
||||
}
|
||||
|
||||
|
@ -93,7 +98,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||
?.bufferedReader()
|
||||
?.use { it.readText() }
|
||||
?.let {
|
||||
ssss_key_enter_edittext.setText(it)
|
||||
views.ssssKeyEnterEdittext.setText(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.crypto.quads
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.text.toSpannable
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -29,16 +31,19 @@ import im.vector.app.core.extensions.showPassword
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentSsssAccessFromPassphraseBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_ssss_access_from_passphrase
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromPassphraseBinding {
|
||||
return FragmentSsssAccessFromPassphraseBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||
|
||||
|
@ -48,7 +53,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||
// If has passphrase
|
||||
val pass = getString(R.string.recovery_passphrase)
|
||||
val key = getString(R.string.recovery_key)
|
||||
ssss_restore_with_passphrase_warning_text.text = getString(
|
||||
views.ssssRestoreWithPassphraseWarningText.text = getString(
|
||||
R.string.enter_secret_storage_passphrase_or_key,
|
||||
pass,
|
||||
key
|
||||
|
@ -57,7 +62,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||
.colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||
.colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||
|
||||
ssss_passphrase_enter_edittext.editorActionEvents()
|
||||
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -67,40 +72,40 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_passphrase_enter_edittext.textChanges()
|
||||
views.ssssPassphraseEnterEdittext.textChanges()
|
||||
.subscribe {
|
||||
ssss_passphrase_enter_til.error = null
|
||||
ssss_passphrase_submit.isEnabled = it.isNotBlank()
|
||||
views.ssssPassphraseEnterTil.error = null
|
||||
views.ssssPassphraseSubmit.isEnabled = it.isNotBlank()
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_passphrase_reset.clickableView.debouncedClicks {
|
||||
views.ssssPassphraseReset.views.itemVerificationClickableZone.debouncedClicks {
|
||||
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
|
||||
}
|
||||
|
||||
sharedViewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is SharedSecureStorageViewEvent.InlineError -> {
|
||||
ssss_passphrase_enter_til.error = it.message
|
||||
views.ssssPassphraseEnterTil.error = it.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssss_passphrase_submit.debouncedClicks { submit() }
|
||||
ssss_passphrase_use_key.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
|
||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
|
||||
views.ssssPassphraseSubmit.debouncedClicks { submit() }
|
||||
views.ssssPassphraseUseKey.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
|
||||
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
|
||||
}
|
||||
|
||||
fun submit() {
|
||||
val text = ssss_passphrase_enter_edittext.text.toString()
|
||||
val text = views.ssssPassphraseEnterEdittext.text.toString()
|
||||
if (text.isBlank()) return // Should not reach this point as button disabled
|
||||
ssss_passphrase_submit.isEnabled = false
|
||||
views.ssssPassphraseSubmit.isEnabled = false
|
||||
sharedViewModel.handle(SharedSecureStorageAction.SubmitPassphrase(text))
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
val shouldBeVisible = state.passphraseVisible
|
||||
ssss_passphrase_enter_edittext.showPassword(shouldBeVisible)
|
||||
ssss_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||
views.ssssViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,41 +17,47 @@
|
|||
package im.vector.app.features.crypto.quads
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentSsssResetAllBinding
|
||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||
import kotlinx.android.synthetic.main.fragment_ssss_reset_all.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class SharedSecuredStorageResetAllFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class SharedSecuredStorageResetAllFragment @Inject constructor()
|
||||
: VectorBaseFragment<FragmentSsssResetAllBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_ssss_reset_all
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssResetAllBinding {
|
||||
return FragmentSsssResetAllBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
ssss_reset_button_reset.debouncedClicks {
|
||||
views.ssssResetButtonReset.debouncedClicks {
|
||||
sharedViewModel.handle(SharedSecureStorageAction.DoResetAll)
|
||||
}
|
||||
|
||||
ssss_reset_button_cancel.debouncedClicks {
|
||||
views.ssssResetButtonCancel.debouncedClicks {
|
||||
sharedViewModel.handle(SharedSecureStorageAction.Back)
|
||||
}
|
||||
|
||||
ssss_reset_other_devices.debouncedClicks {
|
||||
views.ssssResetOtherDevices.debouncedClicks {
|
||||
withState(sharedViewModel) {
|
||||
DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST")
|
||||
}
|
||||
}
|
||||
|
||||
sharedViewModel.subscribe(this) { state ->
|
||||
ssss_reset_other_devices.setTextOrHide(
|
||||
views.ssssResetOtherDevices.setTextOrHide(
|
||||
state.activeDeviceCount
|
||||
.takeIf { it > 0 }
|
||||
?.let { resources.getQuantityString(R.plurals.secure_backup_reset_devices_you_can_verify, it, it) }
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.text.toSpannable
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -30,18 +32,19 @@ import im.vector.app.core.extensions.showPassword
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.databinding.FragmentBootstrapEnterAccountPasswordBinding
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_account_password.*
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_view_show_password
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapAccountPasswordFragment @Inject constructor(
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentBootstrapEnterAccountPasswordBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_account_password
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterAccountPasswordBinding {
|
||||
return FragmentBootstrapEnterAccountPasswordBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
|
@ -49,13 +52,13 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val recPassPhrase = getString(R.string.account_password)
|
||||
bootstrapDescriptionText.text = getString(R.string.enter_account_password, recPassPhrase)
|
||||
views.bootstrapDescriptionText.text = getString(R.string.enter_account_password, recPassPhrase)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(recPassPhrase, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||
|
||||
bootstrapAccountPasswordEditText.hint = getString(R.string.account_password)
|
||||
views.bootstrapAccountPasswordEditText.hint = getString(R.string.account_password)
|
||||
|
||||
bootstrapAccountPasswordEditText.editorActionEvents()
|
||||
views.bootstrapAccountPasswordEditText.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -65,21 +68,21 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
bootstrapAccountPasswordEditText.textChanges()
|
||||
views.bootstrapAccountPasswordEditText.textChanges()
|
||||
.distinctUntilChanged()
|
||||
.subscribe {
|
||||
if (!it.isNullOrBlank()) {
|
||||
bootstrapAccountPasswordTil.error = null
|
||||
views.bootstrapAccountPasswordTil.error = null
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
bootstrapPasswordButton.debouncedClicks { submit() }
|
||||
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
views.bootstrapPasswordButton.debouncedClicks { submit() }
|
||||
|
||||
withState(sharedViewModel) { state ->
|
||||
(state.step as? BootstrapStep.AccountPassword)?.failure?.let {
|
||||
bootstrapAccountPasswordTil.error = it
|
||||
views.bootstrapAccountPasswordTil.error = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,9 +91,9 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||
if (state.step !is BootstrapStep.AccountPassword) {
|
||||
return@withState
|
||||
}
|
||||
val accountPassword = bootstrapAccountPasswordEditText.text?.toString()
|
||||
val accountPassword = views.bootstrapAccountPasswordEditText.text?.toString()
|
||||
if (accountPassword.isNullOrBlank()) {
|
||||
bootstrapAccountPasswordTil.error = getString(R.string.error_empty_field_your_password)
|
||||
views.bootstrapAccountPasswordTil.error = getString(R.string.error_empty_field_your_password)
|
||||
} else {
|
||||
view?.hideKeyboard()
|
||||
sharedViewModel.handle(BootstrapActions.ReAuth(accountPassword))
|
||||
|
@ -100,8 +103,8 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
if (state.step is BootstrapStep.AccountPassword) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
bootstrapAccountPasswordEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.bootstrapAccountPasswordEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,12 +36,12 @@ import im.vector.app.core.di.ScreenComponent
|
|||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_bootstrap.*
|
||||
import im.vector.app.databinding.BottomSheetBootstrapBinding
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBootstrapBinding>() {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
|
@ -59,7 +59,9 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
injector.inject(this)
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_bootstrap
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetBootstrapBinding {
|
||||
return BottomSheetBootstrapBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -120,60 +122,60 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
override fun invalidate() = withState(viewModel) { state ->
|
||||
when (state.step) {
|
||||
is BootstrapStep.CheckingMigration -> {
|
||||
bootstrapIcon.isVisible = false
|
||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||
views.bootstrapIcon.isVisible = false
|
||||
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||
showFragment(BootstrapWaitingFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.FirstForm -> {
|
||||
bootstrapIcon.isVisible = false
|
||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||
views.bootstrapIcon.isVisible = false
|
||||
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||
showFragment(BootstrapSetupRecoveryKeyFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.SetupPassphrase -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||
showFragment(BootstrapEnterPassphraseFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.ConfirmPassphrase -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||
showFragment(BootstrapConfirmPassphraseFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.AccountPassword -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
|
||||
bootstrapTitleText.text = getString(R.string.account_password)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
|
||||
views.bootstrapTitleText.text = getString(R.string.account_password)
|
||||
showFragment(BootstrapAccountPasswordFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.Initializing -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
views.bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
|
||||
showFragment(BootstrapWaitingFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.SaveRecoveryKey -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
|
||||
showFragment(BootstrapSaveRecoveryKeyFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.DoneSuccess -> {
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||
views.bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
|
||||
showFragment(BootstrapConclusionFragment::class, Bundle())
|
||||
}
|
||||
is BootstrapStep.GetBackupSecretForMigration -> {
|
||||
val isKey = state.step.useKey()
|
||||
val drawableRes = if (isKey) R.drawable.ic_security_key_24dp else R.drawable.ic_security_phrase_24dp
|
||||
bootstrapIcon.isVisible = true
|
||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
|
||||
views.bootstrapIcon.isVisible = true
|
||||
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
|
||||
requireContext(),
|
||||
drawableRes)
|
||||
)
|
||||
bootstrapTitleText.text = getString(R.string.upgrade_security)
|
||||
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
|
||||
showFragment(BootstrapMigrateBackupFragment::class, Bundle())
|
||||
}
|
||||
}.exhaustive
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.text.toSpannable
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -25,27 +27,30 @@ import im.vector.app.R
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_conclusion.*
|
||||
import im.vector.app.databinding.FragmentBootstrapConclusionBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapConclusionFragment @Inject constructor(
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentBootstrapConclusionBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_conclusion
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapConclusionBinding {
|
||||
return FragmentBootstrapConclusionBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
bootstrapConclusionContinue.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) }
|
||||
views.bootstrapConclusionContinue.views.itemVerificationClickableZone.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) }
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
if (state.step !is BootstrapStep.DoneSuccess) return@withState
|
||||
|
||||
bootstrapConclusionText.text = getString(
|
||||
views.bootstrapConclusionText.text = getString(
|
||||
R.string.bootstrap_cross_signing_success,
|
||||
getString(R.string.recovery_passphrase),
|
||||
getString(R.string.message_key)
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.view.isGone
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
|
@ -28,32 +30,36 @@ import im.vector.app.R
|
|||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class BootstrapConfirmPassphraseFragment @Inject constructor()
|
||||
: VectorBaseFragment<FragmentBootstrapEnterPassphraseBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
|
||||
return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
ssss_passphrase_security_progress.isGone = true
|
||||
views.ssssPassphraseSecurityProgress.isGone = true
|
||||
|
||||
bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_again_notice)
|
||||
ssss_passphrase_enter_edittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||
views.bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_again_notice)
|
||||
views.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||
|
||||
withState(sharedViewModel) {
|
||||
// set initial value (useful when coming back)
|
||||
ssss_passphrase_enter_edittext.setText(it.passphraseRepeat ?: "")
|
||||
ssss_passphrase_enter_edittext.requestFocus()
|
||||
views.ssssPassphraseEnterEdittext.setText(it.passphraseRepeat ?: "")
|
||||
views.ssssPassphraseEnterEdittext.requestFocus()
|
||||
}
|
||||
|
||||
ssss_passphrase_enter_edittext.editorActionEvents()
|
||||
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -63,9 +69,9 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_passphrase_enter_edittext.textChanges()
|
||||
views.ssssPassphraseEnterEdittext.textChanges()
|
||||
.subscribe {
|
||||
ssss_passphrase_enter_til.error = null
|
||||
views.ssssPassphraseEnterTil.error = null
|
||||
sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it?.toString() ?: ""))
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
@ -78,20 +84,20 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||
// }
|
||||
}
|
||||
|
||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
bootstrapSubmit.debouncedClicks { submit() }
|
||||
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
views.bootstrapSubmit.debouncedClicks { submit() }
|
||||
}
|
||||
|
||||
private fun submit() = withState(sharedViewModel) { state ->
|
||||
if (state.step !is BootstrapStep.ConfirmPassphrase) {
|
||||
return@withState
|
||||
}
|
||||
val passphrase = ssss_passphrase_enter_edittext.text?.toString()
|
||||
val passphrase = views.ssssPassphraseEnterEdittext.text?.toString()
|
||||
when {
|
||||
passphrase.isNullOrBlank() ->
|
||||
ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
|
||||
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_empty_error_message)
|
||||
passphrase != state.passphrase ->
|
||||
ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_does_not_match)
|
||||
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_passphrase_does_not_match)
|
||||
else -> {
|
||||
view?.hideKeyboard()
|
||||
sharedViewModel.handle(BootstrapActions.DoInitialize(passphrase))
|
||||
|
@ -102,8 +108,8 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -26,29 +28,33 @@ import com.jakewharton.rxbinding3.widget.textChanges
|
|||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
|
||||
import im.vector.app.features.settings.VectorLocale
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class BootstrapEnterPassphraseFragment @Inject constructor()
|
||||
: VectorBaseFragment<FragmentBootstrapEnterPassphraseBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
|
||||
return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
|
||||
ssss_passphrase_enter_edittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||
views.bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
|
||||
views.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||
|
||||
withState(sharedViewModel) {
|
||||
// set initial value (useful when coming back)
|
||||
ssss_passphrase_enter_edittext.setText(it.passphrase ?: "")
|
||||
views.ssssPassphraseEnterEdittext.setText(it.passphrase ?: "")
|
||||
}
|
||||
ssss_passphrase_enter_edittext.editorActionEvents()
|
||||
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -58,7 +64,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
ssss_passphrase_enter_edittext.textChanges()
|
||||
views.ssssPassphraseEnterEdittext.textChanges()
|
||||
.subscribe {
|
||||
// ssss_passphrase_enter_til.error = null
|
||||
sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
||||
|
@ -74,8 +80,8 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||
// }
|
||||
}
|
||||
|
||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
bootstrapSubmit.debouncedClicks { submit() }
|
||||
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
views.bootstrapSubmit.debouncedClicks { submit() }
|
||||
}
|
||||
|
||||
private fun submit() = withState(sharedViewModel) { state ->
|
||||
|
@ -83,11 +89,11 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||
return@withState
|
||||
}
|
||||
val score = state.passphraseStrength.invoke()?.score
|
||||
val passphrase = ssss_passphrase_enter_edittext.text?.toString()
|
||||
val passphrase = views.ssssPassphraseEnterEdittext.text?.toString()
|
||||
if (passphrase.isNullOrBlank()) {
|
||||
ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
|
||||
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_empty_error_message)
|
||||
} else if (score != 4) {
|
||||
ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_too_weak)
|
||||
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_passphrase_too_weak)
|
||||
} else {
|
||||
sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
|
||||
}
|
||||
|
@ -96,21 +102,21 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
if (state.step is BootstrapStep.SetupPassphrase) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
|
||||
state.passphraseStrength.invoke()?.let { strength ->
|
||||
val score = strength.score
|
||||
ssss_passphrase_security_progress.strength = score
|
||||
views.ssssPassphraseSecurityProgress.strength = score
|
||||
if (score in 1..3) {
|
||||
val hint =
|
||||
strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() }
|
||||
?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()
|
||||
if (hint != null && hint != ssss_passphrase_enter_til.error.toString()) {
|
||||
ssss_passphrase_enter_til.error = hint
|
||||
if (hint != null && hint != views.ssssPassphraseEnterTil.error.toString()) {
|
||||
views.ssssPassphraseEnterTil.error = hint
|
||||
}
|
||||
} else {
|
||||
ssss_passphrase_enter_til.error = null
|
||||
views.ssssPassphraseEnterTil.error = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ import android.os.Bundle
|
|||
import android.text.InputType.TYPE_CLASS_TEXT
|
||||
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
||||
import android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -37,9 +39,9 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||
import im.vector.app.databinding.FragmentBootstrapMigrateBackupBinding
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_migrate_backup.*
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -47,9 +49,11 @@ import javax.inject.Inject
|
|||
|
||||
class BootstrapMigrateBackupFragment @Inject constructor(
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentBootstrapMigrateBackupBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_migrate_backup
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapMigrateBackupBinding {
|
||||
return FragmentBootstrapMigrateBackupBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
|
@ -58,9 +62,9 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
|
||||
withState(sharedViewModel) {
|
||||
// set initial value (useful when coming back)
|
||||
bootstrapMigrateEditText.setText(it.passphrase ?: "")
|
||||
views.bootstrapMigrateEditText.setText(it.passphrase ?: "")
|
||||
}
|
||||
bootstrapMigrateEditText.editorActionEvents()
|
||||
views.bootstrapMigrateEditText.editorActionEvents()
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
|
@ -70,19 +74,19 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
bootstrapMigrateEditText.textChanges()
|
||||
views.bootstrapMigrateEditText.textChanges()
|
||||
.skipInitialValue()
|
||||
.subscribe {
|
||||
bootstrapRecoveryKeyEnterTil.error = null
|
||||
views.bootstrapRecoveryKeyEnterTil.error = null
|
||||
// sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
// sharedViewModel.observeViewEvents {}
|
||||
bootstrapMigrateContinueButton.debouncedClicks { submit() }
|
||||
bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
|
||||
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
views.bootstrapMigrateContinueButton.debouncedClicks { submit() }
|
||||
views.bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||
views.bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
|
||||
views.bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||
}
|
||||
|
||||
private fun submit() = withState(sharedViewModel) { state ->
|
||||
|
@ -90,12 +94,12 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
|
||||
val isEnteringKey = getBackupSecretForMigration.useKey()
|
||||
|
||||
val secret = bootstrapMigrateEditText.text?.toString()
|
||||
val secret = views.bootstrapMigrateEditText.text?.toString()
|
||||
if (secret.isNullOrEmpty()) {
|
||||
val errRes = if (isEnteringKey) R.string.recovery_key_empty_error_message else R.string.passphrase_empty_error_message
|
||||
bootstrapRecoveryKeyEnterTil.error = getString(errRes)
|
||||
views.bootstrapRecoveryKeyEnterTil.error = getString(errRes)
|
||||
} else if (isEnteringKey && !isValidRecoveryKey(secret)) {
|
||||
bootstrapRecoveryKeyEnterTil.error = getString(R.string.bootstrap_invalid_recovery_key)
|
||||
views.bootstrapRecoveryKeyEnterTil.error = getString(R.string.bootstrap_invalid_recovery_key)
|
||||
} else {
|
||||
view?.hideKeyboard()
|
||||
if (isEnteringKey) {
|
||||
|
@ -112,38 +116,38 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
val isEnteringKey = getBackupSecretForMigration.useKey()
|
||||
|
||||
if (isEnteringKey) {
|
||||
bootstrapMigrateShowPassword.isVisible = false
|
||||
bootstrapMigrateEditText.inputType = TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_VISIBLE_PASSWORD or TYPE_TEXT_FLAG_MULTI_LINE
|
||||
views.bootstrapMigrateShowPassword.isVisible = false
|
||||
views.bootstrapMigrateEditText.inputType = TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_VISIBLE_PASSWORD or TYPE_TEXT_FLAG_MULTI_LINE
|
||||
|
||||
val recKey = getString(R.string.bootstrap_migration_backup_recovery_key)
|
||||
bootstrapDescriptionText.text = getString(R.string.enter_account_password, recKey)
|
||||
views.bootstrapDescriptionText.text = getString(R.string.enter_account_password, recKey)
|
||||
|
||||
bootstrapMigrateEditText.hint = recKey
|
||||
views.bootstrapMigrateEditText.hint = recKey
|
||||
|
||||
bootstrapMigrateEditText.hint = recKey
|
||||
bootstrapMigrateForgotPassphrase.isVisible = false
|
||||
bootstrapMigrateUseFile.isVisible = true
|
||||
views.bootstrapMigrateEditText.hint = recKey
|
||||
views.bootstrapMigrateForgotPassphrase.isVisible = false
|
||||
views.bootstrapMigrateUseFile.isVisible = true
|
||||
} else {
|
||||
bootstrapMigrateShowPassword.isVisible = true
|
||||
views.bootstrapMigrateShowPassword.isVisible = true
|
||||
|
||||
if (state.step is BootstrapStep.GetBackupSecretPassForMigration) {
|
||||
val isPasswordVisible = state.step.isPasswordVisible
|
||||
bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||
bootstrapMigrateShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
views.bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||
views.bootstrapMigrateShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
|
||||
bootstrapDescriptionText.text = getString(R.string.bootstrap_migration_enter_backup_password)
|
||||
views.bootstrapDescriptionText.text = getString(R.string.bootstrap_migration_enter_backup_password)
|
||||
|
||||
bootstrapMigrateEditText.hint = getString(R.string.passphrase_enter_passphrase)
|
||||
views.bootstrapMigrateEditText.hint = getString(R.string.passphrase_enter_passphrase)
|
||||
|
||||
bootstrapMigrateForgotPassphrase.isVisible = true
|
||||
views.bootstrapMigrateForgotPassphrase.isVisible = true
|
||||
|
||||
val recKey = getString(R.string.bootstrap_migration_use_recovery_key)
|
||||
bootstrapMigrateForgotPassphrase.text = getString(R.string.bootstrap_migration_with_passphrase_helper_with_link, recKey)
|
||||
views.bootstrapMigrateForgotPassphrase.text = getString(R.string.bootstrap_migration_with_passphrase_helper_with_link, recKey)
|
||||
.toSpannable()
|
||||
.colorizeMatchingText(recKey, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||
|
||||
bootstrapMigrateUseFile.isVisible = false
|
||||
views.bootstrapMigrateUseFile.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,7 +159,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||
?.bufferedReader()
|
||||
?.use { it.readText() }
|
||||
?.let {
|
||||
bootstrapMigrateEditText.setText(it)
|
||||
views.bootstrapMigrateEditText.setText(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ import android.app.Activity
|
|||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -30,7 +32,8 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||
import im.vector.app.core.utils.toast
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_save_key.*
|
||||
import im.vector.app.databinding.FragmentBootstrapSaveKeyBinding
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -38,18 +41,20 @@ import javax.inject.Inject
|
|||
|
||||
class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
||||
private val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentBootstrapSaveKeyBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_save_key
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSaveKeyBinding {
|
||||
return FragmentBootstrapSaveKeyBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() }
|
||||
recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() }
|
||||
recoveryContinue.clickableView.debouncedClicks {
|
||||
views.recoverySave.views.itemVerificationClickableZone.debouncedClicks { downloadRecoveryKey() }
|
||||
views.recoveryCopy.views.itemVerificationClickableZone.debouncedClicks { shareRecoveryKey() }
|
||||
views.recoveryContinue.views.itemVerificationClickableZone.debouncedClicks {
|
||||
// We do not display the final Fragment anymore
|
||||
// TODO Do some cleanup
|
||||
// sharedViewModel.handle(BootstrapActions.GoToCompleted)
|
||||
|
@ -112,7 +117,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||
val step = state.step
|
||||
if (step !is BootstrapStep.SaveRecoveryKey) return@withState
|
||||
|
||||
recoveryContinue.isVisible = step.isSaved
|
||||
bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
||||
views.recoveryContinue.isVisible = step.isSaved
|
||||
views.bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,24 @@
|
|||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_setup_recovery.*
|
||||
import im.vector.app.databinding.FragmentBootstrapSetupRecoveryBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class BootstrapSetupRecoveryKeyFragment @Inject constructor()
|
||||
: VectorBaseFragment<FragmentBootstrapSetupRecoveryBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_setup_recovery
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSetupRecoveryBinding {
|
||||
return FragmentBootstrapSetupRecoveryBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
|
@ -36,15 +42,15 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// Actions when a key backup exist
|
||||
bootstrapSetupSecureSubmit.clickableView.debouncedClicks {
|
||||
views.bootstrapSetupSecureSubmit.views.itemVerificationClickableZone.debouncedClicks {
|
||||
sharedViewModel.handle(BootstrapActions.StartKeyBackupMigration)
|
||||
}
|
||||
|
||||
// Actions when there is no key backup
|
||||
bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks {
|
||||
views.bootstrapSetupSecureUseSecurityKey.views.itemVerificationClickableZone.debouncedClicks {
|
||||
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = false))
|
||||
}
|
||||
bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks {
|
||||
views.bootstrapSetupSecureUseSecurityPassphrase.views.itemVerificationClickableZone.debouncedClicks {
|
||||
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = true))
|
||||
}
|
||||
}
|
||||
|
@ -53,23 +59,23 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
|
|||
if (state.step is BootstrapStep.FirstForm) {
|
||||
if (state.step.keyBackUpExist) {
|
||||
// Display the set up action
|
||||
bootstrapSetupSecureSubmit.isVisible = true
|
||||
bootstrapSetupSecureUseSecurityKey.isVisible = false
|
||||
bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
|
||||
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
|
||||
views.bootstrapSetupSecureSubmit.isVisible = true
|
||||
views.bootstrapSetupSecureUseSecurityKey.isVisible = false
|
||||
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
|
||||
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
|
||||
} else {
|
||||
if (state.step.reset) {
|
||||
bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
|
||||
bootstrapSetupWarningTextView.isVisible = true
|
||||
views.bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
|
||||
views.bootstrapSetupWarningTextView.isVisible = true
|
||||
} else {
|
||||
bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
|
||||
bootstrapSetupWarningTextView.isVisible = false
|
||||
views.bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
|
||||
views.bootstrapSetupWarningTextView.isVisible = false
|
||||
}
|
||||
// Choose between create a passphrase or use a recovery key
|
||||
bootstrapSetupSecureSubmit.isVisible = false
|
||||
bootstrapSetupSecureUseSecurityKey.isVisible = true
|
||||
bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
|
||||
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
|
||||
views.bootstrapSetupSecureSubmit.isVisible = false
|
||||
views.bootstrapSetupSecureUseSecurityKey.isVisible = true
|
||||
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
|
||||
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,26 +16,31 @@
|
|||
|
||||
package im.vector.app.features.crypto.recover
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import kotlinx.android.synthetic.main.fragment_bootstrap_waiting.*
|
||||
import im.vector.app.databinding.FragmentBootstrapWaitingBinding
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() {
|
||||
class BootstrapWaitingFragment @Inject constructor()
|
||||
: VectorBaseFragment<FragmentBootstrapWaitingBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_bootstrap_waiting
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapWaitingBinding {
|
||||
return FragmentBootstrapWaitingBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||
|
||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||
when (state.step) {
|
||||
is BootstrapStep.Initializing -> {
|
||||
bootstrapLoadingStatusText.isVisible = true
|
||||
bootstrapDescriptionText.isVisible = true
|
||||
bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
|
||||
views.bootstrapLoadingStatusText.isVisible = true
|
||||
views.bootstrapDescriptionText.isVisible = true
|
||||
views.bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
|
||||
}
|
||||
// is BootstrapStep.CheckingMigration -> {
|
||||
// bootstrapLoadingStatusText.isVisible = false
|
||||
|
@ -43,8 +48,8 @@ class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() {
|
|||
// }
|
||||
else -> {
|
||||
// just show the spinner
|
||||
bootstrapLoadingStatusText.isVisible = false
|
||||
bootstrapDescriptionText.isVisible = false
|
||||
views.bootstrapLoadingStatusText.isVisible = false
|
||||
views.bootstrapDescriptionText.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ package im.vector.app.features.crypto.recover
|
|||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.view.KeyEvent
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.app.R
|
||||
import im.vector.app.databinding.DialogRecoveryKeySavedInfoBinding
|
||||
import me.gujun.android.span.image
|
||||
import me.gujun.android.span.span
|
||||
|
||||
|
@ -30,10 +30,9 @@ class KeepItSafeDialog {
|
|||
|
||||
fun show(activity: Activity) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_recovery_key_saved_info, null)
|
||||
val views = DialogRecoveryKeySavedInfoBinding.bind(dialogLayout)
|
||||
|
||||
val descriptionText = dialogLayout.findViewById<TextView>(R.id.keepItSafeText)
|
||||
|
||||
descriptionText.text = span {
|
||||
views.keepItSafeText.text = span {
|
||||
span {
|
||||
image(ContextCompat.getDrawable(activity, R.drawable.ic_check_on)!!)
|
||||
+" "
|
||||
|
|
|
@ -69,7 +69,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
context.getString(R.string.sas_incoming_request_notif_content, name),
|
||||
R.drawable.ic_shield_black,
|
||||
shouldBeDisplayedIn = { activity ->
|
||||
if (activity is VectorBaseActivity) {
|
||||
if (activity is VectorBaseActivity<*>) {
|
||||
// TODO a bit too ugly :/
|
||||
activity.supportFragmentManager.findFragmentByTag(VerificationBottomSheet.WAITING_SELF_VERIF_TAG)?.let {
|
||||
false.also {
|
||||
|
@ -82,7 +82,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
)
|
||||
.apply {
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
addButton(
|
||||
context.getString(R.string.action_open),
|
||||
Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||
)
|
||||
.apply {
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
val roomId = pr.roomId
|
||||
if (roomId.isNullOrBlank()) {
|
||||
it.navigator.waitSessionVerification(it)
|
||||
|
|
|
@ -16,10 +16,14 @@
|
|||
|
||||
package im.vector.app.features.crypto.verification
|
||||
|
||||
import im.vector.app.R
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentProgressBinding
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() {
|
||||
override fun getLayoutResId() = R.layout.fragment_progress
|
||||
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment<FragmentProgressBinding>() {
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentProgressBinding {
|
||||
return FragmentProgressBinding.inflate(inflater, container, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,12 @@ import android.app.Dialog
|
|||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import butterknife.BindView
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -37,6 +36,7 @@ import im.vector.app.core.extensions.exhaustive
|
|||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationBinding
|
||||
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
||||
|
@ -48,7 +48,7 @@ import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrS
|
|||
import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
||||
|
@ -60,7 +60,7 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
||||
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
|
||||
|
||||
@Parcelize
|
||||
data class VerificationArgs(
|
||||
|
@ -86,16 +86,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
injector.inject(this)
|
||||
}
|
||||
|
||||
@BindView(R.id.verificationRequestName)
|
||||
lateinit var otherUserNameText: TextView
|
||||
|
||||
@BindView(R.id.verificationRequestShield)
|
||||
lateinit var otherUserShield: ImageView
|
||||
|
||||
@BindView(R.id.verificationRequestAvatar)
|
||||
lateinit var otherUserAvatarImageView: ImageView
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
|
||||
return BottomSheetVerificationBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
init {
|
||||
isCancelable = false
|
||||
|
@ -126,7 +119,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
}
|
||||
VerificationBottomSheetViewEvents.GoToSettings -> {
|
||||
dismiss()
|
||||
(activity as? VectorBaseActivity)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
|
||||
(activity as? VectorBaseActivity<*>)?.let { activity ->
|
||||
activity.navigator.openSettings(activity, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
|
||||
}
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
@ -163,27 +158,27 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
override fun invalidate() = withState(viewModel) { state ->
|
||||
state.otherUserMxItem?.let { matrixItem ->
|
||||
if (state.isMe) {
|
||||
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
|
||||
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
|
||||
if (state.sasTransactionState == VerificationTxState.Verified
|
||||
|| state.qrTransactionState == VerificationTxState.Verified
|
||||
|| state.verifiedFromPrivateKeys) {
|
||||
otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
|
||||
views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
|
||||
} else {
|
||||
otherUserShield.setImageResource(R.drawable.ic_shield_warning)
|
||||
views.otherUserShield.setImageResource(R.drawable.ic_shield_warning)
|
||||
}
|
||||
otherUserNameText.text = getString(
|
||||
views.otherUserNameText.text = getString(
|
||||
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
|
||||
)
|
||||
otherUserShield.isVisible = true
|
||||
views.otherUserShield.isVisible = true
|
||||
} else {
|
||||
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
|
||||
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
|
||||
|
||||
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
||||
otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
|
||||
otherUserShield.isVisible = true
|
||||
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
|
||||
views.otherUserShield.isVisible = true
|
||||
} else {
|
||||
otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
|
||||
otherUserShield.isVisible = false
|
||||
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
|
||||
views.otherUserShield.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,13 +195,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
if (state.userThinkItsNotHim) {
|
||||
otherUserNameText.text = getString(R.string.dialog_title_warning)
|
||||
views.otherUserNameText.text = getString(R.string.dialog_title_warning)
|
||||
showFragment(VerificationNotMeFragment::class, Bundle())
|
||||
return@withState
|
||||
}
|
||||
|
||||
if (state.userWantsToCancel) {
|
||||
otherUserNameText.text = getString(R.string.are_you_sure)
|
||||
views.otherUserNameText.text = getString(R.string.are_you_sure)
|
||||
showFragment(VerificationCancelFragment::class, Bundle())
|
||||
return@withState
|
||||
}
|
||||
|
@ -298,7 +293,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||
// Transaction has not yet started
|
||||
if (state.pendingRequest.invoke()?.cancelConclusion != null) {
|
||||
// The request has been declined, we should dismiss
|
||||
otherUserNameText.text = getString(R.string.verification_cancelled)
|
||||
views.otherUserNameText.text = getString(R.string.verification_cancelled)
|
||||
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
|
||||
false,
|
||||
|
|
|
@ -17,24 +17,29 @@
|
|||
package im.vector.app.features.crypto.verification.cancel
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationCancelFragment @Inject constructor(
|
||||
val controller: VerificationCancelController
|
||||
) : VectorBaseFragment(), VerificationCancelController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationCancelController.Listener {
|
||||
|
||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -42,13 +47,13 @@ class VerificationCancelFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -17,24 +17,29 @@
|
|||
package im.vector.app.features.crypto.verification.cancel
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationNotMeFragment @Inject constructor(
|
||||
val controller: VerificationNotMeController
|
||||
) : VectorBaseFragment(), VerificationNotMeController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationNotMeController.Listener {
|
||||
|
||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -42,13 +47,13 @@ class VerificationNotMeFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@ package im.vector.app.features.crypto.verification.choose
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
|
@ -29,23 +30,27 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.registerForPermissionsResult
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationChooseMethodFragment @Inject constructor(
|
||||
val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
|
||||
val controller: VerificationChooseMethodController
|
||||
) : VectorBaseFragment(), VerificationChooseMethodController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationChooseMethodController.Listener {
|
||||
|
||||
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
|
||||
|
||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -54,13 +59,13 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -17,23 +17,25 @@ package im.vector.app.features.crypto.verification.conclusion
|
|||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationConclusionFragment @Inject constructor(
|
||||
val controller: VerificationConclusionController
|
||||
) : VectorBaseFragment(), VerificationConclusionController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationConclusionController.Listener {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
|
@ -46,7 +48,9 @@ class VerificationConclusionFragment @Inject constructor(
|
|||
|
||||
private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -55,13 +59,13 @@ class VerificationConclusionFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -16,29 +16,34 @@
|
|||
package im.vector.app.features.crypto.verification.emoji
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationEmojiCodeFragment @Inject constructor(
|
||||
val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
|
||||
val controller: VerificationEmojiCodeController
|
||||
) : VectorBaseFragment(), VerificationEmojiCodeController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationEmojiCodeController.Listener {
|
||||
|
||||
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
|
||||
|
||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -47,13 +52,13 @@ class VerificationEmojiCodeFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -18,19 +18,20 @@ package im.vector.app.features.crypto.verification.qrconfirmation
|
|||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationQRWaitingFragment @Inject constructor(
|
||||
val controller: VerificationQRWaitingController
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>() {
|
||||
|
||||
@Parcelize
|
||||
data class Args(
|
||||
|
@ -38,7 +39,9 @@ class VerificationQRWaitingFragment @Inject constructor(
|
|||
val otherUserName: String
|
||||
) : Parcelable
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -49,11 +52,11 @@ class VerificationQRWaitingFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,25 +16,30 @@
|
|||
package im.vector.app.features.crypto.verification.qrconfirmation
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationQrScannedByOtherFragment @Inject constructor(
|
||||
val controller: VerificationQrScannedByOtherController
|
||||
) : VectorBaseFragment(), VerificationQrScannedByOtherController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationQrScannedByOtherController.Listener {
|
||||
|
||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -46,13 +51,13 @@ class VerificationQrScannedByOtherFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -16,25 +16,30 @@
|
|||
package im.vector.app.features.crypto.verification.request
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.parentFragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||
import im.vector.app.features.crypto.verification.VerificationAction
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class VerificationRequestFragment @Inject constructor(
|
||||
val controller: VerificationRequestController
|
||||
) : VectorBaseFragment(), VerificationRequestController.Listener {
|
||||
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||
VerificationRequestController.Listener {
|
||||
|
||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
||||
|
||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
|
||||
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -42,13 +47,13 @@ class VerificationRequestFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
bottomSheetVerificationRecyclerView.cleanup()
|
||||
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||
controller.listener = this
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,11 @@ package im.vector.app.features.discovery
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
|
@ -27,12 +30,12 @@ import im.vector.app.core.extensions.configureWith
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.observeEvent
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.utils.ensureProtocol
|
||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||
import im.vector.app.features.discovery.change.SetIdentityServerFragment
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||
|
||||
import org.matrix.android.sdk.api.session.identity.SharedState
|
||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
|
@ -41,9 +44,12 @@ import javax.inject.Inject
|
|||
class DiscoverySettingsFragment @Inject constructor(
|
||||
private val controller: DiscoverySettingsController,
|
||||
val viewModelFactory: DiscoverySettingsViewModel.Factory
|
||||
) : VectorBaseFragment(), DiscoverySettingsController.Listener {
|
||||
) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
|
||||
DiscoverySettingsController.Listener {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_generic_recycler
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
|
||||
return FragmentGenericRecyclerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val viewModel by fragmentViewModel(DiscoverySettingsViewModel::class)
|
||||
|
||||
|
@ -55,7 +61,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
||||
|
||||
controller.listener = this
|
||||
genericRecyclerView.configureWith(controller)
|
||||
views.genericRecyclerView.configureWith(controller)
|
||||
|
||||
sharedViewModel.navigateEvent.observeEvent(this) {
|
||||
when (it) {
|
||||
|
@ -74,7 +80,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
genericRecyclerView.cleanup()
|
||||
views.genericRecyclerView.cleanup()
|
||||
controller.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
@ -85,7 +91,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category)
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category)
|
||||
|
||||
// If some 3pids are pending, we can try to check if they have been verified here
|
||||
viewModel.handle(DiscoverySettingsAction.Refresh)
|
||||
|
|
|
@ -17,9 +17,12 @@ package im.vector.app.features.discovery.change
|
|||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -29,21 +32,23 @@ import im.vector.app.R
|
|||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||
import im.vector.app.core.extensions.toReducedUrl
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.utils.colorizeMatchingText
|
||||
import im.vector.app.databinding.FragmentSetIdentityServerBinding
|
||||
import im.vector.app.features.discovery.DiscoverySharedViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_set_identity_server.*
|
||||
|
||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||
import javax.inject.Inject
|
||||
|
||||
class SetIdentityServerFragment @Inject constructor(
|
||||
val viewModelFactory: SetIdentityServerViewModel.Factory,
|
||||
val colorProvider: ColorProvider
|
||||
) : VectorBaseFragment() {
|
||||
) : VectorBaseFragment<FragmentSetIdentityServerBinding>() {
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_set_identity_server
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSetIdentityServerBinding {
|
||||
return FragmentSetIdentityServerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val viewModel by fragmentViewModel(SetIdentityServerViewModel::class)
|
||||
|
||||
|
@ -52,11 +57,11 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
override fun invalidate() = withState(viewModel) { state ->
|
||||
if (state.defaultIdentityServerUrl.isNullOrEmpty()) {
|
||||
// No default
|
||||
identityServerSetDefaultNotice.isVisible = false
|
||||
identityServerSetDefaultSubmit.isVisible = false
|
||||
identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice_no_default)
|
||||
views.identityServerSetDefaultNotice.isVisible = false
|
||||
views.identityServerSetDefaultSubmit.isVisible = false
|
||||
views.identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice_no_default)
|
||||
} else {
|
||||
identityServerSetDefaultNotice.text = getString(
|
||||
views.identityServerSetDefaultNotice.text = getString(
|
||||
R.string.identity_server_set_default_notice,
|
||||
state.homeServerUrl.toReducedUrl(),
|
||||
state.defaultIdentityServerUrl.toReducedUrl()
|
||||
|
@ -65,10 +70,10 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
.colorizeMatchingText(state.defaultIdentityServerUrl.toReducedUrl(),
|
||||
colorProvider.getColorFromAttribute(R.attr.riotx_text_primary_body_contrast))
|
||||
|
||||
identityServerSetDefaultNotice.isVisible = true
|
||||
identityServerSetDefaultSubmit.isVisible = true
|
||||
identityServerSetDefaultSubmit.text = getString(R.string.identity_server_set_default_submit, state.defaultIdentityServerUrl.toReducedUrl())
|
||||
identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice)
|
||||
views.identityServerSetDefaultNotice.isVisible = true
|
||||
views.identityServerSetDefaultSubmit.isVisible = true
|
||||
views.identityServerSetDefaultSubmit.text = getString(R.string.identity_server_set_default_submit, state.defaultIdentityServerUrl.toReducedUrl())
|
||||
views.identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,28 +82,28 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
|
||||
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
||||
|
||||
identityServerSetDefaultAlternativeTextInput.setOnEditorActionListener { _, actionId, _ ->
|
||||
views.identityServerSetDefaultAlternativeTextInput.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(identityServerSetDefaultAlternativeTextInput.text.toString()))
|
||||
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(views.identityServerSetDefaultAlternativeTextInput.text.toString()))
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
identityServerSetDefaultAlternativeTextInput
|
||||
views.identityServerSetDefaultAlternativeTextInput
|
||||
.textChanges()
|
||||
.subscribe {
|
||||
identityServerSetDefaultAlternativeTil.error = null
|
||||
identityServerSetDefaultAlternativeSubmit.isEnabled = it.isNotEmpty()
|
||||
views.identityServerSetDefaultAlternativeTil.error = null
|
||||
views.identityServerSetDefaultAlternativeSubmit.isEnabled = it.isNotEmpty()
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
identityServerSetDefaultSubmit.debouncedClicks {
|
||||
views.identityServerSetDefaultSubmit.debouncedClicks {
|
||||
viewModel.handle(SetIdentityServerAction.UseDefaultIdentityServer)
|
||||
}
|
||||
|
||||
identityServerSetDefaultAlternativeSubmit.debouncedClicks {
|
||||
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(identityServerSetDefaultAlternativeTextInput.text.toString()))
|
||||
views.identityServerSetDefaultAlternativeSubmit.debouncedClicks {
|
||||
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(views.identityServerSetDefaultAlternativeTextInput.text.toString()))
|
||||
}
|
||||
|
||||
viewModel.observeViewEvents {
|
||||
|
@ -141,13 +146,13 @@ class SetIdentityServerFragment @Inject constructor(
|
|||
.show()
|
||||
} else {
|
||||
// Display the error inlined
|
||||
identityServerSetDefaultAlternativeTil.error = message
|
||||
views.identityServerSetDefaultAlternativeTil.error = message
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.identity_server)
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.identity_server)
|
||||
}
|
||||
|
||||
private val termsActivityResultLauncher = registerStartForActivityResult {
|
||||
|
|
|
@ -18,39 +18,44 @@
|
|||
package im.vector.app.features.grouplist
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.StateView
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentGroupListBinding
|
||||
import im.vector.app.features.home.HomeActivitySharedAction
|
||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_group_list.*
|
||||
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
class GroupListFragment @Inject constructor(
|
||||
val groupListViewModelFactory: GroupListViewModel.Factory,
|
||||
private val groupController: GroupSummaryController
|
||||
) : VectorBaseFragment(), GroupSummaryController.Callback {
|
||||
) : VectorBaseFragment<FragmentGroupListBinding>(),
|
||||
GroupSummaryController.Callback {
|
||||
|
||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
private val viewModel: GroupListViewModel by fragmentViewModel()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_group_list
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGroupListBinding {
|
||||
return FragmentGroupListBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
groupController.callback = this
|
||||
stateView.contentView = groupListView
|
||||
groupListView.configureWith(groupController)
|
||||
views.stateView.contentView = views.groupListView
|
||||
views.groupListView.configureWith(groupController)
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
||||
|
@ -60,14 +65,14 @@ class GroupListFragment @Inject constructor(
|
|||
|
||||
override fun onDestroyView() {
|
||||
groupController.callback = null
|
||||
groupListView.cleanup()
|
||||
views.groupListView.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
when (state.asyncGroups) {
|
||||
is Incomplete -> stateView.state = StateView.State.Loading
|
||||
is Success -> stateView.state = StateView.State.Content
|
||||
is Incomplete -> views.stateView.state = StateView.State.Loading
|
||||
is Success -> views.stateView.state = StateView.State.Content
|
||||
}
|
||||
groupController.update(state)
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import im.vector.app.core.platform.ToolbarConfigurable
|
|||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.databinding.ActivityHomeBinding
|
||||
import im.vector.app.features.disclaimer.showDisclaimerDialog
|
||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
|
@ -56,9 +57,7 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
|||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.InitialSyncProgressService
|
||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
@ -71,7 +70,11 @@ data class HomeActivityArgs(
|
|||
val accountCreation: Boolean
|
||||
) : Parcelable
|
||||
|
||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory,
|
||||
class HomeActivity :
|
||||
VectorBaseActivity<ActivityHomeBinding>(),
|
||||
ToolbarConfigurable,
|
||||
UnknownDeviceDetectorSharedViewModel.Factory,
|
||||
ServerBackupStatusViewModel.Factory,
|
||||
NavigationInterceptor {
|
||||
|
||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
|
@ -98,7 +101,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
}
|
||||
}
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_home
|
||||
override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater)
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
injector.inject(this)
|
||||
|
@ -116,7 +119,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
super.onCreate(savedInstanceState)
|
||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
drawerLayout.addDrawerListener(drawerListener)
|
||||
views.drawerLayout.addDrawerListener(drawerListener)
|
||||
if (isFirstCreation()) {
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
|
||||
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
||||
|
@ -126,10 +129,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||
}
|
||||
}.exhaustive
|
||||
|
@ -197,24 +200,24 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
private fun renderState(state: HomeActivityViewState) {
|
||||
when (val status = state.initialSyncProgressServiceStatus) {
|
||||
is InitialSyncProgressService.Status.Idle -> {
|
||||
waiting_view.isVisible = false
|
||||
views.waitingView.root.isVisible = false
|
||||
}
|
||||
is InitialSyncProgressService.Status.Progressing -> {
|
||||
Timber.v("${getString(status.statusText)} ${status.percentProgress}")
|
||||
waiting_view.setOnClickListener {
|
||||
views.waitingView.root.setOnClickListener {
|
||||
// block interactions
|
||||
}
|
||||
waiting_view_status_horizontal_progress.apply {
|
||||
views.waitingView.waitingHorizontalProgress.apply {
|
||||
isIndeterminate = false
|
||||
max = 100
|
||||
progress = status.percentProgress
|
||||
isVisible = true
|
||||
}
|
||||
waiting_view_status_text.apply {
|
||||
views.waitingView.waitingStatusText.apply {
|
||||
text = getString(status.statusText)
|
||||
isVisible = true
|
||||
}
|
||||
waiting_view.isVisible = true
|
||||
views.waitingView.root.isVisible = true
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
@ -269,7 +272,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
).apply {
|
||||
colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
// action(it)
|
||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
|
||||
|
@ -282,7 +285,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
}, true)
|
||||
addButton(getString(R.string.settings), Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
// action(it)
|
||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
|
||||
|
@ -292,7 +295,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
)
|
||||
}
|
||||
|
||||
private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity) -> Unit)) {
|
||||
private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) {
|
||||
popupAlertManager.postVectorAlert(
|
||||
VerificationVectorAlert(
|
||||
uid = "upgradeSecurity",
|
||||
|
@ -303,7 +306,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
).apply {
|
||||
colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
action(it)
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +324,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
drawerLayout.removeDrawerListener(drawerListener)
|
||||
views.drawerLayout.removeDrawerListener(drawerListener)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
@ -375,8 +378,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
package im.vector.app.features.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -26,6 +28,7 @@ import com.airbnb.mvrx.withState
|
|||
import com.google.android.material.badge.BadgeDrawable
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
|
@ -33,6 +36,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||
import im.vector.app.core.ui.views.ActiveCallView
|
||||
import im.vector.app.core.ui.views.ActiveCallViewHolder
|
||||
import im.vector.app.core.ui.views.KeysBackupBanner
|
||||
import im.vector.app.databinding.FragmentHomeDetailBinding
|
||||
import im.vector.app.features.call.SharedActiveCallViewModel
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
|
@ -46,7 +50,7 @@ import im.vector.app.features.themes.ThemeUtils
|
|||
import im.vector.app.features.workers.signout.BannerState
|
||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
||||
import kotlinx.android.synthetic.main.fragment_home_detail.*
|
||||
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
|
||||
|
@ -64,7 +68,10 @@ class HomeDetailFragment @Inject constructor(
|
|||
private val alertManager: PopupAlertManager,
|
||||
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
||||
private val vectorPreferences: VectorPreferences
|
||||
) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory {
|
||||
) : VectorBaseFragment<FragmentHomeDetailBinding>(),
|
||||
KeysBackupBanner.Delegate,
|
||||
ActiveCallView.Callback,
|
||||
ServerBackupStatusViewModel.Factory {
|
||||
|
||||
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
|
||||
|
@ -73,7 +80,9 @@ class HomeDetailFragment @Inject constructor(
|
|||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
private lateinit var sharedCallActionViewModel: SharedActiveCallViewModel
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_home_detail
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDetailBinding {
|
||||
return FragmentHomeDetailBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val activeCallViewHolder = ActiveCallViewHolder()
|
||||
|
||||
|
@ -89,7 +98,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
|
||||
withState(viewModel) {
|
||||
// Update the navigation view if needed (for when we restore the tabs)
|
||||
bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
|
||||
views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
|
||||
}
|
||||
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
||||
|
@ -132,8 +141,8 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun checkNotificationTabStatus() {
|
||||
val wasVisible = bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
|
||||
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||
val wasVisible = views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
|
||||
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||
if (wasVisible && !vectorPreferences.labAddNotificationTab()) {
|
||||
// As we hide it check if it's not the current item!
|
||||
withState(viewModel) {
|
||||
|
@ -156,7 +165,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
).apply {
|
||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)
|
||||
?.navigator
|
||||
?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
|
||||
unknownDeviceDetectorSharedViewModel.handle(
|
||||
|
@ -184,7 +193,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
).apply {
|
||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||
contentAction = Runnable {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||
// mark as ignored to avoid showing it again
|
||||
unknownDeviceDetectorSharedViewModel.handle(
|
||||
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
|
||||
|
@ -204,7 +213,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||
groupSummary?.let {
|
||||
// Use GlideApp with activity context to avoid the glideRequests to be paused
|
||||
avatarRenderer.render(it.toMatrixItem(), groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
|
||||
avatarRenderer.render(it.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,20 +221,20 @@ class HomeDetailFragment @Inject constructor(
|
|||
serverBackupStatusViewModel
|
||||
.subscribe(this) {
|
||||
when (val banState = it.bannerState.invoke()) {
|
||||
is BannerState.Setup -> homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
|
||||
BannerState.BackingUp -> homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
|
||||
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
|
||||
BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
|
||||
null,
|
||||
BannerState.Hidden -> homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
|
||||
BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
|
||||
}
|
||||
}
|
||||
homeKeysBackupBanner.delegate = this
|
||||
views.homeKeysBackupBanner.delegate = this
|
||||
}
|
||||
|
||||
private fun setupActiveCallView() {
|
||||
activeCallViewHolder.bind(
|
||||
activeCallPiP,
|
||||
activeCallView,
|
||||
activeCallPiPWrap,
|
||||
views.activeCallPiP,
|
||||
views.activeCallView,
|
||||
views.activeCallPiPWrap,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
@ -233,17 +242,17 @@ class HomeDetailFragment @Inject constructor(
|
|||
private fun setupToolbar() {
|
||||
val parentActivity = vectorBaseActivity
|
||||
if (parentActivity is ToolbarConfigurable) {
|
||||
parentActivity.configure(groupToolbar)
|
||||
parentActivity.configure(views.groupToolbar)
|
||||
}
|
||||
groupToolbar.title = ""
|
||||
groupToolbarAvatarImageView.debouncedClicks {
|
||||
views.groupToolbar.title = ""
|
||||
views.groupToolbarAvatarImageView.debouncedClicks {
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupBottomNavigationView() {
|
||||
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||
bottomNavigationView.setOnNavigationItemSelectedListener {
|
||||
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||
views.bottomNavigationView.setOnNavigationItemSelectedListener {
|
||||
val displayMode = when (it.itemId) {
|
||||
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
|
||||
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
|
||||
|
@ -266,7 +275,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
|
||||
groupToolbarTitleView.setText(displayMode.titleRes)
|
||||
views.groupToolbarTitleView.setText(displayMode.titleRes)
|
||||
updateSelectedFragment(displayMode)
|
||||
}
|
||||
|
||||
|
@ -302,10 +311,10 @@ class HomeDetailFragment @Inject constructor(
|
|||
|
||||
override fun invalidate() = withState(viewModel) {
|
||||
Timber.v(it.toString())
|
||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
||||
syncStateView.render(it.syncState)
|
||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
||||
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
||||
views.syncStateView.render(it.syncState)
|
||||
}
|
||||
|
||||
private fun BadgeDrawable.render(count: Int, highlight: Boolean) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue