Merge pull request #2542 from vector-im/feature/bma/view_bindings
View bindings
This commit is contained in:
commit
2b780a8b76
@ -23,7 +23,7 @@ Test:
|
|||||||
-
|
-
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
-
|
- Migrate to ViewBindings (#1072)
|
||||||
|
|
||||||
Changes in Element 1.0.13 (2020-12-18)
|
Changes in Element 1.0.13 (2020-12-18)
|
||||||
===================================================
|
===================================================
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
@ -55,6 +54,10 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = '1.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -17,19 +17,17 @@
|
|||||||
package im.vector.lib.attachmentviewer
|
package im.vector.lib.attachmentviewer
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import im.vector.lib.attachmentviewer.databinding.ItemAnimatedImageAttachmentBinding
|
||||||
import android.widget.ProgressBar
|
|
||||||
|
|
||||||
class AnimatedImageViewHolder constructor(itemView: View) :
|
class AnimatedImageViewHolder constructor(itemView: View) :
|
||||||
BaseViewHolder(itemView) {
|
BaseViewHolder(itemView) {
|
||||||
|
|
||||||
val touchImageView: ImageView = itemView.findViewById(R.id.imageView)
|
val views = ItemAnimatedImageAttachmentBinding.bind(itemView)
|
||||||
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
|
|
||||||
|
|
||||||
internal val target = DefaultImageLoaderTarget(this, this.touchImageView)
|
internal val target = DefaultImageLoaderTarget(this, views.imageView)
|
||||||
|
|
||||||
override fun onRecycled() {
|
override fun onRecycled() {
|
||||||
super.onRecycled()
|
super.onRecycled()
|
||||||
touchImageView.setImageDrawable(null)
|
views.imageView.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
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 java.lang.ref.WeakReference
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@ -50,12 +51,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
private var overlayView: View? = null
|
private var overlayView: View? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value == overlayView) return
|
if (value == overlayView) return
|
||||||
overlayView?.let { rootContainer.removeView(it) }
|
overlayView?.let { views.rootContainer.removeView(it) }
|
||||||
rootContainer.addView(value)
|
views.rootContainer.addView(value)
|
||||||
value?.updatePadding(top = topInset, bottom = bottomInset)
|
value?.updatePadding(top = topInset, bottom = bottomInset)
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var views: ActivityAttachmentViewerBinding
|
||||||
|
|
||||||
private lateinit var swipeDismissHandler: SwipeToDismissHandler
|
private lateinit var swipeDismissHandler: SwipeToDismissHandler
|
||||||
private lateinit var directionDetector: SwipeDirectionDetector
|
private lateinit var directionDetector: SwipeDirectionDetector
|
||||||
private lateinit var scaleDetector: ScaleGestureDetector
|
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_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||||
|
|
||||||
setContentView(R.layout.activity_attachment_viewer)
|
views = ActivityAttachmentViewerBinding.inflate(layoutInflater)
|
||||||
attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
|
setContentView(views.root)
|
||||||
|
views.attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
|
||||||
attachmentsAdapter = AttachmentsAdapter()
|
attachmentsAdapter = AttachmentsAdapter()
|
||||||
attachmentPager.adapter = attachmentsAdapter
|
views.attachmentPager.adapter = attachmentsAdapter
|
||||||
imageTransitionView = transitionImageView
|
imageTransitionView = views.transitionImageView
|
||||||
transitionImageContainer = findViewById(R.id.transitionImageContainer)
|
pager2 = views.attachmentPager
|
||||||
pager2 = attachmentPager
|
|
||||||
directionDetector = createSwipeDirectionDetector()
|
directionDetector = createSwipeDirectionDetector()
|
||||||
gestureDetector = createGestureDetector()
|
gestureDetector = createGestureDetector()
|
||||||
|
|
||||||
attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
views.attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
override fun onPageScrollStateChanged(state: Int) {
|
override fun onPageScrollStateChanged(state: Int) {
|
||||||
isImagePagerIdle = state == ViewPager2.SCROLL_STATE_IDLE
|
isImagePagerIdle = state == ViewPager2.SCROLL_STATE_IDLE
|
||||||
}
|
}
|
||||||
@ -116,12 +119,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
})
|
})
|
||||||
|
|
||||||
swipeDismissHandler = createSwipeToDismissHandler()
|
swipeDismissHandler = createSwipeToDismissHandler()
|
||||||
rootContainer.setOnTouchListener(swipeDismissHandler)
|
views.rootContainer.setOnTouchListener(swipeDismissHandler)
|
||||||
rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = dismissContainer.height / 4 }
|
views.rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = views.dismissContainer.height / 4 }
|
||||||
|
|
||||||
scaleDetector = createScaleGestureDetector()
|
scaleDetector = createScaleGestureDetector()
|
||||||
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { _, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(views.rootContainer) { _, insets ->
|
||||||
overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom)
|
overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom)
|
||||||
topInset = insets.systemWindowInsetTop
|
topInset = insets.systemWindowInsetTop
|
||||||
bottomInset = insets.systemWindowInsetBottom
|
bottomInset = insets.systemWindowInsetBottom
|
||||||
@ -170,7 +173,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
if (swipeDirection == null && (scaleDetector.isInProgress || ev.pointerCount > 1 || wasScaled)) {
|
if (swipeDirection == null && (scaleDetector.isInProgress || ev.pointerCount > 1 || wasScaled)) {
|
||||||
wasScaled = true
|
wasScaled = true
|
||||||
// Log.v("ATTACHEMENTS", "dispatch to pager")
|
// Log.v("ATTACHEMENTS", "dispatch to pager")
|
||||||
return attachmentPager.dispatchTouchEvent(ev)
|
return views.attachmentPager.dispatchTouchEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log.v("ATTACHEMENTS", "is current item scaled ${isScaled()}")
|
// Log.v("ATTACHEMENTS", "is current item scaled ${isScaled()}")
|
||||||
@ -196,16 +199,16 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
private fun handleEventActionDown(event: MotionEvent) {
|
private fun handleEventActionDown(event: MotionEvent) {
|
||||||
swipeDirection = null
|
swipeDirection = null
|
||||||
wasScaled = false
|
wasScaled = false
|
||||||
attachmentPager.dispatchTouchEvent(event)
|
views.attachmentPager.dispatchTouchEvent(event)
|
||||||
|
|
||||||
swipeDismissHandler.onTouch(rootContainer, event)
|
swipeDismissHandler.onTouch(views.rootContainer, event)
|
||||||
isOverlayWasClicked = dispatchOverlayTouch(event)
|
isOverlayWasClicked = dispatchOverlayTouch(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEventActionUp(event: MotionEvent) {
|
private fun handleEventActionUp(event: MotionEvent) {
|
||||||
// wasDoubleTapped = false
|
// wasDoubleTapped = false
|
||||||
swipeDismissHandler.onTouch(rootContainer, event)
|
swipeDismissHandler.onTouch(views.rootContainer, event)
|
||||||
attachmentPager.dispatchTouchEvent(event)
|
views.attachmentPager.dispatchTouchEvent(event)
|
||||||
isOverlayWasClicked = dispatchOverlayTouch(event)
|
isOverlayWasClicked = dispatchOverlayTouch(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,12 +223,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
private fun toggleOverlayViewVisibility() {
|
private fun toggleOverlayViewVisibility() {
|
||||||
if (systemUiVisibility) {
|
if (systemUiVisibility) {
|
||||||
// we hide
|
// we hide
|
||||||
TransitionManager.beginDelayedTransition(rootContainer)
|
TransitionManager.beginDelayedTransition(views.rootContainer)
|
||||||
hideSystemUI()
|
hideSystemUI()
|
||||||
overlayView?.isVisible = false
|
overlayView?.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
// we show
|
// we show
|
||||||
TransitionManager.beginDelayedTransition(rootContainer)
|
TransitionManager.beginDelayedTransition(views.rootContainer)
|
||||||
showSystemUI()
|
showSystemUI()
|
||||||
overlayView?.isVisible = true
|
overlayView?.isVisible = true
|
||||||
}
|
}
|
||||||
@ -238,11 +241,11 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
return when (swipeDirection) {
|
return when (swipeDirection) {
|
||||||
SwipeDirection.Up, SwipeDirection.Down -> {
|
SwipeDirection.Up, SwipeDirection.Down -> {
|
||||||
if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) {
|
if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) {
|
||||||
swipeDismissHandler.onTouch(rootContainer, event)
|
swipeDismissHandler.onTouch(views.rootContainer, event)
|
||||||
} else true
|
} else true
|
||||||
}
|
}
|
||||||
SwipeDirection.Left, SwipeDirection.Right -> {
|
SwipeDirection.Left, SwipeDirection.Right -> {
|
||||||
attachmentPager.dispatchTouchEvent(event)
|
views.attachmentPager.dispatchTouchEvent(event)
|
||||||
}
|
}
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
@ -250,8 +253,8 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
|
|
||||||
private fun handleSwipeViewMove(translationY: Float, translationLimit: Int) {
|
private fun handleSwipeViewMove(translationY: Float, translationLimit: Int) {
|
||||||
val alpha = calculateTranslationAlpha(translationY, translationLimit)
|
val alpha = calculateTranslationAlpha(translationY, translationLimit)
|
||||||
backgroundView.alpha = alpha
|
views.backgroundView.alpha = alpha
|
||||||
dismissContainer.alpha = alpha
|
views.dismissContainer.alpha = alpha
|
||||||
overlayView?.alpha = alpha
|
overlayView?.alpha = alpha
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +268,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
|
|
||||||
private fun createSwipeToDismissHandler()
|
private fun createSwipeToDismissHandler()
|
||||||
: SwipeToDismissHandler = SwipeToDismissHandler(
|
: SwipeToDismissHandler = SwipeToDismissHandler(
|
||||||
swipeView = dismissContainer,
|
swipeView = views.dismissContainer,
|
||||||
shouldAnimateDismiss = { shouldAnimateDismiss() },
|
shouldAnimateDismiss = { shouldAnimateDismiss() },
|
||||||
onDismiss = { animateClose() },
|
onDismiss = { animateClose() },
|
||||||
onSwipeViewMove = ::handleSwipeViewMove)
|
onSwipeViewMove = ::handleSwipeViewMove)
|
||||||
|
@ -98,7 +98,7 @@ class AttachmentsAdapter : RecyclerView.Adapter<BaseViewHolder>() {
|
|||||||
fun isScaled(position: Int): Boolean {
|
fun isScaled(position: Int): Boolean {
|
||||||
val holder = recyclerView?.findViewHolderForAdapterPosition(position)
|
val holder = recyclerView?.findViewHolderForAdapterPosition(position)
|
||||||
if (holder is ZoomableImageViewHolder) {
|
if (holder is ZoomableImageViewHolder) {
|
||||||
return holder.touchImageView.attacher.scale > 1f
|
return holder.views.touchImageView.attacher.scale > 1f
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -44,29 +44,29 @@ internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, pri
|
|||||||
|
|
||||||
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = true
|
holder.views.imageLoaderProgress.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = false
|
holder.views.imageLoaderProgress.isVisible = false
|
||||||
holder.touchImageView.setImageDrawable(errorDrawable)
|
holder.views.imageView.setImageDrawable(errorDrawable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.touchImageView.setImageDrawable(placeholder)
|
holder.views.imageView.setImageDrawable(placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceReady(uid: String, resource: Drawable) {
|
override fun onResourceReady(uid: String, resource: Drawable) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = false
|
holder.views.imageLoaderProgress.isVisible = false
|
||||||
// Glide mess up the view size :/
|
// Glide mess up the view size :/
|
||||||
holder.touchImageView.updateLayoutParams {
|
holder.views.imageView.updateLayoutParams {
|
||||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
height = LinearLayout.LayoutParams.MATCH_PARENT
|
height = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
}
|
}
|
||||||
holder.touchImageView.setImageDrawable(resource)
|
holder.views.imageView.setImageDrawable(resource)
|
||||||
if (resource is Animatable) {
|
if (resource is Animatable) {
|
||||||
resource.start()
|
resource.start()
|
||||||
}
|
}
|
||||||
@ -77,30 +77,30 @@ internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, pri
|
|||||||
|
|
||||||
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
override fun onResourceLoading(uid: String, placeholder: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = true
|
holder.views.imageLoaderProgress.isVisible = true
|
||||||
holder.touchImageView.setImageDrawable(placeholder)
|
holder.views.touchImageView.setImageDrawable(placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
override fun onLoadFailed(uid: String, errorDrawable: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = false
|
holder.views.imageLoaderProgress.isVisible = false
|
||||||
holder.touchImageView.setImageDrawable(errorDrawable)
|
holder.views.touchImageView.setImageDrawable(errorDrawable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
override fun onResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.touchImageView.setImageDrawable(placeholder)
|
holder.views.touchImageView.setImageDrawable(placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceReady(uid: String, resource: Drawable) {
|
override fun onResourceReady(uid: String, resource: Drawable) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.imageLoaderProgress.isVisible = false
|
holder.views.imageLoaderProgress.isVisible = false
|
||||||
// Glide mess up the view size :/
|
// Glide mess up the view size :/
|
||||||
holder.touchImageView.updateLayoutParams {
|
holder.views.touchImageView.updateLayoutParams {
|
||||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
height = 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?) {
|
override fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.thumbnailImage.setImageDrawable(placeholder)
|
holder.views.videoThumbnailImage.setImageDrawable(placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onThumbnailResourceReady(uid: String, resource: Drawable) {
|
override fun onThumbnailResourceReady(uid: String, resource: Drawable) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.thumbnailImage.setImageDrawable(resource)
|
holder.views.videoThumbnailImage.setImageDrawable(resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onVideoFileLoading(uid: String) {
|
override fun onVideoFileLoading(uid: String) {
|
||||||
if (holder.boundResourceUid != uid) return
|
if (holder.boundResourceUid != uid) return
|
||||||
holder.thumbnailImage.isVisible = true
|
holder.views.videoThumbnailImage.isVisible = true
|
||||||
holder.loaderProgressBar.isVisible = true
|
holder.views.videoLoaderProgress.isVisible = true
|
||||||
holder.videoView.isVisible = false
|
holder.views.videoView.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onVideoFileLoadFailed(uid: String) {
|
override fun onVideoFileLoadFailed(uid: String) {
|
||||||
@ -82,8 +82,8 @@ internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun arrangeForVideoReady() {
|
private fun arrangeForVideoReady() {
|
||||||
holder.thumbnailImage.isVisible = false
|
holder.views.videoThumbnailImage.isVisible = false
|
||||||
holder.loaderProgressBar.isVisible = false
|
holder.views.videoLoaderProgress.isVisible = false
|
||||||
holder.videoView.isVisible = true
|
holder.views.videoView.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,8 @@ package im.vector.lib.attachmentviewer
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
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 androidx.core.view.isVisible
|
||||||
|
import im.vector.lib.attachmentviewer.databinding.ItemVideoAttachmentBinding
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
@ -44,13 +41,9 @@ class VideoViewHolder constructor(itemView: View) :
|
|||||||
|
|
||||||
var eventListener: WeakReference<AttachmentEventListener>? = null
|
var eventListener: WeakReference<AttachmentEventListener>? = null
|
||||||
|
|
||||||
val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage)
|
val views = ItemVideoAttachmentBinding.bind(itemView)
|
||||||
val videoView: VideoView = itemView.findViewById(R.id.videoView)
|
|
||||||
val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress)
|
|
||||||
val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon)
|
|
||||||
val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView)
|
|
||||||
|
|
||||||
internal val target = DefaultVideoLoaderTarget(this, thumbnailImage)
|
internal val target = DefaultVideoLoaderTarget(this, views.videoThumbnailImage)
|
||||||
|
|
||||||
override fun onRecycled() {
|
override fun onRecycled() {
|
||||||
super.onRecycled()
|
super.onRecycled()
|
||||||
@ -77,12 +70,12 @@ class VideoViewHolder constructor(itemView: View) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun entersBackground() {
|
override fun entersBackground() {
|
||||||
if (videoView.isPlaying) {
|
if (views.videoView.isPlaying) {
|
||||||
progress = videoView.currentPosition
|
progress = views.videoView.currentPosition
|
||||||
progressDisposable?.dispose()
|
progressDisposable?.dispose()
|
||||||
progressDisposable = null
|
progressDisposable = null
|
||||||
videoView.stopPlayback()
|
views.videoView.stopPlayback()
|
||||||
videoView.pause()
|
views.videoView.pause()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +85,9 @@ class VideoViewHolder constructor(itemView: View) :
|
|||||||
|
|
||||||
override fun onSelected(selected: Boolean) {
|
override fun onSelected(selected: Boolean) {
|
||||||
if (!selected) {
|
if (!selected) {
|
||||||
if (videoView.isPlaying) {
|
if (views.videoView.isPlaying) {
|
||||||
progress = videoView.currentPosition
|
progress = views.videoView.currentPosition
|
||||||
videoView.stopPlayback()
|
views.videoView.stopPlayback()
|
||||||
} else {
|
} else {
|
||||||
progress = 0
|
progress = 0
|
||||||
}
|
}
|
||||||
@ -109,34 +102,34 @@ class VideoViewHolder constructor(itemView: View) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startPlaying() {
|
private fun startPlaying() {
|
||||||
thumbnailImage.isVisible = false
|
views.videoThumbnailImage.isVisible = false
|
||||||
loaderProgressBar.isVisible = false
|
views.videoLoaderProgress.isVisible = false
|
||||||
videoView.isVisible = true
|
views.videoView.isVisible = true
|
||||||
|
|
||||||
videoView.setOnPreparedListener {
|
views.videoView.setOnPreparedListener {
|
||||||
progressDisposable?.dispose()
|
progressDisposable?.dispose()
|
||||||
progressDisposable = Observable.interval(100, TimeUnit.MILLISECONDS)
|
progressDisposable = Observable.interval(100, TimeUnit.MILLISECONDS)
|
||||||
.timeInterval()
|
.timeInterval()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
val duration = videoView.duration
|
val duration = views.videoView.duration
|
||||||
val progress = videoView.currentPosition
|
val progress = views.videoView.currentPosition
|
||||||
val isPlaying = videoView.isPlaying
|
val isPlaying = views.videoView.isPlaying
|
||||||
// Log.v("FOO", "isPlaying $isPlaying $progress/$duration")
|
// Log.v("FOO", "isPlaying $isPlaying $progress/$duration")
|
||||||
eventListener?.get()?.onEvent(AttachmentEvents.VideoEvent(isPlaying, progress, duration))
|
eventListener?.get()?.onEvent(AttachmentEvents.VideoEvent(isPlaying, progress, duration))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
videoView.setVideoPath(mVideoPath)
|
views.videoView.setVideoPath(mVideoPath)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
// Couldn't open
|
// Couldn't open
|
||||||
Log.v(VideoViewHolder::class.java.name, "Failed to start video")
|
Log.v(VideoViewHolder::class.java.name, "Failed to start video")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasPaused) {
|
if (!wasPaused) {
|
||||||
videoView.start()
|
views.videoView.start()
|
||||||
if (progress > 0) {
|
if (progress > 0) {
|
||||||
videoView.seekTo(progress)
|
views.videoView.seekTo(progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,17 +139,17 @@ class VideoViewHolder constructor(itemView: View) :
|
|||||||
when (commands) {
|
when (commands) {
|
||||||
AttachmentCommands.StartVideo -> {
|
AttachmentCommands.StartVideo -> {
|
||||||
wasPaused = false
|
wasPaused = false
|
||||||
videoView.start()
|
views.videoView.start()
|
||||||
}
|
}
|
||||||
AttachmentCommands.PauseVideo -> {
|
AttachmentCommands.PauseVideo -> {
|
||||||
wasPaused = true
|
wasPaused = true
|
||||||
videoView.pause()
|
views.videoView.pause()
|
||||||
}
|
}
|
||||||
is AttachmentCommands.SeekTo -> {
|
is AttachmentCommands.SeekTo -> {
|
||||||
val duration = videoView.duration
|
val duration = views.videoView.duration
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
val seekDuration = duration * (commands.percentProgress / 100f)
|
val seekDuration = duration * (commands.percentProgress / 100f)
|
||||||
videoView.seekTo(seekDuration.toInt())
|
views.videoView.seekTo(seekDuration.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,31 +17,29 @@
|
|||||||
package im.vector.lib.attachmentviewer
|
package im.vector.lib.attachmentviewer
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ProgressBar
|
import im.vector.lib.attachmentviewer.databinding.ItemImageAttachmentBinding
|
||||||
import com.github.chrisbanes.photoview.PhotoView
|
|
||||||
|
|
||||||
class ZoomableImageViewHolder constructor(itemView: View) :
|
class ZoomableImageViewHolder constructor(itemView: View) :
|
||||||
BaseViewHolder(itemView) {
|
BaseViewHolder(itemView) {
|
||||||
|
|
||||||
val touchImageView: PhotoView = itemView.findViewById(R.id.touchImageView)
|
val views = ItemImageAttachmentBinding.bind(itemView)
|
||||||
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
touchImageView.setAllowParentInterceptOnEdge(false)
|
views.touchImageView.setAllowParentInterceptOnEdge(false)
|
||||||
touchImageView.setOnScaleChangeListener { scaleFactor, _, _ ->
|
views.touchImageView.setOnScaleChangeListener { scaleFactor, _, _ ->
|
||||||
// Log.v("ATTACHEMENTS", "scaleFactor $scaleFactor")
|
// Log.v("ATTACHEMENTS", "scaleFactor $scaleFactor")
|
||||||
// It's a bit annoying but when you pitch down the scaling
|
// It's a bit annoying but when you pitch down the scaling
|
||||||
// is not exactly one :/
|
// is not exactly one :/
|
||||||
touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f)
|
views.touchImageView.setAllowParentInterceptOnEdge(scaleFactor <= 1.0008f)
|
||||||
}
|
}
|
||||||
touchImageView.setScale(1.0f, true)
|
views.touchImageView.setScale(1.0f, true)
|
||||||
touchImageView.setAllowParentInterceptOnEdge(true)
|
views.touchImageView.setAllowParentInterceptOnEdge(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView)
|
internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, views.touchImageView)
|
||||||
|
|
||||||
override fun onRecycled() {
|
override fun onRecycled() {
|
||||||
super.onRecycled()
|
super.onRecycled()
|
||||||
touchImageView.setImageDrawable(null)
|
views.touchImageView.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-parcelize'
|
||||||
apply plugin: 'realm-android'
|
apply plugin: 'realm-android'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
@ -13,10 +13,6 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
|
||||||
experimental = true
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
testOptions.unitTests.includeAndroidResources = true
|
testOptions.unitTests.includeAndroidResources = true
|
||||||
|
@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth.data
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -20,7 +20,7 @@ import android.net.Uri
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
|
import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package org.matrix.android.sdk.internal.auth.registration
|
package org.matrix.android.sdk.internal.auth.registration
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represent a localized privacy policy for registration Flow.
|
* 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 android.os.Parcelable
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? {
|
fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? {
|
||||||
// Check the validity of some fields
|
// Check the validity of some fields
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-parcelize'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
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
|
### This is generally not necessary, no need to reset the padding if there is no drawable
|
||||||
setCompoundDrawablePadding\(0\)
|
setCompoundDrawablePadding\(0\)
|
||||||
|
|
||||||
### Deprecated use class form SDK API 26
|
|
||||||
ButterKnife\.findById\(
|
|
||||||
|
|
||||||
# Change thread with Rx
|
# Change thread with Rx
|
||||||
# DISABLED
|
# DISABLED
|
||||||
#runOnUiThread
|
#runOnUiThread
|
||||||
@ -175,3 +172,6 @@ getSystemService\(Context
|
|||||||
|
|
||||||
### Use DefaultSharedPreferences.getInstance() instead for better performance
|
### Use DefaultSharedPreferences.getInstance() instead for better performance
|
||||||
PreferenceManager\.getDefaultSharedPreferences==2
|
PreferenceManager\.getDefaultSharedPreferences==2
|
||||||
|
|
||||||
|
### Use ViewBindings
|
||||||
|
# findViewById
|
||||||
|
@ -3,7 +3,7 @@ package ${escapeKotlinIdentifiers(packageName)}
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
<#if createFragmentArgs>
|
<#if createFragmentArgs>
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
</#if>
|
</#if>
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -36,8 +36,8 @@ class ${fragmentClass} @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
|
||||||
// Clear your view, unsubscribe...
|
// Clear your view, unsubscribe...
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
@ -3,17 +3,13 @@ import com.android.build.OutputFile
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
|
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-parcelize'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
kapt {
|
kapt {
|
||||||
correctErrorTypes = true
|
correctErrorTypes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
androidExtensions {
|
|
||||||
experimental = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: 2 digits max for each value
|
// Note: 2 digits max for each value
|
||||||
ext.versionMajor = 1
|
ext.versionMajor = 1
|
||||||
ext.versionMinor = 0
|
ext.versionMinor = 0
|
||||||
@ -280,6 +276,10 @@ android {
|
|||||||
java.srcDirs += "src/sharedTest/java"
|
java.srcDirs += "src/sharedTest/java"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -386,10 +386,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
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
|
// Shake detection
|
||||||
implementation 'com.squareup:seismic:1.0.2'
|
implementation 'com.squareup:seismic:1.0.2'
|
||||||
|
|
||||||
|
@ -76,7 +76,9 @@ class UiAllScreensSanityTest {
|
|||||||
|
|
||||||
private val uiTestBase = UiTestBase()
|
private val uiTestBase = UiTestBase()
|
||||||
|
|
||||||
// Last passing: 2020-11-09
|
// Last passing:
|
||||||
|
// 2020-11-09
|
||||||
|
// 2020-12-16 After ViewBinding huge change
|
||||||
@Test
|
@Test
|
||||||
fun allScreensTest() {
|
fun allScreensTest() {
|
||||||
// Create an account
|
// Create an account
|
||||||
|
@ -24,26 +24,27 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.utils.toast
|
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
|
// Rendering is not the same with VectorBaseActivity
|
||||||
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_test_material_theme)
|
val views = ActivityTestMaterialThemeBinding.inflate(layoutInflater)
|
||||||
|
setContentView(views.root)
|
||||||
|
|
||||||
debugShowSnackbar.setOnClickListener {
|
views.debugShowSnackbar.setOnClickListener {
|
||||||
Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT)
|
Snackbar.make(views.coordinatorLayout, "Snackbar!", Snackbar.LENGTH_SHORT)
|
||||||
.setAction("Action") { }
|
.setAction("Action") { }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowToast.setOnClickListener {
|
views.debugShowToast.setOnClickListener {
|
||||||
toast("Toast")
|
toast("Toast")
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowDialog.setOnClickListener {
|
views.debugShowDialog.setOnClickListener {
|
||||||
AlertDialog.Builder(this)
|
AlertDialog.Builder(this)
|
||||||
.setMessage("Dialog content")
|
.setMessage("Dialog content")
|
||||||
.setIcon(R.drawable.ic_settings_x)
|
.setIcon(R.drawable.ic_settings_x)
|
||||||
@ -53,7 +54,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowBottomSheet.setOnClickListener {
|
views.debugShowBottomSheet.setOnClickListener {
|
||||||
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import android.os.Build
|
|||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import butterknife.OnClick
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.ScreenComponent
|
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.allGranted
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.toast
|
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.debug.sas.DebugSasEmojiActivity
|
||||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||||
import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData
|
import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData
|
||||||
import kotlinx.android.synthetic.debug.activity_debug_menu.*
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
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
|
@Inject
|
||||||
lateinit var activeSessionHolder: ActiveSessionHolder
|
lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
@ -66,24 +66,32 @@ class DebugMenuActivity : VectorBaseActivity() {
|
|||||||
val string = buffer.toString(Charsets.ISO_8859_1)
|
val string = buffer.toString(Charsets.ISO_8859_1)
|
||||||
|
|
||||||
renderQrCode(string)
|
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) {
|
private fun renderQrCode(text: String) {
|
||||||
debug_qr_code.setData(text)
|
views.debugQrCode.setData(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_test_text_view_link)
|
private fun testTextViewLink() {
|
||||||
fun testTextViewLink() {
|
|
||||||
startActivity(Intent(this, TestLinkifyActivity::class.java))
|
startActivity(Intent(this, TestLinkifyActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_show_sas_emoji)
|
private fun showSasEmoji() {
|
||||||
fun showSasEmoji() {
|
|
||||||
startActivity(Intent(this, DebugSasEmojiActivity::class.java))
|
startActivity(Intent(this, DebugSasEmojiActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_test_notification)
|
private fun testNotification() {
|
||||||
fun testNotification() {
|
|
||||||
val notificationManager = getSystemService<NotificationManager>()!!
|
val notificationManager = getSystemService<NotificationManager>()!!
|
||||||
|
|
||||||
// Create channel first
|
// Create channel first
|
||||||
@ -166,23 +174,19 @@ class DebugMenuActivity : VectorBaseActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_test_material_theme_light)
|
private fun testMaterialThemeLight() {
|
||||||
fun testMaterialThemeLight() {
|
|
||||||
startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java))
|
startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_test_material_theme_dark)
|
private fun testMaterialThemeDark() {
|
||||||
fun testMaterialThemeDark() {
|
|
||||||
startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java))
|
startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_test_crash)
|
private fun testCrash() {
|
||||||
fun testCrash() {
|
|
||||||
throw RuntimeException("Application crashed from user demand")
|
throw RuntimeException("Application crashed from user demand")
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.debug_scan_qr_code)
|
private fun scanQRCode() {
|
||||||
fun scanQRCode() {
|
|
||||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||||
doScanQRCode()
|
doScanQRCode()
|
||||||
}
|
}
|
||||||
|
@ -19,28 +19,18 @@ package im.vector.app.features.debug
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.R
|
||||||
|
import im.vector.app.databinding.ActivityTestLinkifyBinding
|
||||||
|
import im.vector.app.databinding.ItemTestLinkifyBinding
|
||||||
|
|
||||||
class TestLinkifyActivity : AppCompatActivity() {
|
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?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_test_linkify)
|
val views = ActivityTestLinkifyBinding.inflate(layoutInflater)
|
||||||
ButterKnife.bind(this)
|
setContentView(views.root)
|
||||||
|
views.testLinkifyContentView.removeAllViews()
|
||||||
scrollContent.removeAllViews()
|
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
||||||
@ -89,43 +79,42 @@ class TestLinkifyActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
.forEach { textContent ->
|
.forEach { textContent ->
|
||||||
val item = LayoutInflater.from(this)
|
val item = LayoutInflater.from(this)
|
||||||
.inflate(R.layout.item_test_linkify, scrollContent, false)
|
.inflate(R.layout.item_test_linkify, views.testLinkifyContentView, false)
|
||||||
|
val subViews = ItemTestLinkifyBinding.bind(item)
|
||||||
item.findViewById<TextView>(R.id.test_linkify_auto_text)
|
subViews.testLinkifyAutoText.apply {
|
||||||
?.apply {
|
text = textContent
|
||||||
text = textContent
|
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
override fun onURLClick(uri: Uri?) {
|
||||||
override fun onURLClick(uri: Uri?) {
|
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
.setAction("open") {
|
||||||
.setAction("open") {
|
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
}
|
||||||
}
|
.show()
|
||||||
.show()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
item.findViewById<TextView>(R.id.test_linkify_custom_text)
|
subViews.testLinkifyCustomText.apply {
|
||||||
?.apply {
|
text = textContent
|
||||||
text = textContent
|
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
override fun onURLClick(uri: Uri?) {
|
||||||
override fun onURLClick(uri: Uri?) {
|
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
.setAction("open") {
|
||||||
.setAction("open") {
|
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
}
|
||||||
}
|
.show()
|
||||||
.show()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO Call VectorLinkify.addLinks(text)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
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 android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||||
import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis
|
import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis
|
||||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
|
||||||
|
|
||||||
class DebugSasEmojiActivity : AppCompatActivity() {
|
class DebugSasEmojiActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var views: FragmentGenericRecyclerBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.fragment_generic_recycler)
|
views = FragmentGenericRecyclerBinding.inflate(layoutInflater)
|
||||||
|
setContentView(views.root)
|
||||||
val controller = SasEmojiController()
|
val controller = SasEmojiController()
|
||||||
genericRecyclerView.configureWith(controller)
|
views.genericRecyclerView.configureWith(controller)
|
||||||
controller.setData(SasState(getAllVerificationEmojis()))
|
controller.setData(SasState(getAllVerificationEmojis()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
genericRecyclerView.cleanup()
|
views.genericRecyclerView.cleanup()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/coordinatorLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".features.debug.DebugMenuActivity"
|
tools:context=".features.debug.DebugMenuActivity"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/test_linkify_coordinator"
|
android:id="@+id/coordinatorLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#7F70808D"
|
android:background="#7F70808D"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/debugMaterialCoordinator"
|
android:id="@+id/coordinatorLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
@ -312,11 +312,6 @@ SOFTWARE.
|
|||||||
<br/>
|
<br/>
|
||||||
Copyright (c) 2017
|
Copyright (c) 2017
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<b>Butterknife</b>
|
|
||||||
<br/>
|
|
||||||
Copyright 2013 Jake Wharton
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<b>seismic</b>
|
<b>seismic</b>
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -21,7 +21,7 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.*
|
import im.vector.app.databinding.DialogConfirmationWithReasonBinding
|
||||||
|
|
||||||
object ConfirmationDialogBuilder {
|
object ConfirmationDialogBuilder {
|
||||||
|
|
||||||
@ -33,25 +33,26 @@ object ConfirmationDialogBuilder {
|
|||||||
@StringRes reasonHintRes: Int,
|
@StringRes reasonHintRes: Int,
|
||||||
confirmation: (String?) -> Unit) {
|
confirmation: (String?) -> Unit) {
|
||||||
val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null)
|
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
|
views.dialogReasonCheck.isVisible = askForReason
|
||||||
layout.dialogReasonTextInputLayout.isVisible = askForReason
|
views.dialogReasonTextInputLayout.isVisible = askForReason
|
||||||
|
|
||||||
layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked ->
|
views.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked ->
|
||||||
layout.dialogReasonTextInputLayout.isEnabled = isChecked
|
views.dialogReasonTextInputLayout.isEnabled = isChecked
|
||||||
}
|
}
|
||||||
if (askForReason && reasonHintRes != 0) {
|
if (askForReason && reasonHintRes != 0) {
|
||||||
layout.dialogReasonInput.setHint(reasonHintRes)
|
views.dialogReasonInput.setHint(reasonHintRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
.setTitle(titleRes)
|
.setTitle(titleRes)
|
||||||
.setView(layout)
|
.setView(layout)
|
||||||
.setPositiveButton(positiveRes) { _, _ ->
|
.setPositiveButton(positiveRes) { _, _ ->
|
||||||
val reason = layout.dialogReasonInput.text.toString()
|
val reason = views.dialogReasonInput.text.toString()
|
||||||
.takeIf { askForReason }
|
.takeIf { askForReason }
|
||||||
?.takeIf { layout.dialogReasonCheck.isChecked }
|
?.takeIf { views.dialogReasonCheck.isChecked }
|
||||||
?.takeIf { it.isNotBlank() }
|
?.takeIf { it.isNotBlank() }
|
||||||
confirmation(reason)
|
confirmation(reason)
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,11 @@ package im.vector.app.core.dialogs
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
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.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.SimpleTextWatcher
|
import im.vector.app.core.platform.SimpleTextWatcher
|
||||||
|
import im.vector.app.databinding.DialogExportE2eKeysBinding
|
||||||
|
|
||||||
class ExportKeysDialog {
|
class ExportKeysDialog {
|
||||||
|
|
||||||
@ -33,48 +30,44 @@ class ExportKeysDialog {
|
|||||||
|
|
||||||
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
||||||
|
val views = DialogExportE2eKeysBinding.bind(dialogLayout)
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.encryption_export_room_keys)
|
.setTitle(R.string.encryption_export_room_keys)
|
||||||
.setView(dialogLayout)
|
.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() {
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
when {
|
when {
|
||||||
passPhrase1EditText.text.isNullOrEmpty() -> {
|
views.exportDialogEt.text.isNullOrEmpty() -> {
|
||||||
exportButton.isEnabled = false
|
views.exportDialogSubmit.isEnabled = false
|
||||||
passPhrase2Til.error = null
|
views.exportDialogTilConfirm.error = null
|
||||||
}
|
}
|
||||||
passPhrase1EditText.text.toString() == passPhrase2EditText.text.toString() -> {
|
views.exportDialogEt.text.toString() == views.exportDialogEtConfirm.text.toString() -> {
|
||||||
exportButton.isEnabled = true
|
views.exportDialogSubmit.isEnabled = true
|
||||||
passPhrase2Til.error = null
|
views.exportDialogTilConfirm.error = null
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
exportButton.isEnabled = false
|
views.exportDialogSubmit.isEnabled = false
|
||||||
passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
views.exportDialogTilConfirm.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
passPhrase1EditText.addTextChangedListener(textWatcher)
|
views.exportDialogEt.addTextChangedListener(textWatcher)
|
||||||
passPhrase2EditText.addTextChangedListener(textWatcher)
|
views.exportDialogEtConfirm.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
views.exportDialogShowPassword.setOnClickListener {
|
||||||
showPassword.setOnClickListener {
|
|
||||||
passwordVisible = !passwordVisible
|
passwordVisible = !passwordVisible
|
||||||
passPhrase1EditText.showPassword(passwordVisible)
|
views.exportDialogEt.showPassword(passwordVisible)
|
||||||
passPhrase2EditText.showPassword(passwordVisible)
|
views.exportDialogEtConfirm.showPassword(passwordVisible)
|
||||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.exportDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
val exportDialog = builder.show()
|
val exportDialog = builder.show()
|
||||||
|
|
||||||
exportButton.setOnClickListener {
|
views.exportDialogSubmit.setOnClickListener {
|
||||||
exportKeyDialogListener.onPassphrase(passPhrase1EditText.text.toString())
|
exportKeyDialogListener.onPassphrase(views.exportDialogEt.text.toString())
|
||||||
|
|
||||||
exportDialog.dismiss()
|
exportDialog.dismiss()
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
package im.vector.app.core.dialogs
|
package im.vector.app.core.dialogs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogDeviceVerifyBinding
|
||||||
import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
|
import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
|
||||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ object ManuallyVerifyDialog {
|
|||||||
|
|
||||||
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
||||||
|
val views = DialogDeviceVerifyBinding.bind(dialogLayout)
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.cross_signing_verify_by_text)
|
.setTitle(R.string.cross_signing_verify_by_text)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
@ -35,17 +36,9 @@ object ManuallyVerifyDialog {
|
|||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
|
||||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_name)?.let {
|
views.encryptedDeviceInfoDeviceName.text = cryptoDeviceInfo.displayName()
|
||||||
it.text = cryptoDeviceInfo.displayName()
|
views.encryptedDeviceInfoDeviceId.text = cryptoDeviceInfo.deviceId
|
||||||
}
|
views.encryptedDeviceInfoDeviceKey.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.show()
|
builder.show()
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,12 @@ import android.app.Activity
|
|||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
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.R
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.SimpleTextWatcher
|
import im.vector.app.core.platform.SimpleTextWatcher
|
||||||
|
import im.vector.app.databinding.DialogPromptPasswordBinding
|
||||||
|
|
||||||
class PromptPasswordDialog {
|
class PromptPasswordDialog {
|
||||||
|
|
||||||
@ -35,21 +33,18 @@ class PromptPasswordDialog {
|
|||||||
|
|
||||||
fun show(activity: Activity, listener: (String) -> Unit) {
|
fun show(activity: Activity, listener: (String) -> Unit) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
||||||
|
val views = DialogPromptPasswordBinding.bind(dialogLayout)
|
||||||
val passwordTil = dialogLayout.findViewById<TextInputLayout>(R.id.promptPasswordTil)
|
|
||||||
val passwordEditText = dialogLayout.findViewById<TextInputEditText>(R.id.promptPassword)
|
|
||||||
val textWatcher = object : SimpleTextWatcher() {
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
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)
|
views.promptPasswordPasswordReveal.setOnClickListener {
|
||||||
showPassword.setOnClickListener {
|
|
||||||
passwordVisible = !passwordVisible
|
passwordVisible = !passwordVisible
|
||||||
passwordEditText.showPassword(passwordVisible)
|
views.promptPassword.showPassword(passwordVisible)
|
||||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.promptPasswordPasswordReveal.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
@ -73,10 +68,10 @@ class PromptPasswordDialog {
|
|||||||
setOnShowListener {
|
setOnShowListener {
|
||||||
getButton(AlertDialog.BUTTON_POSITIVE)
|
getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
if (passwordEditText.text.toString().isEmpty()) {
|
if (views.promptPassword.text.toString().isEmpty()) {
|
||||||
passwordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
views.promptPasswordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||||
} else {
|
} else {
|
||||||
listener.invoke(passwordEditText.text.toString())
|
listener.invoke(views.promptPassword.text.toString())
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,11 @@
|
|||||||
package im.vector.app.core.dialogs
|
package im.vector.app.core.dialogs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.view.View
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.databinding.DialogSslFingerprintBinding
|
||||||
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
import org.matrix.android.sdk.internal.network.ssl.Fingerprint
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
@ -95,30 +94,27 @@ class UnrecognizedCertificateDialog @Inject constructor(
|
|||||||
|
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
val inflater = activity.layoutInflater
|
val inflater = activity.layoutInflater
|
||||||
val layout: View = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
|
val layout = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
|
||||||
val sslFingerprintTitle = layout.findViewById<TextView>(R.id.ssl_fingerprint_title)
|
val views = DialogSslFingerprintBinding.bind(layout)
|
||||||
sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
|
views.sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
|
||||||
val sslFingerprint = layout.findViewById<TextView>(R.id.ssl_fingerprint)
|
views.sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
|
||||||
sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
|
|
||||||
val sslUserId = layout.findViewById<TextView>(R.id.ssl_user_id)
|
|
||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
views.sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
||||||
stringProvider.getString(R.string.username),
|
stringProvider.getString(R.string.username),
|
||||||
userId)
|
userId)
|
||||||
} else {
|
} else {
|
||||||
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
views.sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
||||||
stringProvider.getString(R.string.hs_url),
|
stringProvider.getString(R.string.hs_url),
|
||||||
homeServerUrl)
|
homeServerUrl)
|
||||||
}
|
}
|
||||||
val sslExpl = layout.findViewById<TextView>(R.id.ssl_explanation)
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (homeServerConnectionConfigHasFingerprints) {
|
if (homeServerConnectionConfigHasFingerprints) {
|
||||||
sslExpl.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
|
views.sslExplanation.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
|
||||||
} else {
|
} else {
|
||||||
sslExpl.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
|
views.sslExplanation.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sslExpl.text = stringProvider.getString(R.string.ssl_cert_new_account_expl)
|
views.sslExplanation.text = stringProvider.getString(R.string.ssl_cert_new_account_expl)
|
||||||
}
|
}
|
||||||
builder.setView(layout)
|
builder.setView(layout)
|
||||||
builder.setTitle(R.string.ssl_could_not_verify)
|
builder.setTitle(R.string.ssl_could_not_verify)
|
||||||
|
@ -23,15 +23,15 @@ import androidx.activity.ComponentActivity
|
|||||||
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.ActivityResult
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
|
||||||
|
|
||||||
fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher<Intent> {
|
fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher<Intent> {
|
||||||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseActivity.addFragment(
|
fun AppCompatActivity.addFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
allowStateLoss: Boolean = false
|
allowStateLoss: Boolean = false
|
||||||
@ -39,7 +39,7 @@ fun VectorBaseActivity.addFragment(
|
|||||||
supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseActivity.addFragment(
|
fun <T : Fragment> AppCompatActivity.addFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -51,7 +51,7 @@ fun <T : Fragment> VectorBaseActivity.addFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseActivity.replaceFragment(
|
fun AppCompatActivity.replaceFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -60,7 +60,7 @@ fun VectorBaseActivity.replaceFragment(
|
|||||||
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseActivity.replaceFragment(
|
fun <T : Fragment> AppCompatActivity.replaceFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -72,7 +72,7 @@ fun <T : Fragment> VectorBaseActivity.replaceFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseActivity.addFragmentToBackstack(
|
fun AppCompatActivity.addFragmentToBackstack(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -81,19 +81,20 @@ fun VectorBaseActivity.addFragmentToBackstack(
|
|||||||
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int,
|
fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
|
||||||
fragmentClass: Class<T>,
|
frameId: Int,
|
||||||
params: Parcelable? = null,
|
fragmentClass: Class<T>,
|
||||||
tag: String? = null,
|
params: Parcelable? = null,
|
||||||
allowStateLoss: Boolean = false,
|
tag: String? = null,
|
||||||
option: ((FragmentTransaction) -> Unit)? = null) {
|
allowStateLoss: Boolean = false,
|
||||||
|
option: ((FragmentTransaction) -> Unit)? = null) {
|
||||||
supportFragmentManager.commitTransaction(allowStateLoss) {
|
supportFragmentManager.commitTransaction(allowStateLoss) {
|
||||||
option?.invoke(this)
|
option?.invoke(this)
|
||||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseActivity.hideKeyboard() {
|
fun AppCompatActivity.hideKeyboard() {
|
||||||
currentFocus?.hideKeyboard()
|
currentFocus?.hideKeyboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import androidx.activity.result.ActivityResultLauncher
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
|
||||||
import im.vector.app.core.utils.selectTxtFileToWrite
|
import im.vector.app.core.utils.selectTxtFileToWrite
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@ -34,7 +33,7 @@ fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit):
|
|||||||
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.addFragment(
|
fun Fragment.addFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
allowStateLoss: Boolean = false
|
allowStateLoss: Boolean = false
|
||||||
@ -42,7 +41,7 @@ fun VectorBaseFragment.addFragment(
|
|||||||
parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.addFragment(
|
fun <T : Fragment> Fragment.addFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -54,7 +53,7 @@ fun <T : Fragment> VectorBaseFragment.addFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.replaceFragment(
|
fun Fragment.replaceFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
allowStateLoss: Boolean = false
|
allowStateLoss: Boolean = false
|
||||||
@ -62,7 +61,7 @@ fun VectorBaseFragment.replaceFragment(
|
|||||||
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) }
|
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.replaceFragment(
|
fun <T : Fragment> Fragment.replaceFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -74,7 +73,7 @@ fun <T : Fragment> VectorBaseFragment.replaceFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.addFragmentToBackstack(
|
fun Fragment.addFragmentToBackstack(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -83,7 +82,7 @@ fun VectorBaseFragment.addFragmentToBackstack(
|
|||||||
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) }
|
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
|
fun <T : Fragment> Fragment.addFragmentToBackstack(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -95,7 +94,7 @@ fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.addChildFragment(
|
fun Fragment.addChildFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -104,7 +103,7 @@ fun VectorBaseFragment.addChildFragment(
|
|||||||
childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) }
|
childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.addChildFragment(
|
fun <T : Fragment> Fragment.addChildFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -116,7 +115,7 @@ fun <T : Fragment> VectorBaseFragment.addChildFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.replaceChildFragment(
|
fun Fragment.replaceChildFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -125,7 +124,7 @@ fun VectorBaseFragment.replaceChildFragment(
|
|||||||
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
|
fun <T : Fragment> Fragment.replaceChildFragment(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
params: Parcelable? = null,
|
||||||
@ -137,7 +136,7 @@ fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseFragment.addChildFragmentToBackstack(
|
fun Fragment.addChildFragmentToBackstack(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
@ -146,7 +145,7 @@ fun VectorBaseFragment.addChildFragmentToBackstack(
|
|||||||
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(
|
fun <T : Fragment> Fragment.addChildFragmentToBackstack(
|
||||||
frameId: Int,
|
frameId: Int,
|
||||||
fragmentClass: Class<T>,
|
fragmentClass: Class<T>,
|
||||||
params: Parcelable? = null,
|
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.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import 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)
|
class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||||
: FrameLayout(context, attrs, defStyle) {
|
: FrameLayout(context, attrs, defStyle) {
|
||||||
@ -47,11 +46,15 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||||||
// Big or Flat button
|
// Big or Flat button
|
||||||
var button: Button
|
var button: Button
|
||||||
|
|
||||||
|
private val views: ViewButtonStateBinding
|
||||||
|
|
||||||
init {
|
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)
|
layoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
|
||||||
buttonStateRetry.setOnClickListener {
|
views.buttonStateRetry.setOnClickListener {
|
||||||
callback?.onRetryClicked()
|
callback?.onRetryClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,15 +66,15 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||||||
.apply {
|
.apply {
|
||||||
try {
|
try {
|
||||||
if (getBoolean(R.styleable.ButtonStateView_bsv_use_flat_button, true)) {
|
if (getBoolean(R.styleable.ButtonStateView_bsv_use_flat_button, true)) {
|
||||||
button = buttonStateButtonFlat
|
button = views.buttonStateButtonFlat
|
||||||
buttonStateButtonBig.isVisible = false
|
views.buttonStateButtonBig.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
button = buttonStateButtonBig
|
button = views.buttonStateButtonBig
|
||||||
buttonStateButtonFlat.isVisible = false
|
views.buttonStateButtonFlat.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
button.text = getString(R.styleable.ButtonStateView_bsv_button_text)
|
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 {
|
} finally {
|
||||||
recycle()
|
recycle()
|
||||||
}
|
}
|
||||||
@ -90,8 +93,8 @@ class ButtonStateView @JvmOverloads constructor(context: Context, attrs: Attribu
|
|||||||
button.isInvisible = true
|
button.isInvisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonStateLoading.isVisible = newState == State.Loading
|
views.buttonStateLoading.isVisible = newState == State.Loading
|
||||||
buttonStateLoaded.isVisible = newState == State.Loaded
|
views.buttonStateLoaded.isVisible = newState == State.Loaded
|
||||||
buttonStateRetry.isVisible = newState == State.Error
|
views.buttonStateRetry.isVisible = newState == State.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,37 +15,25 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.core.platform
|
package im.vector.app.core.platform
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ProgressBar
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
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.di.ScreenComponent
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
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 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.
|
* 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)
|
final override fun getCoordinatorLayout() = views.coordinatorLayout
|
||||||
lateinit var waitingCircularProgress: View
|
|
||||||
|
|
||||||
@BindView(R.id.waiting_view_status_text)
|
lateinit var session: Session
|
||||||
lateinit var waitingStatusText: TextView
|
|
||||||
|
|
||||||
@BindView(R.id.waiting_view_status_horizontal_progress)
|
|
||||||
lateinit var waitingHorizontalProgress: ProgressBar
|
|
||||||
|
|
||||||
@Inject lateinit var session: Session
|
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun injectWith(injector: ScreenComponent) {
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
@ -53,8 +41,8 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun initUiAndData() {
|
override fun initUiAndData() {
|
||||||
configureToolbar(toolbar)
|
configureToolbar(views.toolbar)
|
||||||
waitingView = findViewById(R.id.waiting_view)
|
waitingView = views.waitingView.waitingView
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,21 +51,21 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||||||
*/
|
*/
|
||||||
fun updateWaitingView(data: WaitingViewData?) {
|
fun updateWaitingView(data: WaitingViewData?) {
|
||||||
data?.let {
|
data?.let {
|
||||||
waitingStatusText.text = data.message
|
views.waitingView.waitingStatusText.text = data.message
|
||||||
|
|
||||||
if (data.progress != null && data.progressTotal != null) {
|
if (data.progress != null && data.progressTotal != null) {
|
||||||
waitingHorizontalProgress.isIndeterminate = false
|
views.waitingView.waitingHorizontalProgress.isIndeterminate = false
|
||||||
waitingHorizontalProgress.progress = data.progress
|
views.waitingView.waitingHorizontalProgress.progress = data.progress
|
||||||
waitingHorizontalProgress.max = data.progressTotal
|
views.waitingView.waitingHorizontalProgress.max = data.progressTotal
|
||||||
waitingHorizontalProgress.isVisible = true
|
views.waitingView.waitingHorizontalProgress.isVisible = true
|
||||||
waitingCircularProgress.isVisible = false
|
views.waitingView.waitingCircularProgress.isVisible = false
|
||||||
} else if (data.isIndeterminate) {
|
} else if (data.isIndeterminate) {
|
||||||
waitingHorizontalProgress.isIndeterminate = true
|
views.waitingView.waitingHorizontalProgress.isIndeterminate = true
|
||||||
waitingHorizontalProgress.isVisible = true
|
views.waitingView.waitingHorizontalProgress.isVisible = true
|
||||||
waitingCircularProgress.isVisible = false
|
views.waitingView.waitingCircularProgress.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
waitingHorizontalProgress.isVisible = false
|
views.waitingView.waitingHorizontalProgress.isVisible = false
|
||||||
waitingCircularProgress.isVisible = true
|
views.waitingView.waitingCircularProgress.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
showWaitingView()
|
showWaitingView()
|
||||||
@ -86,17 +74,17 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showWaitingView() {
|
override fun showWaitingView(text: String?) {
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
waitingStatusText.isGone = waitingStatusText.text.isNullOrBlank()
|
views.waitingView.waitingStatusText.isGone = views.waitingView.waitingStatusText.text.isNullOrBlank()
|
||||||
super.showWaitingView()
|
super.showWaitingView(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hideWaitingView() {
|
override fun hideWaitingView() {
|
||||||
waitingStatusText.text = null
|
views.waitingView.waitingStatusText.text = null
|
||||||
waitingStatusText.isGone = true
|
views.waitingView.waitingStatusText.isGone = true
|
||||||
waitingHorizontalProgress.progress = 0
|
views.waitingView.waitingHorizontalProgress.progress = 0
|
||||||
waitingHorizontalProgress.isVisible = false
|
views.waitingView.waitingHorizontalProgress.isVisible = false
|
||||||
super.hideWaitingView()
|
super.hideWaitingView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import android.widget.FrameLayout
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.updateConstraintSet
|
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)
|
class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||||
: FrameLayout(context, attrs, defStyle) {
|
: FrameLayout(context, attrs, defStyle) {
|
||||||
@ -42,6 +42,8 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||||||
data class Error(val message: CharSequence? = null) : State()
|
data class Error(val message: CharSequence? = null) : State()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val views: ViewStateBinding
|
||||||
|
|
||||||
var eventCallback: EventCallback? = null
|
var eventCallback: EventCallback? = null
|
||||||
|
|
||||||
var contentView: View? = null
|
var contentView: View? = null
|
||||||
@ -58,33 +60,34 @@ class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
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)
|
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||||
errorRetryView.setOnClickListener {
|
views.errorRetryView.setOnClickListener {
|
||||||
eventCallback?.onRetryClicked()
|
eventCallback?.onRetryClicked()
|
||||||
}
|
}
|
||||||
state = State.Content
|
state = State.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update(newState: State) {
|
private fun update(newState: State) {
|
||||||
progressBar.isVisible = newState is State.Loading
|
views.progressBar.isVisible = newState is State.Loading
|
||||||
errorView.isVisible = newState is State.Error
|
views.errorView.isVisible = newState is State.Error
|
||||||
emptyView.isVisible = newState is State.Empty
|
views.emptyView.isVisible = newState is State.Empty
|
||||||
contentView?.isVisible = newState is State.Content
|
contentView?.isVisible = newState is State.Content
|
||||||
|
|
||||||
when (newState) {
|
when (newState) {
|
||||||
is State.Content -> Unit
|
is State.Content -> Unit
|
||||||
is State.Loading -> Unit
|
is State.Loading -> Unit
|
||||||
is State.Empty -> {
|
is State.Empty -> {
|
||||||
emptyImageView.setImageDrawable(newState.image)
|
views.emptyImageView.setImageDrawable(newState.image)
|
||||||
emptyView.updateConstraintSet {
|
views.emptyView.updateConstraintSet {
|
||||||
it.constrainPercentHeight(R.id.emptyImageView, if (newState.isBigImage) 0.5f else 0.1f)
|
it.constrainPercentHeight(R.id.emptyImageView, if (newState.isBigImage) 0.5f else 0.1f)
|
||||||
}
|
}
|
||||||
emptyMessageView.text = newState.message
|
views.emptyMessageView.text = newState.message
|
||||||
emptyTitleView.text = newState.title
|
views.emptyTitleView.text = newState.title
|
||||||
}
|
}
|
||||||
is State.Error -> {
|
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.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.CallSuper
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.annotation.MenuRes
|
import androidx.annotation.MenuRes
|
||||||
import androidx.annotation.Nullable
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
@ -40,10 +39,7 @@ import androidx.fragment.app.FragmentFactory
|
|||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import butterknife.BindView
|
import androidx.viewbinding.ViewBinding
|
||||||
import butterknife.ButterKnife
|
|
||||||
import butterknife.Unbinder
|
|
||||||
import com.airbnb.mvrx.MvRx
|
|
||||||
import com.bumptech.glide.util.Util
|
import com.bumptech.glide.util.Util
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import im.vector.app.BuildConfig
|
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.observeNotNull
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.extensions.restart
|
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.extensions.vectorComponent
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.features.MainActivity
|
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.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.failure.GlobalError
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScreenInjector {
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* UI
|
* View
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
@Nullable
|
protected lateinit var views: VB
|
||||||
@JvmField
|
|
||||||
@BindView(R.id.vector_coordinator_layout)
|
|
||||||
var coordinatorLayout: CoordinatorLayout? = null
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* View model
|
* View model
|
||||||
@ -138,8 +133,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
// Filter for multiple invalid token error
|
// Filter for multiple invalid token error
|
||||||
private var mainActivityStarted = false
|
private var mainActivityStarted = false
|
||||||
|
|
||||||
private var unBinder: Unbinder? = null
|
|
||||||
|
|
||||||
private var savedInstanceState: Bundle? = null
|
private var savedInstanceState: Bundle? = null
|
||||||
|
|
||||||
// For debug only
|
// For debug only
|
||||||
@ -176,6 +169,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
uiDisposables.add(this)
|
uiDisposables.add(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
Timber.i("onCreate Activity ${javaClass.simpleName}")
|
Timber.i("onCreate Activity ${javaClass.simpleName}")
|
||||||
val vectorComponent = getVectorComponent()
|
val vectorComponent = getVectorComponent()
|
||||||
@ -223,11 +217,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
// Hack for font size
|
// Hack for font size
|
||||||
applyFontSize()
|
applyFontSize()
|
||||||
|
|
||||||
if (getLayoutRes() != -1) {
|
views = getBinding()
|
||||||
setContentView(getLayoutRes())
|
setContentView(views.root)
|
||||||
}
|
|
||||||
|
|
||||||
unBinder = ButterKnife.bind(this)
|
|
||||||
|
|
||||||
this.savedInstanceState = savedInstanceState
|
this.savedInstanceState = savedInstanceState
|
||||||
|
|
||||||
@ -306,8 +297,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
Timber.i("onDestroy Activity ${javaClass.simpleName}")
|
Timber.i("onDestroy Activity ${javaClass.simpleName}")
|
||||||
unBinder?.unbind()
|
|
||||||
unBinder = null
|
|
||||||
|
|
||||||
uiDisposables.dispose()
|
uiDisposables.dispose()
|
||||||
}
|
}
|
||||||
@ -467,7 +456,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun recursivelyDispatchOnBackPressed(fm: FragmentManager, fromToolbar: Boolean): Boolean {
|
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) {
|
for (f in reverseOrder) {
|
||||||
val handledByChildFragments = recursivelyDispatchOnBackPressed(f.childFragmentManager, fromToolbar)
|
val handledByChildFragments = recursivelyDispatchOnBackPressed(f.childFragmentManager, fromToolbar)
|
||||||
if (handledByChildFragments) {
|
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)
|
// Handle loading view (also called waiting view or spinner view)
|
||||||
// ==============================================================================================
|
// ==============================================================================================
|
||||||
@ -537,10 +522,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
fun isWaitingViewVisible() = waitingView?.isVisible == true
|
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
|
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
|
* OPEN METHODS
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
@LayoutRes
|
abstract fun getBinding(): VB
|
||||||
open fun getLayoutRes() = -1
|
|
||||||
|
|
||||||
open fun displayInFullscreen() = false
|
open fun displayInFullscreen() = false
|
||||||
|
|
||||||
@ -582,13 +569,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
fun showSnackbar(message: String) {
|
fun showSnackbar(message: String) {
|
||||||
coordinatorLayout?.let {
|
getCoordinatorLayout()?.let {
|
||||||
Snackbar.make(it, message, Snackbar.LENGTH_SHORT).show()
|
Snackbar.make(it, message, Snackbar.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) {
|
fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) {
|
||||||
coordinatorLayout?.let {
|
getCoordinatorLayout()?.let {
|
||||||
Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply {
|
Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply {
|
||||||
withActionTitle?.let {
|
withActionTitle?.let {
|
||||||
setAction(withActionTitle, { action?.invoke() })
|
setAction(withActionTitle, { action?.invoke() })
|
||||||
@ -597,6 +584,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun getCoordinatorLayout(): CoordinatorLayout? = null
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* User Consent
|
* User Consent
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
@ -25,10 +25,8 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.annotation.LayoutRes
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import butterknife.ButterKnife
|
import androidx.viewbinding.ViewBinding
|
||||||
import butterknife.Unbinder
|
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import com.airbnb.mvrx.MvRxView
|
import com.airbnb.mvrx.MvRxView
|
||||||
import com.airbnb.mvrx.MvRxViewId
|
import com.airbnb.mvrx.MvRxViewId
|
||||||
@ -48,7 +46,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
/**
|
/**
|
||||||
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
||||||
*/
|
*/
|
||||||
abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView {
|
abstract class VectorBaseBottomSheetDialogFragment<VB: ViewBinding> : BottomSheetDialogFragment(), MvRxView {
|
||||||
|
|
||||||
private val mvrxViewIdProperty = MvRxViewId()
|
private val mvrxViewIdProperty = MvRxViewId()
|
||||||
final override val mvrxViewId: String by mvrxViewIdProperty
|
final override val mvrxViewId: String by mvrxViewIdProperty
|
||||||
@ -58,10 +56,13 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||||||
* View
|
* View
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
||||||
@LayoutRes
|
private var _binding: VB? = null
|
||||||
abstract fun getLayoutResId(): Int
|
|
||||||
|
|
||||||
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
|
* View model
|
||||||
@ -81,8 +82,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||||||
|
|
||||||
private var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>? = null
|
private var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>? = null
|
||||||
|
|
||||||
val vectorBaseActivity: VectorBaseActivity by lazy {
|
val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||||
activity as VectorBaseActivity
|
activity as VectorBaseActivity<*>
|
||||||
}
|
}
|
||||||
|
|
||||||
open val showExpanded = false
|
open val showExpanded = false
|
||||||
@ -106,17 +107,14 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
val view = inflater.inflate(getLayoutResId(), container, false)
|
_binding = getBinding(inflater, container)
|
||||||
unBinder = ButterKnife.bind(this, view)
|
return views.root
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
|
||||||
unBinder?.unbind()
|
|
||||||
unBinder = null
|
|
||||||
uiDisposables.clear()
|
uiDisposables.clear()
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
|
@ -28,15 +28,12 @@ import android.view.MenuInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.annotation.LayoutRes
|
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import butterknife.ButterKnife
|
import androidx.viewbinding.ViewBinding
|
||||||
import butterknife.Unbinder
|
|
||||||
import com.airbnb.mvrx.BaseMvRxFragment
|
import com.airbnb.mvrx.BaseMvRxFragment
|
||||||
import com.airbnb.mvrx.MvRx
|
|
||||||
import com.bumptech.glide.util.Util.assertMainThread
|
import com.bumptech.glide.util.Util.assertMainThread
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.jakewharton.rxbinding3.view.clicks
|
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.di.ScreenComponent
|
||||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
|
import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
abstract class VectorBaseFragment<VB: ViewBinding> : BaseMvRxFragment(), HasScreenInjector {
|
||||||
|
|
||||||
// Butterknife unbinder
|
protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
|
||||||
private var mUnBinder: Unbinder? = null
|
activity as VectorBaseActivity<*>
|
||||||
|
|
||||||
protected val vectorBaseActivity: VectorBaseActivity by lazy {
|
|
||||||
activity as VectorBaseActivity
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
@ -86,6 +82,16 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
protected val fragmentViewModelProvider
|
protected val fragmentViewModelProvider
|
||||||
get() = ViewModelProvider(this, viewModelFactory)
|
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
|
* Life cycle
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
@ -110,11 +116,11 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
|
|
||||||
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
Timber.i("onCreateView Fragment ${javaClass.simpleName}")
|
Timber.i("onCreateView Fragment ${javaClass.simpleName}")
|
||||||
return inflater.inflate(getLayoutResId(), container, false)
|
_binding = getBinding(inflater, container)
|
||||||
|
return views.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@LayoutRes
|
abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB
|
||||||
abstract fun getLayoutResId(): Int
|
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@ -125,7 +131,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
mUnBinder = ButterKnife.bind(this, view)
|
Timber.i("onViewCreated Fragment ${javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun showLoading(message: CharSequence?) {
|
open fun showLoading(message: CharSequence?) {
|
||||||
@ -138,11 +144,10 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
|
||||||
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
|
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
|
||||||
mUnBinder?.unbind()
|
|
||||||
mUnBinder = null
|
|
||||||
uiDisposables.clear()
|
uiDisposables.clear()
|
||||||
|
_binding = null
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
@ -180,10 +185,6 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
arguments = args.toMvRxBundle()
|
arguments = args.toMvRxBundle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Parcelable?.toMvRxBundle(): Bundle? {
|
|
||||||
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
protected fun <T : Restorable> T.register(): T {
|
protected fun <T : Restorable> T.register(): T {
|
||||||
assertMainThread()
|
assertMainThread()
|
||||||
@ -192,7 +193,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun showErrorInSnackbar(throwable: Throwable) {
|
protected fun showErrorInSnackbar(throwable: Throwable) {
|
||||||
vectorBaseActivity.coordinatorLayout?.let {
|
vectorBaseActivity.getCoordinatorLayout()?.let {
|
||||||
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
|
||||||
.show()
|
.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
|
package im.vector.app.core.ui.bottomsheet
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetGenericListBinding
|
||||||
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic Bottom sheet with actions
|
* Generic Bottom sheet with actions
|
||||||
*/
|
*/
|
||||||
abstract class BottomSheetGeneric<STATE : BottomSheetGenericState, ACTION : BottomSheetGenericAction> :
|
abstract class BottomSheetGeneric<STATE : BottomSheetGenericState, ACTION : BottomSheetGenericAction> :
|
||||||
VectorBaseBottomSheetDialogFragment(),
|
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
|
||||||
BottomSheetGenericController.Listener<ACTION> {
|
BottomSheetGenericController.Listener<ACTION> {
|
||||||
|
|
||||||
@Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
|
@Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
|
||||||
|
|
||||||
@BindView(R.id.bottomSheetRecyclerView)
|
|
||||||
lateinit var recyclerView: RecyclerView
|
|
||||||
|
|
||||||
final override val showExpanded = true
|
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>
|
abstract fun getController(): BottomSheetGenericController<STATE, ACTION>
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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
|
getController().listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
recyclerView.cleanup()
|
views.bottomSheetRecyclerView.cleanup()
|
||||||
getController().listener = null
|
getController().listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ import android.text.style.ClickableSpan
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.utils.tappableMatchingText
|
import im.vector.app.core.utils.tappableMatchingText
|
||||||
|
import im.vector.app.databinding.ViewActiveConferenceViewBinding
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
@ -48,12 +48,15 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
var jitsiWidget: Widget? = null
|
var jitsiWidget: Widget? = null
|
||||||
|
|
||||||
|
private lateinit var views: ViewActiveConferenceViewBinding
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupView()
|
setupView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
inflate(context, R.layout.view_active_conference_view, this)
|
inflate(context, R.layout.view_active_conference_view, this)
|
||||||
|
views = ViewActiveConferenceViewBinding.bind(this)
|
||||||
setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
|
setBackgroundColor(ThemeUtils.getColor(context, R.attr.colorPrimary))
|
||||||
|
|
||||||
// "voice" and "video" texts are underlined and clickable
|
// "voice" and "video" texts are underlined and clickable
|
||||||
@ -78,12 +81,12 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
findViewById<TextView>(R.id.activeConferenceInfo).apply {
|
views.activeConferenceInfo.apply {
|
||||||
text = styledText
|
text = styledText
|
||||||
movementMethod = LinkMovementMethod.getInstance()
|
movementMethod = LinkMovementMethod.getInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
findViewById<TextView>(R.id.deleteWidgetButton).setOnClickListener {
|
views.deleteWidgetButton.setOnClickListener {
|
||||||
jitsiWidget?.let { callback?.onDelete(it) }
|
jitsiWidget?.let { callback?.onDelete(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +108,7 @@ class ActiveConferenceView @JvmOverloads constructor(
|
|||||||
jitsiWidget = activeConf
|
jitsiWidget = activeConf
|
||||||
}
|
}
|
||||||
// if sent by me or if i can moderate?
|
// if sent by me or if i can moderate?
|
||||||
findViewById<TextView>(R.id.deleteWidgetButton).isVisible = state.isAllowedToManageWidgets
|
views.deleteWidgetButton.isVisible = state.isAllowedToManageWidgets
|
||||||
} else {
|
} else {
|
||||||
isVisible = false
|
isVisible = false
|
||||||
}
|
}
|
||||||
|
@ -20,19 +20,15 @@ import android.content.Context
|
|||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.ButterKnife
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
import im.vector.app.databinding.ItemVerificationActionBinding
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
class BottomSheetActionButton @JvmOverloads constructor(
|
class BottomSheetActionButton @JvmOverloads constructor(
|
||||||
@ -40,32 +36,18 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||||
|
val views : ItemVerificationActionBinding
|
||||||
@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
|
|
||||||
|
|
||||||
var title: String? = null
|
var title: String? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
actionTextView.setTextOrHide(value)
|
views.itemVerificationActionTitle.setTextOrHide(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var subTitle: String? = null
|
var subTitle: String? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
descriptionTextView.setTextOrHide(value)
|
views.itemVerificationActionSubTitle.setTextOrHide(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var forceStartPadding: Boolean? = null
|
var forceStartPadding: Boolean? = null
|
||||||
@ -73,9 +55,9 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||||||
field = value
|
field = value
|
||||||
if (leftIcon == null) {
|
if (leftIcon == null) {
|
||||||
if (forceStartPadding == true) {
|
if (forceStartPadding == true) {
|
||||||
leftIconImageView.isInvisible = true
|
views.itemVerificationLeftIcon.isInvisible = true
|
||||||
} else {
|
} else {
|
||||||
leftIconImageView.isGone = true
|
views.itemVerificationLeftIcon.isGone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,38 +67,38 @@ class BottomSheetActionButton @JvmOverloads constructor(
|
|||||||
field = value
|
field = value
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (forceStartPadding == true) {
|
if (forceStartPadding == true) {
|
||||||
leftIconImageView.isInvisible = true
|
views.itemVerificationLeftIcon.isInvisible = true
|
||||||
} else {
|
} else {
|
||||||
leftIconImageView.isGone = true
|
views.itemVerificationLeftIcon.isGone = true
|
||||||
}
|
}
|
||||||
leftIconImageView.setImageDrawable(null)
|
views.itemVerificationLeftIcon.setImageDrawable(null)
|
||||||
} else {
|
} else {
|
||||||
leftIconImageView.isVisible = true
|
views.itemVerificationLeftIcon.isVisible = true
|
||||||
leftIconImageView.setImageDrawable(value)
|
views.itemVerificationLeftIcon.setImageDrawable(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rightIcon: Drawable? = null
|
var rightIcon: Drawable? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
rightIconImageView.setImageDrawable(value)
|
views.itemVerificationActionIcon.setImageDrawable(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tint: Int? = null
|
var tint: Int? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
leftIconImageView.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
views.itemVerificationLeftIcon.imageTintList = value?.let { ColorStateList.valueOf(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
var titleTextColor: Int? = null
|
var titleTextColor: Int? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
value?.let { actionTextView.setTextColor(it) }
|
value?.let { views.itemVerificationActionTitle.setTextColor(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.item_verification_action, this)
|
inflate(context, R.layout.item_verification_action, this)
|
||||||
ButterKnife.bind(this)
|
views = ItemVerificationActionBinding.bind(this)
|
||||||
|
|
||||||
context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) {
|
context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) {
|
||||||
title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: ""
|
title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: ""
|
||||||
|
@ -22,7 +22,7 @@ import android.view.View
|
|||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import im.vector.app.R
|
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(
|
class JumpToReadMarkerView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -43,11 +43,12 @@ class JumpToReadMarkerView @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
inflate(context, R.layout.view_jump_to_read_marker, this)
|
inflate(context, R.layout.view_jump_to_read_marker, this)
|
||||||
|
val views = ViewJumpToReadMarkerBinding.bind(this)
|
||||||
setBackgroundColor(ContextCompat.getColor(context, R.color.notification_accent_color))
|
setBackgroundColor(ContextCompat.getColor(context, R.color.notification_accent_color))
|
||||||
jumpToReadMarkerLabelView.setOnClickListener {
|
views.jumpToReadMarkerLabelView.setOnClickListener {
|
||||||
callback?.onJumpToReadMarkerClicked()
|
callback?.onJumpToReadMarkerClicked()
|
||||||
}
|
}
|
||||||
closeJumpToReadMarkerView.setOnClickListener {
|
views.closeJumpToReadMarkerView.setOnClickListener {
|
||||||
visibility = View.INVISIBLE
|
visibility = View.INVISIBLE
|
||||||
callback?.onClearReadMarkerClicked()
|
callback?.onClearReadMarkerClicked()
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,13 @@ package im.vector.app.core.ui.views
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.ButterKnife
|
|
||||||
import butterknife.OnClick
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.DefaultSharedPreferences
|
import im.vector.app.core.di.DefaultSharedPreferences
|
||||||
|
import im.vector.app.databinding.ViewKeysBackupBannerBinding
|
||||||
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,21 +38,11 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener {
|
) : 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
|
var delegate: Delegate? = null
|
||||||
private var state: State = State.Initial
|
private var state: State = State.Initial
|
||||||
|
|
||||||
|
private lateinit var views: ViewKeysBackupBannerBinding
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupView()
|
setupView()
|
||||||
DefaultSharedPreferences.getInstance(context).edit {
|
DefaultSharedPreferences.getInstance(context).edit {
|
||||||
@ -100,8 +88,7 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.view_keys_backup_banner_close)
|
private fun onCloseClicked() {
|
||||||
internal fun onCloseClicked() {
|
|
||||||
state.let {
|
state.let {
|
||||||
when (it) {
|
when (it) {
|
||||||
is State.Setup -> {
|
is State.Setup -> {
|
||||||
@ -133,11 +120,12 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
inflate(context, R.layout.view_keys_backup_banner, this)
|
inflate(context, R.layout.view_keys_backup_banner, this)
|
||||||
ButterKnife.bind(this)
|
|
||||||
|
|
||||||
setOnClickListener(this)
|
setOnClickListener(this)
|
||||||
textView1.setOnClickListener(this)
|
views = ViewKeysBackupBannerBinding.bind(this)
|
||||||
textView2.setOnClickListener(this)
|
views.viewKeysBackupBannerText1.setOnClickListener(this)
|
||||||
|
views.viewKeysBackupBannerText2.setOnClickListener(this)
|
||||||
|
views.viewKeysBackupBannerClose.setOnClickListener { onCloseClicked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderInitial() {
|
private fun renderInitial() {
|
||||||
@ -156,10 +144,10 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
} else {
|
} else {
|
||||||
isVisible = true
|
isVisible = true
|
||||||
|
|
||||||
textView1.setText(R.string.secure_backup_banner_setup_line1)
|
views.viewKeysBackupBannerText1.setText(R.string.secure_backup_banner_setup_line1)
|
||||||
textView2.isVisible = true
|
views.viewKeysBackupBannerText2.isVisible = true
|
||||||
textView2.setText(R.string.secure_backup_banner_setup_line2)
|
views.viewKeysBackupBannerText2.setText(R.string.secure_backup_banner_setup_line2)
|
||||||
close.isVisible = true
|
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,10 +157,10 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
} else {
|
} else {
|
||||||
isVisible = true
|
isVisible = true
|
||||||
|
|
||||||
textView1.setText(R.string.keys_backup_banner_recover_line1)
|
views.viewKeysBackupBannerText1.setText(R.string.keys_backup_banner_recover_line1)
|
||||||
textView2.isVisible = true
|
views.viewKeysBackupBannerText2.isVisible = true
|
||||||
textView2.setText(R.string.keys_backup_banner_recover_line2)
|
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_recover_line2)
|
||||||
close.isVisible = true
|
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,28 +170,28 @@ class KeysBackupBanner @JvmOverloads constructor(
|
|||||||
} else {
|
} else {
|
||||||
isVisible = true
|
isVisible = true
|
||||||
|
|
||||||
textView1.setText(R.string.keys_backup_banner_update_line1)
|
views.viewKeysBackupBannerText1.setText(R.string.keys_backup_banner_update_line1)
|
||||||
textView2.isVisible = true
|
views.viewKeysBackupBannerText2.isVisible = true
|
||||||
textView2.setText(R.string.keys_backup_banner_update_line2)
|
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_update_line2)
|
||||||
close.isVisible = true
|
views.viewKeysBackupBannerCloseGroup.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderBackingUp() {
|
private fun renderBackingUp() {
|
||||||
isVisible = true
|
isVisible = true
|
||||||
textView1.setText(R.string.secure_backup_banner_setup_line1)
|
views.viewKeysBackupBannerText1.setText(R.string.secure_backup_banner_setup_line1)
|
||||||
textView2.isVisible = true
|
views.viewKeysBackupBannerText2.isVisible = true
|
||||||
textView2.setText(R.string.keys_backup_banner_in_progress)
|
views.viewKeysBackupBannerText2.setText(R.string.keys_backup_banner_in_progress)
|
||||||
loading.isVisible = true
|
views.viewKeysBackupBannerLoading.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide all views that are not visible in all state
|
* Hide all views that are not visible in all state
|
||||||
*/
|
*/
|
||||||
private fun hideAll() {
|
private fun hideAll() {
|
||||||
textView2.isVisible = false
|
views.viewKeysBackupBannerText2.isVisible = false
|
||||||
close.isVisible = false
|
views.viewKeysBackupBannerCloseGroup.isVisible = false
|
||||||
loading.isVisible = false
|
views.viewKeysBackupBannerLoading.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,8 +27,9 @@ import androidx.core.text.italic
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.error.ResourceLimitErrorFormatter
|
import im.vector.app.core.error.ResourceLimitErrorFormatter
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
|
import im.vector.app.databinding.ViewNotificationAreaBinding
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import kotlinx.android.synthetic.main.view_notification_area.view.*
|
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
import me.saket.bettermovementmethod.BetterLinkMovementMethod
|
import me.saket.bettermovementmethod.BetterLinkMovementMethod
|
||||||
import org.matrix.android.sdk.api.failure.MatrixError
|
import org.matrix.android.sdk.api.failure.MatrixError
|
||||||
@ -48,6 +49,8 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
var delegate: Delegate? = null
|
var delegate: Delegate? = null
|
||||||
private var state: State = State.Initial
|
private var state: State = State.Initial
|
||||||
|
|
||||||
|
private lateinit var views : ViewNotificationAreaBinding
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupView()
|
setupView()
|
||||||
}
|
}
|
||||||
@ -78,27 +81,28 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
inflate(context, R.layout.view_notification_area, this)
|
inflate(context, R.layout.view_notification_area, this)
|
||||||
|
views = ViewNotificationAreaBinding.bind(this)
|
||||||
minimumHeight = DimensionConverter(resources).dpToPx(48)
|
minimumHeight = DimensionConverter(resources).dpToPx(48)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanUp() {
|
private fun cleanUp() {
|
||||||
roomNotificationMessage.setOnClickListener(null)
|
views.roomNotificationMessage.setOnClickListener(null)
|
||||||
roomNotificationIcon.setOnClickListener(null)
|
views.roomNotificationIcon.setOnClickListener(null)
|
||||||
setBackgroundColor(Color.TRANSPARENT)
|
setBackgroundColor(Color.TRANSPARENT)
|
||||||
roomNotificationMessage.text = null
|
views.roomNotificationMessage.text = null
|
||||||
roomNotificationIcon.setImageResource(0)
|
views.roomNotificationIcon.setImageResource(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderNoPermissionToPost() {
|
private fun renderNoPermissionToPost() {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
roomNotificationIcon.setImageDrawable(null)
|
views.roomNotificationIcon.setImageDrawable(null)
|
||||||
val message = span {
|
val message = span {
|
||||||
italic {
|
italic {
|
||||||
+resources.getString(R.string.room_do_not_have_permission_to_post)
|
+resources.getString(R.string.room_do_not_have_permission_to_post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomNotificationMessage.text = message
|
views.roomNotificationMessage.text = message
|
||||||
roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
views.roomNotificationMessage.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) {
|
private fun renderResourceLimitExceededError(state: State.ResourceLimitExceededError) {
|
||||||
@ -114,16 +118,16 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
formatterMode = ResourceLimitErrorFormatter.Mode.Hard
|
formatterMode = ResourceLimitErrorFormatter.Mode.Hard
|
||||||
}
|
}
|
||||||
val message = resourceLimitErrorFormatter.format(state.matrixError, formatterMode, clickable = true)
|
val message = resourceLimitErrorFormatter.format(state.matrixError, formatterMode, clickable = true)
|
||||||
roomNotificationMessage.setTextColor(Color.WHITE)
|
views.roomNotificationMessage.setTextColor(Color.WHITE)
|
||||||
roomNotificationMessage.text = message
|
views.roomNotificationMessage.text = message
|
||||||
roomNotificationMessage.movementMethod = LinkMovementMethod.getInstance()
|
views.roomNotificationMessage.movementMethod = LinkMovementMethod.getInstance()
|
||||||
roomNotificationMessage.setLinkTextColor(Color.WHITE)
|
views.roomNotificationMessage.setLinkTextColor(Color.WHITE)
|
||||||
setBackgroundColor(ContextCompat.getColor(context, backgroundColor))
|
setBackgroundColor(ContextCompat.getColor(context, backgroundColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTombstone(state: State.Tombstone) {
|
private fun renderTombstone(state: State.Tombstone) {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
roomNotificationIcon.setImageResource(R.drawable.error)
|
views.roomNotificationIcon.setImageResource(R.drawable.error)
|
||||||
val message = span {
|
val message = span {
|
||||||
+resources.getString(R.string.room_tombstone_versioned_description)
|
+resources.getString(R.string.room_tombstone_versioned_description)
|
||||||
+"\n"
|
+"\n"
|
||||||
@ -132,8 +136,8 @@ class NotificationAreaView @JvmOverloads constructor(
|
|||||||
onClick = { delegate?.onTombstoneEventClicked(state.tombstoneEvent) }
|
onClick = { delegate?.onTombstoneEventClicked(state.tombstoneEvent) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomNotificationMessage.movementMethod = BetterLinkMovementMethod.getInstance()
|
views.roomNotificationMessage.movementMethod = BetterLinkMovementMethod.getInstance()
|
||||||
roomNotificationMessage.text = message
|
views.roomNotificationMessage.text = message
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderDefault() {
|
private fun renderDefault() {
|
||||||
|
@ -17,14 +17,11 @@ package im.vector.app.core.ui.views
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.IntRange
|
import androidx.annotation.IntRange
|
||||||
import butterknife.BindColor
|
import androidx.core.content.ContextCompat
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.ButterKnife
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ViewPasswordStrengthBarBinding
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A password strength bar custom widget
|
* A password strength bar custom widget
|
||||||
@ -41,37 +38,13 @@ class PasswordStrengthBar @JvmOverloads constructor(
|
|||||||
defStyleAttr: Int = 0)
|
defStyleAttr: Int = 0)
|
||||||
: LinearLayout(context, attrs, defStyleAttr) {
|
: LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
@BindView(R.id.password_strength_bar_1)
|
private val views: ViewPasswordStrengthBarBinding
|
||||||
lateinit var bar1: View
|
|
||||||
|
|
||||||
@BindView(R.id.password_strength_bar_2)
|
private val colorBackground = ContextCompat.getColor(context, R.color.password_strength_bar_undefined)
|
||||||
lateinit var bar2: View
|
private val colorWeak = ContextCompat.getColor(context, R.color.password_strength_bar_weak)
|
||||||
|
private val colorLow = ContextCompat.getColor(context, R.color.password_strength_bar_low)
|
||||||
@BindView(R.id.password_strength_bar_3)
|
private val colorOk = ContextCompat.getColor(context, R.color.password_strength_bar_ok)
|
||||||
lateinit var bar3: View
|
private val colorStrong = ContextCompat.getColor(context, R.color.password_strength_bar_strong)
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
@IntRange(from = 0, to = 4)
|
@IntRange(from = 0, to = 4)
|
||||||
var strength = 0
|
var strength = 0
|
||||||
@ -80,43 +53,42 @@ class PasswordStrengthBar @JvmOverloads constructor(
|
|||||||
|
|
||||||
when (newValue) {
|
when (newValue) {
|
||||||
0 -> {
|
0 -> {
|
||||||
bar1.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar1.setBackgroundColor(colorBackground)
|
||||||
bar2.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar2.setBackgroundColor(colorBackground)
|
||||||
bar3.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||||
bar4.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
bar1.setBackgroundColor(colorWeak)
|
views.passwordStrengthBar1.setBackgroundColor(colorWeak)
|
||||||
bar2.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar2.setBackgroundColor(colorBackground)
|
||||||
bar3.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||||
bar4.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
bar1.setBackgroundColor(colorLow)
|
views.passwordStrengthBar1.setBackgroundColor(colorLow)
|
||||||
bar2.setBackgroundColor(colorLow)
|
views.passwordStrengthBar2.setBackgroundColor(colorLow)
|
||||||
bar3.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar3.setBackgroundColor(colorBackground)
|
||||||
bar4.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||||
}
|
}
|
||||||
3 -> {
|
3 -> {
|
||||||
bar1.setBackgroundColor(colorOk)
|
views.passwordStrengthBar1.setBackgroundColor(colorOk)
|
||||||
bar2.setBackgroundColor(colorOk)
|
views.passwordStrengthBar2.setBackgroundColor(colorOk)
|
||||||
bar3.setBackgroundColor(colorOk)
|
views.passwordStrengthBar3.setBackgroundColor(colorOk)
|
||||||
bar4.setBackgroundColor(colorBackground)
|
views.passwordStrengthBar4.setBackgroundColor(colorBackground)
|
||||||
}
|
}
|
||||||
4 -> {
|
4 -> {
|
||||||
bar1.setBackgroundColor(colorStrong)
|
views.passwordStrengthBar1.setBackgroundColor(colorStrong)
|
||||||
bar2.setBackgroundColor(colorStrong)
|
views.passwordStrengthBar2.setBackgroundColor(colorStrong)
|
||||||
bar3.setBackgroundColor(colorStrong)
|
views.passwordStrengthBar3.setBackgroundColor(colorStrong)
|
||||||
bar4.setBackgroundColor(colorStrong)
|
views.passwordStrengthBar4.setBackgroundColor(colorStrong)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
LayoutInflater.from(context)
|
inflate(context, R.layout.view_password_strength_bar, this)
|
||||||
.inflate(R.layout.view_password_strength_bar, this, true)
|
views = ViewPasswordStrengthBarBinding.bind(this)
|
||||||
orientation = HORIZONTAL
|
orientation = HORIZONTAL
|
||||||
ButterKnife.bind(this)
|
|
||||||
strength = 0
|
strength = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ import android.widget.ImageView
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ViewReadReceiptsBinding
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
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.ReadReceiptData
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem
|
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_DISPLAYED = 5
|
||||||
private const val MAX_RECEIPT_DESCRIBED = 3
|
private const val MAX_RECEIPT_DESCRIBED = 3
|
||||||
@ -37,12 +37,21 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
private val receiptAvatars: List<ImageView> by lazy {
|
private val views : ViewReadReceiptsBinding
|
||||||
listOf(receiptAvatar1, receiptAvatar2, receiptAvatar3, receiptAvatar4, receiptAvatar5)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setupView()
|
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() {
|
private fun setupView() {
|
||||||
@ -69,12 +78,12 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||||||
.take(MAX_RECEIPT_DESCRIBED)
|
.take(MAX_RECEIPT_DESCRIBED)
|
||||||
|
|
||||||
if (readReceipts.size > MAX_RECEIPT_DISPLAYED) {
|
if (readReceipts.size > MAX_RECEIPT_DISPLAYED) {
|
||||||
receiptMore.visibility = View.VISIBLE
|
views.receiptMore.visibility = View.VISIBLE
|
||||||
receiptMore.text = context.getString(
|
views.receiptMore.text = context.getString(
|
||||||
R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED
|
R.string.x_plus, readReceipts.size - MAX_RECEIPT_DISPLAYED
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
receiptMore.visibility = View.GONE
|
views.receiptMore.visibility = View.GONE
|
||||||
}
|
}
|
||||||
contentDescription = when (readReceipts.size) {
|
contentDescription = when (readReceipts.size) {
|
||||||
1 ->
|
1 ->
|
||||||
|
@ -285,7 +285,7 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
|||||||
return isPermissionGranted
|
return isPermissionGranted
|
||||||
}
|
}
|
||||||
|
|
||||||
fun VectorBaseActivity.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) {
|
fun VectorBaseActivity<*>.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) {
|
||||||
showSnackbar(getString(rationaleMessage), R.string.settings) {
|
showSnackbar(getString(rationaleMessage), R.string.settings) {
|
||||||
openAppSettingsPage(this)
|
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.extensions.startSyncing
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.utils.deleteAllFiles
|
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.HomeActivity
|
||||||
import im.vector.app.features.home.ShortcutsHandler
|
import im.vector.app.features.home.ShortcutsHandler
|
||||||
import im.vector.app.features.login.LoginActivity
|
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.hard.SignedOutActivity
|
||||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
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,
|
* 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
|
* clears cache, is logged out, or is soft logged out
|
||||||
*/
|
*/
|
||||||
class MainActivity : VectorBaseActivity(), UnlockedActivity {
|
class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActivity {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_ARGS = "EXTRA_ARGS"
|
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
|
private lateinit var args: MainActivityArgs
|
||||||
|
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
|
@ -30,7 +30,6 @@ import android.view.animation.AnimationSet
|
|||||||
import android.view.animation.OvershootInterpolator
|
import android.view.animation.OvershootInterpolator
|
||||||
import android.view.animation.ScaleAnimation
|
import android.view.animation.ScaleAnimation
|
||||||
import android.view.animation.TranslateAnimation
|
import android.view.animation.TranslateAnimation
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.PopupWindow
|
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_EMPTY
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
|
import im.vector.app.databinding.ViewAttachmentTypeSelectorBinding
|
||||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@ -62,25 +62,19 @@ class AttachmentTypeSelectorView(context: Context,
|
|||||||
|
|
||||||
private val iconColorGenerator = ColorGenerator.MATERIAL
|
private val iconColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
|
||||||
private var galleryButton: ImageButton
|
private val views: ViewAttachmentTypeSelectorBinding
|
||||||
private var cameraButton: ImageButton
|
|
||||||
private var fileButton: ImageButton
|
|
||||||
private var stickersButton: ImageButton
|
|
||||||
private var audioButton: ImageButton
|
|
||||||
private var contactButton: ImageButton
|
|
||||||
|
|
||||||
private var anchor: View? = null
|
private var anchor: View? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val root = FrameLayout(context)
|
contentView = inflater.inflate(R.layout.view_attachment_type_selector, null, false)
|
||||||
val layout = inflater.inflate(R.layout.view_attachment_type_selector, root, true)
|
views = ViewAttachmentTypeSelectorBinding.bind(contentView)
|
||||||
galleryButton = layout.findViewById<ImageButton>(R.id.attachmentGalleryButton).configure(Type.GALLERY)
|
views.attachmentGalleryButton.configure(Type.GALLERY)
|
||||||
cameraButton = layout.findViewById<ImageButton>(R.id.attachmentCameraButton).configure(Type.CAMERA)
|
views.attachmentCameraButton.configure(Type.CAMERA)
|
||||||
fileButton = layout.findViewById<ImageButton>(R.id.attachmentFileButton).configure(Type.FILE)
|
views.attachmentFileButton.configure(Type.FILE)
|
||||||
stickersButton = layout.findViewById<ImageButton>(R.id.attachmentStickersButton).configure(Type.STICKER)
|
views.attachmentStickersButton.configure(Type.STICKER)
|
||||||
audioButton = layout.findViewById<ImageButton>(R.id.attachmentAudioButton).configure(Type.AUDIO)
|
views.attachmentAudioButton.configure(Type.AUDIO)
|
||||||
contactButton = layout.findViewById<ImageButton>(R.id.attachmentContactButton).configure(Type.CONTACT)
|
views.attachmentContactButton.configure(Type.CONTACT)
|
||||||
contentView = root
|
|
||||||
width = LinearLayout.LayoutParams.MATCH_PARENT
|
width = LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
height = LinearLayout.LayoutParams.WRAP_CONTENT
|
height = LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
animationStyle = 0
|
animationStyle = 0
|
||||||
@ -108,12 +102,12 @@ class AttachmentTypeSelectorView(context: Context,
|
|||||||
contentView.doOnNextLayout {
|
contentView.doOnNextLayout {
|
||||||
animateWindowInCircular(anchor, contentView)
|
animateWindowInCircular(anchor, contentView)
|
||||||
}
|
}
|
||||||
animateButtonIn(galleryButton, ANIMATION_DURATION / 2)
|
animateButtonIn(views.attachmentGalleryButton, ANIMATION_DURATION / 2)
|
||||||
animateButtonIn(cameraButton, ANIMATION_DURATION / 2)
|
animateButtonIn(views.attachmentCameraButton, ANIMATION_DURATION / 2)
|
||||||
animateButtonIn(fileButton, ANIMATION_DURATION / 4)
|
animateButtonIn(views.attachmentFileButton, ANIMATION_DURATION / 4)
|
||||||
animateButtonIn(audioButton, ANIMATION_DURATION / 2)
|
animateButtonIn(views.attachmentAudioButton, ANIMATION_DURATION / 2)
|
||||||
animateButtonIn(contactButton, ANIMATION_DURATION / 4)
|
animateButtonIn(views.attachmentContactButton, ANIMATION_DURATION / 4)
|
||||||
animateButtonIn(stickersButton, 0)
|
animateButtonIn(views.attachmentStickersButton, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dismiss() {
|
override fun dismiss() {
|
||||||
|
@ -24,10 +24,11 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.extensions.addFragment
|
import im.vector.app.core.extensions.addFragment
|
||||||
import im.vector.app.core.platform.ToolbarConfigurable
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
import im.vector.app.features.themes.ActivityOtherThemes
|
import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
|
|
||||||
class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
||||||
@ -51,7 +52,9 @@ class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
|
|
||||||
override fun getOtherThemes() = ActivityOtherThemes.AttachmentsPreview
|
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() {
|
override fun initUiAndData() {
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
|
@ -21,6 +21,7 @@ import android.app.Activity.RESULT_CANCELED
|
|||||||
import android.app.Activity.RESULT_OK
|
import android.app.Activity.RESULT_OK
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
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.OnSnapPositionChangeListener
|
||||||
import im.vector.app.core.utils.SnapOnScrollListener
|
import im.vector.app.core.utils.SnapOnScrollListener
|
||||||
import im.vector.app.core.utils.attachSnapHelperWithListener
|
import im.vector.app.core.utils.attachSnapHelperWithListener
|
||||||
|
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
|
||||||
import im.vector.app.features.media.createUCropWithDefaultSettings
|
import im.vector.app.features.media.createUCropWithDefaultSettings
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
|
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -62,19 +63,21 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||||||
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
|
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
|
||||||
private val attachmentBigPreviewController: AttachmentBigPreviewController,
|
private val attachmentBigPreviewController: AttachmentBigPreviewController,
|
||||||
private val colorProvider: ColorProvider
|
private val colorProvider: ColorProvider
|
||||||
) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback {
|
) : VectorBaseFragment<FragmentAttachmentsPreviewBinding>(), AttachmentMiniaturePreviewController.Callback {
|
||||||
|
|
||||||
private val fragmentArgs: AttachmentsPreviewArgs by args()
|
private val fragmentArgs: AttachmentsPreviewArgs by args()
|
||||||
private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel()
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
applyInsets()
|
applyInsets()
|
||||||
setupRecyclerViews()
|
setupRecyclerViews()
|
||||||
setupToolbar(attachmentPreviewerToolbar)
|
setupToolbar(views.attachmentPreviewerToolbar)
|
||||||
attachmentPreviewerSendButton.setOnClickListener {
|
views.attachmentPreviewerSendButton.setOnClickListener {
|
||||||
setResultAndFinish()
|
setResultAndFinish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,10 +122,10 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||||||
override fun getMenuRes() = R.menu.vector_attachments_preview
|
override fun getMenuRes() = R.menu.vector_attachments_preview
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
views.attachmentPreviewerMiniatureList.cleanup()
|
||||||
attachmentPreviewerMiniatureList.cleanup()
|
views.attachmentPreviewerBigList.cleanup()
|
||||||
attachmentPreviewerBigList.cleanup()
|
|
||||||
attachmentMiniaturePreviewController.callback = null
|
attachmentMiniaturePreviewController.callback = null
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
@ -133,9 +136,9 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||||||
} else {
|
} else {
|
||||||
attachmentMiniaturePreviewController.setData(state)
|
attachmentMiniaturePreviewController.setData(state)
|
||||||
attachmentBigPreviewController.setData(state)
|
attachmentBigPreviewController.setData(state)
|
||||||
attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
views.attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
||||||
attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
views.attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
||||||
attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
|
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) {
|
private fun setResultAndFinish() = withState(viewModel) {
|
||||||
(requireActivity() as? AttachmentsPreviewActivity)?.setResultAndFinish(
|
(requireActivity() as? AttachmentsPreviewActivity)?.setResultAndFinish(
|
||||||
it.attachments,
|
it.attachments,
|
||||||
attachmentPreviewerSendImageOriginalSize.isChecked
|
views.attachmentPreviewerSendImageOriginalSize.isChecked
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyInsets() {
|
private fun applyInsets() {
|
||||||
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
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)
|
v.updatePadding(bottom = insets.systemWindowInsetBottom)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerToolbar) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerToolbar) { v, insets ->
|
||||||
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
topMargin = insets.systemWindowInsetTop
|
topMargin = insets.systemWindowInsetTop
|
||||||
}
|
}
|
||||||
@ -180,13 +183,13 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||||||
private fun setupRecyclerViews() {
|
private fun setupRecyclerViews() {
|
||||||
attachmentMiniaturePreviewController.callback = this
|
attachmentMiniaturePreviewController.callback = this
|
||||||
|
|
||||||
attachmentPreviewerMiniatureList.let {
|
views.attachmentPreviewerMiniatureList.let {
|
||||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
it.setHasFixedSize(true)
|
it.setHasFixedSize(true)
|
||||||
it.adapter = attachmentMiniaturePreviewController.adapter
|
it.adapter = attachmentMiniaturePreviewController.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentPreviewerBigList.let {
|
views.attachmentPreviewerBigList.let {
|
||||||
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
it.attachSnapHelperWithListener(
|
it.attachSnapHelperWithListener(
|
||||||
PagerSnapHelper(),
|
PagerSnapHelper(),
|
||||||
|
@ -17,18 +17,23 @@
|
|||||||
package im.vector.app.features.call
|
package im.vector.app.features.call
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
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
|
import me.gujun.android.span.span
|
||||||
|
|
||||||
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
|
||||||
override fun getLayoutResId() = R.layout.bottom_sheet_call_controls
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallControlsBinding {
|
||||||
|
return BottomSheetCallControlsBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
private val callViewModel: VectorCallViewModel by activityViewModel()
|
private val callViewModel: VectorCallViewModel by activityViewModel()
|
||||||
|
|
||||||
@ -39,16 +44,16 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
renderState(it)
|
renderState(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
callControlsSoundDevice.clickableView.debouncedClicks {
|
views.callControlsSoundDevice.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
callViewModel.handle(VectorCallViewActions.SwitchSoundDevice)
|
callViewModel.handle(VectorCallViewActions.SwitchSoundDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
callControlsSwitchCamera.clickableView.debouncedClicks {
|
views.callControlsSwitchCamera.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
callControlsToggleSDHD.clickableView.debouncedClicks {
|
views.callControlsToggleSDHD.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
callViewModel.handle(VectorCallViewActions.ToggleHDSD)
|
callViewModel.handle(VectorCallViewActions.ToggleHDSD)
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
@ -109,30 +114,30 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun renderState(state: VectorCallViewState) {
|
private fun renderState(state: VectorCallViewState) {
|
||||||
callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
|
views.callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
|
||||||
callControlsSoundDevice.subTitle = when (state.soundDevice) {
|
views.callControlsSoundDevice.subTitle = when (state.soundDevice) {
|
||||||
CallAudioManager.SoundDevice.PHONE -> getString(R.string.sound_device_phone)
|
CallAudioManager.SoundDevice.PHONE -> getString(R.string.sound_device_phone)
|
||||||
CallAudioManager.SoundDevice.SPEAKER -> getString(R.string.sound_device_speaker)
|
CallAudioManager.SoundDevice.SPEAKER -> getString(R.string.sound_device_speaker)
|
||||||
CallAudioManager.SoundDevice.HEADSET -> getString(R.string.sound_device_headset)
|
CallAudioManager.SoundDevice.HEADSET -> getString(R.string.sound_device_headset)
|
||||||
CallAudioManager.SoundDevice.WIRELESS_HEADSET -> getString(R.string.sound_device_wireless_headset)
|
CallAudioManager.SoundDevice.WIRELESS_HEADSET -> getString(R.string.sound_device_wireless_headset)
|
||||||
}
|
}
|
||||||
|
|
||||||
callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera
|
views.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.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
|
||||||
|
|
||||||
if (state.isVideoCall) {
|
if (state.isVideoCall) {
|
||||||
callControlsToggleSDHD.isVisible = true
|
views.callControlsToggleSDHD.isVisible = true
|
||||||
if (state.isHD) {
|
if (state.isHD) {
|
||||||
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
|
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
|
||||||
callControlsToggleSDHD.subTitle = null
|
views.callControlsToggleSDHD.subTitle = null
|
||||||
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
|
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
|
||||||
} else {
|
} else {
|
||||||
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
|
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
|
||||||
callControlsToggleSDHD.subTitle = null
|
views.callControlsToggleSDHD.subTitle = null
|
||||||
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
|
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callControlsToggleSDHD.isVisible = false
|
views.callControlsToggleSDHD.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,11 @@ package im.vector.app.features.call
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.ButterKnife
|
|
||||||
import butterknife.OnClick
|
|
||||||
import im.vector.app.R
|
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.matrix.android.sdk.api.session.call.CallState
|
||||||
import org.webrtc.PeerConnection
|
import org.webrtc.PeerConnection
|
||||||
|
|
||||||
@ -35,115 +30,100 @@ class CallControlsView @JvmOverloads constructor(
|
|||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private val views: ViewCallControlsBinding
|
||||||
|
|
||||||
var interactionListener: InteractionListener? = null
|
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 {
|
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)
|
// 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)
|
private fun acceptIncomingCall() {
|
||||||
fun acceptIncomingCall() {
|
|
||||||
interactionListener?.didAcceptIncomingCall()
|
interactionListener?.didAcceptIncomingCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_icr_end_call)
|
private fun declineIncomingCall() {
|
||||||
fun declineIncomingCall() {
|
|
||||||
interactionListener?.didDeclineIncomingCall()
|
interactionListener?.didDeclineIncomingCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_end_call)
|
private fun endOngoingCall() {
|
||||||
fun endOngoingCall() {
|
|
||||||
interactionListener?.didEndCall()
|
interactionListener?.didEndCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_mute_toggle)
|
private fun toggleMute() {
|
||||||
fun toggleMute() {
|
|
||||||
interactionListener?.didTapToggleMute()
|
interactionListener?.didTapToggleMute()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_video_toggle)
|
private fun toggleVideo() {
|
||||||
fun toggleVideo() {
|
|
||||||
interactionListener?.didTapToggleVideo()
|
interactionListener?.didTapToggleVideo()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_leftMiniControl)
|
private fun returnToChat() {
|
||||||
fun returnToChat() {
|
|
||||||
interactionListener?.returnToChat()
|
interactionListener?.returnToChat()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.iv_more)
|
private fun moreControlOption() {
|
||||||
fun moreControlOption() {
|
|
||||||
interactionListener?.didTapMore()
|
interactionListener?.didTapMore()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateForState(state: VectorCallViewState) {
|
fun updateForState(state: VectorCallViewState) {
|
||||||
val callState = state.callState.invoke()
|
val callState = state.callState.invoke()
|
||||||
if (state.isAudioMuted) {
|
if (state.isAudioMuted) {
|
||||||
muteIcon.setImageResource(R.drawable.ic_microphone_off)
|
views.muteIcon.setImageResource(R.drawable.ic_microphone_off)
|
||||||
muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone)
|
views.muteIcon.contentDescription = resources.getString(R.string.a11y_unmute_microphone)
|
||||||
} else {
|
} else {
|
||||||
muteIcon.setImageResource(R.drawable.ic_microphone_on)
|
views.muteIcon.setImageResource(R.drawable.ic_microphone_on)
|
||||||
muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone)
|
views.muteIcon.contentDescription = resources.getString(R.string.a11y_mute_microphone)
|
||||||
}
|
}
|
||||||
if (state.isVideoEnabled) {
|
if (state.isVideoEnabled) {
|
||||||
videoToggleIcon.setImageResource(R.drawable.ic_video)
|
views.videoToggleIcon.setImageResource(R.drawable.ic_video)
|
||||||
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera)
|
views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_stop_camera)
|
||||||
} else {
|
} else {
|
||||||
videoToggleIcon.setImageResource(R.drawable.ic_video_off)
|
views.videoToggleIcon.setImageResource(R.drawable.ic_video_off)
|
||||||
videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera)
|
views.videoToggleIcon.contentDescription = resources.getString(R.string.a11y_start_camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (callState) {
|
when (callState) {
|
||||||
is CallState.Idle,
|
is CallState.Idle,
|
||||||
is CallState.Dialing,
|
is CallState.Dialing,
|
||||||
is CallState.Answering -> {
|
is CallState.Answering -> {
|
||||||
ringingControls.isVisible = true
|
views.ringingControls.isVisible = true
|
||||||
ringingControlAccept.isVisible = false
|
views.ringingControlAccept.isVisible = false
|
||||||
ringingControlDecline.isVisible = true
|
views.ringingControlDecline.isVisible = true
|
||||||
connectedControls.isVisible = false
|
views.connectedControls.isVisible = false
|
||||||
}
|
}
|
||||||
is CallState.LocalRinging -> {
|
is CallState.LocalRinging -> {
|
||||||
ringingControls.isVisible = true
|
views.ringingControls.isVisible = true
|
||||||
ringingControlAccept.isVisible = true
|
views.ringingControlAccept.isVisible = true
|
||||||
ringingControlDecline.isVisible = true
|
views.ringingControlDecline.isVisible = true
|
||||||
connectedControls.isVisible = false
|
views.connectedControls.isVisible = false
|
||||||
}
|
}
|
||||||
is CallState.Connected -> {
|
is CallState.Connected -> {
|
||||||
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
||||||
ringingControls.isVisible = false
|
views.ringingControls.isVisible = false
|
||||||
connectedControls.isVisible = true
|
views.connectedControls.isVisible = true
|
||||||
iv_video_toggle.isVisible = state.isVideoCall
|
views.videoToggleIcon.isVisible = state.isVideoCall
|
||||||
} else {
|
} else {
|
||||||
ringingControls.isVisible = true
|
views.ringingControls.isVisible = true
|
||||||
ringingControlAccept.isVisible = false
|
views.ringingControlAccept.isVisible = false
|
||||||
ringingControlDecline.isVisible = true
|
views.ringingControlDecline.isVisible = true
|
||||||
connectedControls.isVisible = false
|
views.connectedControls.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallState.Terminated,
|
is CallState.Terminated,
|
||||||
null -> {
|
null -> {
|
||||||
ringingControls.isVisible = false
|
views.ringingControls.isVisible = false
|
||||||
connectedControls.isVisible = false
|
views.connectedControls.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import androidx.core.view.ViewCompat
|
|||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import butterknife.BindView
|
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import com.airbnb.mvrx.viewModel
|
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.PERMISSIONS_FOR_VIDEO_IP_CALL
|
||||||
import im.vector.app.core.utils.allGranted
|
import im.vector.app.core.utils.allGranted
|
||||||
import im.vector.app.core.utils.checkPermissions
|
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.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
import im.vector.app.features.home.room.detail.RoomDetailArgs
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.android.synthetic.main.activity_call.*
|
|
||||||
import org.matrix.android.sdk.api.session.call.CallState
|
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.EglUtils
|
||||||
import org.matrix.android.sdk.api.session.call.MxCallDetail
|
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.EglBase
|
||||||
import org.webrtc.PeerConnection
|
import org.webrtc.PeerConnection
|
||||||
import org.webrtc.RendererCommon
|
import org.webrtc.RendererCommon
|
||||||
import org.webrtc.SurfaceViewRenderer
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -72,9 +70,9 @@ data class CallArgs(
|
|||||||
val isVideoCall: Boolean
|
val isVideoCall: Boolean
|
||||||
) : Parcelable
|
) : 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
|
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
|
||||||
@ -90,15 +88,6 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
|
|
||||||
@Inject lateinit var viewModelFactory: VectorCallViewModel.Factory
|
@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
|
private var rootEglBase: EglBase? = null
|
||||||
|
|
||||||
var systemUiVisibility = false
|
var systemUiVisibility = false
|
||||||
@ -158,7 +147,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
// This will need to be refined
|
// 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)
|
v.updatePadding(bottom = if (systemUiVisibility) insets.systemWindowInsetBottom else 0)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
@ -178,7 +167,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
turnScreenOnAndKeyguardOff()
|
turnScreenOnAndKeyguardOff()
|
||||||
}
|
}
|
||||||
|
|
||||||
constraintLayout.clicks()
|
views.constraintLayout.clicks()
|
||||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe { toggleUiSystemVisibility() }
|
.subscribe { toggleUiSystemVisibility() }
|
||||||
@ -210,10 +199,10 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
peerConnectionManager.detachRenderers(listOf(pipRenderer, fullscreenRenderer))
|
peerConnectionManager.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer))
|
||||||
if (surfaceRenderersAreInitialized) {
|
if (surfaceRenderersAreInitialized) {
|
||||||
pipRenderer.release()
|
views.pipRenderer.release()
|
||||||
fullscreenRenderer.release()
|
views.fullscreenRenderer.release()
|
||||||
}
|
}
|
||||||
turnScreenOffAndKeyguardOn()
|
turnScreenOffAndKeyguardOn()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
@ -228,54 +217,54 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
callControlsView.updateForState(state)
|
views.callControlsView.updateForState(state)
|
||||||
val callState = state.callState.invoke()
|
val callState = state.callState.invoke()
|
||||||
callConnectingProgress.isVisible = false
|
views.callConnectingProgress.isVisible = false
|
||||||
when (callState) {
|
when (callState) {
|
||||||
is CallState.Idle,
|
is CallState.Idle,
|
||||||
is CallState.Dialing -> {
|
is CallState.Dialing -> {
|
||||||
callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
callStatusText.setText(R.string.call_ring)
|
views.callStatusText.setText(R.string.call_ring)
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.LocalRinging -> {
|
is CallState.LocalRinging -> {
|
||||||
callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
callStatusText.text = null
|
views.callStatusText.text = null
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.Answering -> {
|
is CallState.Answering -> {
|
||||||
callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
callStatusText.setText(R.string.call_connecting)
|
views.callStatusText.setText(R.string.call_connecting)
|
||||||
callConnectingProgress.isVisible = true
|
views.callConnectingProgress.isVisible = true
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
}
|
}
|
||||||
is CallState.Connected -> {
|
is CallState.Connected -> {
|
||||||
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
|
||||||
if (callArgs.isVideoCall) {
|
if (callArgs.isVideoCall) {
|
||||||
callVideoGroup.isVisible = true
|
views.callVideoGroup.isVisible = true
|
||||||
callInfoGroup.isVisible = false
|
views.callInfoGroup.isVisible = false
|
||||||
pip_video_view.isVisible = !state.isVideoCaptureInError
|
views.pipRenderer.isVisible = !state.isVideoCaptureInError
|
||||||
} else {
|
} else {
|
||||||
callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
callStatusText.text = null
|
views.callStatusText.text = null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This state is not final, if you change network, new candidates will be sent
|
// This state is not final, if you change network, new candidates will be sent
|
||||||
callVideoGroup.isInvisible = true
|
views.callVideoGroup.isInvisible = true
|
||||||
callInfoGroup.isVisible = true
|
views.callInfoGroup.isVisible = true
|
||||||
configureCallInfo(state)
|
configureCallInfo(state)
|
||||||
callStatusText.setText(R.string.call_connecting)
|
views.callStatusText.setText(R.string.call_connecting)
|
||||||
callConnectingProgress.isVisible = true
|
views.callConnectingProgress.isVisible = true
|
||||||
}
|
}
|
||||||
// ensure all attached?
|
// ensure all attached?
|
||||||
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer, null)
|
peerConnectionManager.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, null)
|
||||||
}
|
}
|
||||||
is CallState.Terminated -> {
|
is CallState.Terminated -> {
|
||||||
finish()
|
finish()
|
||||||
@ -287,14 +276,14 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
|
|||||||
|
|
||||||
private fun configureCallInfo(state: VectorCallViewState) {
|
private fun configureCallInfo(state: VectorCallViewState) {
|
||||||
state.otherUserMatrixItem.invoke()?.let {
|
state.otherUserMatrixItem.invoke()?.let {
|
||||||
avatarRenderer.render(it, otherMemberAvatar)
|
avatarRenderer.render(it, views.otherMemberAvatar)
|
||||||
participantNameText.text = it.getBestName()
|
views.participantNameText.text = it.getBestName()
|
||||||
callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
|
views.callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureCallViews() {
|
private fun configureCallViews() {
|
||||||
callControlsView.interactionListener = this
|
views.callControlsView.interactionListener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
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
|
// Init Picture in Picture renderer
|
||||||
pipRenderer.init(rootEglBase!!.eglBaseContext, null)
|
views.pipRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||||
pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
views.pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||||
|
|
||||||
// Init Full Screen renderer
|
// Init Full Screen renderer
|
||||||
fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
|
views.fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
|
||||||
fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
|
||||||
|
|
||||||
pipRenderer.setZOrderMediaOverlay(true)
|
views.pipRenderer.setZOrderMediaOverlay(true)
|
||||||
pipRenderer.setEnableHardwareScaler(true /* enabled */)
|
views.pipRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||||
fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
|
views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
|
||||||
|
|
||||||
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer,
|
peerConnectionManager.attachViewRenderers(
|
||||||
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() })
|
views.pipRenderer,
|
||||||
|
views.fullscreenRenderer,
|
||||||
|
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() }
|
||||||
|
)
|
||||||
|
|
||||||
pipRenderer.setOnClickListener {
|
views.pipRenderer.setOnClickListener {
|
||||||
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
callViewModel.handle(VectorCallViewActions.ToggleCamera)
|
||||||
}
|
}
|
||||||
surfaceRenderersAreInitialized = true
|
surfaceRenderersAreInitialized = true
|
||||||
|
@ -20,7 +20,6 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.View
|
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
@ -28,11 +27,10 @@ import com.airbnb.mvrx.MvRx
|
|||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.viewModel
|
import com.airbnb.mvrx.viewModel
|
||||||
import com.facebook.react.modules.core.PermissionListener
|
import com.facebook.react.modules.core.PermissionListener
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.di.ScreenComponent
|
import im.vector.app.core.di.ScreenComponent
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import kotlinx.android.parcel.Parcelize
|
import im.vector.app.databinding.ActivityJitsiBinding
|
||||||
import kotlinx.android.synthetic.main.activity_jitsi.*
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
||||||
import org.jitsi.meet.sdk.JitsiMeetActivityInterface
|
import org.jitsi.meet.sdk.JitsiMeetActivityInterface
|
||||||
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
|
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
|
||||||
@ -42,7 +40,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener {
|
class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMeetActivityInterface, JitsiMeetViewListener {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Args(
|
data class Args(
|
||||||
@ -51,7 +49,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||||||
val enableVideo: Boolean
|
val enableVideo: Boolean
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
override fun getLayoutRes() = R.layout.activity_jitsi
|
override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
|
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
|
||||||
|
|
||||||
@ -76,7 +74,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||||||
super.initUiAndData()
|
super.initUiAndData()
|
||||||
jitsiMeetView = JitsiMeetView(this)
|
jitsiMeetView = JitsiMeetView(this)
|
||||||
val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
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
|
jitsiMeetView?.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,13 +82,13 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
|
|||||||
when (viewState.widget) {
|
when (viewState.widget) {
|
||||||
is Fail -> finish()
|
is Fail -> finish()
|
||||||
is Success -> {
|
is Success -> {
|
||||||
findViewById<View>(R.id.jitsi_progress_layout).isVisible = false
|
views.jitsiProgressLayout.isVisible = false
|
||||||
jitsiMeetView?.isVisible = true
|
jitsiMeetView?.isVisible = true
|
||||||
configureJitsiView(viewState)
|
configureJitsiView(viewState)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
jitsiMeetView?.isVisible = false
|
jitsiMeetView?.isVisible = false
|
||||||
findViewById<View>(R.id.jitsi_progress_layout).isVisible = true
|
views.jitsiProgressLayout.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package im.vector.app.features.contactsbook
|
package im.vector.app.features.contactsbook
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.activityViewModel
|
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.configureWith
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.PendingInvitee
|
||||||
import im.vector.app.features.userdirectory.UserListAction
|
import im.vector.app.features.userdirectory.UserListAction
|
||||||
import im.vector.app.features.userdirectory.UserListSharedAction
|
import im.vector.app.features.userdirectory.UserListSharedAction
|
||||||
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
|
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
|
||||||
import im.vector.app.features.userdirectory.UserListViewModel
|
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.identity.ThreePid
|
||||||
import org.matrix.android.sdk.api.session.user.model.User
|
import org.matrix.android.sdk.api.session.user.model.User
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -43,9 +46,12 @@ import javax.inject.Inject
|
|||||||
class ContactsBookFragment @Inject constructor(
|
class ContactsBookFragment @Inject constructor(
|
||||||
val contactsBookViewModelFactory: ContactsBookViewModel.Factory,
|
val contactsBookViewModelFactory: ContactsBookViewModel.Factory,
|
||||||
private val contactsBookController: ContactsBookController
|
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()
|
private val viewModel: UserListViewModel by activityViewModel()
|
||||||
|
|
||||||
// Use activityViewModel to avoid loading several times the data
|
// Use activityViewModel to avoid loading several times the data
|
||||||
@ -64,7 +70,7 @@ class ContactsBookFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupConsentView() {
|
private fun setupConsentView() {
|
||||||
phoneBookSearchForMatrixContacts.setOnClickListener {
|
views.phoneBookSearchForMatrixContacts.setOnClickListener {
|
||||||
withState(contactsBookViewModel) { state ->
|
withState(contactsBookViewModel) { state ->
|
||||||
AlertDialog.Builder(requireActivity())
|
AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.identity_server_consent_dialog_title)
|
.setTitle(R.string.identity_server_consent_dialog_title)
|
||||||
@ -79,7 +85,7 @@ class ContactsBookFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupOnlyBoundContactsView() {
|
private fun setupOnlyBoundContactsView() {
|
||||||
phoneBookOnlyBoundContacts.checkedChanges()
|
views.phoneBookOnlyBoundContacts.checkedChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it))
|
contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it))
|
||||||
}
|
}
|
||||||
@ -87,7 +93,7 @@ class ContactsBookFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupFilterView() {
|
private fun setupFilterView() {
|
||||||
phoneBookFilter
|
views.phoneBookFilter
|
||||||
.textChanges()
|
.textChanges()
|
||||||
.skipInitialValue()
|
.skipInitialValue()
|
||||||
.debounce(300, TimeUnit.MILLISECONDS)
|
.debounce(300, TimeUnit.MILLISECONDS)
|
||||||
@ -98,25 +104,25 @@ class ContactsBookFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
phoneBookRecyclerView.cleanup()
|
views.phoneBookRecyclerView.cleanup()
|
||||||
contactsBookController.callback = null
|
contactsBookController.callback = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
contactsBookController.callback = this
|
contactsBookController.callback = this
|
||||||
phoneBookRecyclerView.configureWith(contactsBookController)
|
views.phoneBookRecyclerView.configureWith(contactsBookController)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupCloseView() {
|
private fun setupCloseView() {
|
||||||
phoneBookClose.debouncedClicks {
|
views.phoneBookClose.debouncedClicks {
|
||||||
sharedActionViewModel.post(UserListSharedAction.GoBack)
|
sharedActionViewModel.post(UserListSharedAction.GoBack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(contactsBookViewModel) { state ->
|
override fun invalidate() = withState(contactsBookViewModel) { state ->
|
||||||
phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
|
views.phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
|
||||||
phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
|
views.phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
|
||||||
contactsBookController.setData(state)
|
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.UserListSharedActionViewModel
|
||||||
import im.vector.app.features.userdirectory.UserListViewModel
|
import im.vector.app.features.userdirectory.UserListViewModel
|
||||||
import im.vector.app.features.userdirectory.UserListViewState
|
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.failure.Failure
|
||||||
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
@ -77,7 +77,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
toolbar.visibility = View.GONE
|
views.toolbar.visibility = View.GONE
|
||||||
|
|
||||||
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java)
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package im.vector.app.features.createdirect
|
package im.vector.app.features.createdirect
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.google.zxing.Result
|
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.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
|
import im.vector.app.databinding.FragmentQrCodeScannerBinding
|
||||||
import im.vector.app.features.userdirectory.PendingInvitee
|
import im.vector.app.features.userdirectory.PendingInvitee
|
||||||
import kotlinx.android.synthetic.main.fragment_qr_code_scanner.*
|
|
||||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
|
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.permalinks.PermalinkParser
|
||||||
import org.matrix.android.sdk.api.session.user.model.User
|
import org.matrix.android.sdk.api.session.user.model.User
|
||||||
import javax.inject.Inject
|
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()
|
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 ->
|
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||||
if (allGranted) {
|
if (allGranted) {
|
||||||
@ -48,14 +53,14 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
|
|
||||||
private fun startCamera() {
|
private fun startCamera() {
|
||||||
// Start camera on resume
|
// Start camera on resume
|
||||||
scannerView.startCamera()
|
views.scannerView.startCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
view?.hideKeyboard()
|
view?.hideKeyboard()
|
||||||
// Register ourselves as a handler for scan results.
|
// Register ourselves as a handler for scan results.
|
||||||
scannerView.setResultHandler(this)
|
views.scannerView.setResultHandler(this)
|
||||||
// Start camera on resume
|
// Start camera on resume
|
||||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
|
||||||
startCamera()
|
startCamera()
|
||||||
@ -65,9 +70,9 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
// Unregister ourselves as a handler for scan results.
|
// Unregister ourselves as a handler for scan results.
|
||||||
scannerView.setResultHandler(null)
|
views.scannerView.setResultHandler(null)
|
||||||
// Stop camera on pause
|
// Stop camera on pause
|
||||||
scannerView.stopCamera()
|
views.scannerView.stopCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from https://github.com/markusfisch/BinaryEye/blob/
|
// 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.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.Observer
|
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.R
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||||
|
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
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 viewModel: KeysBackupRestoreFromKeyViewModel
|
||||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java)
|
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java)
|
||||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||||
mKeyTextEdit.setText(viewModel.recoveryCode.value)
|
views.keyTextEdit.setText(viewModel.recoveryCode.value)
|
||||||
mKeyTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
views.keyTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
onRestoreFromKey()
|
onRestoreFromKey()
|
||||||
return@setOnEditorActionListener true
|
return@setOnEditorActionListener true
|
||||||
@ -60,21 +55,23 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||||||
return@setOnEditorActionListener false
|
return@setOnEditorActionListener false
|
||||||
}
|
}
|
||||||
|
|
||||||
mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value
|
views.keyInputLayout.error = viewModel.recoveryCodeErrorText.value
|
||||||
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
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)
|
private fun onRestoreKeyTextEditChange(s: CharSequence?) {
|
||||||
fun onRestoreKeyTextEditChange(s: Editable?) {
|
|
||||||
s?.toString()?.let {
|
s?.toString()?.let {
|
||||||
viewModel.updateCode(it)
|
viewModel.updateCode(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_restore_button)
|
private fun onRestoreFromKey() {
|
||||||
fun onRestoreFromKey() {
|
|
||||||
val value = viewModel.recoveryCode.value
|
val value = viewModel.recoveryCode.value
|
||||||
if (value.isNullOrBlank()) {
|
if (value.isNullOrBlank()) {
|
||||||
viewModel.recoveryCodeErrorText.value = context?.getString(R.string.keys_backup_recovery_code_empty_error_message)
|
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)
|
private fun onImport() {
|
||||||
fun onImport() {
|
|
||||||
startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult)
|
startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +94,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
|
|||||||
?.bufferedReader()
|
?.bufferedReader()
|
||||||
?.use { it.readText() }
|
?.use { it.readText() }
|
||||||
?.let {
|
?.let {
|
||||||
mKeyTextEdit.setText(it)
|
views.keyTextEdit.setText(it)
|
||||||
mKeyTextEdit.setSelection(it.length)
|
views.keyTextEdit.setSelection(it.length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,46 +16,32 @@
|
|||||||
package im.vector.app.features.crypto.keysbackup.restore
|
package im.vector.app.features.crypto.keysbackup.restore
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.style.ClickableSpan
|
import android.text.style.ClickableSpan
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
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.text.set
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.Observer
|
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.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding
|
||||||
|
|
||||||
import javax.inject.Inject
|
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 viewModel: KeysBackupRestoreFromPassphraseViewModel
|
||||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||||
|
|
||||||
@BindView(R.id.keys_backup_passphrase_enter_til)
|
private fun toggleVisibilityMode() {
|
||||||
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() {
|
|
||||||
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,24 +52,29 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||||||
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
|
||||||
|
|
||||||
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue ->
|
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 {
|
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||||
val shouldBeVisible = it ?: false
|
val shouldBeVisible = it ?: false
|
||||||
mPassphraseTextEdit.showPassword(shouldBeVisible)
|
views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||||
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
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) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
onRestoreBackup()
|
onRestoreBackup()
|
||||||
return@setOnEditorActionListener true
|
return@setOnEditorActionListener true
|
||||||
}
|
}
|
||||||
return@setOnEditorActionListener false
|
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 {
|
private fun spannableStringForHelperText(): SpannableString {
|
||||||
@ -102,18 +93,15 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
|
|||||||
return spanString
|
return spanString
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnTextChanged(R.id.keys_backup_passphrase_enter_edittext)
|
private fun onPassphraseTextEditChange(s: CharSequence?) {
|
||||||
fun onPassphraseTextEditChange(s: Editable?) {
|
|
||||||
s?.toString()?.let { viewModel.updatePassphrase(it) }
|
s?.toString()?.let { viewModel.updatePassphrase(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_passphrase_help_with_link)
|
private fun onUseRecoveryKey() {
|
||||||
fun onUseRecoveryKey() {
|
|
||||||
sharedViewModel.moveToRecoverWithKey()
|
sharedViewModel.moveToRecoverWithKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_restore_with_passphrase_submit)
|
private fun onRestoreBackup() {
|
||||||
fun onRestoreBackup() {
|
|
||||||
val value = viewModel.passphrase.value
|
val value = viewModel.passphrase.value
|
||||||
if (value.isNullOrBlank()) {
|
if (value.isNullOrBlank()) {
|
||||||
viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message)
|
viewModel.passphraseErrorText.value = getString(R.string.passphrase_empty_error_message)
|
||||||
|
@ -16,25 +16,22 @@
|
|||||||
package im.vector.app.features.crypto.keysbackup.restore
|
package im.vector.app.features.crypto.keysbackup.restore
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.OnClick
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.LiveEvent
|
import im.vector.app.core.utils.LiveEvent
|
||||||
|
import im.vector.app.databinding.FragmentKeysBackupRestoreSuccessBinding
|
||||||
|
|
||||||
import javax.inject.Inject
|
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
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreSuccessBinding {
|
||||||
|
return FragmentKeysBackupRestoreSuccessBinding.inflate(inflater, container, false)
|
||||||
@BindView(R.id.keys_backup_restore_success)
|
}
|
||||||
lateinit var mSuccessText: TextView
|
|
||||||
|
|
||||||
@BindView(R.id.keys_backup_restore_success_info)
|
|
||||||
lateinit var mSuccessDetailsText: TextView
|
|
||||||
|
|
||||||
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
|
||||||
|
|
||||||
@ -48,18 +45,18 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
it.totalNumberOfKeys, it.totalNumberOfKeys)
|
it.totalNumberOfKeys, it.totalNumberOfKeys)
|
||||||
val part2 = resources.getQuantityString(R.plurals.keys_backup_restore_success_description_part2,
|
val part2 = resources.getQuantityString(R.plurals.keys_backup_restore_success_description_part2,
|
||||||
it.successfullyNumberOfImportedKeys, it.successfullyNumberOfImportedKeys)
|
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
|
// 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 {
|
} else {
|
||||||
mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
|
views.successText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
|
||||||
mSuccessDetailsText.isVisible = false
|
views.successDetailsText.isVisible = false
|
||||||
}
|
}
|
||||||
|
views.keysBackupSetupDoneButton.setOnClickListener { onDone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_setup_done_button)
|
private fun onDone() {
|
||||||
fun onDone() {
|
|
||||||
sharedViewModel.importRoomKeysFinishWithResult.value = LiveEvent(sharedViewModel.importKeyResult!!)
|
sharedViewModel.importRoomKeysFinishWithResult.value = LiveEvent(sharedViewModel.importKeyResult!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
package im.vector.app.features.crypto.keysbackup.settings
|
package im.vector.app.features.crypto.keysbackup.settings
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.withState
|
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.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.restore.KeysBackupRestoreActivity
|
||||||
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
||||||
import kotlinx.android.synthetic.main.fragment_keys_backup_settings.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController)
|
class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController)
|
||||||
: VectorBaseFragment(),
|
: VectorBaseFragment<FragmentKeysBackupSettingsBinding>(),
|
||||||
KeysBackupSettingsRecyclerViewController.Listener {
|
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()
|
private val viewModel: KeysBackupSettingsViewModel by activityViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
|
views.keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
|
||||||
keysBackupSettingsRecyclerViewController.listener = this
|
keysBackupSettingsRecyclerViewController.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
keysBackupSettingsRecyclerViewController.listener = null
|
keysBackupSettingsRecyclerViewController.listener = null
|
||||||
keysBackupSettingsRecyclerView.cleanup()
|
views.keysBackupSettingsRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,29 +17,24 @@
|
|||||||
package im.vector.app.features.crypto.keysbackup.setup
|
package im.vector.app.features.crypto.keysbackup.setup
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Button
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.lifecycle.Observer
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.LiveEvent
|
import im.vector.app.core.utils.LiveEvent
|
||||||
|
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
|
||||||
|
|
||||||
import javax.inject.Inject
|
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
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
@ -48,18 +43,19 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
|
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
|
||||||
val showOption = it ?: false
|
val showOption = it ?: false
|
||||||
// Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated
|
// 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
|
views.keysBackupSetupStep1AdvancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
|
||||||
manualExportButton.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)
|
private fun onButtonClick() {
|
||||||
fun onButtonClick() {
|
|
||||||
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2)
|
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_setup_step1_manualExport)
|
private fun onManualExportClick() {
|
||||||
fun onManualExportClick() {
|
|
||||||
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT)
|
viewModel.navigateEvent.value = LiveEvent(KeysBackupSetupSharedViewModel.NAVIGATE_MANUAL_EXPORT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,64 +16,40 @@
|
|||||||
package im.vector.app.features.crypto.keysbackup.setup
|
package im.vector.app.features.crypto.keysbackup.setup
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.EditText
|
import androidx.core.widget.doOnTextChanged
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.transition.TransitionManager
|
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 com.nulabinc.zxcvbn.Zxcvbn
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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 im.vector.app.features.settings.VectorLocale
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
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
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep2Binding {
|
||||||
|
return FragmentKeysBackupSetupStep2Binding.inflate(inflater, container, false)
|
||||||
@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
|
|
||||||
|
|
||||||
private val zxcvbn = Zxcvbn()
|
private val zxcvbn = Zxcvbn()
|
||||||
|
|
||||||
@OnTextChanged(R.id.keys_backup_passphrase_enter_edittext)
|
private fun onPassphraseChanged() {
|
||||||
fun onPassphraseChanged() {
|
viewModel.passphrase.value = views.keysBackupSetupStep2PassphraseEnterEdittext.text.toString()
|
||||||
viewModel.passphrase.value = mPassphraseTextEdit.text.toString()
|
|
||||||
viewModel.confirmPassphraseError.value = null
|
viewModel.confirmPassphraseError.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnTextChanged(R.id.keys_backup_passphrase_confirm_edittext)
|
private fun onConfirmPassphraseChanged() {
|
||||||
fun onConfirmPassphraseChanged() {
|
viewModel.confirmPassphrase.value = views.keysBackupSetupStep2PassphraseConfirmEditText.text.toString()
|
||||||
viewModel.confirmPassphrase.value = mPassphraseConfirmTextEdit.text.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||||
@ -85,6 +61,7 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
|
|
||||||
viewModel.shouldPromptOnBack = true
|
viewModel.shouldPromptOnBack = true
|
||||||
bindViewToViewModel()
|
bindViewToViewModel()
|
||||||
|
setupViews()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
@ -94,24 +71,24 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
private fun bindViewToViewModel() {
|
private fun bindViewToViewModel() {
|
||||||
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength ->
|
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength ->
|
||||||
if (strength == null) {
|
if (strength == null) {
|
||||||
mPassphraseProgressLevel.strength = 0
|
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = 0
|
||||||
mPassphraseInputLayout.error = null
|
views.keysBackupSetupStep2PassphraseEnterTil.error = null
|
||||||
} else {
|
} else {
|
||||||
val score = strength.score
|
val score = strength.score
|
||||||
mPassphraseProgressLevel.strength = score
|
views.keysBackupSetupStep2PassphraseStrengthLevel.strength = score
|
||||||
|
|
||||||
if (score in 1..3) {
|
if (score in 1..3) {
|
||||||
val warning = strength.feedback?.getWarning(VectorLocale.applicationLocale)
|
val warning = strength.feedback?.getWarning(VectorLocale.applicationLocale)
|
||||||
if (warning != null) {
|
if (warning != null) {
|
||||||
mPassphraseInputLayout.error = warning
|
views.keysBackupSetupStep2PassphraseEnterTil.error = warning
|
||||||
}
|
}
|
||||||
|
|
||||||
val suggestions = strength.feedback?.getSuggestions(VectorLocale.applicationLocale)
|
val suggestions = strength.feedback?.getSuggestions(VectorLocale.applicationLocale)
|
||||||
if (suggestions != null) {
|
if (suggestions != null) {
|
||||||
mPassphraseInputLayout.error = suggestions.firstOrNull()
|
views.keysBackupSetupStep2PassphraseEnterTil.error = suggestions.firstOrNull()
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
viewModel.passphraseError.observe(viewLifecycleOwner, Observer {
|
||||||
TransitionManager.beginDelayedTransition(rootGroup)
|
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
|
||||||
mPassphraseInputLayout.error = it
|
views.keysBackupSetupStep2PassphraseEnterTil.error = it
|
||||||
})
|
})
|
||||||
|
|
||||||
mPassphraseConfirmTextEdit.setText(viewModel.confirmPassphrase.value)
|
views.keysBackupSetupStep2PassphraseConfirmEditText.setText(viewModel.confirmPassphrase.value)
|
||||||
|
|
||||||
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
|
||||||
val shouldBeVisible = it ?: false
|
val shouldBeVisible = it ?: false
|
||||||
mPassphraseTextEdit.showPassword(shouldBeVisible)
|
views.keysBackupSetupStep2PassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||||
mPassphraseConfirmTextEdit.showPassword(shouldBeVisible)
|
views.keysBackupSetupStep2PassphraseConfirmEditText.showPassword(shouldBeVisible)
|
||||||
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.keysBackupSetupStep2ShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer {
|
viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer {
|
||||||
TransitionManager.beginDelayedTransition(rootGroup)
|
TransitionManager.beginDelayedTransition(views.keysBackupRoot)
|
||||||
mPassphraseConfirmInputLayout.error = it
|
views.keysBackupSetupStep2PassphraseConfirmTil.error = it
|
||||||
})
|
})
|
||||||
|
|
||||||
mPassphraseConfirmTextEdit.setOnEditorActionListener { _, actionId, _ ->
|
views.keysBackupSetupStep2PassphraseConfirmEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
doNext()
|
doNext()
|
||||||
return@setOnEditorActionListener true
|
return@setOnEditorActionListener true
|
||||||
@ -159,13 +136,20 @@ class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_view_show_password)
|
private fun setupViews() {
|
||||||
fun toggleVisibilityMode() {
|
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)
|
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_setup_step2_button)
|
private fun doNext() {
|
||||||
fun doNext() {
|
|
||||||
when {
|
when {
|
||||||
viewModel.passphrase.value.isNullOrEmpty() -> {
|
viewModel.passphrase.value.isNullOrEmpty() -> {
|
||||||
viewModel.passphraseError.value = context?.getString(R.string.passphrase_empty_error_message)
|
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)
|
private fun skipPassphrase() {
|
||||||
fun skipPassphrase() {
|
|
||||||
when {
|
when {
|
||||||
viewModel.passphrase.value.isNullOrEmpty() -> {
|
viewModel.passphrase.value.isNullOrEmpty() -> {
|
||||||
// Generate a recovery key for the user
|
// 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.app.Activity
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Button
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import arrow.core.Try
|
import arrow.core.Try
|
||||||
import butterknife.BindView
|
|
||||||
import butterknife.OnClick
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
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.copyToClipboard
|
||||||
import im.vector.app.core.utils.selectTxtFileToWrite
|
import im.vector.app.core.utils.selectTxtFileToWrite
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
|
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -46,18 +47,11 @@ import java.util.Date
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
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
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep3Binding {
|
||||||
|
return FragmentKeysBackupSetupStep3Binding.inflate(inflater, container, false)
|
||||||
@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
|
|
||||||
|
|
||||||
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
private lateinit var viewModel: KeysBackupSetupSharedViewModel
|
||||||
|
|
||||||
@ -70,10 +64,10 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
viewModel.passphrase.observe(viewLifecycleOwner, Observer {
|
viewModel.passphrase.observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNullOrBlank()) {
|
if (it.isNullOrBlank()) {
|
||||||
// Recovery was generated, so show key and options to save
|
// Recovery was generated, so show key and options to save
|
||||||
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)
|
views.keysBackupSetupStep3Label2.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.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(" ", "")
|
.replace(" ", "")
|
||||||
.chunked(16)
|
.chunked(16)
|
||||||
.joinToString("\n") {
|
.joinToString("\n") {
|
||||||
@ -81,17 +75,24 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
.chunked(4)
|
.chunked(4)
|
||||||
.joinToString(" ")
|
.joinToString(" ")
|
||||||
}
|
}
|
||||||
mRecoveryKeyTextView.isVisible = true
|
views.keysBackupSetupStep3RecoveryKeyText.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2)
|
views.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2)
|
||||||
mFinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
|
views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title)
|
||||||
mRecoveryKeyTextView.isVisible = false
|
views.keysBackupSetupStep3RecoveryKeyText.isVisible = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setupViews()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_setup_step3_button)
|
private fun setupViews() {
|
||||||
fun onFinishButtonClicked() {
|
views.keysBackupSetupStep3FinishButton.setOnClickListener { onFinishButtonClicked() }
|
||||||
|
views.keysBackupSetupStep3CopyButton.setOnClickListener { onCopyButtonClicked() }
|
||||||
|
views.keysBackupSetupStep3RecoveryKeyText.setOnClickListener { onRecoveryKeyClicked() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFinishButtonClicked() {
|
||||||
if (viewModel.megolmBackupCreationInfo == null) {
|
if (viewModel.megolmBackupCreationInfo == null) {
|
||||||
// nothing
|
// nothing
|
||||||
} else {
|
} else {
|
||||||
@ -103,8 +104,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_setup_step3_copy_button)
|
private fun onCopyButtonClicked() {
|
||||||
fun onCopyButtonClicked() {
|
|
||||||
val dialog = BottomSheetDialog(requireActivity())
|
val dialog = BottomSheetDialog(requireActivity())
|
||||||
dialog.setContentView(R.layout.bottom_sheet_save_recovery_key)
|
dialog.setContentView(R.layout.bottom_sheet_save_recovery_key)
|
||||||
dialog.setCanceledOnTouchOutside(true)
|
dialog.setCanceledOnTouchOutside(true)
|
||||||
@ -155,8 +155,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.keys_backup_recovery_key_text)
|
private fun onRecoveryKeyClicked() {
|
||||||
fun onRecoveryKeyClicked() {
|
|
||||||
viewModel.recoveryKey.value?.let {
|
viewModel.recoveryKey.value?.let {
|
||||||
viewModel.copyHasBeenMade = true
|
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.SimpleFragmentActivity
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import im.vector.app.features.crypto.recover.SetupMode
|
import im.vector.app.features.crypto.recover.SetupMode
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.android.synthetic.main.activity.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ class SharedSecureStorageActivity :
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
supportFragmentManager.addFragmentOnAttachListener(this)
|
supportFragmentManager.addFragmentOnAttachListener(this)
|
||||||
|
|
||||||
toolbar.visibility = View.GONE
|
views.toolbar.visibility = View.GONE
|
||||||
|
|
||||||
viewModel.observeViewEvents { observeViewEvents(it) }
|
viewModel.observeViewEvents { observeViewEvents(it) }
|
||||||
|
|
||||||
@ -132,7 +131,7 @@ class SharedSecureStorageActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttachFragment(fragmentManager: FragmentManager, fragment: Fragment) {
|
override fun onAttachFragment(fragmentManager: FragmentManager, fragment: Fragment) {
|
||||||
if (fragment is VectorBaseBottomSheetDialogFragment) {
|
if (fragment is VectorBaseBottomSheetDialogFragment<*>) {
|
||||||
fragment.resultListener = this
|
fragment.resultListener = this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,9 @@ package im.vector.app.features.crypto.quads
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.jakewharton.rxbinding3.widget.editorActionEvents
|
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.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||||
|
import im.vector.app.databinding.FragmentSsssAccessFromKeyBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
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 org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
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()
|
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -53,35 +58,35 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_key_enter_edittext.textChanges()
|
views.ssssKeyEnterEdittext.textChanges()
|
||||||
.skipInitialValue()
|
.skipInitialValue()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
ssss_key_enter_til.error = null
|
views.ssssKeyEnterTil.error = null
|
||||||
ssss_key_submit.isEnabled = it.isNotBlank()
|
views.ssssKeySubmit.isEnabled = it.isNotBlank()
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.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.handle(SharedSecureStorageAction.ForgotResetAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedViewModel.observeViewEvents {
|
sharedViewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SharedSecureStorageViewEvent.KeyInlineError -> {
|
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() {
|
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
|
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))
|
sharedViewModel.handle(SharedSecureStorageAction.SubmitKey(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +98,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
|
|||||||
?.bufferedReader()
|
?.bufferedReader()
|
||||||
?.use { it.readText() }
|
?.use { it.readText() }
|
||||||
?.let {
|
?.let {
|
||||||
ssss_key_enter_edittext.setText(it)
|
views.ssssKeyEnterEdittext.setText(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package im.vector.app.features.crypto.quads
|
package im.vector.app.features.crypto.quads
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import com.airbnb.mvrx.activityViewModel
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
import im.vector.app.core.utils.colorizeMatchingText
|
||||||
|
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
||||||
private val colorProvider: ColorProvider
|
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()
|
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||||
|
|
||||||
@ -48,7 +53,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||||||
// If has passphrase
|
// If has passphrase
|
||||||
val pass = getString(R.string.recovery_passphrase)
|
val pass = getString(R.string.recovery_passphrase)
|
||||||
val key = getString(R.string.recovery_key)
|
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,
|
R.string.enter_secret_storage_passphrase_or_key,
|
||||||
pass,
|
pass,
|
||||||
key
|
key
|
||||||
@ -57,7 +62,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||||||
.colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
.colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||||
.colorizeMatchingText(key, 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)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -67,40 +72,40 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_passphrase_enter_edittext.textChanges()
|
views.ssssPassphraseEnterEdittext.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
ssss_passphrase_enter_til.error = null
|
views.ssssPassphraseEnterTil.error = null
|
||||||
ssss_passphrase_submit.isEnabled = it.isNotBlank()
|
views.ssssPassphraseSubmit.isEnabled = it.isNotBlank()
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_passphrase_reset.clickableView.debouncedClicks {
|
views.ssssPassphraseReset.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
|
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedViewModel.observeViewEvents {
|
sharedViewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SharedSecureStorageViewEvent.InlineError -> {
|
is SharedSecureStorageViewEvent.InlineError -> {
|
||||||
ssss_passphrase_enter_til.error = it.message
|
views.ssssPassphraseEnterTil.error = it.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_passphrase_submit.debouncedClicks { submit() }
|
views.ssssPassphraseSubmit.debouncedClicks { submit() }
|
||||||
ssss_passphrase_use_key.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
|
views.ssssPassphraseUseKey.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
|
||||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
|
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun submit() {
|
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
|
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))
|
sharedViewModel.handle(SharedSecureStorageAction.SubmitPassphrase(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
val shouldBeVisible = state.passphraseVisible
|
val shouldBeVisible = state.passphraseVisible
|
||||||
ssss_passphrase_enter_edittext.showPassword(shouldBeVisible)
|
views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible)
|
||||||
ssss_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
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
|
package im.vector.app.features.crypto.quads
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentSsssResetAllBinding
|
||||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||||
import kotlinx.android.synthetic.main.fragment_ssss_reset_all.*
|
|
||||||
import javax.inject.Inject
|
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()
|
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
ssss_reset_button_reset.debouncedClicks {
|
views.ssssResetButtonReset.debouncedClicks {
|
||||||
sharedViewModel.handle(SharedSecureStorageAction.DoResetAll)
|
sharedViewModel.handle(SharedSecureStorageAction.DoResetAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_reset_button_cancel.debouncedClicks {
|
views.ssssResetButtonCancel.debouncedClicks {
|
||||||
sharedViewModel.handle(SharedSecureStorageAction.Back)
|
sharedViewModel.handle(SharedSecureStorageAction.Back)
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_reset_other_devices.debouncedClicks {
|
views.ssssResetOtherDevices.debouncedClicks {
|
||||||
withState(sharedViewModel) {
|
withState(sharedViewModel) {
|
||||||
DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST")
|
DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedViewModel.subscribe(this) { state ->
|
sharedViewModel.subscribe(this) { state ->
|
||||||
ssss_reset_other_devices.setTextOrHide(
|
views.ssssResetOtherDevices.setTextOrHide(
|
||||||
state.activeDeviceCount
|
state.activeDeviceCount
|
||||||
.takeIf { it > 0 }
|
.takeIf { it > 0 }
|
||||||
?.let { resources.getQuantityString(R.plurals.secure_backup_reset_devices_you_can_verify, it, it) }
|
?.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
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
import im.vector.app.core.utils.colorizeMatchingText
|
||||||
|
import im.vector.app.databinding.FragmentBootstrapEnterAccountPasswordBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
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 java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BootstrapAccountPasswordFragment @Inject constructor(
|
class BootstrapAccountPasswordFragment @Inject constructor(
|
||||||
private val colorProvider: ColorProvider
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
@ -49,13 +52,13 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
val recPassPhrase = getString(R.string.account_password)
|
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()
|
.toSpannable()
|
||||||
.colorizeMatchingText(recPassPhrase, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
.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)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -65,21 +68,21 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
bootstrapAccountPasswordEditText.textChanges()
|
views.bootstrapAccountPasswordEditText.textChanges()
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
if (!it.isNullOrBlank()) {
|
if (!it.isNullOrBlank()) {
|
||||||
bootstrapAccountPasswordTil.error = null
|
views.bootstrapAccountPasswordTil.error = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||||
bootstrapPasswordButton.debouncedClicks { submit() }
|
views.bootstrapPasswordButton.debouncedClicks { submit() }
|
||||||
|
|
||||||
withState(sharedViewModel) { state ->
|
withState(sharedViewModel) { state ->
|
||||||
(state.step as? BootstrapStep.AccountPassword)?.failure?.let {
|
(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) {
|
if (state.step !is BootstrapStep.AccountPassword) {
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
val accountPassword = bootstrapAccountPasswordEditText.text?.toString()
|
val accountPassword = views.bootstrapAccountPasswordEditText.text?.toString()
|
||||||
if (accountPassword.isNullOrBlank()) {
|
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 {
|
} else {
|
||||||
view?.hideKeyboard()
|
view?.hideKeyboard()
|
||||||
sharedViewModel.handle(BootstrapActions.ReAuth(accountPassword))
|
sharedViewModel.handle(BootstrapActions.ReAuth(accountPassword))
|
||||||
@ -100,8 +103,8 @@ class BootstrapAccountPasswordFragment @Inject constructor(
|
|||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
if (state.step is BootstrapStep.AccountPassword) {
|
if (state.step is BootstrapStep.AccountPassword) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
bootstrapAccountPasswordEditText.showPassword(isPasswordVisible, updateCursor = false)
|
views.bootstrapAccountPasswordEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
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.commitTransaction
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
import kotlinx.android.parcel.Parcelize
|
import im.vector.app.databinding.BottomSheetBootstrapBinding
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_bootstrap.*
|
import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBootstrapBinding>() {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Args(
|
data class Args(
|
||||||
@ -59,7 +59,9 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
injector.inject(this)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -120,60 +122,60 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
when (state.step) {
|
when (state.step) {
|
||||||
is BootstrapStep.CheckingMigration -> {
|
is BootstrapStep.CheckingMigration -> {
|
||||||
bootstrapIcon.isVisible = false
|
views.bootstrapIcon.isVisible = false
|
||||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||||
showFragment(BootstrapWaitingFragment::class, Bundle())
|
showFragment(BootstrapWaitingFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.FirstForm -> {
|
is BootstrapStep.FirstForm -> {
|
||||||
bootstrapIcon.isVisible = false
|
views.bootstrapIcon.isVisible = false
|
||||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
|
||||||
showFragment(BootstrapSetupRecoveryKeyFragment::class, Bundle())
|
showFragment(BootstrapSetupRecoveryKeyFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.SetupPassphrase -> {
|
is BootstrapStep.SetupPassphrase -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||||
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||||
showFragment(BootstrapEnterPassphraseFragment::class, Bundle())
|
showFragment(BootstrapEnterPassphraseFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.ConfirmPassphrase -> {
|
is BootstrapStep.ConfirmPassphrase -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
|
||||||
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
|
||||||
showFragment(BootstrapConfirmPassphraseFragment::class, Bundle())
|
showFragment(BootstrapConfirmPassphraseFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.AccountPassword -> {
|
is BootstrapStep.AccountPassword -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
|
||||||
bootstrapTitleText.text = getString(R.string.account_password)
|
views.bootstrapTitleText.text = getString(R.string.account_password)
|
||||||
showFragment(BootstrapAccountPasswordFragment::class, Bundle())
|
showFragment(BootstrapAccountPasswordFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.Initializing -> {
|
is BootstrapStep.Initializing -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||||
bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
|
views.bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
|
||||||
showFragment(BootstrapWaitingFragment::class, Bundle())
|
showFragment(BootstrapWaitingFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.SaveRecoveryKey -> {
|
is BootstrapStep.SaveRecoveryKey -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||||
bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
|
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
|
||||||
showFragment(BootstrapSaveRecoveryKeyFragment::class, Bundle())
|
showFragment(BootstrapSaveRecoveryKeyFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.DoneSuccess -> {
|
is BootstrapStep.DoneSuccess -> {
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
|
||||||
bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
|
views.bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
|
||||||
showFragment(BootstrapConclusionFragment::class, Bundle())
|
showFragment(BootstrapConclusionFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
is BootstrapStep.GetBackupSecretForMigration -> {
|
is BootstrapStep.GetBackupSecretForMigration -> {
|
||||||
val isKey = state.step.useKey()
|
val isKey = state.step.useKey()
|
||||||
val drawableRes = if (isKey) R.drawable.ic_security_key_24dp else R.drawable.ic_security_phrase_24dp
|
val drawableRes = if (isKey) R.drawable.ic_security_key_24dp else R.drawable.ic_security_phrase_24dp
|
||||||
bootstrapIcon.isVisible = true
|
views.bootstrapIcon.isVisible = true
|
||||||
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
|
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
drawableRes)
|
drawableRes)
|
||||||
)
|
)
|
||||||
bootstrapTitleText.text = getString(R.string.upgrade_security)
|
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
|
||||||
showFragment(BootstrapMigrateBackupFragment::class, Bundle())
|
showFragment(BootstrapMigrateBackupFragment::class, Bundle())
|
||||||
}
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package im.vector.app.features.crypto.recover
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
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
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BootstrapConclusionFragment @Inject constructor(
|
class BootstrapConclusionFragment @Inject constructor(
|
||||||
private val colorProvider: ColorProvider
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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 ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
if (state.step !is BootstrapStep.DoneSuccess) return@withState
|
if (state.step !is BootstrapStep.DoneSuccess) return@withState
|
||||||
|
|
||||||
bootstrapConclusionText.text = getString(
|
views.bootstrapConclusionText.text = getString(
|
||||||
R.string.bootstrap_cross_signing_success,
|
R.string.bootstrap_cross_signing_success,
|
||||||
getString(R.string.recovery_passphrase),
|
getString(R.string.recovery_passphrase),
|
||||||
getString(R.string.message_key)
|
getString(R.string.message_key)
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package im.vector.app.features.crypto.recover
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
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.hideKeyboard
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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)
|
views.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.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||||
|
|
||||||
withState(sharedViewModel) {
|
withState(sharedViewModel) {
|
||||||
// set initial value (useful when coming back)
|
// set initial value (useful when coming back)
|
||||||
ssss_passphrase_enter_edittext.setText(it.passphraseRepeat ?: "")
|
views.ssssPassphraseEnterEdittext.setText(it.passphraseRepeat ?: "")
|
||||||
ssss_passphrase_enter_edittext.requestFocus()
|
views.ssssPassphraseEnterEdittext.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_passphrase_enter_edittext.editorActionEvents()
|
views.ssssPassphraseEnterEdittext.editorActionEvents()
|
||||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -63,9 +69,9 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_passphrase_enter_edittext.textChanges()
|
views.ssssPassphraseEnterEdittext.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
ssss_passphrase_enter_til.error = null
|
views.ssssPassphraseEnterTil.error = null
|
||||||
sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it?.toString() ?: ""))
|
sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it?.toString() ?: ""))
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
@ -78,20 +84,20 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||||
bootstrapSubmit.debouncedClicks { submit() }
|
views.bootstrapSubmit.debouncedClicks { submit() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun submit() = withState(sharedViewModel) { state ->
|
private fun submit() = withState(sharedViewModel) { state ->
|
||||||
if (state.step !is BootstrapStep.ConfirmPassphrase) {
|
if (state.step !is BootstrapStep.ConfirmPassphrase) {
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
val passphrase = ssss_passphrase_enter_edittext.text?.toString()
|
val passphrase = views.ssssPassphraseEnterEdittext.text?.toString()
|
||||||
when {
|
when {
|
||||||
passphrase.isNullOrBlank() ->
|
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 ->
|
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 -> {
|
else -> {
|
||||||
view?.hideKeyboard()
|
view?.hideKeyboard()
|
||||||
sharedViewModel.handle(BootstrapActions.DoInitialize(passphrase))
|
sharedViewModel.handle(BootstrapActions.DoInitialize(passphrase))
|
||||||
@ -102,8 +108,8 @@ class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragm
|
|||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
if (state.step is BootstrapStep.ConfirmPassphrase) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
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
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
@ -26,29 +28,33 @@ import com.jakewharton.rxbinding3.widget.textChanges
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
|
||||||
import im.vector.app.features.settings.VectorLocale
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
|
views.bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
|
||||||
ssss_passphrase_enter_edittext.hint = getString(R.string.set_a_security_phrase_hint)
|
views.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint)
|
||||||
|
|
||||||
withState(sharedViewModel) {
|
withState(sharedViewModel) {
|
||||||
// set initial value (useful when coming back)
|
// 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)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -58,7 +64,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
ssss_passphrase_enter_edittext.textChanges()
|
views.ssssPassphraseEnterEdittext.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
// ssss_passphrase_enter_til.error = null
|
// ssss_passphrase_enter_til.error = null
|
||||||
sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
||||||
@ -74,8 +80,8 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||||
bootstrapSubmit.debouncedClicks { submit() }
|
views.bootstrapSubmit.debouncedClicks { submit() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun submit() = withState(sharedViewModel) { state ->
|
private fun submit() = withState(sharedViewModel) { state ->
|
||||||
@ -83,11 +89,11 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
val score = state.passphraseStrength.invoke()?.score
|
val score = state.passphraseStrength.invoke()?.score
|
||||||
val passphrase = ssss_passphrase_enter_edittext.text?.toString()
|
val passphrase = views.ssssPassphraseEnterEdittext.text?.toString()
|
||||||
if (passphrase.isNullOrBlank()) {
|
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) {
|
} 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 {
|
} else {
|
||||||
sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
|
sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
|
||||||
}
|
}
|
||||||
@ -96,21 +102,21 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
|
|||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
if (state.step is BootstrapStep.SetupPassphrase) {
|
if (state.step is BootstrapStep.SetupPassphrase) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
|
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
|
|
||||||
state.passphraseStrength.invoke()?.let { strength ->
|
state.passphraseStrength.invoke()?.let { strength ->
|
||||||
val score = strength.score
|
val score = strength.score
|
||||||
ssss_passphrase_security_progress.strength = score
|
views.ssssPassphraseSecurityProgress.strength = score
|
||||||
if (score in 1..3) {
|
if (score in 1..3) {
|
||||||
val hint =
|
val hint =
|
||||||
strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() }
|
strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() }
|
||||||
?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()
|
?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()
|
||||||
if (hint != null && hint != ssss_passphrase_enter_til.error.toString()) {
|
if (hint != null && hint != views.ssssPassphraseEnterTil.error.toString()) {
|
||||||
ssss_passphrase_enter_til.error = hint
|
views.ssssPassphraseEnterTil.error = hint
|
||||||
}
|
}
|
||||||
} else {
|
} 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_CLASS_TEXT
|
||||||
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
|
||||||
import android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
import android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import androidx.core.view.isVisible
|
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.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
import im.vector.app.core.utils.colorizeMatchingText
|
||||||
import im.vector.app.core.utils.startImportTextFromFileIntent
|
import im.vector.app.core.utils.startImportTextFromFileIntent
|
||||||
|
import im.vector.app.databinding.FragmentBootstrapMigrateBackupBinding
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
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.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey
|
import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -47,9 +49,11 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class BootstrapMigrateBackupFragment @Inject constructor(
|
class BootstrapMigrateBackupFragment @Inject constructor(
|
||||||
private val colorProvider: ColorProvider
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
@ -58,9 +62,9 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||||||
|
|
||||||
withState(sharedViewModel) {
|
withState(sharedViewModel) {
|
||||||
// set initial value (useful when coming back)
|
// 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)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
@ -70,19 +74,19 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
bootstrapMigrateEditText.textChanges()
|
views.bootstrapMigrateEditText.textChanges()
|
||||||
.skipInitialValue()
|
.skipInitialValue()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
bootstrapRecoveryKeyEnterTil.error = null
|
views.bootstrapRecoveryKeyEnterTil.error = null
|
||||||
// sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
// sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
// sharedViewModel.observeViewEvents {}
|
// sharedViewModel.observeViewEvents {}
|
||||||
bootstrapMigrateContinueButton.debouncedClicks { submit() }
|
views.bootstrapMigrateContinueButton.debouncedClicks { submit() }
|
||||||
bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
views.bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
|
||||||
bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
|
views.bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
|
||||||
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
views.bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun submit() = withState(sharedViewModel) { state ->
|
private fun submit() = withState(sharedViewModel) { state ->
|
||||||
@ -90,12 +94,12 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||||||
|
|
||||||
val isEnteringKey = getBackupSecretForMigration.useKey()
|
val isEnteringKey = getBackupSecretForMigration.useKey()
|
||||||
|
|
||||||
val secret = bootstrapMigrateEditText.text?.toString()
|
val secret = views.bootstrapMigrateEditText.text?.toString()
|
||||||
if (secret.isNullOrEmpty()) {
|
if (secret.isNullOrEmpty()) {
|
||||||
val errRes = if (isEnteringKey) R.string.recovery_key_empty_error_message else R.string.passphrase_empty_error_message
|
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)) {
|
} 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 {
|
} else {
|
||||||
view?.hideKeyboard()
|
view?.hideKeyboard()
|
||||||
if (isEnteringKey) {
|
if (isEnteringKey) {
|
||||||
@ -112,38 +116,38 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||||||
val isEnteringKey = getBackupSecretForMigration.useKey()
|
val isEnteringKey = getBackupSecretForMigration.useKey()
|
||||||
|
|
||||||
if (isEnteringKey) {
|
if (isEnteringKey) {
|
||||||
bootstrapMigrateShowPassword.isVisible = false
|
views.bootstrapMigrateShowPassword.isVisible = false
|
||||||
bootstrapMigrateEditText.inputType = TYPE_CLASS_TEXT or TYPE_TEXT_VARIATION_VISIBLE_PASSWORD or TYPE_TEXT_FLAG_MULTI_LINE
|
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)
|
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
|
views.bootstrapMigrateEditText.hint = recKey
|
||||||
bootstrapMigrateForgotPassphrase.isVisible = false
|
views.bootstrapMigrateForgotPassphrase.isVisible = false
|
||||||
bootstrapMigrateUseFile.isVisible = true
|
views.bootstrapMigrateUseFile.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
bootstrapMigrateShowPassword.isVisible = true
|
views.bootstrapMigrateShowPassword.isVisible = true
|
||||||
|
|
||||||
if (state.step is BootstrapStep.GetBackupSecretPassForMigration) {
|
if (state.step is BootstrapStep.GetBackupSecretPassForMigration) {
|
||||||
val isPasswordVisible = state.step.isPasswordVisible
|
val isPasswordVisible = state.step.isPasswordVisible
|
||||||
bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false)
|
views.bootstrapMigrateEditText.showPassword(isPasswordVisible, updateCursor = false)
|
||||||
bootstrapMigrateShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
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)
|
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()
|
.toSpannable()
|
||||||
.colorizeMatchingText(recKey, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
.colorizeMatchingText(recKey, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
|
||||||
|
|
||||||
bootstrapMigrateUseFile.isVisible = false
|
views.bootstrapMigrateUseFile.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +159,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
|
|||||||
?.bufferedReader()
|
?.bufferedReader()
|
||||||
?.use { it.readText() }
|
?.use { it.readText() }
|
||||||
?.let {
|
?.let {
|
||||||
bootstrapMigrateEditText.setText(it)
|
views.bootstrapMigrateEditText.setText(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ import android.app.Activity
|
|||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
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.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.core.utils.toast
|
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.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -38,18 +41,20 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
||||||
private val colorProvider: ColorProvider
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() }
|
views.recoverySave.views.itemVerificationClickableZone.debouncedClicks { downloadRecoveryKey() }
|
||||||
recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() }
|
views.recoveryCopy.views.itemVerificationClickableZone.debouncedClicks { shareRecoveryKey() }
|
||||||
recoveryContinue.clickableView.debouncedClicks {
|
views.recoveryContinue.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
// We do not display the final Fragment anymore
|
// We do not display the final Fragment anymore
|
||||||
// TODO Do some cleanup
|
// TODO Do some cleanup
|
||||||
// sharedViewModel.handle(BootstrapActions.GoToCompleted)
|
// sharedViewModel.handle(BootstrapActions.GoToCompleted)
|
||||||
@ -112,7 +117,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||||||
val step = state.step
|
val step = state.step
|
||||||
if (step !is BootstrapStep.SaveRecoveryKey) return@withState
|
if (step !is BootstrapStep.SaveRecoveryKey) return@withState
|
||||||
|
|
||||||
recoveryContinue.isVisible = step.isSaved
|
views.recoveryContinue.isVisible = step.isSaved
|
||||||
bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
views.bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,24 @@
|
|||||||
package im.vector.app.features.crypto.recover
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
@ -36,15 +42,15 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
// Actions when a key backup exist
|
// Actions when a key backup exist
|
||||||
bootstrapSetupSecureSubmit.clickableView.debouncedClicks {
|
views.bootstrapSetupSecureSubmit.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
sharedViewModel.handle(BootstrapActions.StartKeyBackupMigration)
|
sharedViewModel.handle(BootstrapActions.StartKeyBackupMigration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions when there is no key backup
|
// Actions when there is no key backup
|
||||||
bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks {
|
views.bootstrapSetupSecureUseSecurityKey.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = false))
|
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = false))
|
||||||
}
|
}
|
||||||
bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks {
|
views.bootstrapSetupSecureUseSecurityPassphrase.views.itemVerificationClickableZone.debouncedClicks {
|
||||||
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = true))
|
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,23 +59,23 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
|
|||||||
if (state.step is BootstrapStep.FirstForm) {
|
if (state.step is BootstrapStep.FirstForm) {
|
||||||
if (state.step.keyBackUpExist) {
|
if (state.step.keyBackUpExist) {
|
||||||
// Display the set up action
|
// Display the set up action
|
||||||
bootstrapSetupSecureSubmit.isVisible = true
|
views.bootstrapSetupSecureSubmit.isVisible = true
|
||||||
bootstrapSetupSecureUseSecurityKey.isVisible = false
|
views.bootstrapSetupSecureUseSecurityKey.isVisible = false
|
||||||
bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
|
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
|
||||||
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
|
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
if (state.step.reset) {
|
if (state.step.reset) {
|
||||||
bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
|
views.bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
|
||||||
bootstrapSetupWarningTextView.isVisible = true
|
views.bootstrapSetupWarningTextView.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
|
views.bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
|
||||||
bootstrapSetupWarningTextView.isVisible = false
|
views.bootstrapSetupWarningTextView.isVisible = false
|
||||||
}
|
}
|
||||||
// Choose between create a passphrase or use a recovery key
|
// Choose between create a passphrase or use a recovery key
|
||||||
bootstrapSetupSecureSubmit.isVisible = false
|
views.bootstrapSetupSecureSubmit.isVisible = false
|
||||||
bootstrapSetupSecureUseSecurityKey.isVisible = true
|
views.bootstrapSetupSecureUseSecurityKey.isVisible = true
|
||||||
bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
|
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
|
||||||
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
|
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,26 +16,31 @@
|
|||||||
|
|
||||||
package im.vector.app.features.crypto.recover
|
package im.vector.app.features.crypto.recover
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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
|
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()
|
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
|
||||||
|
|
||||||
override fun invalidate() = withState(sharedViewModel) { state ->
|
override fun invalidate() = withState(sharedViewModel) { state ->
|
||||||
when (state.step) {
|
when (state.step) {
|
||||||
is BootstrapStep.Initializing -> {
|
is BootstrapStep.Initializing -> {
|
||||||
bootstrapLoadingStatusText.isVisible = true
|
views.bootstrapLoadingStatusText.isVisible = true
|
||||||
bootstrapDescriptionText.isVisible = true
|
views.bootstrapDescriptionText.isVisible = true
|
||||||
bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
|
views.bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
|
||||||
}
|
}
|
||||||
// is BootstrapStep.CheckingMigration -> {
|
// is BootstrapStep.CheckingMigration -> {
|
||||||
// bootstrapLoadingStatusText.isVisible = false
|
// bootstrapLoadingStatusText.isVisible = false
|
||||||
@ -43,8 +48,8 @@ class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() {
|
|||||||
// }
|
// }
|
||||||
else -> {
|
else -> {
|
||||||
// just show the spinner
|
// just show the spinner
|
||||||
bootstrapLoadingStatusText.isVisible = false
|
views.bootstrapLoadingStatusText.isVisible = false
|
||||||
bootstrapDescriptionText.isVisible = false
|
views.bootstrapDescriptionText.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ package im.vector.app.features.crypto.recover
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogRecoveryKeySavedInfoBinding
|
||||||
import me.gujun.android.span.image
|
import me.gujun.android.span.image
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
|
|
||||||
@ -30,10 +30,9 @@ class KeepItSafeDialog {
|
|||||||
|
|
||||||
fun show(activity: Activity) {
|
fun show(activity: Activity) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_recovery_key_saved_info, null)
|
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)
|
views.keepItSafeText.text = span {
|
||||||
|
|
||||||
descriptionText.text = span {
|
|
||||||
span {
|
span {
|
||||||
image(ContextCompat.getDrawable(activity, R.drawable.ic_check_on)!!)
|
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),
|
context.getString(R.string.sas_incoming_request_notif_content, name),
|
||||||
R.drawable.ic_shield_black,
|
R.drawable.ic_shield_black,
|
||||||
shouldBeDisplayedIn = { activity ->
|
shouldBeDisplayedIn = { activity ->
|
||||||
if (activity is VectorBaseActivity) {
|
if (activity is VectorBaseActivity<*>) {
|
||||||
// TODO a bit too ugly :/
|
// TODO a bit too ugly :/
|
||||||
activity.supportFragmentManager.findFragmentByTag(VerificationBottomSheet.WAITING_SELF_VERIF_TAG)?.let {
|
activity.supportFragmentManager.findFragmentByTag(VerificationBottomSheet.WAITING_SELF_VERIF_TAG)?.let {
|
||||||
false.also {
|
false.also {
|
||||||
@ -82,7 +82,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
addButton(
|
addButton(
|
||||||
context.getString(R.string.action_open),
|
context.getString(R.string.action_open),
|
||||||
Runnable {
|
Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
it.navigator.performDeviceVerification(it, tx.otherUserId, tx.transactionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
val roomId = pr.roomId
|
val roomId = pr.roomId
|
||||||
if (roomId.isNullOrBlank()) {
|
if (roomId.isNullOrBlank()) {
|
||||||
it.navigator.waitSessionVerification(it)
|
it.navigator.waitSessionVerification(it)
|
||||||
|
@ -16,10 +16,14 @@
|
|||||||
|
|
||||||
package im.vector.app.features.crypto.verification
|
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.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentProgressBinding
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() {
|
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment<FragmentProgressBinding>() {
|
||||||
override fun getLayoutResId() = R.layout.fragment_progress
|
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.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import butterknife.BindView
|
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
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.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
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.quads.SharedSecureStorageActivity
|
||||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
||||||
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
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.crypto.verification.request.VerificationRequestFragment
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
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.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
|
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
|
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 javax.inject.Inject
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class VerificationArgs(
|
data class VerificationArgs(
|
||||||
@ -86,16 +86,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
injector.inject(this)
|
injector.inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@BindView(R.id.verificationRequestName)
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
|
||||||
lateinit var otherUserNameText: TextView
|
return BottomSheetVerificationBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
@BindView(R.id.verificationRequestShield)
|
|
||||||
lateinit var otherUserShield: ImageView
|
|
||||||
|
|
||||||
@BindView(R.id.verificationRequestAvatar)
|
|
||||||
lateinit var otherUserAvatarImageView: ImageView
|
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.bottom_sheet_verification
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
isCancelable = false
|
isCancelable = false
|
||||||
@ -126,7 +119,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
VerificationBottomSheetViewEvents.GoToSettings -> {
|
VerificationBottomSheetViewEvents.GoToSettings -> {
|
||||||
dismiss()
|
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
|
}.exhaustive
|
||||||
}
|
}
|
||||||
@ -163,27 +158,27 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
state.otherUserMxItem?.let { matrixItem ->
|
state.otherUserMxItem?.let { matrixItem ->
|
||||||
if (state.isMe) {
|
if (state.isMe) {
|
||||||
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
|
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
|
||||||
if (state.sasTransactionState == VerificationTxState.Verified
|
if (state.sasTransactionState == VerificationTxState.Verified
|
||||||
|| state.qrTransactionState == VerificationTxState.Verified
|
|| state.qrTransactionState == VerificationTxState.Verified
|
||||||
|| state.verifiedFromPrivateKeys) {
|
|| state.verifiedFromPrivateKeys) {
|
||||||
otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
|
views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
|
||||||
} else {
|
} 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
|
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
|
||||||
)
|
)
|
||||||
otherUserShield.isVisible = true
|
views.otherUserShield.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
|
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
|
||||||
|
|
||||||
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
|
||||||
otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
|
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
|
||||||
otherUserShield.isVisible = true
|
views.otherUserShield.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
|
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
|
||||||
otherUserShield.isVisible = false
|
views.otherUserShield.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,13 +195,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.userThinkItsNotHim) {
|
if (state.userThinkItsNotHim) {
|
||||||
otherUserNameText.text = getString(R.string.dialog_title_warning)
|
views.otherUserNameText.text = getString(R.string.dialog_title_warning)
|
||||||
showFragment(VerificationNotMeFragment::class, Bundle())
|
showFragment(VerificationNotMeFragment::class, Bundle())
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.userWantsToCancel) {
|
if (state.userWantsToCancel) {
|
||||||
otherUserNameText.text = getString(R.string.are_you_sure)
|
views.otherUserNameText.text = getString(R.string.are_you_sure)
|
||||||
showFragment(VerificationCancelFragment::class, Bundle())
|
showFragment(VerificationCancelFragment::class, Bundle())
|
||||||
return@withState
|
return@withState
|
||||||
}
|
}
|
||||||
@ -298,7 +293,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
|
|||||||
// Transaction has not yet started
|
// Transaction has not yet started
|
||||||
if (state.pendingRequest.invoke()?.cancelConclusion != null) {
|
if (state.pendingRequest.invoke()?.cancelConclusion != null) {
|
||||||
// The request has been declined, we should dismiss
|
// 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 {
|
showFragment(VerificationConclusionFragment::class, Bundle().apply {
|
||||||
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
|
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
|
||||||
false,
|
false,
|
||||||
|
@ -17,24 +17,29 @@
|
|||||||
package im.vector.app.features.crypto.verification.cancel
|
package im.vector.app.features.crypto.verification.cancel
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationCancelFragment @Inject constructor(
|
class VerificationCancelFragment @Inject constructor(
|
||||||
val controller: VerificationCancelController
|
val controller: VerificationCancelController
|
||||||
) : VectorBaseFragment(), VerificationCancelController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationCancelController.Listener {
|
||||||
|
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -42,13 +47,13 @@ class VerificationCancelFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,24 +17,29 @@
|
|||||||
package im.vector.app.features.crypto.verification.cancel
|
package im.vector.app.features.crypto.verification.cancel
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationNotMeFragment @Inject constructor(
|
class VerificationNotMeFragment @Inject constructor(
|
||||||
val controller: VerificationNotMeController
|
val controller: VerificationNotMeController
|
||||||
) : VectorBaseFragment(), VerificationNotMeController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationNotMeController.Listener {
|
||||||
|
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -42,13 +47,13 @@ class VerificationNotMeFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,11 +17,12 @@ package im.vector.app.features.crypto.verification.choose
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
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.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
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.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationChooseMethodFragment @Inject constructor(
|
class VerificationChooseMethodFragment @Inject constructor(
|
||||||
val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
|
val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
|
||||||
val controller: VerificationChooseMethodController
|
val controller: VerificationChooseMethodController
|
||||||
) : VectorBaseFragment(), VerificationChooseMethodController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationChooseMethodController.Listener {
|
||||||
|
|
||||||
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
|
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
|
||||||
|
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -54,13 +59,13 @@ class VerificationChooseMethodFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,23 +17,25 @@ package im.vector.app.features.crypto.verification.conclusion
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationConclusionFragment @Inject constructor(
|
class VerificationConclusionFragment @Inject constructor(
|
||||||
val controller: VerificationConclusionController
|
val controller: VerificationConclusionController
|
||||||
) : VectorBaseFragment(), VerificationConclusionController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationConclusionController.Listener {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Args(
|
data class Args(
|
||||||
@ -46,7 +48,9 @@ class VerificationConclusionFragment @Inject constructor(
|
|||||||
|
|
||||||
private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -55,13 +59,13 @@ class VerificationConclusionFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,29 +16,34 @@
|
|||||||
package im.vector.app.features.crypto.verification.emoji
|
package im.vector.app.features.crypto.verification.emoji
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationEmojiCodeFragment @Inject constructor(
|
class VerificationEmojiCodeFragment @Inject constructor(
|
||||||
val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
|
val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
|
||||||
val controller: VerificationEmojiCodeController
|
val controller: VerificationEmojiCodeController
|
||||||
) : VectorBaseFragment(), VerificationEmojiCodeController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationEmojiCodeController.Listener {
|
||||||
|
|
||||||
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
|
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
|
||||||
|
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -47,13 +52,13 @@ class VerificationEmojiCodeFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,19 +18,20 @@ package im.vector.app.features.crypto.verification.qrconfirmation
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import kotlinx.android.parcel.Parcelize
|
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationQRWaitingFragment @Inject constructor(
|
class VerificationQRWaitingFragment @Inject constructor(
|
||||||
val controller: VerificationQRWaitingController
|
val controller: VerificationQRWaitingController
|
||||||
) : VectorBaseFragment() {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>() {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Args(
|
data class Args(
|
||||||
@ -38,7 +39,9 @@ class VerificationQRWaitingFragment @Inject constructor(
|
|||||||
val otherUserName: String
|
val otherUserName: String
|
||||||
) : Parcelable
|
) : 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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -49,11 +52,11 @@ class VerificationQRWaitingFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
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
|
package im.vector.app.features.crypto.verification.qrconfirmation
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationQrScannedByOtherFragment @Inject constructor(
|
class VerificationQrScannedByOtherFragment @Inject constructor(
|
||||||
val controller: VerificationQrScannedByOtherController
|
val controller: VerificationQrScannedByOtherController
|
||||||
) : VectorBaseFragment(), VerificationQrScannedByOtherController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationQrScannedByOtherController.Listener {
|
||||||
|
|
||||||
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -46,13 +51,13 @@ class VerificationQrScannedByOtherFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,25 +16,30 @@
|
|||||||
package im.vector.app.features.crypto.verification.request
|
package im.vector.app.features.crypto.verification.request
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.parentFragmentViewModel
|
import com.airbnb.mvrx.parentFragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.VerificationAction
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
|
||||||
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VerificationRequestFragment @Inject constructor(
|
class VerificationRequestFragment @Inject constructor(
|
||||||
val controller: VerificationRequestController
|
val controller: VerificationRequestController
|
||||||
) : VectorBaseFragment(), VerificationRequestController.Listener {
|
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
|
||||||
|
VerificationRequestController.Listener {
|
||||||
|
|
||||||
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
@ -42,13 +47,13 @@ class VerificationRequestFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
bottomSheetVerificationRecyclerView.cleanup()
|
views.bottomSheetVerificationRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,11 @@ package im.vector.app.features.discovery
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
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.exhaustive
|
||||||
import im.vector.app.core.extensions.observeEvent
|
import im.vector.app.core.extensions.observeEvent
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.ensureProtocol
|
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.discovery.change.SetIdentityServerFragment
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
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.SharedState
|
||||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||||
@ -41,9 +44,12 @@ import javax.inject.Inject
|
|||||||
class DiscoverySettingsFragment @Inject constructor(
|
class DiscoverySettingsFragment @Inject constructor(
|
||||||
private val controller: DiscoverySettingsController,
|
private val controller: DiscoverySettingsController,
|
||||||
val viewModelFactory: DiscoverySettingsViewModel.Factory
|
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)
|
private val viewModel by fragmentViewModel(DiscoverySettingsViewModel::class)
|
||||||
|
|
||||||
@ -55,7 +61,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||||||
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
||||||
|
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
genericRecyclerView.configureWith(controller)
|
views.genericRecyclerView.configureWith(controller)
|
||||||
|
|
||||||
sharedViewModel.navigateEvent.observeEvent(this) {
|
sharedViewModel.navigateEvent.observeEvent(this) {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -74,7 +80,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
genericRecyclerView.cleanup()
|
views.genericRecyclerView.cleanup()
|
||||||
controller.listener = null
|
controller.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
@ -85,7 +91,7 @@ class DiscoverySettingsFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.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
|
// If some 3pids are pending, we can try to check if they have been verified here
|
||||||
viewModel.handle(DiscoverySettingsAction.Refresh)
|
viewModel.handle(DiscoverySettingsAction.Refresh)
|
||||||
|
@ -17,9 +17,12 @@ package im.vector.app.features.discovery.change
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
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.exhaustive
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.extensions.toReducedUrl
|
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.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.colorizeMatchingText
|
import im.vector.app.core.utils.colorizeMatchingText
|
||||||
|
import im.vector.app.databinding.FragmentSetIdentityServerBinding
|
||||||
import im.vector.app.features.discovery.DiscoverySharedViewModel
|
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 org.matrix.android.sdk.api.session.terms.TermsService
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SetIdentityServerFragment @Inject constructor(
|
class SetIdentityServerFragment @Inject constructor(
|
||||||
val viewModelFactory: SetIdentityServerViewModel.Factory,
|
val viewModelFactory: SetIdentityServerViewModel.Factory,
|
||||||
val colorProvider: ColorProvider
|
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)
|
private val viewModel by fragmentViewModel(SetIdentityServerViewModel::class)
|
||||||
|
|
||||||
@ -52,11 +57,11 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
if (state.defaultIdentityServerUrl.isNullOrEmpty()) {
|
if (state.defaultIdentityServerUrl.isNullOrEmpty()) {
|
||||||
// No default
|
// No default
|
||||||
identityServerSetDefaultNotice.isVisible = false
|
views.identityServerSetDefaultNotice.isVisible = false
|
||||||
identityServerSetDefaultSubmit.isVisible = false
|
views.identityServerSetDefaultSubmit.isVisible = false
|
||||||
identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice_no_default)
|
views.identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice_no_default)
|
||||||
} else {
|
} else {
|
||||||
identityServerSetDefaultNotice.text = getString(
|
views.identityServerSetDefaultNotice.text = getString(
|
||||||
R.string.identity_server_set_default_notice,
|
R.string.identity_server_set_default_notice,
|
||||||
state.homeServerUrl.toReducedUrl(),
|
state.homeServerUrl.toReducedUrl(),
|
||||||
state.defaultIdentityServerUrl.toReducedUrl()
|
state.defaultIdentityServerUrl.toReducedUrl()
|
||||||
@ -65,10 +70,10 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
.colorizeMatchingText(state.defaultIdentityServerUrl.toReducedUrl(),
|
.colorizeMatchingText(state.defaultIdentityServerUrl.toReducedUrl(),
|
||||||
colorProvider.getColorFromAttribute(R.attr.riotx_text_primary_body_contrast))
|
colorProvider.getColorFromAttribute(R.attr.riotx_text_primary_body_contrast))
|
||||||
|
|
||||||
identityServerSetDefaultNotice.isVisible = true
|
views.identityServerSetDefaultNotice.isVisible = true
|
||||||
identityServerSetDefaultSubmit.isVisible = true
|
views.identityServerSetDefaultSubmit.isVisible = true
|
||||||
identityServerSetDefaultSubmit.text = getString(R.string.identity_server_set_default_submit, state.defaultIdentityServerUrl.toReducedUrl())
|
views.identityServerSetDefaultSubmit.text = getString(R.string.identity_server_set_default_submit, state.defaultIdentityServerUrl.toReducedUrl())
|
||||||
identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice)
|
views.identityServerSetDefaultAlternative.setText(R.string.identity_server_set_alternative_notice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,28 +82,28 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
|
|
||||||
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
|
||||||
|
|
||||||
identityServerSetDefaultAlternativeTextInput.setOnEditorActionListener { _, actionId, _ ->
|
views.identityServerSetDefaultAlternativeTextInput.setOnEditorActionListener { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
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 true
|
||||||
}
|
}
|
||||||
return@setOnEditorActionListener false
|
return@setOnEditorActionListener false
|
||||||
}
|
}
|
||||||
|
|
||||||
identityServerSetDefaultAlternativeTextInput
|
views.identityServerSetDefaultAlternativeTextInput
|
||||||
.textChanges()
|
.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
identityServerSetDefaultAlternativeTil.error = null
|
views.identityServerSetDefaultAlternativeTil.error = null
|
||||||
identityServerSetDefaultAlternativeSubmit.isEnabled = it.isNotEmpty()
|
views.identityServerSetDefaultAlternativeSubmit.isEnabled = it.isNotEmpty()
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
|
||||||
identityServerSetDefaultSubmit.debouncedClicks {
|
views.identityServerSetDefaultSubmit.debouncedClicks {
|
||||||
viewModel.handle(SetIdentityServerAction.UseDefaultIdentityServer)
|
viewModel.handle(SetIdentityServerAction.UseDefaultIdentityServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
identityServerSetDefaultAlternativeSubmit.debouncedClicks {
|
views.identityServerSetDefaultAlternativeSubmit.debouncedClicks {
|
||||||
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(identityServerSetDefaultAlternativeTextInput.text.toString()))
|
viewModel.handle(SetIdentityServerAction.UseCustomIdentityServer(views.identityServerSetDefaultAlternativeTextInput.text.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
@ -141,13 +146,13 @@ class SetIdentityServerFragment @Inject constructor(
|
|||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
// Display the error inlined
|
// Display the error inlined
|
||||||
identityServerSetDefaultAlternativeTil.error = message
|
views.identityServerSetDefaultAlternativeTil.error = message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.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 {
|
private val termsActivityResultLauncher = registerStartForActivityResult {
|
||||||
|
@ -18,39 +18,44 @@
|
|||||||
package im.vector.app.features.grouplist
|
package im.vector.app.features.grouplist
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import com.airbnb.mvrx.Incomplete
|
import com.airbnb.mvrx.Incomplete
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.StateView
|
import im.vector.app.core.platform.StateView
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
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.HomeActivitySharedAction
|
||||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
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 org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GroupListFragment @Inject constructor(
|
class GroupListFragment @Inject constructor(
|
||||||
val groupListViewModelFactory: GroupListViewModel.Factory,
|
val groupListViewModelFactory: GroupListViewModel.Factory,
|
||||||
private val groupController: GroupSummaryController
|
private val groupController: GroupSummaryController
|
||||||
) : VectorBaseFragment(), GroupSummaryController.Callback {
|
) : VectorBaseFragment<FragmentGroupListBinding>(),
|
||||||
|
GroupSummaryController.Callback {
|
||||||
|
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
private val viewModel: GroupListViewModel by fragmentViewModel()
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
groupController.callback = this
|
groupController.callback = this
|
||||||
stateView.contentView = groupListView
|
views.stateView.contentView = views.groupListView
|
||||||
groupListView.configureWith(groupController)
|
views.groupListView.configureWith(groupController)
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
||||||
@ -60,14 +65,14 @@ class GroupListFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
groupController.callback = null
|
groupController.callback = null
|
||||||
groupListView.cleanup()
|
views.groupListView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
when (state.asyncGroups) {
|
when (state.asyncGroups) {
|
||||||
is Incomplete -> stateView.state = StateView.State.Loading
|
is Incomplete -> views.stateView.state = StateView.State.Loading
|
||||||
is Success -> stateView.state = StateView.State.Content
|
is Success -> views.stateView.state = StateView.State.Content
|
||||||
}
|
}
|
||||||
groupController.update(state)
|
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.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.utils.toast
|
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.disclaimer.showDisclaimerDialog
|
||||||
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
import im.vector.app.features.matrixto.MatrixToBottomSheet
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
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.features.workers.signout.ServerBackupStatusViewState
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
|
||||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
|
||||||
import org.matrix.android.sdk.api.session.InitialSyncProgressService
|
import org.matrix.android.sdk.api.session.InitialSyncProgressService
|
||||||
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
@ -71,7 +70,11 @@ data class HomeActivityArgs(
|
|||||||
val accountCreation: Boolean
|
val accountCreation: Boolean
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory,
|
class HomeActivity :
|
||||||
|
VectorBaseActivity<ActivityHomeBinding>(),
|
||||||
|
ToolbarConfigurable,
|
||||||
|
UnknownDeviceDetectorSharedViewModel.Factory,
|
||||||
|
ServerBackupStatusViewModel.Factory,
|
||||||
NavigationInterceptor {
|
NavigationInterceptor {
|
||||||
|
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
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) {
|
override fun injectWith(injector: ScreenComponent) {
|
||||||
injector.inject(this)
|
injector.inject(this)
|
||||||
@ -116,7 +119,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
|
||||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
drawerLayout.addDrawerListener(drawerListener)
|
views.drawerLayout.addDrawerListener(drawerListener)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
|
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
|
||||||
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
||||||
@ -126,10 +129,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
.observe()
|
.observe()
|
||||||
.subscribe { sharedAction ->
|
.subscribe { sharedAction ->
|
||||||
when (sharedAction) {
|
when (sharedAction) {
|
||||||
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
|
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
|
||||||
is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START)
|
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
is HomeActivitySharedAction.OpenGroup -> {
|
is HomeActivitySharedAction.OpenGroup -> {
|
||||||
drawerLayout.closeDrawer(GravityCompat.START)
|
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||||
}
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
@ -197,24 +200,24 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
private fun renderState(state: HomeActivityViewState) {
|
private fun renderState(state: HomeActivityViewState) {
|
||||||
when (val status = state.initialSyncProgressServiceStatus) {
|
when (val status = state.initialSyncProgressServiceStatus) {
|
||||||
is InitialSyncProgressService.Status.Idle -> {
|
is InitialSyncProgressService.Status.Idle -> {
|
||||||
waiting_view.isVisible = false
|
views.waitingView.root.isVisible = false
|
||||||
}
|
}
|
||||||
is InitialSyncProgressService.Status.Progressing -> {
|
is InitialSyncProgressService.Status.Progressing -> {
|
||||||
Timber.v("${getString(status.statusText)} ${status.percentProgress}")
|
Timber.v("${getString(status.statusText)} ${status.percentProgress}")
|
||||||
waiting_view.setOnClickListener {
|
views.waitingView.root.setOnClickListener {
|
||||||
// block interactions
|
// block interactions
|
||||||
}
|
}
|
||||||
waiting_view_status_horizontal_progress.apply {
|
views.waitingView.waitingHorizontalProgress.apply {
|
||||||
isIndeterminate = false
|
isIndeterminate = false
|
||||||
max = 100
|
max = 100
|
||||||
progress = status.percentProgress
|
progress = status.percentProgress
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
waiting_view_status_text.apply {
|
views.waitingView.waitingStatusText.apply {
|
||||||
text = getString(status.statusText)
|
text = getString(status.statusText)
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
waiting_view.isVisible = true
|
views.waitingView.root.isVisible = true
|
||||||
}
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
@ -269,7 +272,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
).apply {
|
).apply {
|
||||||
colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary)
|
colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary)
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
// action(it)
|
// action(it)
|
||||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||||
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
|
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
|
||||||
@ -282,7 +285,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||||
}, true)
|
}, true)
|
||||||
addButton(getString(R.string.settings), Runnable {
|
addButton(getString(R.string.settings), Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
// action(it)
|
// action(it)
|
||||||
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
|
||||||
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
|
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(
|
popupAlertManager.postVectorAlert(
|
||||||
VerificationVectorAlert(
|
VerificationVectorAlert(
|
||||||
uid = "upgradeSecurity",
|
uid = "upgradeSecurity",
|
||||||
@ -303,7 +306,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
).apply {
|
).apply {
|
||||||
colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent)
|
colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent)
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
action(it)
|
action(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,7 +324,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
drawerLayout.removeDrawerListener(drawerListener)
|
views.drawerLayout.removeDrawerListener(drawerListener)
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,8 +378,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||||
drawerLayout.closeDrawer(GravityCompat.START)
|
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
} else {
|
} else {
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
@ -26,6 +28,7 @@ import com.airbnb.mvrx.withState
|
|||||||
import com.google.android.material.badge.BadgeDrawable
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.commitTransaction
|
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.glide.GlideApp
|
||||||
import im.vector.app.core.platform.ToolbarConfigurable
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
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.ActiveCallView
|
||||||
import im.vector.app.core.ui.views.ActiveCallViewHolder
|
import im.vector.app.core.ui.views.ActiveCallViewHolder
|
||||||
import im.vector.app.core.ui.views.KeysBackupBanner
|
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.SharedActiveCallViewModel
|
||||||
import im.vector.app.features.call.VectorCallActivity
|
import im.vector.app.features.call.VectorCallActivity
|
||||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
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.BannerState
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
|
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.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
|
||||||
@ -64,7 +68,10 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
private val alertManager: PopupAlertManager,
|
private val alertManager: PopupAlertManager,
|
||||||
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
||||||
private val vectorPreferences: VectorPreferences
|
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 viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||||
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
|
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
|
||||||
@ -73,7 +80,9 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||||
private lateinit var sharedCallActionViewModel: SharedActiveCallViewModel
|
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()
|
private val activeCallViewHolder = ActiveCallViewHolder()
|
||||||
|
|
||||||
@ -89,7 +98,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
withState(viewModel) {
|
withState(viewModel) {
|
||||||
// Update the navigation view if needed (for when we restore the tabs)
|
// 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 ->
|
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
||||||
@ -132,8 +141,8 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNotificationTabStatus() {
|
private fun checkNotificationTabStatus() {
|
||||||
val wasVisible = bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
|
val wasVisible = views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
|
||||||
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||||
if (wasVisible && !vectorPreferences.labAddNotificationTab()) {
|
if (wasVisible && !vectorPreferences.labAddNotificationTab()) {
|
||||||
// As we hide it check if it's not the current item!
|
// As we hide it check if it's not the current item!
|
||||||
withState(viewModel) {
|
withState(viewModel) {
|
||||||
@ -156,7 +165,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
).apply {
|
).apply {
|
||||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)
|
||||||
?.navigator
|
?.navigator
|
||||||
?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
|
?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
|
||||||
unknownDeviceDetectorSharedViewModel.handle(
|
unknownDeviceDetectorSharedViewModel.handle(
|
||||||
@ -184,7 +193,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
).apply {
|
).apply {
|
||||||
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
// mark as ignored to avoid showing it again
|
// mark as ignored to avoid showing it again
|
||||||
unknownDeviceDetectorSharedViewModel.handle(
|
unknownDeviceDetectorSharedViewModel.handle(
|
||||||
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
|
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
|
||||||
@ -204,7 +213,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||||
groupSummary?.let {
|
groupSummary?.let {
|
||||||
// Use GlideApp with activity context to avoid the glideRequests to be paused
|
// 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
|
serverBackupStatusViewModel
|
||||||
.subscribe(this) {
|
.subscribe(this) {
|
||||||
when (val banState = it.bannerState.invoke()) {
|
when (val banState = it.bannerState.invoke()) {
|
||||||
is BannerState.Setup -> homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
|
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
|
||||||
BannerState.BackingUp -> homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
|
BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
|
||||||
null,
|
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() {
|
private fun setupActiveCallView() {
|
||||||
activeCallViewHolder.bind(
|
activeCallViewHolder.bind(
|
||||||
activeCallPiP,
|
views.activeCallPiP,
|
||||||
activeCallView,
|
views.activeCallView,
|
||||||
activeCallPiPWrap,
|
views.activeCallPiPWrap,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -233,17 +242,17 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
val parentActivity = vectorBaseActivity
|
val parentActivity = vectorBaseActivity
|
||||||
if (parentActivity is ToolbarConfigurable) {
|
if (parentActivity is ToolbarConfigurable) {
|
||||||
parentActivity.configure(groupToolbar)
|
parentActivity.configure(views.groupToolbar)
|
||||||
}
|
}
|
||||||
groupToolbar.title = ""
|
views.groupToolbar.title = ""
|
||||||
groupToolbarAvatarImageView.debouncedClicks {
|
views.groupToolbarAvatarImageView.debouncedClicks {
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
|
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBottomNavigationView() {
|
private fun setupBottomNavigationView() {
|
||||||
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
|
||||||
bottomNavigationView.setOnNavigationItemSelectedListener {
|
views.bottomNavigationView.setOnNavigationItemSelectedListener {
|
||||||
val displayMode = when (it.itemId) {
|
val displayMode = when (it.itemId) {
|
||||||
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
|
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
|
||||||
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
|
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
|
||||||
@ -266,7 +275,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
|
private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
|
||||||
groupToolbarTitleView.setText(displayMode.titleRes)
|
views.groupToolbarTitleView.setText(displayMode.titleRes)
|
||||||
updateSelectedFragment(displayMode)
|
updateSelectedFragment(displayMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,10 +311,10 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun invalidate() = withState(viewModel) {
|
override fun invalidate() = withState(viewModel) {
|
||||||
Timber.v(it.toString())
|
Timber.v(it.toString())
|
||||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
|
||||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
|
||||||
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
|
||||||
syncStateView.render(it.syncState)
|
views.syncStateView.render(it.syncState)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun BadgeDrawable.render(count: Int, highlight: Boolean) {
|
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…
x
Reference in New Issue
Block a user