Migrate to ViewBindings (#1072) - WIP

This commit is contained in:
Benoit Marty 2020-12-16 00:46:52 +01:00
parent 838340bbc8
commit 706736273c
204 changed files with 2225 additions and 1380 deletions

View file

@ -23,7 +23,7 @@ Test:
-
Other changes:
-
- Migrate to ViewBindings (#1072)
Changes in Element 1.0.12 (2020-12-15)
===================================================

View file

@ -16,7 +16,6 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
buildscript {
repositories {
@ -55,6 +54,10 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
}
dependencies {

View file

@ -33,7 +33,8 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.transition.TransitionManager
import androidx.viewpager2.widget.ViewPager2
import kotlinx.android.synthetic.main.activity_attachment_viewer.*
import im.vector.lib.attachmentviewer.databinding.ActivityAttachmentViewerBinding
import java.lang.ref.WeakReference
import kotlin.math.abs
@ -50,12 +51,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private var overlayView: View? = null
set(value) {
if (value == overlayView) return
overlayView?.let { rootContainer.removeView(it) }
rootContainer.addView(value)
overlayView?.let { views.rootContainer.removeView(it) }
views.rootContainer.addView(value)
value?.updatePadding(top = topInset, bottom = bottomInset)
field = value
}
private lateinit var views: ActivityAttachmentViewerBinding
private lateinit var swipeDismissHandler: SwipeToDismissHandler
private lateinit var directionDetector: SwipeDirectionDetector
private lateinit var scaleDetector: ScaleGestureDetector
@ -95,17 +98,18 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
setContentView(R.layout.activity_attachment_viewer)
attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
views = ActivityAttachmentViewerBinding.inflate(layoutInflater)
setContentView(views.root)
views.attachmentPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL
attachmentsAdapter = AttachmentsAdapter()
attachmentPager.adapter = attachmentsAdapter
imageTransitionView = transitionImageView
views.attachmentPager.adapter = attachmentsAdapter
imageTransitionView = views.transitionImageView
transitionImageContainer = findViewById(R.id.transitionImageContainer)
pager2 = attachmentPager
pager2 = views.attachmentPager
directionDetector = createSwipeDirectionDetector()
gestureDetector = createGestureDetector()
attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
views.attachmentPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
isImagePagerIdle = state == ViewPager2.SCROLL_STATE_IDLE
}
@ -116,12 +120,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
})
swipeDismissHandler = createSwipeToDismissHandler()
rootContainer.setOnTouchListener(swipeDismissHandler)
rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = dismissContainer.height / 4 }
views.rootContainer.setOnTouchListener(swipeDismissHandler)
views.rootContainer.viewTreeObserver.addOnGlobalLayoutListener { swipeDismissHandler.translationLimit = views.dismissContainer.height / 4 }
scaleDetector = createScaleGestureDetector()
ViewCompat.setOnApplyWindowInsetsListener(rootContainer) { _, insets ->
ViewCompat.setOnApplyWindowInsetsListener(views.rootContainer) { _, insets ->
overlayView?.updatePadding(top = insets.systemWindowInsetTop, bottom = insets.systemWindowInsetBottom)
topInset = insets.systemWindowInsetTop
bottomInset = insets.systemWindowInsetBottom
@ -170,7 +174,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
if (swipeDirection == null && (scaleDetector.isInProgress || ev.pointerCount > 1 || wasScaled)) {
wasScaled = true
// Log.v("ATTACHEMENTS", "dispatch to pager")
return attachmentPager.dispatchTouchEvent(ev)
return views.attachmentPager.dispatchTouchEvent(ev)
}
// Log.v("ATTACHEMENTS", "is current item scaled ${isScaled()}")
@ -196,16 +200,16 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private fun handleEventActionDown(event: MotionEvent) {
swipeDirection = null
wasScaled = false
attachmentPager.dispatchTouchEvent(event)
views.attachmentPager.dispatchTouchEvent(event)
swipeDismissHandler.onTouch(rootContainer, event)
swipeDismissHandler.onTouch(views.rootContainer, event)
isOverlayWasClicked = dispatchOverlayTouch(event)
}
private fun handleEventActionUp(event: MotionEvent) {
// wasDoubleTapped = false
swipeDismissHandler.onTouch(rootContainer, event)
attachmentPager.dispatchTouchEvent(event)
swipeDismissHandler.onTouch(views.rootContainer, event)
views.attachmentPager.dispatchTouchEvent(event)
isOverlayWasClicked = dispatchOverlayTouch(event)
}
@ -220,12 +224,12 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private fun toggleOverlayViewVisibility() {
if (systemUiVisibility) {
// we hide
TransitionManager.beginDelayedTransition(rootContainer)
TransitionManager.beginDelayedTransition(views.rootContainer)
hideSystemUI()
overlayView?.isVisible = false
} else {
// we show
TransitionManager.beginDelayedTransition(rootContainer)
TransitionManager.beginDelayedTransition(views.rootContainer)
showSystemUI()
overlayView?.isVisible = true
}
@ -238,11 +242,11 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
return when (swipeDirection) {
SwipeDirection.Up, SwipeDirection.Down -> {
if (isSwipeToDismissAllowed && !wasScaled && isImagePagerIdle) {
swipeDismissHandler.onTouch(rootContainer, event)
swipeDismissHandler.onTouch(views.rootContainer, event)
} else true
}
SwipeDirection.Left, SwipeDirection.Right -> {
attachmentPager.dispatchTouchEvent(event)
views.attachmentPager.dispatchTouchEvent(event)
}
else -> true
}
@ -250,8 +254,8 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private fun handleSwipeViewMove(translationY: Float, translationLimit: Int) {
val alpha = calculateTranslationAlpha(translationY, translationLimit)
backgroundView.alpha = alpha
dismissContainer.alpha = alpha
views.backgroundView.alpha = alpha
views.dismissContainer.alpha = alpha
overlayView?.alpha = alpha
}
@ -265,7 +269,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
private fun createSwipeToDismissHandler()
: SwipeToDismissHandler = SwipeToDismissHandler(
swipeView = dismissContainer,
swipeView = views.dismissContainer,
shouldAnimateDismiss = { shouldAnimateDismiss() },
onDismiss = { animateClose() },
onSwipeViewMove = ::handleSwipeViewMove)

View file

@ -1,7 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-parcelize'
apply plugin: 'realm-android'
buildscript {
@ -13,10 +13,6 @@ buildscript {
}
}
androidExtensions {
experimental = true
}
android {
compileSdkVersion 29
testOptions.unitTests.includeAndroidResources = true

View file

@ -19,7 +19,7 @@ package org.matrix.android.sdk.api.auth.data
import android.os.Parcelable
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
@JsonClass(generateAdapter = true)
@Parcelize

View file

@ -20,7 +20,7 @@ import android.net.Uri
import android.os.Parcelable
import androidx.exifinterface.media.ExifInterface
import com.squareup.moshi.JsonClass
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
@Parcelize

View file

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.auth.registration
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
/**
* This class represent a localized privacy policy for registration Flow.

View file

@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.attachments
import android.os.Parcelable
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
fun EncryptedFileInfo.toElementToDecrypt(): ElementToDecrypt? {
// Check the validity of some fields

View file

@ -16,7 +16,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-parcelize'
android {
compileSdkVersion 29

View file

@ -3,7 +3,7 @@ package ${escapeKotlinIdentifiers(packageName)}
import android.os.Bundle
<#if createFragmentArgs>
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
import com.airbnb.mvrx.args
</#if>
import android.view.View

View file

@ -3,17 +3,13 @@ import com.android.build.OutputFile
apply plugin: 'com.android.application'
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
kapt {
correctErrorTypes = true
}
androidExtensions {
experimental = true
}
// Note: 2 digits max for each value
ext.versionMajor = 1
ext.versionMinor = 0
@ -280,6 +276,10 @@ android {
java.srcDirs += "src/sharedTest/java"
}
}
buildFeatures {
viewBinding true
}
}
dependencies {

View file

@ -24,7 +24,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.snackbar.Snackbar
import im.vector.app.R
import im.vector.app.core.utils.toast
import kotlinx.android.synthetic.debug.activity_test_material_theme.*
// Rendering is not the same with VectorBaseActivity
abstract class DebugMaterialThemeActivity : AppCompatActivity() {

View file

@ -21,6 +21,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Intent
import android.os.Build
import android.view.LayoutInflater
import androidx.core.app.NotificationCompat
import androidx.core.app.Person
import androidx.core.content.getSystemService
@ -34,16 +35,17 @@ import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
import im.vector.app.core.utils.allGranted
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityDebugMenuBinding
import im.vector.app.features.debug.sas.DebugSasEmojiActivity
import im.vector.app.features.qrcode.QrCodeScannerActivity
import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData
import kotlinx.android.synthetic.debug.activity_debug_menu.*
import timber.log.Timber
import javax.inject.Inject
class DebugMenuActivity : VectorBaseActivity() {
class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
override fun getLayoutRes() = R.layout.activity_debug_menu
override fun getBinding() = ActivityDebugMenuBinding.inflate(layoutInflater)
@Inject
lateinit var activeSessionHolder: ActiveSessionHolder
@ -69,17 +71,17 @@ class DebugMenuActivity : VectorBaseActivity() {
}
private fun setupViews() {
debug_test_text_view_link.setOnClickListener { testTextViewLink() }
debug_show_sas_emoji.setOnClickListener { showSasEmoji() }
debug_test_notification.setOnClickListener { testNotification() }
debug_test_material_theme_light.setOnClickListener { testMaterialThemeLight() }
debug_test_material_theme_dark.setOnClickListener { testMaterialThemeDark() }
debug_test_crash.setOnClickListener { testCrash() }
debug_scan_qr_code.setOnClickListener { scanQRCode() }
views.debugTestTextViewLink.setOnClickListener { testTextViewLink() }
views.debugShowSasEmoji.setOnClickListener { showSasEmoji() }
views.debugTestNotification.setOnClickListener { testNotification() }
views.debugTestMaterialThemeLight.setOnClickListener { testMaterialThemeLight() }
views.debugTestMaterialThemeDark.setOnClickListener { testMaterialThemeDark() }
views.debugTestCrash.setOnClickListener { testCrash() }
views.debugScanQrCode.setOnClickListener { scanQRCode() }
}
private fun renderQrCode(text: String) {
debug_qr_code.setData(text)
views.debugQrCode.setData(text)
}
private fun testTextViewLink() {

View file

@ -22,7 +22,7 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import im.vector.app.R
import kotlinx.android.synthetic.debug.activity_test_linkify.*
class TestLinkifyActivity : AppCompatActivity() {

View file

@ -22,7 +22,7 @@ import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
class DebugSasEmojiActivity : AppCompatActivity() {
@ -30,12 +30,12 @@ class DebugSasEmojiActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_generic_recycler)
val controller = SasEmojiController()
genericRecyclerView.configureWith(controller)
views.genericRecyclerView.configureWith(controller)
controller.setData(SasState(getAllVerificationEmojis()))
}
override fun onDestroy() {
genericRecyclerView.cleanup()
views.genericRecyclerView.cleanup()
super.onDestroy()
}
}

View file

@ -21,7 +21,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import im.vector.app.R
import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.*
object ConfirmationDialogBuilder {

View file

@ -31,7 +31,7 @@ fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult)
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
}
fun VectorBaseActivity.addFragment(
fun VectorBaseActivity<*>.addFragment(
frameId: Int,
fragment: Fragment,
allowStateLoss: Boolean = false
@ -39,7 +39,7 @@ fun VectorBaseActivity.addFragment(
supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
}
fun <T : Fragment> VectorBaseActivity.addFragment(
fun <T : Fragment> VectorBaseActivity<*>.addFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -51,7 +51,7 @@ fun <T : Fragment> VectorBaseActivity.addFragment(
}
}
fun VectorBaseActivity.replaceFragment(
fun VectorBaseActivity<*>.replaceFragment(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -60,7 +60,7 @@ fun VectorBaseActivity.replaceFragment(
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
}
fun <T : Fragment> VectorBaseActivity.replaceFragment(
fun <T : Fragment> VectorBaseActivity<*>.replaceFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -72,7 +72,7 @@ fun <T : Fragment> VectorBaseActivity.replaceFragment(
}
}
fun VectorBaseActivity.addFragmentToBackstack(
fun VectorBaseActivity<*>.addFragmentToBackstack(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -81,19 +81,19 @@ fun VectorBaseActivity.addFragmentToBackstack(
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
}
fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
tag: String? = null,
allowStateLoss: Boolean = false,
option: ((FragmentTransaction) -> Unit)? = null) {
fun <T : Fragment> VectorBaseActivity<*>.addFragmentToBackstack(frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
tag: String? = null,
allowStateLoss: Boolean = false,
option: ((FragmentTransaction) -> Unit)? = null) {
supportFragmentManager.commitTransaction(allowStateLoss) {
option?.invoke(this)
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
}
}
fun VectorBaseActivity.hideKeyboard() {
fun VectorBaseActivity<*>.hideKeyboard() {
currentFocus?.hideKeyboard()
}

View file

@ -23,6 +23,7 @@ import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import com.airbnb.mvrx.BaseMvRxFragment
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.selectTxtFileToWrite
@ -34,7 +35,7 @@ fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit):
return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult)
}
fun VectorBaseFragment.addFragment(
fun Fragment.addFragment(
frameId: Int,
fragment: Fragment,
allowStateLoss: Boolean = false
@ -42,7 +43,7 @@ fun VectorBaseFragment.addFragment(
parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
}
fun <T : Fragment> VectorBaseFragment.addFragment(
fun <T : Fragment> VectorBaseFragment<*>.addFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -54,7 +55,7 @@ fun <T : Fragment> VectorBaseFragment.addFragment(
}
}
fun VectorBaseFragment.replaceFragment(
fun Fragment.replaceFragment(
frameId: Int,
fragment: Fragment,
allowStateLoss: Boolean = false
@ -62,7 +63,7 @@ fun VectorBaseFragment.replaceFragment(
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment) }
}
fun <T : Fragment> VectorBaseFragment.replaceFragment(
fun <T : Fragment> VectorBaseFragment<*>.replaceFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -74,7 +75,7 @@ fun <T : Fragment> VectorBaseFragment.replaceFragment(
}
}
fun VectorBaseFragment.addFragmentToBackstack(
fun Fragment.addFragmentToBackstack(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -83,7 +84,7 @@ fun VectorBaseFragment.addFragmentToBackstack(
parentFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag).addToBackStack(tag) }
}
fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
fun <T : Fragment> VectorBaseFragment<*>.addFragmentToBackstack(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -95,7 +96,7 @@ fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(
}
}
fun VectorBaseFragment.addChildFragment(
fun Fragment.addChildFragment(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -104,7 +105,7 @@ fun VectorBaseFragment.addChildFragment(
childFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) }
}
fun <T : Fragment> VectorBaseFragment.addChildFragment(
fun <T : Fragment> VectorBaseFragment<*>.addChildFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -116,7 +117,7 @@ fun <T : Fragment> VectorBaseFragment.addChildFragment(
}
}
fun VectorBaseFragment.replaceChildFragment(
fun Fragment.replaceChildFragment(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -125,7 +126,7 @@ fun VectorBaseFragment.replaceChildFragment(
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) }
}
fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
fun <T : Fragment> VectorBaseFragment<*>.replaceChildFragment(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,
@ -137,7 +138,7 @@ fun <T : Fragment> VectorBaseFragment.replaceChildFragment(
}
}
fun VectorBaseFragment.addChildFragmentToBackstack(
fun Fragment.addChildFragmentToBackstack(
frameId: Int,
fragment: Fragment,
tag: String? = null,
@ -146,7 +147,7 @@ fun VectorBaseFragment.addChildFragmentToBackstack(
childFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) }
}
fun <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(
fun <T : Fragment> VectorBaseFragment<*>.addChildFragmentToBackstack(
frameId: Int,
fragmentClass: Class<T>,
params: Parcelable? = null,

View file

@ -25,7 +25,7 @@ import android.widget.FrameLayout
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import im.vector.app.R
import kotlinx.android.synthetic.main.view_button_state.view.*
class ButtonStateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: FrameLayout(context, attrs, defStyle) {

View file

@ -15,23 +15,24 @@
*/
package im.vector.app.core.platform
import android.view.LayoutInflater
import androidx.annotation.CallSuper
import androidx.core.view.isGone
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.hideKeyboard
import kotlinx.android.synthetic.main.activity.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import im.vector.app.databinding.ActivityBinding
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject
/**
* Simple activity with a toolbar, a waiting overlay, and a fragment container and a session.
*/
abstract class SimpleFragmentActivity : VectorBaseActivity() {
abstract class SimpleFragmentActivity : VectorBaseActivity<ActivityBinding>() {
override fun getLayoutRes() = R.layout.activity
override fun getBinding() = ActivityBinding.inflate(layoutInflater)
@Inject lateinit var session: Session
@ -41,8 +42,8 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
}
override fun initUiAndData() {
configureToolbar(toolbar)
waitingView = findViewById(R.id.waiting_view)
configureToolbar(views.toolbar)
waitingView = views.overlayWaitingView.waitingView
}
/**
@ -51,21 +52,21 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
*/
fun updateWaitingView(data: WaitingViewData?) {
data?.let {
waitingStatusText.text = data.message
views.overlayWaitingView.waitingStatusText.text = data.message
if (data.progress != null && data.progressTotal != null) {
waitingHorizontalProgress.isIndeterminate = false
waitingHorizontalProgress.progress = data.progress
waitingHorizontalProgress.max = data.progressTotal
waitingHorizontalProgress.isVisible = true
waitingCircularProgress.isVisible = false
views.overlayWaitingView.waitingHorizontalProgress.isIndeterminate = false
views.overlayWaitingView.waitingHorizontalProgress.progress = data.progress
views.overlayWaitingView.waitingHorizontalProgress.max = data.progressTotal
views.overlayWaitingView.waitingHorizontalProgress.isVisible = true
views.overlayWaitingView.waitingCircularProgress.isVisible = false
} else if (data.isIndeterminate) {
waitingHorizontalProgress.isIndeterminate = true
waitingHorizontalProgress.isVisible = true
waitingCircularProgress.isVisible = false
views.overlayWaitingView.waitingHorizontalProgress.isIndeterminate = true
views.overlayWaitingView.waitingHorizontalProgress.isVisible = true
views.overlayWaitingView.waitingCircularProgress.isVisible = false
} else {
waitingHorizontalProgress.isVisible = false
waitingCircularProgress.isVisible = true
views.overlayWaitingView.waitingHorizontalProgress.isVisible = false
views.overlayWaitingView.waitingCircularProgress.isVisible = true
}
showWaitingView()
@ -76,15 +77,15 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
override fun showWaitingView() {
hideKeyboard()
waitingStatusText.isGone = waitingStatusText.text.isNullOrBlank()
views.overlayWaitingView.waitingStatusText.isGone = views.overlayWaitingView.waitingStatusText.text.isNullOrBlank()
super.showWaitingView()
}
override fun hideWaitingView() {
waitingStatusText.text = null
waitingStatusText.isGone = true
waitingHorizontalProgress.progress = 0
waitingHorizontalProgress.isVisible = false
views.overlayWaitingView.waitingStatusText.text = null
views.overlayWaitingView.waitingStatusText.isGone = true
views.overlayWaitingView.waitingHorizontalProgress.progress = 0
views.overlayWaitingView.waitingHorizontalProgress.isVisible = false
super.hideWaitingView()
}

View file

@ -24,7 +24,7 @@ import android.widget.FrameLayout
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.extensions.updateConstraintSet
import kotlinx.android.synthetic.main.view_state.view.*
class StateView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: FrameLayout(context, attrs, defStyle) {

View file

@ -21,24 +21,26 @@ import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.WindowManager
import androidx.annotation.AttrRes
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes
import androidx.annotation.MainThread
import androidx.annotation.MenuRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.MvRx
import com.bumptech.glide.util.Util
import com.google.android.material.snackbar.Snackbar
@ -79,13 +81,19 @@ import im.vector.app.receivers.DebugReceiver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.activity.*
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.GlobalError
import timber.log.Timber
import kotlin.system.measureTimeMillis
abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScreenInjector {
/* ==========================================================================================
* View
* ========================================================================================== */
protected lateinit var views: VB
/* ==========================================================================================
* View model
* ========================================================================================== */
@ -210,9 +218,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
// Hack for font size
applyFontSize()
if (getLayoutRes() != -1) {
setContentView(getLayoutRes())
}
views = getBinding()
setContentView(views.root)
this.savedInstanceState = savedInstanceState
@ -450,7 +457,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
}
private fun recursivelyDispatchOnBackPressed(fm: FragmentManager, fromToolbar: Boolean): Boolean {
val reverseOrder = fm.fragments.filterIsInstance<VectorBaseFragment>().reversed()
val reverseOrder = fm.fragments.filterIsInstance<VectorBaseFragment<*>>().reversed()
for (f in reverseOrder) {
val handledByChildFragments = recursivelyDispatchOnBackPressed(f.childFragmentManager, fromToolbar)
if (handledByChildFragments) {
@ -537,8 +544,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
* OPEN METHODS
* ========================================================================================== */
@LayoutRes
open fun getLayoutRes() = -1
abstract fun getBinding(): VB
open fun displayInFullscreen() = false
@ -565,13 +571,13 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
* ========================================================================================== */
fun showSnackbar(message: String) {
coordinatorLayout?.let {
getCoordinatorLayout()?.let {
Snackbar.make(it, message, Snackbar.LENGTH_SHORT).show()
}
}
fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) {
coordinatorLayout?.let {
getCoordinatorLayout()?.let {
Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply {
withActionTitle?.let {
setAction(withActionTitle, { action?.invoke() })
@ -580,6 +586,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
}
}
// TODO BMA Provide the CL from the Views
open fun getCoordinatorLayout(): CoordinatorLayout? = null
/* ==========================================================================================
* User Consent
* ========================================================================================== */

View file

@ -27,6 +27,7 @@ import android.widget.FrameLayout
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.MvRxView
import com.airbnb.mvrx.MvRxViewId
@ -46,7 +47,7 @@ import java.util.concurrent.TimeUnit
/**
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
*/
abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView {
abstract class VectorBaseBottomSheetDialogFragment<VB: ViewBinding> : BottomSheetDialogFragment(), MvRxView {
private val mvrxViewIdProperty = MvRxViewId()
final override val mvrxViewId: String by mvrxViewIdProperty
@ -56,8 +57,13 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
* View
* ========================================================================================== */
@LayoutRes
abstract fun getLayoutResId(): Int
private var _binding: VB? = 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
@ -77,8 +83,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
private var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>? = null
val vectorBaseActivity: VectorBaseActivity by lazy {
activity as VectorBaseActivity
val vectorBaseActivity: VectorBaseActivity<*> by lazy {
activity as VectorBaseActivity<*>
}
open val showExpanded = false
@ -102,7 +108,8 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(getLayoutResId(), container, false)
_binding = getBinding(inflater, container)
return views.root
}
@CallSuper

View file

@ -33,6 +33,7 @@ import androidx.annotation.MainThread
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import com.airbnb.mvrx.BaseMvRxFragment
import com.airbnb.mvrx.MvRx
import com.bumptech.glide.util.Util.assertMainThread
@ -48,14 +49,14 @@ import im.vector.app.features.navigation.Navigator
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.activity.*
import timber.log.Timber
import java.util.concurrent.TimeUnit
abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
abstract class VectorBaseFragment<VB: ViewBinding> : BaseMvRxFragment(), HasScreenInjector {
protected val vectorBaseActivity: VectorBaseActivity by lazy {
activity as VectorBaseActivity
protected val vectorBaseActivity: VectorBaseActivity<*> by lazy {
activity as VectorBaseActivity<*>
}
/* ==========================================================================================
@ -82,6 +83,16 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
protected val fragmentViewModelProvider
get() = ViewModelProvider(this, viewModelFactory)
/* ==========================================================================================
* Views
* ========================================================================================== */
private var _binding: VB? = null
// This property is only valid between onCreateView and onDestroyView.
protected val views: VB
get() = _binding!!
/* ==========================================================================================
* Life cycle
* ========================================================================================== */
@ -106,11 +117,11 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Timber.i("onCreateView Fragment ${javaClass.simpleName}")
return inflater.inflate(getLayoutResId(), container, false)
_binding = getBinding(inflater, container)
return views.root
}
@LayoutRes
abstract fun getLayoutResId(): Int
abstract fun getBinding(inflater: LayoutInflater, container: ViewGroup?): VB
@CallSuper
override fun onResume() {
@ -137,6 +148,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
super.onDestroyView()
Timber.i("onDestroyView Fragment ${javaClass.simpleName}")
uiDisposables.clear()
_binding = null
}
override fun onDestroy() {
@ -174,6 +186,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
arguments = args.toMvRxBundle()
}
// TODO BMA Extract this and use simple type in Fragment.kt
fun Parcelable?.toMvRxBundle(): Bundle? {
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
}
@ -186,7 +199,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
}
protected fun showErrorInSnackbar(throwable: Throwable) {
vectorBaseActivity.coordinatorLayout?.let {
vectorBaseActivity.getCoordinatorLayout()?.let {
Snackbar.make(it, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
.show()
}

View file

@ -17,41 +17,47 @@
package im.vector.app.core.ui.bottomsheet
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import kotlinx.android.synthetic.main.bottom_sheet_generic_list.*
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import javax.inject.Inject
/**
* Generic Bottom sheet with actions
*/
abstract class BottomSheetGeneric<STATE : BottomSheetGenericState, ACTION : BottomSheetGenericAction> :
VectorBaseBottomSheetDialogFragment(),
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
BottomSheetGenericController.Listener<ACTION> {
@Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
final override val showExpanded = true
final override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
final override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
return BottomSheetGenericListBinding.inflate(inflater, container, false)
}
abstract fun getController(): BottomSheetGenericController<STATE, ACTION>
@CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomSheetRecyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
views.views.bottomSheetRecyclerView.configureWith(getController(), viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
getController().listener = this
}
@CallSuper
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.views.bottomSheetRecyclerView.cleanup()
getController().listener = null
super.onDestroyView()
}

View file

@ -29,8 +29,6 @@ import androidx.core.content.withStyledAttributes
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import butterknife.BindView
import butterknife.ButterKnife
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.themes.ThemeUtils
@ -41,20 +39,11 @@ class BottomSheetActionButton @JvmOverloads constructor(
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
@BindView(R.id.itemVerificationActionTitle)
lateinit var actionTextView: TextView
@BindView(R.id.itemVerificationActionSubTitle)
lateinit var descriptionTextView: TextView
@BindView(R.id.itemVerificationLeftIcon)
lateinit var leftIconImageView: ImageView
@BindView(R.id.itemVerificationActionIcon)
lateinit var rightIconImageView: ImageView
@BindView(R.id.itemVerificationClickableZone)
lateinit var clickableView: View
private val actionTextView: TextView
private val descriptionTextView: TextView
private val leftIconImageView: ImageView
private val rightIconImageView: ImageView
private val clickableView: View
var title: String? = null
set(value) {
@ -116,7 +105,12 @@ class BottomSheetActionButton @JvmOverloads constructor(
init {
inflate(context, R.layout.item_verification_action, this)
ButterKnife.bind(this)
actionTextView = findViewById(R.id.itemVerificationActionTitle)
descriptionTextView = findViewById(R.id.itemVerificationActionSubTitle)
leftIconImageView = findViewById(R.id.itemVerificationLeftIcon)
rightIconImageView = findViewById(R.id.itemVerificationActionIcon)
clickableView = findViewById(R.id.itemVerificationClickableZone)
context.withStyledAttributes(attrs, R.styleable.BottomSheetActionButton) {
title = getString(R.styleable.BottomSheetActionButton_actionTitle) ?: ""

View file

@ -22,7 +22,7 @@ import android.view.View
import android.widget.RelativeLayout
import androidx.core.content.ContextCompat
import im.vector.app.R
import kotlinx.android.synthetic.main.view_jump_to_read_marker.view.*
class JumpToReadMarkerView @JvmOverloads constructor(
context: Context,

View file

@ -24,7 +24,7 @@ import androidx.core.content.edit
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.di.DefaultSharedPreferences
import kotlinx.android.synthetic.main.view_keys_backup_banner.view.*
import timber.log.Timber
/**

View file

@ -28,7 +28,7 @@ import im.vector.app.R
import im.vector.app.core.error.ResourceLimitErrorFormatter
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.themes.ThemeUtils
import kotlinx.android.synthetic.main.view_notification_area.view.*
import me.gujun.android.span.span
import me.saket.bettermovementmethod.BetterLinkMovementMethod
import org.matrix.android.sdk.api.failure.MatrixError

View file

@ -22,7 +22,7 @@ import android.widget.LinearLayout
import androidx.annotation.IntRange
import androidx.core.content.ContextCompat
import im.vector.app.R
import kotlinx.android.synthetic.main.view_password_strength_bar.view.*
/**
* A password strength bar custom widget

View file

@ -26,7 +26,7 @@ import im.vector.app.R
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
import im.vector.app.features.home.room.detail.timeline.item.toMatrixItem
import kotlinx.android.synthetic.main.view_read_receipts.view.*
private const val MAX_RECEIPT_DISPLAYED = 5
private const val MAX_RECEIPT_DESCRIBED = 3

View file

@ -20,6 +20,7 @@ import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.Lifecycle
import com.bumptech.glide.Glide
@ -30,6 +31,7 @@ import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.deleteAllFiles
import im.vector.app.databinding.FragmentLoadingBinding
import im.vector.app.features.home.HomeActivity
import im.vector.app.features.home.ShortcutsHandler
import im.vector.app.features.login.LoginActivity
@ -42,7 +44,7 @@ import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.signout.hard.SignedOutActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.ui.UiStateRepository
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -66,7 +68,7 @@ data class MainActivityArgs(
* This Activity, when started with argument, is also doing some cleanup when user signs out,
* clears cache, is logged out, or is soft logged out
*/
class MainActivity : VectorBaseActivity(), UnlockedActivity {
class MainActivity : VectorBaseActivity<FragmentLoadingBinding>(), UnlockedActivity {
companion object {
private const val EXTRA_ARGS = "EXTRA_ARGS"
@ -83,6 +85,8 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity {
}
}
override fun getBinding() = FragmentLoadingBinding.inflate(layoutInflater)
private lateinit var args: MainActivityArgs
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager

View file

@ -19,15 +19,17 @@ package im.vector.app.features.attachments.preview
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import androidx.appcompat.widget.Toolbar
import im.vector.app.R
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.themes.ActivityOtherThemes
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
companion object {
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
@ -51,7 +53,7 @@ class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
override fun getOtherThemes() = ActivityOtherThemes.AttachmentsPreview
override fun getLayoutRes() = R.layout.activity_simple
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
override fun initUiAndData() {
if (isFirstCreation()) {

View file

@ -21,6 +21,7 @@ import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -45,9 +46,10 @@ import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.OnSnapPositionChangeListener
import im.vector.app.core.utils.SnapOnScrollListener
import im.vector.app.core.utils.attachSnapHelperWithListener
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
import im.vector.app.features.media.createUCropWithDefaultSettings
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import java.io.File
@ -62,19 +64,21 @@ class AttachmentsPreviewFragment @Inject constructor(
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
private val attachmentBigPreviewController: AttachmentBigPreviewController,
private val colorProvider: ColorProvider
) : VectorBaseFragment(), AttachmentMiniaturePreviewController.Callback {
) : VectorBaseFragment<FragmentAttachmentsPreviewBinding>(), AttachmentMiniaturePreviewController.Callback {
private val fragmentArgs: AttachmentsPreviewArgs by args()
private val viewModel: AttachmentsPreviewViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_attachments_preview
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentAttachmentsPreviewBinding {
return FragmentAttachmentsPreviewBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
applyInsets()
setupRecyclerViews()
setupToolbar(attachmentPreviewerToolbar)
attachmentPreviewerSendButton.setOnClickListener {
setupToolbar(views.attachmentPreviewerToolbar)
views.attachmentPreviewerSendButton.setOnClickListener {
setResultAndFinish()
}
}
@ -120,8 +124,8 @@ class AttachmentsPreviewFragment @Inject constructor(
override fun onDestroyView() {
super.onDestroyView()
attachmentPreviewerMiniatureList.cleanup()
attachmentPreviewerBigList.cleanup()
views.attachmentPreviewerMiniatureList.cleanup()
views.attachmentPreviewerBigList.cleanup()
attachmentMiniaturePreviewController.callback = null
}
@ -133,9 +137,9 @@ class AttachmentsPreviewFragment @Inject constructor(
} else {
attachmentMiniaturePreviewController.setData(state)
attachmentBigPreviewController.setData(state)
attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
views.attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
views.attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
views.attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
}
}
@ -146,17 +150,17 @@ class AttachmentsPreviewFragment @Inject constructor(
private fun setResultAndFinish() = withState(viewModel) {
(requireActivity() as? AttachmentsPreviewActivity)?.setResultAndFinish(
it.attachments,
attachmentPreviewerSendImageOriginalSize.isChecked
views.attachmentPreviewerSendImageOriginalSize.isChecked
)
}
private fun applyInsets() {
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerBottomContainer) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets ->
v.updatePadding(bottom = insets.systemWindowInsetBottom)
insets
}
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerToolbar) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerToolbar) { v, insets ->
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.systemWindowInsetTop
}
@ -180,13 +184,13 @@ class AttachmentsPreviewFragment @Inject constructor(
private fun setupRecyclerViews() {
attachmentMiniaturePreviewController.callback = this
attachmentPreviewerMiniatureList.let {
views.attachmentPreviewerMiniatureList.let {
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
it.setHasFixedSize(true)
it.adapter = attachmentMiniaturePreviewController.adapter
}
attachmentPreviewerBigList.let {
views.attachmentPreviewerBigList.let {
it.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
it.attachSnapHelperWithListener(
PagerSnapHelper(),

View file

@ -17,18 +17,24 @@
package im.vector.app.features.call
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.airbnb.mvrx.activityViewModel
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import kotlinx.android.synthetic.main.bottom_sheet_call_controls.*
import im.vector.app.databinding.BottomSheetCallControlsBinding
import im.vector.app.databinding.BottomSheetGenericListBinding
import me.gujun.android.span.span
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun getLayoutResId() = R.layout.bottom_sheet_call_controls
class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetCallControlsBinding>() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetCallControlsBinding {
return BottomSheetCallControlsBinding.inflate(inflater, container, false)
}
private val callViewModel: VectorCallViewModel by activityViewModel()
@ -39,16 +45,16 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
renderState(it)
}
callControlsSoundDevice.clickableView.debouncedClicks {
views.callControlsSoundDevice.clickableView.debouncedClicks {
callViewModel.handle(VectorCallViewActions.SwitchSoundDevice)
}
callControlsSwitchCamera.clickableView.debouncedClicks {
views.callControlsSwitchCamera.clickableView.debouncedClicks {
callViewModel.handle(VectorCallViewActions.ToggleCamera)
dismiss()
}
callControlsToggleSDHD.clickableView.debouncedClicks {
views.callControlsToggleSDHD.clickableView.debouncedClicks {
callViewModel.handle(VectorCallViewActions.ToggleHDSD)
dismiss()
}
@ -109,30 +115,30 @@ class CallControlsBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
private fun renderState(state: VectorCallViewState) {
callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
callControlsSoundDevice.subTitle = when (state.soundDevice) {
views.callControlsSoundDevice.title = getString(R.string.call_select_sound_device)
views.callControlsSoundDevice.subTitle = when (state.soundDevice) {
CallAudioManager.SoundDevice.PHONE -> getString(R.string.sound_device_phone)
CallAudioManager.SoundDevice.SPEAKER -> getString(R.string.sound_device_speaker)
CallAudioManager.SoundDevice.HEADSET -> getString(R.string.sound_device_headset)
CallAudioManager.SoundDevice.WIRELESS_HEADSET -> getString(R.string.sound_device_wireless_headset)
}
callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera
callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
views.callControlsSwitchCamera.isVisible = state.isVideoCall && state.canSwitchCamera
views.callControlsSwitchCamera.subTitle = getString(if (state.isFrontCamera) R.string.call_camera_front else R.string.call_camera_back)
if (state.isVideoCall) {
callControlsToggleSDHD.isVisible = true
views.callControlsToggleSDHD.isVisible = true
if (state.isHD) {
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
callControlsToggleSDHD.subTitle = null
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_off)
views.callControlsToggleSDHD.subTitle = null
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd_disabled)
} else {
callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
callControlsToggleSDHD.subTitle = null
callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
views.callControlsToggleSDHD.title = getString(R.string.call_format_turn_hd_on)
views.callControlsToggleSDHD.subTitle = null
views.callControlsToggleSDHD.leftIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_hd)
}
} else {
callControlsToggleSDHD.isVisible = false
views.callControlsToggleSDHD.isVisible = false
}
}
}

View file

@ -18,11 +18,13 @@ package im.vector.app.features.call
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import im.vector.app.R
import kotlinx.android.synthetic.main.view_call_controls.view.*
import org.matrix.android.sdk.api.session.call.CallState
import org.webrtc.PeerConnection
@ -30,19 +32,40 @@ class CallControlsView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
private var ringingControls: View
private var connectedControls: View
private val ringingControlAccept: View
private var ringingControlDecline: View
private var iv_end_call: View
private var muteIcon: ImageView
private var videoToggleIcon: ImageView
private var iv_leftMiniControl: View
private var iv_more: View
var interactionListener: InteractionListener? = null
init {
ConstraintLayout.inflate(context, R.layout.view_call_controls, this)
View.inflate(context, R.layout.view_call_controls, this)
// layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
ringingControlAccept.setOnClickListener { acceptIncomingCall() }
ringingControlDecline.setOnClickListener { declineIncomingCall() }
iv_end_call.setOnClickListener { endOngoingCall() }
muteIcon.setOnClickListener { toggleMute() }
videoToggleIcon.setOnClickListener { toggleVideo() }
iv_leftMiniControl.setOnClickListener { returnToChat() }
iv_more.setOnClickListener { moreControlOption() }
ringingControlAccept = findViewById<View>(R.id.ringingControlAccept)
.also { it.setOnClickListener { acceptIncomingCall() } }
ringingControlDecline = findViewById<View>(R.id.ringingControlDecline)
.also { it.setOnClickListener { declineIncomingCall() } }
iv_end_call = findViewById<View>(R.id.iv_end_call)
.also { it.setOnClickListener { endOngoingCall() } }
muteIcon = findViewById<ImageView>(R.id.muteIcon)
.also { it.setOnClickListener { toggleMute() } }
videoToggleIcon = findViewById<ImageView>(R.id.videoToggleIcon)
.also { it.setOnClickListener { toggleVideo() } }
iv_leftMiniControl = findViewById<View>(R.id.iv_leftMiniControl)
.also { it.setOnClickListener { returnToChat() } }
iv_more = findViewById<View>(R.id.iv_more)
.also { it.setOnClickListener { moreControlOption() } }
ringingControls = findViewById(R.id.ringingControls)
connectedControls = findViewById(R.id.connectedControls)
}
private fun acceptIncomingCall() {

View file

@ -23,6 +23,7 @@ import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.view.WindowManager
@ -44,12 +45,13 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
import im.vector.app.core.utils.allGranted
import im.vector.app.core.utils.checkPermissions
import im.vector.app.databinding.ActivityCallBinding
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.RoomDetailActivity
import im.vector.app.features.home.room.detail.RoomDetailArgs
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_call.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.EglUtils
import org.matrix.android.sdk.api.session.call.MxCallDetail
@ -70,9 +72,9 @@ data class CallArgs(
val isVideoCall: Boolean
) : Parcelable
class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener {
class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallControlsView.InteractionListener {
override fun getLayoutRes() = R.layout.activity_call
override fun getBinding() = ActivityCallBinding.inflate(layoutInflater)
@Inject lateinit var avatarRenderer: AvatarRenderer
@ -147,7 +149,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
super.onCreate(savedInstanceState)
// This will need to be refined
ViewCompat.setOnApplyWindowInsetsListener(constraintLayout) { v, insets ->
ViewCompat.setOnApplyWindowInsetsListener(views.constraintLayout) { v, insets ->
v.updatePadding(bottom = if (systemUiVisibility) insets.systemWindowInsetBottom else 0)
insets
}
@ -167,7 +169,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
turnScreenOnAndKeyguardOff()
}
constraintLayout.clicks()
views.constraintLayout.clicks()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { toggleUiSystemVisibility() }
@ -199,10 +201,10 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
}
override fun onDestroy() {
peerConnectionManager.detachRenderers(listOf(pipRenderer, fullscreenRenderer))
peerConnectionManager.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer))
if (surfaceRenderersAreInitialized) {
pipRenderer.release()
fullscreenRenderer.release()
views.pipRenderer.release()
views.fullscreenRenderer.release()
}
turnScreenOffAndKeyguardOn()
super.onDestroy()
@ -217,54 +219,54 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
return
}
callControlsView.updateForState(state)
views.callControlsView.updateForState(state)
val callState = state.callState.invoke()
callConnectingProgress.isVisible = false
views.callConnectingProgress.isVisible = false
when (callState) {
is CallState.Idle,
is CallState.Dialing -> {
callVideoGroup.isInvisible = true
callInfoGroup.isVisible = true
callStatusText.setText(R.string.call_ring)
views.callVideoGroup.isInvisible = true
views.callInfoGroup.isVisible = true
views.callStatusText.setText(R.string.call_ring)
configureCallInfo(state)
}
is CallState.LocalRinging -> {
callVideoGroup.isInvisible = true
callInfoGroup.isVisible = true
callStatusText.text = null
views.callVideoGroup.isInvisible = true
views.callInfoGroup.isVisible = true
views.callStatusText.text = null
configureCallInfo(state)
}
is CallState.Answering -> {
callVideoGroup.isInvisible = true
callInfoGroup.isVisible = true
callStatusText.setText(R.string.call_connecting)
callConnectingProgress.isVisible = true
views.callVideoGroup.isInvisible = true
views.callInfoGroup.isVisible = true
views.callStatusText.setText(R.string.call_connecting)
views.callConnectingProgress.isVisible = true
configureCallInfo(state)
}
is CallState.Connected -> {
if (callState.iceConnectionState == PeerConnection.PeerConnectionState.CONNECTED) {
if (callArgs.isVideoCall) {
callVideoGroup.isVisible = true
callInfoGroup.isVisible = false
pipRenderer.isVisible = !state.isVideoCaptureInError
views.callVideoGroup.isVisible = true
views.callInfoGroup.isVisible = false
views.pipRenderer.isVisible = !state.isVideoCaptureInError
} else {
callVideoGroup.isInvisible = true
callInfoGroup.isVisible = true
views.callVideoGroup.isInvisible = true
views.callInfoGroup.isVisible = true
configureCallInfo(state)
callStatusText.text = null
views.callStatusText.text = null
}
} else {
// This state is not final, if you change network, new candidates will be sent
callVideoGroup.isInvisible = true
callInfoGroup.isVisible = true
views.callVideoGroup.isInvisible = true
views.callInfoGroup.isVisible = true
configureCallInfo(state)
callStatusText.setText(R.string.call_connecting)
callConnectingProgress.isVisible = true
views.callStatusText.setText(R.string.call_connecting)
views.callConnectingProgress.isVisible = true
}
// ensure all attached?
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer, null)
peerConnectionManager.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, null)
}
is CallState.Terminated -> {
finish()
@ -276,14 +278,14 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
private fun configureCallInfo(state: VectorCallViewState) {
state.otherUserMatrixItem.invoke()?.let {
avatarRenderer.render(it, otherMemberAvatar)
participantNameText.text = it.getBestName()
callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
avatarRenderer.render(it, views.otherMemberAvatar)
views.participantNameText.text = it.getBestName()
views.callTypeText.setText(if (state.isVideoCall) R.string.action_video_call else R.string.action_voice_call)
}
}
private fun configureCallViews() {
callControlsView.interactionListener = this
views.callControlsView.interactionListener = this
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
@ -303,21 +305,24 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis
}
// Init Picture in Picture renderer
pipRenderer.init(rootEglBase!!.eglBaseContext, null)
pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
views.pipRenderer.init(rootEglBase!!.eglBaseContext, null)
views.pipRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
// Init Full Screen renderer
fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
views.fullscreenRenderer.init(rootEglBase!!.eglBaseContext, null)
views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
pipRenderer.setZOrderMediaOverlay(true)
pipRenderer.setEnableHardwareScaler(true /* enabled */)
fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
views.pipRenderer.setZOrderMediaOverlay(true)
views.pipRenderer.setEnableHardwareScaler(true /* enabled */)
views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
peerConnectionManager.attachViewRenderers(pipRenderer, fullscreenRenderer,
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() })
peerConnectionManager.attachViewRenderers(
views.pipRenderer,
views.fullscreenRenderer,
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() }
)
pipRenderer.setOnClickListener {
views.pipRenderer.setOnClickListener {
callViewModel.handle(VectorCallViewActions.ToggleCamera)
}
surfaceRenderersAreInitialized = true

View file

@ -20,6 +20,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.isVisible
@ -31,8 +32,9 @@ import com.facebook.react.modules.core.PermissionListener
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.platform.VectorBaseActivity
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_jitsi.*
import im.vector.app.databinding.ActivityJitsiBinding
import kotlinx.parcelize.Parcelize
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
import org.jitsi.meet.sdk.JitsiMeetActivityInterface
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
@ -42,7 +44,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import java.net.URL
import javax.inject.Inject
class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, JitsiMeetViewListener {
class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMeetActivityInterface, JitsiMeetViewListener {
@Parcelize
data class Args(
@ -51,7 +53,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
val enableVideo: Boolean
) : Parcelable
override fun getLayoutRes() = R.layout.activity_jitsi
override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater)
@Inject lateinit var viewModelFactory: JitsiCallViewModel.Factory
@ -76,7 +78,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji
super.initUiAndData()
jitsiMeetView = JitsiMeetView(this)
val params = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
jitsi_layout.addView(jitsiMeetView, params)
views.jitsiLayout.addView(jitsiMeetView, params)
jitsiMeetView?.listener = this
}

View file

@ -17,7 +17,9 @@
package im.vector.app.features.contactsbook
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import com.airbnb.mvrx.activityViewModel
@ -29,12 +31,14 @@ import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
import im.vector.app.databinding.FragmentContactsBookBinding
import im.vector.app.features.userdirectory.PendingInvitee
import im.vector.app.features.userdirectory.UserListAction
import im.vector.app.features.userdirectory.UserListSharedAction
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
import im.vector.app.features.userdirectory.UserListViewModel
import kotlinx.android.synthetic.main.fragment_contacts_book.*
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.user.model.User
import java.util.concurrent.TimeUnit
@ -43,9 +47,12 @@ import javax.inject.Inject
class ContactsBookFragment @Inject constructor(
val contactsBookViewModelFactory: ContactsBookViewModel.Factory,
private val contactsBookController: ContactsBookController
) : VectorBaseFragment(), ContactsBookController.Callback {
) : VectorBaseFragment<FragmentContactsBookBinding>(), ContactsBookController.Callback {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentContactsBookBinding {
return FragmentContactsBookBinding.inflate(inflater, container, false)
}
override fun getLayoutResId() = R.layout.fragment_contacts_book
private val viewModel: UserListViewModel by activityViewModel()
// Use activityViewModel to avoid loading several times the data
@ -64,7 +71,7 @@ class ContactsBookFragment @Inject constructor(
}
private fun setupConsentView() {
phoneBookSearchForMatrixContacts.setOnClickListener {
views.phoneBookSearchForMatrixContacts.setOnClickListener {
withState(contactsBookViewModel) { state ->
AlertDialog.Builder(requireActivity())
.setTitle(R.string.identity_server_consent_dialog_title)
@ -79,7 +86,7 @@ class ContactsBookFragment @Inject constructor(
}
private fun setupOnlyBoundContactsView() {
phoneBookOnlyBoundContacts.checkedChanges()
views.phoneBookOnlyBoundContacts.checkedChanges()
.subscribe {
contactsBookViewModel.handle(ContactsBookAction.OnlyBoundContacts(it))
}
@ -87,7 +94,7 @@ class ContactsBookFragment @Inject constructor(
}
private fun setupFilterView() {
phoneBookFilter
views.phoneBookFilter
.textChanges()
.skipInitialValue()
.debounce(300, TimeUnit.MILLISECONDS)
@ -98,25 +105,25 @@ class ContactsBookFragment @Inject constructor(
}
override fun onDestroyView() {
phoneBookRecyclerView.cleanup()
views.phoneBookRecyclerView.cleanup()
contactsBookController.callback = null
super.onDestroyView()
}
private fun setupRecyclerView() {
contactsBookController.callback = this
phoneBookRecyclerView.configureWith(contactsBookController)
views.phoneBookRecyclerView.configureWith(contactsBookController)
}
private fun setupCloseView() {
phoneBookClose.debouncedClicks {
views.phoneBookClose.debouncedClicks {
sharedActionViewModel.post(UserListSharedAction.GoBack)
}
}
override fun invalidate() = withState(contactsBookViewModel) { state ->
phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
views.phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
views.phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
contactsBookController.setData(state)
}

View file

@ -51,7 +51,7 @@ import im.vector.app.features.userdirectory.UserListSharedAction
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
import im.vector.app.features.userdirectory.UserListViewModel
import im.vector.app.features.userdirectory.UserListViewState
import kotlinx.android.synthetic.main.activity.*
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import java.net.HttpURLConnection

View file

@ -16,6 +16,8 @@
package im.vector.app.features.createdirect
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import com.airbnb.mvrx.activityViewModel
import com.google.zxing.Result
@ -26,19 +28,23 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
import im.vector.app.databinding.FragmentQrCodeScannerBinding
import im.vector.app.features.userdirectory.PendingInvitee
import kotlinx.android.synthetic.main.fragment_qr_code_scanner.*
import me.dm7.barcodescanner.zxing.ZXingScannerView
import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
import org.matrix.android.sdk.api.session.user.model.User
import javax.inject.Inject
class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment(), ZXingScannerView.ResultHandler {
class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragment<FragmentQrCodeScannerBinding>(), ZXingScannerView.ResultHandler {
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
override fun getLayoutResId() = R.layout.fragment_qr_code_scanner
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentQrCodeScannerBinding {
return FragmentQrCodeScannerBinding.inflate(inflater, container, false)
}
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
@ -48,14 +54,14 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
private fun startCamera() {
// Start camera on resume
scannerView.startCamera()
views.scannerView.startCamera()
}
override fun onResume() {
super.onResume()
view?.hideKeyboard()
// Register ourselves as a handler for scan results.
scannerView.setResultHandler(this)
views.scannerView.setResultHandler(this)
// Start camera on resume
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
startCamera()
@ -65,9 +71,9 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
override fun onPause() {
super.onPause()
// Unregister ourselves as a handler for scan results.
scannerView.setResultHandler(null)
views.scannerView.setResultHandler(null)
// Stop camera on pause
scannerView.stopCamera()
views.scannerView.stopCamera()
}
// Copied from https://github.com/markusfisch/BinaryEye/blob/

View file

@ -17,7 +17,9 @@ package im.vector.app.features.crypto.keysbackup.restore
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.Observer
@ -25,14 +27,18 @@ import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startImportTextFromFileIntent
import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_key.*
import im.vector.app.databinding.FragmentAttachmentsPreviewBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import org.matrix.android.sdk.api.extensions.tryOrNull
import javax.inject.Inject
class KeysBackupRestoreFromKeyFragment @Inject constructor()
: VectorBaseFragment() {
: VectorBaseFragment<FragmentKeysBackupRestoreFromKeyBinding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_key
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromKeyBinding {
return FragmentKeysBackupRestoreFromKeyBinding.inflate(inflater, container, false)
}
private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
@ -41,8 +47,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
super.onViewCreated(view, savedInstanceState)
viewModel = fragmentViewModelProvider.get(KeysBackupRestoreFromKeyViewModel::class.java)
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
mKeyTextEdit.setText(viewModel.recoveryCode.value)
mKeyTextEdit.setOnEditorActionListener { _, actionId, _ ->
views.mKeyTextEdit.setText(viewModel.recoveryCode.value)
views.mKeyTextEdit.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
onRestoreFromKey()
return@setOnEditorActionListener true
@ -50,14 +56,14 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
return@setOnEditorActionListener false
}
mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value
views.mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue ->
mKeyInputLayout.error = newValue
views.mKeyInputLayout.error = newValue
})
keys_restore_button.setOnClickListener { onRestoreFromKey() }
keys_backup_import.setOnClickListener { onImport() }
mKeyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) }
views.keysRestoreButton.setOnClickListener { onRestoreFromKey() }
views.keysBackupImport.setOnClickListener { onImport() }
views.mKeyTextEdit.doOnTextChanged { text, _, _, _ -> onRestoreKeyTextEditChange(text) }
}
private fun onRestoreKeyTextEditChange(s: CharSequence?) {
@ -89,8 +95,8 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
?.bufferedReader()
?.use { it.readText() }
?.let {
mKeyTextEdit.setText(it)
mKeyTextEdit.setSelection(it.length)
views.mKeyTextEdit.setText(it)
views.mKeyTextEdit.setSelection(it.length)
}
}
}

View file

@ -18,7 +18,9 @@ package im.vector.app.features.crypto.keysbackup.restore
import android.os.Bundle
import android.text.SpannableString
import android.text.style.ClickableSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.text.set
import androidx.core.widget.doOnTextChanged
@ -26,12 +28,16 @@ import androidx.lifecycle.Observer
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_keys_backup_restore_from_passphrase.*
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromPassphraseBinding
import javax.inject.Inject
class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment() {
class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupRestoreFromPassphraseBinding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_passphrase
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreFromPassphraseBinding {
return FragmentKeysBackupRestoreFromPassphraseBinding.inflate(inflater, container, false)
}
private lateinit var viewModel: KeysBackupRestoreFromPassphraseViewModel
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
@ -47,18 +53,18 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
sharedViewModel = activityViewModelProvider.get(KeysBackupRestoreSharedViewModel::class.java)
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue ->
keys_backup_passphrase_enter_til.error = newValue
views.keysBackupPassphraseEnterTil.error = newValue
})
helperTextWithLink.text = spannableStringForHelperText()
views.helperTextWithLink.text = spannableStringForHelperText()
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
val shouldBeVisible = it ?: false
keys_backup_passphrase_enter_edittext.showPassword(shouldBeVisible)
keys_backup_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
views.keysBackupPassphraseEnterEdittext.showPassword(shouldBeVisible)
views.keysBackupViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
})
keys_backup_passphrase_enter_edittext.setOnEditorActionListener { _, actionId, _ ->
views.keysBackupPassphraseEnterEdittext.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
onRestoreBackup()
return@setOnEditorActionListener true
@ -66,10 +72,10 @@ class KeysBackupRestoreFromPassphraseFragment @Inject constructor() : VectorBase
return@setOnEditorActionListener false
}
keys_backup_view_show_password.setOnClickListener { toggleVisibilityMode() }
helperTextWithLink.setOnClickListener { onUseRecoveryKey() }
keys_backup_restore_with_passphrase_submit.setOnClickListener { onRestoreBackup() }
keys_backup_passphrase_enter_edittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) }
views.keysBackupViewShowPassword.setOnClickListener { toggleVisibilityMode() }
views.helperTextWithLink.setOnClickListener { onUseRecoveryKey() }
views.keysBackupRestoreWithPassphraseSubmit.setOnClickListener { onRestoreBackup() }
views.keysBackupPassphraseEnterEdittext.doOnTextChanged { text, _, _, _ -> onPassphraseTextEditChange(text) }
}
private fun spannableStringForHelperText(): SpannableString {

View file

@ -16,17 +16,23 @@
package im.vector.app.features.crypto.keysbackup.restore
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.LiveEvent
import kotlinx.android.synthetic.main.fragment_keys_backup_restore_success.*
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreSuccessBinding
import javax.inject.Inject
class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() {
class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupRestoreSuccessBinding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_success
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupRestoreSuccessBinding {
return FragmentKeysBackupRestoreSuccessBinding.inflate(inflater, container, false)
}
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
@ -40,15 +46,15 @@ class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragmen
it.totalNumberOfKeys, it.totalNumberOfKeys)
val part2 = resources.getQuantityString(R.plurals.keys_backup_restore_success_description_part2,
it.successfullyNumberOfImportedKeys, it.successfullyNumberOfImportedKeys)
mSuccessDetailsText.text = String.format("%s\n%s", part1, part2)
views.mSuccessDetailsText.text = String.format("%s\n%s", part1, part2)
}
// We don't put emoji in string xml as it will crash on old devices
mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉")
views.mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title, "🎉")
} else {
mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
mSuccessDetailsText.isVisible = false
views.mSuccessText.text = context?.getString(R.string.keys_backup_restore_success_title_already_up_to_date)
views.mSuccessDetailsText.isVisible = false
}
keys_backup_setup_done_button.setOnClickListener { onDone() }
views.keysBackupSetupDoneButton.setOnClickListener { onDone() }
}
private fun onDone() {

View file

@ -16,7 +16,9 @@
package im.vector.app.features.crypto.keysbackup.settings
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
@ -24,28 +26,32 @@ import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupSettingsBinding
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
import kotlinx.android.synthetic.main.fragment_keys_backup_settings.*
import javax.inject.Inject
class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController)
: VectorBaseFragment(),
: VectorBaseFragment<FragmentKeysBackupSettingsBinding>(),
KeysBackupSettingsRecyclerViewController.Listener {
override fun getLayoutResId() = R.layout.fragment_keys_backup_settings
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSettingsBinding {
return FragmentKeysBackupSettingsBinding.inflate(inflater, container, false)
}
private val viewModel: KeysBackupSettingsViewModel by activityViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
views.keysBackupSettingsRecyclerView.configureWith(keysBackupSettingsRecyclerViewController)
keysBackupSettingsRecyclerViewController.listener = this
}
override fun onDestroyView() {
keysBackupSettingsRecyclerViewController.listener = null
keysBackupSettingsRecyclerView.cleanup()
views.keysBackupSettingsRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -17,17 +17,23 @@
package im.vector.app.features.crypto.keysbackup.setup
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.LiveEvent
import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step1.*
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupSetupStep1Binding
import javax.inject.Inject
class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() {
class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep1Binding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step1
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep1Binding {
return FragmentKeysBackupSetupStep1Binding.inflate(inflater, container, false)
}
private lateinit var viewModel: KeysBackupSetupSharedViewModel
@ -39,12 +45,12 @@ class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment()
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
val showOption = it ?: false
// Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated
advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
views.advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE
views.manualExportButton.visibility = if (showOption) View.VISIBLE else View.GONE
})
keys_backup_setup_step1_button.setOnClickListener { onButtonClick() }
manualExportButton.setOnClickListener { onManualExportClick() }
views.keysBackupSetupStep1Button.setOnClickListener { onButtonClick() }
views.manualExportButton.setOnClickListener { onManualExportClick() }
}
private fun onButtonClick() {

View file

@ -16,7 +16,9 @@
package im.vector.app.features.crypto.keysbackup.setup
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.Observer
@ -26,15 +28,19 @@ import com.nulabinc.zxcvbn.Zxcvbn
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding
import im.vector.app.features.settings.VectorLocale
import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step2.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() {
class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep2Binding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step2
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep2Binding {
return FragmentKeysBackupSetupStep2Binding.inflate(inflater, container, false)
}
private val zxcvbn = Zxcvbn()

View file

@ -18,7 +18,9 @@ package im.vector.app.features.crypto.keysbackup.setup
import android.app.Activity
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
@ -33,7 +35,9 @@ import im.vector.app.core.utils.LiveEvent
import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.selectTxtFileToWrite
import im.vector.app.core.utils.startSharePlainTextIntent
import kotlinx.android.synthetic.main.fragment_keys_backup_setup_step3.*
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentKeysBackupSetupStep3Binding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -44,9 +48,11 @@ import java.util.Date
import java.util.Locale
import javax.inject.Inject
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<FragmentKeysBackupSetupStep3Binding>() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentKeysBackupSetupStep3Binding {
return FragmentKeysBackupSetupStep3Binding.inflate(inflater, container, false)
}
private lateinit var viewModel: KeysBackupSetupSharedViewModel

View file

@ -35,8 +35,8 @@ import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.platform.SimpleFragmentActivity
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.features.crypto.recover.SetupMode
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity.*
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
import kotlin.reflect.KClass

View file

@ -18,7 +18,9 @@ package im.vector.app.features.crypto.quads
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.airbnb.mvrx.activityViewModel
import com.jakewharton.rxbinding3.widget.editorActionEvents
@ -27,15 +29,19 @@ import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startImportTextFromFileIntent
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentSsssAccessFromKeyBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_ssss_access_from_key.*
import org.matrix.android.sdk.api.extensions.tryOrNull
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment() {
class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment<FragmentSsssAccessFromKeyBinding>() {
override fun getLayoutResId() = R.layout.fragment_ssss_access_from_key
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromKeyBinding {
return FragmentSsssAccessFromKeyBinding.inflate(inflater, container, false)
}
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()

View file

@ -17,7 +17,9 @@
package im.vector.app.features.crypto.quads
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.text.toSpannable
import com.airbnb.mvrx.activityViewModel
@ -29,16 +31,20 @@ import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentSsssAccessFromPassphraseBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class SharedSecuredStoragePassphraseFragment @Inject constructor(
private val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentSsssAccessFromPassphraseBinding>() {
override fun getLayoutResId() = R.layout.fragment_ssss_access_from_passphrase
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssAccessFromPassphraseBinding {
return FragmentSsssAccessFromPassphraseBinding.inflate(inflater, container, false)
}
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
@ -48,7 +54,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
// If has passphrase
val pass = getString(R.string.recovery_passphrase)
val key = getString(R.string.recovery_key)
ssss_restore_with_passphrase_warning_text.text = getString(
views.ssssRestoreWithPassphraseWarningText.text = getString(
R.string.enter_secret_storage_passphrase_or_key,
pass,
key
@ -57,7 +63,7 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
.colorizeMatchingText(pass, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
.colorizeMatchingText(key, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
ssss_passphrase_enter_edittext.editorActionEvents()
views.ssssPassphraseEnterEdittext.editorActionEvents()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
@ -67,40 +73,40 @@ class SharedSecuredStoragePassphraseFragment @Inject constructor(
}
.disposeOnDestroyView()
ssss_passphrase_enter_edittext.textChanges()
views.ssssPassphraseEnterEdittext.textChanges()
.subscribe {
ssss_passphrase_enter_til.error = null
ssss_passphrase_submit.isEnabled = it.isNotBlank()
views.ssssPassphraseEnterTil.error = null
views.ssssPassphraseSubmit.isEnabled = it.isNotBlank()
}
.disposeOnDestroyView()
ssss_passphrase_reset.clickableView.debouncedClicks {
views.ssssPassphraseReset.clickableView.debouncedClicks {
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
}
sharedViewModel.observeViewEvents {
when (it) {
is SharedSecureStorageViewEvent.InlineError -> {
ssss_passphrase_enter_til.error = it.message
views.ssssPassphraseEnterTil.error = it.message
}
}
}
ssss_passphrase_submit.debouncedClicks { submit() }
ssss_passphrase_use_key.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
views.ssssPassphraseSubmit.debouncedClicks { submit() }
views.ssssPassphraseUseKey.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.UseKey) }
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(SharedSecureStorageAction.TogglePasswordVisibility) }
}
fun submit() {
val text = ssss_passphrase_enter_edittext.text.toString()
val text = views.ssssPassphraseEnterEdittext.text.toString()
if (text.isBlank()) return // Should not reach this point as button disabled
ssss_passphrase_submit.isEnabled = false
views.ssssPassphraseSubmit.isEnabled = false
sharedViewModel.handle(SharedSecureStorageAction.SubmitPassphrase(text))
}
override fun invalidate() = withState(sharedViewModel) { state ->
val shouldBeVisible = state.passphraseVisible
ssss_passphrase_enter_edittext.showPassword(shouldBeVisible)
ssss_view_show_password.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
views.ssssPassphraseEnterEdittext.showPassword(shouldBeVisible)
views.ssssViewShowPassword.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
}
}

View file

@ -17,41 +17,48 @@
package im.vector.app.features.crypto.quads
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentSsssResetAllBinding
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
import kotlinx.android.synthetic.main.fragment_ssss_reset_all.*
import javax.inject.Inject
class SharedSecuredStorageResetAllFragment @Inject constructor() : VectorBaseFragment() {
class SharedSecuredStorageResetAllFragment @Inject constructor()
: VectorBaseFragment<FragmentSsssResetAllBinding>() {
override fun getLayoutResId() = R.layout.fragment_ssss_reset_all
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSsssResetAllBinding {
return FragmentSsssResetAllBinding.inflate(inflater, container, false)
}
val sharedViewModel: SharedSecureStorageViewModel by activityViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ssss_reset_button_reset.debouncedClicks {
views.ssssResetButtonReset.debouncedClicks {
sharedViewModel.handle(SharedSecureStorageAction.DoResetAll)
}
ssss_reset_button_cancel.debouncedClicks {
views.ssssResetButtonCancel.debouncedClicks {
sharedViewModel.handle(SharedSecureStorageAction.Back)
}
ssss_reset_other_devices.debouncedClicks {
views.ssssResetOtherDevices.debouncedClicks {
withState(sharedViewModel) {
DeviceListBottomSheet.newInstance(it.userId, false).show(childFragmentManager, "DEV_LIST")
}
}
sharedViewModel.subscribe(this) { state ->
ssss_reset_other_devices.setTextOrHide(
views.ssssResetOtherDevices.setTextOrHide(
state.activeDeviceCount
.takeIf { it > 0 }
?.let { resources.getQuantityString(R.plurals.secure_backup_reset_devices_you_can_verify, it, it) }

View file

@ -17,7 +17,9 @@
package im.vector.app.features.crypto.recover
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.text.toSpannable
import com.airbnb.mvrx.parentFragmentViewModel
@ -30,18 +32,22 @@ import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.databinding.FragmentBootstrapEnterAccountPasswordBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_account_password.*
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_view_show_password
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class BootstrapAccountPasswordFragment @Inject constructor(
private val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentBootstrapEnterAccountPasswordBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_account_password
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterAccountPasswordBinding {
return FragmentBootstrapEnterAccountPasswordBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()

View file

@ -36,12 +36,14 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_bootstrap.*
import im.vector.app.databinding.BottomSheetBootstrapBinding
import im.vector.app.databinding.BottomSheetGenericListBinding
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
import kotlin.reflect.KClass
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBootstrapBinding>() {
@Parcelize
data class Args(
@ -59,7 +61,9 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_bootstrap
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetBootstrapBinding {
return BottomSheetBootstrapBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -120,60 +124,60 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun invalidate() = withState(viewModel) { state ->
when (state.step) {
is BootstrapStep.CheckingMigration -> {
bootstrapIcon.isVisible = false
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
views.bootstrapIcon.isVisible = false
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
showFragment(BootstrapWaitingFragment::class, Bundle())
}
is BootstrapStep.FirstForm -> {
bootstrapIcon.isVisible = false
bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
views.bootstrapIcon.isVisible = false
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_setup_secure_backup_title)
showFragment(BootstrapSetupRecoveryKeyFragment::class, Bundle())
}
is BootstrapStep.SetupPassphrase -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
showFragment(BootstrapEnterPassphraseFragment::class, Bundle())
}
is BootstrapStep.ConfirmPassphrase -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_phrase_24dp))
views.bootstrapTitleText.text = getString(R.string.set_a_security_phrase_title)
showFragment(BootstrapConfirmPassphraseFragment::class, Bundle())
}
is BootstrapStep.AccountPassword -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
bootstrapTitleText.text = getString(R.string.account_password)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_user))
views.bootstrapTitleText.text = getString(R.string.account_password)
showFragment(BootstrapAccountPasswordFragment::class, Bundle())
}
is BootstrapStep.Initializing -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
views.bootstrapTitleText.text = getString(R.string.bootstrap_loading_title)
showFragment(BootstrapWaitingFragment::class, Bundle())
}
is BootstrapStep.SaveRecoveryKey -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
views.bootstrapTitleText.text = getString(R.string.bottom_sheet_save_your_recovery_key_title)
showFragment(BootstrapSaveRecoveryKeyFragment::class, Bundle())
}
is BootstrapStep.DoneSuccess -> {
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_security_key_24dp))
views.bootstrapTitleText.text = getString(R.string.bootstrap_finish_title)
showFragment(BootstrapConclusionFragment::class, Bundle())
}
is BootstrapStep.GetBackupSecretForMigration -> {
val isKey = state.step.useKey()
val drawableRes = if (isKey) R.drawable.ic_security_key_24dp else R.drawable.ic_security_phrase_24dp
bootstrapIcon.isVisible = true
bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
views.bootstrapIcon.isVisible = true
views.bootstrapIcon.setImageDrawable(ContextCompat.getDrawable(
requireContext(),
drawableRes)
)
bootstrapTitleText.text = getString(R.string.upgrade_security)
views.bootstrapTitleText.text = getString(R.string.upgrade_security)
showFragment(BootstrapMigrateBackupFragment::class, Bundle())
}
}.exhaustive

View file

@ -17,7 +17,9 @@
package im.vector.app.features.crypto.recover
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.text.toSpannable
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -25,27 +27,31 @@ import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.colorizeMatchingText
import kotlinx.android.synthetic.main.fragment_bootstrap_conclusion.*
import im.vector.app.databinding.FragmentBootstrapConclusionBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import javax.inject.Inject
class BootstrapConclusionFragment @Inject constructor(
private val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentBootstrapConclusionBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_conclusion
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapConclusionBinding {
return FragmentBootstrapConclusionBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bootstrapConclusionContinue.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) }
views.bootstrapConclusionContinue.clickableView.debouncedClicks { sharedViewModel.handle(BootstrapActions.Completed) }
}
override fun invalidate() = withState(sharedViewModel) { state ->
if (state.step !is BootstrapStep.DoneSuccess) return@withState
bootstrapConclusionText.text = getString(
views.bootstrapConclusionText.text = getString(
R.string.bootstrap_cross_signing_success,
getString(R.string.recovery_passphrase),
getString(R.string.message_key)

View file

@ -17,7 +17,9 @@
package im.vector.app.features.crypto.recover
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.view.isGone
import com.airbnb.mvrx.parentFragmentViewModel
@ -28,14 +30,19 @@ import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class BootstrapConfirmPassphraseFragment @Inject constructor() : VectorBaseFragment() {
class BootstrapConfirmPassphraseFragment @Inject constructor()
: VectorBaseFragment<FragmentBootstrapEnterPassphraseBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()

View file

@ -17,7 +17,9 @@
package im.vector.app.features.crypto.recover
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -26,29 +28,34 @@ import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.app.R
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBootstrapEnterPassphraseBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.features.settings.VectorLocale
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragment() {
class BootstrapEnterPassphraseFragment @Inject constructor()
: VectorBaseFragment<FragmentBootstrapEnterPassphraseBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapEnterPassphraseBinding {
return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
ssss_passphrase_enter_edittext.hint = getString(R.string.set_a_security_phrase_hint)
views.bootstrapDescriptionText.text = getString(R.string.set_a_security_phrase_notice)
views.ssssPassphraseEnterEdittext.hint = getString(R.string.set_a_security_phrase_hint)
withState(sharedViewModel) {
// set initial value (useful when coming back)
ssss_passphrase_enter_edittext.setText(it.passphrase ?: "")
views.ssssPassphraseEnterEdittext.setText(it.passphrase ?: "")
}
ssss_passphrase_enter_edittext.editorActionEvents()
views.ssssPassphraseEnterEdittext.editorActionEvents()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
@ -58,7 +65,7 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
}
.disposeOnDestroyView()
ssss_passphrase_enter_edittext.textChanges()
views.ssssPassphraseEnterEdittext.textChanges()
.subscribe {
// ssss_passphrase_enter_til.error = null
sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
@ -74,8 +81,8 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
// }
}
ssss_view_show_password.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
bootstrapSubmit.debouncedClicks { submit() }
views.ssssViewShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
views.bootstrapSubmit.debouncedClicks { submit() }
}
private fun submit() = withState(sharedViewModel) { state ->
@ -83,11 +90,11 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
return@withState
}
val score = state.passphraseStrength.invoke()?.score
val passphrase = ssss_passphrase_enter_edittext.text?.toString()
val passphrase = views.ssssPassphraseEnterEdittext.text?.toString()
if (passphrase.isNullOrBlank()) {
ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_empty_error_message)
} else if (score != 4) {
ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_too_weak)
views.ssssPassphraseEnterTil.error = getString(R.string.passphrase_passphrase_too_weak)
} else {
sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
}
@ -96,21 +103,21 @@ class BootstrapEnterPassphraseFragment @Inject constructor() : VectorBaseFragmen
override fun invalidate() = withState(sharedViewModel) { state ->
if (state.step is BootstrapStep.SetupPassphrase) {
val isPasswordVisible = state.step.isPasswordVisible
ssss_passphrase_enter_edittext.showPassword(isPasswordVisible, updateCursor = false)
ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
views.ssssPassphraseEnterEdittext.showPassword(isPasswordVisible, updateCursor = false)
views.ssssViewShowPassword.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
state.passphraseStrength.invoke()?.let { strength ->
val score = strength.score
ssss_passphrase_security_progress.strength = score
views.ssssPassphraseSecurityProgress.strength = score
if (score in 1..3) {
val hint =
strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() }
?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()
if (hint != null && hint != ssss_passphrase_enter_til.error.toString()) {
ssss_passphrase_enter_til.error = hint
if (hint != null && hint != views.ssssPassphraseEnterTil.error.toString()) {
views.ssssPassphraseEnterTil.error = hint
}
} else {
ssss_passphrase_enter_til.error = null
views.ssssPassphraseEnterTil.error = null
}
}
}

View file

@ -21,7 +21,9 @@ import android.os.Bundle
import android.text.InputType.TYPE_CLASS_TEXT
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
import android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.core.text.toSpannable
import androidx.core.view.isVisible
@ -37,9 +39,11 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.core.utils.startImportTextFromFileIntent
import im.vector.app.databinding.FragmentBootstrapMigrateBackupBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.bootstrapDescriptionText
import kotlinx.android.synthetic.main.fragment_bootstrap_migrate_backup.*
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.internal.crypto.keysbackup.util.isValidRecoveryKey
import java.util.concurrent.TimeUnit
@ -47,9 +51,11 @@ import javax.inject.Inject
class BootstrapMigrateBackupFragment @Inject constructor(
private val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentBootstrapMigrateBackupBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_migrate_backup
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapMigrateBackupBinding {
return FragmentBootstrapMigrateBackupBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()

View file

@ -20,7 +20,9 @@ import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -30,7 +32,9 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.core.utils.toast
import kotlinx.android.synthetic.main.fragment_bootstrap_save_key.*
import im.vector.app.databinding.FragmentBootstrapSaveKeyBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
@ -38,18 +42,20 @@ import javax.inject.Inject
class BootstrapSaveRecoveryKeyFragment @Inject constructor(
private val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentBootstrapSaveKeyBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_save_key
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSaveKeyBinding {
return FragmentBootstrapSaveKeyBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() }
recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() }
recoveryContinue.clickableView.debouncedClicks {
views.recoverySave.clickableView.debouncedClicks { downloadRecoveryKey() }
views.recoveryCopy.clickableView.debouncedClicks { shareRecoveryKey() }
views.recoveryContinue.clickableView.debouncedClicks {
// We do not display the final Fragment anymore
// TODO Do some cleanup
// sharedViewModel.handle(BootstrapActions.GoToCompleted)
@ -112,7 +118,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
val step = state.step
if (step !is BootstrapStep.SaveRecoveryKey) return@withState
recoveryContinue.isVisible = step.isSaved
bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
views.recoveryContinue.isVisible = step.isSaved
views.bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
}
}

View file

@ -17,18 +17,25 @@
package im.vector.app.features.crypto.recover
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_bootstrap_setup_recovery.*
import im.vector.app.databinding.FragmentBootstrapSetupRecoveryBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import javax.inject.Inject
class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragment() {
class BootstrapSetupRecoveryKeyFragment @Inject constructor()
: VectorBaseFragment<FragmentBootstrapSetupRecoveryBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_setup_recovery
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapSetupRecoveryBinding {
return FragmentBootstrapSetupRecoveryBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
@ -36,15 +43,15 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
super.onViewCreated(view, savedInstanceState)
// Actions when a key backup exist
bootstrapSetupSecureSubmit.clickableView.debouncedClicks {
views.bootstrapSetupSecureSubmit.clickableView.debouncedClicks {
sharedViewModel.handle(BootstrapActions.StartKeyBackupMigration)
}
// Actions when there is no key backup
bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks {
views.bootstrapSetupSecureUseSecurityKey.clickableView.debouncedClicks {
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = false))
}
bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks {
views.bootstrapSetupSecureUseSecurityPassphrase.clickableView.debouncedClicks {
sharedViewModel.handle(BootstrapActions.Start(userWantsToEnterPassphrase = true))
}
}
@ -53,23 +60,23 @@ class BootstrapSetupRecoveryKeyFragment @Inject constructor() : VectorBaseFragme
if (state.step is BootstrapStep.FirstForm) {
if (state.step.keyBackUpExist) {
// Display the set up action
bootstrapSetupSecureSubmit.isVisible = true
bootstrapSetupSecureUseSecurityKey.isVisible = false
bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
views.bootstrapSetupSecureSubmit.isVisible = true
views.bootstrapSetupSecureUseSecurityKey.isVisible = false
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = false
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = false
} else {
if (state.step.reset) {
bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
bootstrapSetupWarningTextView.isVisible = true
views.bootstrapSetupSecureText.text = getString(R.string.reset_secure_backup_title)
views.bootstrapSetupWarningTextView.isVisible = true
} else {
bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
bootstrapSetupWarningTextView.isVisible = false
views.bootstrapSetupSecureText.text = getString(R.string.bottom_sheet_setup_secure_backup_subtitle)
views.bootstrapSetupWarningTextView.isVisible = false
}
// Choose between create a passphrase or use a recovery key
bootstrapSetupSecureSubmit.isVisible = false
bootstrapSetupSecureUseSecurityKey.isVisible = true
bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
views.bootstrapSetupSecureSubmit.isVisible = false
views.bootstrapSetupSecureUseSecurityKey.isVisible = true
views.bootstrapSetupSecureUseSecurityPassphrase.isVisible = true
views.bootstrapSetupSecureUseSecurityPassphraseSeparator.isVisible = true
}
}
}

View file

@ -16,26 +16,33 @@
package im.vector.app.features.crypto.recover
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_bootstrap_waiting.*
import im.vector.app.databinding.FragmentBootstrapWaitingBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import javax.inject.Inject
class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() {
class BootstrapWaitingFragment @Inject constructor()
: VectorBaseFragment<FragmentBootstrapWaitingBinding>() {
override fun getLayoutResId() = R.layout.fragment_bootstrap_waiting
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBootstrapWaitingBinding {
return FragmentBootstrapWaitingBinding.inflate(inflater, container, false)
}
val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
override fun invalidate() = withState(sharedViewModel) { state ->
when (state.step) {
is BootstrapStep.Initializing -> {
bootstrapLoadingStatusText.isVisible = true
bootstrapDescriptionText.isVisible = true
bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
views.bootstrapLoadingStatusText.isVisible = true
views.bootstrapDescriptionText.isVisible = true
views.bootstrapLoadingStatusText.text = state.initializationWaitingViewData?.message
}
// is BootstrapStep.CheckingMigration -> {
// bootstrapLoadingStatusText.isVisible = false
@ -43,8 +50,8 @@ class BootstrapWaitingFragment @Inject constructor() : VectorBaseFragment() {
// }
else -> {
// just show the spinner
bootstrapLoadingStatusText.isVisible = false
bootstrapDescriptionText.isVisible = false
views.bootstrapLoadingStatusText.isVisible = false
views.bootstrapDescriptionText.isVisible = false
}
}
}

View file

@ -16,10 +16,16 @@
package im.vector.app.features.crypto.verification
import android.view.LayoutInflater
import android.view.ViewGroup
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.databinding.FragmentProgressBinding
import javax.inject.Inject
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_progress
class QuadSLoadingFragment @Inject constructor() : VectorBaseFragment<FragmentProgressBinding>() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentProgressBinding {
return FragmentProgressBinding.inflate(inflater, container, false)
}
}

View file

@ -20,7 +20,9 @@ import android.app.Dialog
import android.os.Bundle
import android.os.Parcelable
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
@ -34,6 +36,8 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.BottomSheetVerificationBinding
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
@ -45,8 +49,8 @@ import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrS
import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.settings.VectorSettingsActivity
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_verification.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
@ -58,7 +62,7 @@ import timber.log.Timber
import javax.inject.Inject
import kotlin.reflect.KClass
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetVerificationBinding>() {
@Parcelize
data class VerificationArgs(
@ -84,7 +88,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_verification
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationBinding {
return BottomSheetVerificationBinding.inflate(inflater, container, false)
}
init {
isCancelable = false
@ -115,7 +121,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
VerificationBottomSheetViewEvents.GoToSettings -> {
dismiss()
(activity as? VectorBaseActivity)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
(activity as? VectorBaseActivity<*>)?.navigator?.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY)
}
}.exhaustive
}
@ -152,27 +158,27 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
override fun invalidate() = withState(viewModel) { state ->
state.otherUserMxItem?.let { matrixItem ->
if (state.isMe) {
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
if (state.sasTransactionState == VerificationTxState.Verified
|| state.qrTransactionState == VerificationTxState.Verified
|| state.verifiedFromPrivateKeys) {
otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
views.otherUserShield.setImageResource(R.drawable.ic_shield_trusted)
} else {
otherUserShield.setImageResource(R.drawable.ic_shield_warning)
views.otherUserShield.setImageResource(R.drawable.ic_shield_warning)
}
otherUserNameText.text = getString(
views.otherUserNameText.text = getString(
if (state.selfVerificationMode) R.string.crosssigning_verify_this_session else R.string.crosssigning_verify_session
)
otherUserShield.isVisible = true
views.otherUserShield.isVisible = true
} else {
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
avatarRenderer.render(matrixItem, views.otherUserAvatarImageView)
if (state.sasTransactionState == VerificationTxState.Verified || state.qrTransactionState == VerificationTxState.Verified) {
otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
otherUserShield.isVisible = true
views.otherUserNameText.text = getString(R.string.verification_verified_user, matrixItem.getBestName())
views.otherUserShield.isVisible = true
} else {
otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
otherUserShield.isVisible = false
views.otherUserNameText.text = getString(R.string.verification_verify_user, matrixItem.getBestName())
views.otherUserShield.isVisible = false
}
}
}
@ -189,13 +195,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
if (state.userThinkItsNotHim) {
otherUserNameText.text = getString(R.string.dialog_title_warning)
views.otherUserNameText.text = getString(R.string.dialog_title_warning)
showFragment(VerificationNotMeFragment::class, Bundle())
return@withState
}
if (state.userWantsToCancel) {
otherUserNameText.text = getString(R.string.are_you_sure)
views.otherUserNameText.text = getString(R.string.are_you_sure)
showFragment(VerificationCancelFragment::class, Bundle())
return@withState
}
@ -287,7 +293,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
// Transaction has not yet started
if (state.pendingRequest.invoke()?.cancelConclusion != null) {
// The request has been declined, we should dismiss
otherUserNameText.text = getString(R.string.verification_cancelled)
views.otherUserNameText.text = getString(R.string.verification_cancelled)
showFragment(VerificationConclusionFragment::class, Bundle().apply {
putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(
false,

View file

@ -17,24 +17,31 @@
package im.vector.app.features.crypto.verification.cancel
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import javax.inject.Inject
class VerificationCancelFragment @Inject constructor(
val controller: VerificationCancelController
) : VectorBaseFragment(), VerificationCancelController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationCancelController.Listener {
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -42,13 +49,13 @@ class VerificationCancelFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -17,24 +17,31 @@
package im.vector.app.features.crypto.verification.cancel
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.databinding.FragmentKeysBackupRestoreFromKeyBinding
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import javax.inject.Inject
class VerificationNotMeFragment @Inject constructor(
val controller: VerificationNotMeController
) : VectorBaseFragment(), VerificationNotMeController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationNotMeController.Listener {
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -42,13 +49,13 @@ class VerificationNotMeFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -17,7 +17,9 @@ package im.vector.app.features.crypto.verification.choose
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -29,23 +31,27 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import im.vector.app.features.qrcode.QrCodeScannerActivity
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import timber.log.Timber
import javax.inject.Inject
class VerificationChooseMethodFragment @Inject constructor(
val verificationChooseMethodViewModelFactory: VerificationChooseMethodViewModel.Factory,
val controller: VerificationChooseMethodController
) : VectorBaseFragment(), VerificationChooseMethodController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationChooseMethodController.Listener {
private val viewModel by fragmentViewModel(VerificationChooseMethodViewModel::class)
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -54,13 +60,13 @@ class VerificationChooseMethodFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -17,7 +17,9 @@ package im.vector.app.features.crypto.verification.conclusion
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -25,15 +27,17 @@ import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
class VerificationConclusionFragment @Inject constructor(
val controller: VerificationConclusionController
) : VectorBaseFragment(), VerificationConclusionController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationConclusionController.Listener {
@Parcelize
data class Args(
@ -46,7 +50,9 @@ class VerificationConclusionFragment @Inject constructor(
private val viewModel by fragmentViewModel(VerificationConclusionViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -55,13 +61,13 @@ class VerificationConclusionFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -16,7 +16,9 @@
package im.vector.app.features.crypto.verification.emoji
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
@ -24,21 +26,25 @@ import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import javax.inject.Inject
class VerificationEmojiCodeFragment @Inject constructor(
val viewModelFactory: VerificationEmojiCodeViewModel.Factory,
val controller: VerificationEmojiCodeController
) : VectorBaseFragment(), VerificationEmojiCodeController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationEmojiCodeController.Listener {
private val viewModel by fragmentViewModel(VerificationEmojiCodeViewModel::class)
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -47,13 +53,13 @@ class VerificationEmojiCodeFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -18,19 +18,22 @@ package im.vector.app.features.crypto.verification.qrconfirmation
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.MvRx
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
class VerificationQRWaitingFragment @Inject constructor(
val controller: VerificationQRWaitingController
) : VectorBaseFragment() {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>() {
@Parcelize
data class Args(
@ -38,7 +41,9 @@ class VerificationQRWaitingFragment @Inject constructor(
val otherUserName: String
) : Parcelable
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -49,11 +54,11 @@ class VerificationQRWaitingFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
}
}

View file

@ -16,25 +16,31 @@
package im.vector.app.features.crypto.verification.qrconfirmation
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import javax.inject.Inject
class VerificationQrScannedByOtherFragment @Inject constructor(
val controller: VerificationQrScannedByOtherController
) : VectorBaseFragment(), VerificationQrScannedByOtherController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationQrScannedByOtherController.Listener {
private val sharedViewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -46,13 +52,13 @@ class VerificationQrScannedByOtherFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -16,25 +16,31 @@
package im.vector.app.features.crypto.verification.request
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.*
import javax.inject.Inject
class VerificationRequestFragment @Inject constructor(
val controller: VerificationRequestController
) : VectorBaseFragment(), VerificationRequestController.Listener {
) : VectorBaseFragment<BottomSheetVerificationChildFragmentBinding>(),
VerificationRequestController.Listener {
private val viewModel by parentFragmentViewModel(VerificationBottomSheetViewModel::class)
override fun getLayoutResId() = R.layout.bottom_sheet_verification_child_fragment
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetVerificationChildFragmentBinding {
return BottomSheetVerificationChildFragmentBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -42,13 +48,13 @@ class VerificationRequestFragment @Inject constructor(
}
override fun onDestroyView() {
bottomSheetVerificationRecyclerView.cleanup()
views.bottomSheetVerificationRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetVerificationRecyclerView.configureWith(controller, hasFixedSize = false, disableItemAnimation = true)
controller.listener = this
}

View file

@ -17,8 +17,11 @@ package im.vector.app.features.discovery
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
@ -30,9 +33,11 @@ import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.ensureProtocol
import im.vector.app.databinding.BottomSheetVerificationChildFragmentBinding
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.features.discovery.change.SetIdentityServerFragment
import im.vector.app.features.settings.VectorSettingsActivity
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
import org.matrix.android.sdk.api.session.identity.SharedState
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.terms.TermsService
@ -41,9 +46,12 @@ import javax.inject.Inject
class DiscoverySettingsFragment @Inject constructor(
private val controller: DiscoverySettingsController,
val viewModelFactory: DiscoverySettingsViewModel.Factory
) : VectorBaseFragment(), DiscoverySettingsController.Listener {
) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
DiscoverySettingsController.Listener {
override fun getLayoutResId() = R.layout.fragment_generic_recycler
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
return FragmentGenericRecyclerBinding.inflate(inflater, container, false)
}
private val viewModel by fragmentViewModel(DiscoverySettingsViewModel::class)
@ -55,7 +63,7 @@ class DiscoverySettingsFragment @Inject constructor(
sharedViewModel = activityViewModelProvider.get(DiscoverySharedViewModel::class.java)
controller.listener = this
genericRecyclerView.configureWith(controller)
views.genericRecyclerView.configureWith(controller)
sharedViewModel.navigateEvent.observeEvent(this) {
when (it) {
@ -74,7 +82,7 @@ class DiscoverySettingsFragment @Inject constructor(
}
override fun onDestroyView() {
genericRecyclerView.cleanup()
views.genericRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
@ -85,7 +93,7 @@ class DiscoverySettingsFragment @Inject constructor(
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category)
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_discovery_category)
// If some 3pids are pending, we can try to check if they have been verified here
viewModel.handle(DiscoverySettingsAction.Refresh)

View file

@ -17,7 +17,9 @@ package im.vector.app.features.discovery.change
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.appcompat.app.AlertDialog
import androidx.core.text.toSpannable
@ -33,17 +35,21 @@ import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.colorizeMatchingText
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentSetIdentityServerBinding
import im.vector.app.features.discovery.DiscoverySharedViewModel
import kotlinx.android.synthetic.main.fragment_set_identity_server.*
import org.matrix.android.sdk.api.session.terms.TermsService
import javax.inject.Inject
class SetIdentityServerFragment @Inject constructor(
val viewModelFactory: SetIdentityServerViewModel.Factory,
val colorProvider: ColorProvider
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentSetIdentityServerBinding>() {
override fun getLayoutResId() = R.layout.fragment_set_identity_server
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSetIdentityServerBinding {
return FragmentSetIdentityServerBinding.inflate(inflater, container, false)
}
private val viewModel by fragmentViewModel(SetIdentityServerViewModel::class)
@ -147,7 +153,7 @@ class SetIdentityServerFragment @Inject constructor(
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.identity_server)
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.identity_server)
}
private val termsActivityResultLauncher = registerStartForActivityResult {

View file

@ -18,7 +18,9 @@
package im.vector.app.features.grouplist
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
@ -29,28 +31,33 @@ import im.vector.app.core.extensions.configureWith
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentGroupListBinding
import im.vector.app.features.home.HomeActivitySharedAction
import im.vector.app.features.home.HomeSharedActionViewModel
import kotlinx.android.synthetic.main.fragment_group_list.*
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import javax.inject.Inject
class GroupListFragment @Inject constructor(
val groupListViewModelFactory: GroupListViewModel.Factory,
private val groupController: GroupSummaryController
) : VectorBaseFragment(), GroupSummaryController.Callback {
) : VectorBaseFragment<FragmentGroupListBinding>(),
GroupSummaryController.Callback {
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
private val viewModel: GroupListViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_group_list
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGroupListBinding {
return FragmentGroupListBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
groupController.callback = this
stateView.contentView = groupListView
groupListView.configureWith(groupController)
views.stateView.contentView = views.groupListView
views.groupListView.configureWith(groupController)
viewModel.observeViewEvents {
when (it) {
is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
@ -60,14 +67,14 @@ class GroupListFragment @Inject constructor(
override fun onDestroyView() {
groupController.callback = null
groupListView.cleanup()
views.groupListView.cleanup()
super.onDestroyView()
}
override fun invalidate() = withState(viewModel) { state ->
when (state.asyncGroups) {
is Incomplete -> stateView.state = StateView.State.Loading
is Success -> stateView.state = StateView.State.Content
is Incomplete -> views.stateView.state = StateView.State.Loading
is Success -> views.stateView.state = StateView.State.Content
}
groupController.update(state)
}

View file

@ -21,8 +21,10 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.MenuItem
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
@ -40,6 +42,7 @@ import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityHomeBinding
import im.vector.app.features.disclaimer.showDisclaimerDialog
import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.notifications.NotificationDrawerManager
@ -56,9 +59,9 @@ import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
import im.vector.app.push.fcm.FcmHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.InitialSyncProgressService
import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.util.MatrixItem
@ -71,7 +74,11 @@ data class HomeActivityArgs(
val accountCreation: Boolean
) : Parcelable
class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDetectorSharedViewModel.Factory, ServerBackupStatusViewModel.Factory,
class HomeActivity :
VectorBaseActivity<ActivityHomeBinding>(),
ToolbarConfigurable,
UnknownDeviceDetectorSharedViewModel.Factory,
ServerBackupStatusViewModel.Factory,
NavigationInterceptor {
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
@ -98,7 +105,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
}
override fun getLayoutRes() = R.layout.activity_home
override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater)
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
@ -116,7 +123,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
super.onCreate(savedInstanceState)
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
drawerLayout.addDrawerListener(drawerListener)
views.drawerLayout.addDrawerListener(drawerListener)
if (isFirstCreation()) {
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
@ -126,10 +133,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
.observe()
.subscribe { sharedAction ->
when (sharedAction) {
is HomeActivitySharedAction.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
is HomeActivitySharedAction.CloseDrawer -> drawerLayout.closeDrawer(GravityCompat.START)
is HomeActivitySharedAction.OpenDrawer -> views.drawerLayout.openDrawer(GravityCompat.START)
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
is HomeActivitySharedAction.OpenGroup -> {
drawerLayout.closeDrawer(GravityCompat.START)
views.drawerLayout.closeDrawer(GravityCompat.START)
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
}
}.exhaustive
@ -197,24 +204,24 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
private fun renderState(state: HomeActivityViewState) {
when (val status = state.initialSyncProgressServiceStatus) {
is InitialSyncProgressService.Status.Idle -> {
waiting_view.isVisible = false
views.waitingView.root.isVisible = false
}
is InitialSyncProgressService.Status.Progressing -> {
Timber.v("${getString(status.statusText)} ${status.percentProgress}")
waiting_view.setOnClickListener {
views.waitingView.root.setOnClickListener {
// block interactions
}
waitingHorizontalProgress.apply {
views.waitingView.waitingHorizontalProgress.apply {
isIndeterminate = false
max = 100
progress = status.percentProgress
isVisible = true
}
waitingStatusText.apply {
views.waitingView.waitingStatusText.apply {
text = getString(status.statusText)
isVisible = true
}
waiting_view.isVisible = true
views.waitingView.root.isVisible = true
}
}.exhaustive
}
@ -269,7 +276,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
).apply {
colorInt = ThemeUtils.getColor(this@HomeActivity, R.attr.vctr_notice_secondary)
contentAction = Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
// action(it)
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
@ -282,7 +289,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
}, true)
addButton(getString(R.string.settings), Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
// action(it)
homeActivityViewModel.handle(HomeActivityViewActions.PushPromptHasBeenReviewed)
it.navigator.openSettings(it, VectorSettingsActivity.EXTRA_DIRECT_ACCESS_NOTIFICATIONS)
@ -292,7 +299,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
)
}
private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity) -> Unit)) {
private fun promptSecurityEvent(userItem: MatrixItem.UserItem?, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) {
popupAlertManager.postVectorAlert(
VerificationVectorAlert(
uid = "upgradeSecurity",
@ -303,7 +310,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
).apply {
colorInt = ContextCompat.getColor(this@HomeActivity, R.color.riotx_positive_accent)
contentAction = Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
action(it)
}
}
@ -321,7 +328,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
override fun onDestroy() {
drawerLayout.removeDrawerListener(drawerListener)
views.drawerLayout.removeDrawerListener(drawerListener)
super.onDestroy()
}
@ -375,8 +382,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
}
override fun onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START)
if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
views.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}

View file

@ -17,7 +17,9 @@
package im.vector.app.features.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import com.airbnb.mvrx.activityViewModel
@ -33,6 +35,8 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.ui.views.ActiveCallView
import im.vector.app.core.ui.views.ActiveCallViewHolder
import im.vector.app.core.ui.views.KeysBackupBanner
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentHomeDetailBinding
import im.vector.app.features.call.SharedActiveCallViewModel
import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.WebRtcPeerConnectionManager
@ -46,7 +50,7 @@ import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.workers.signout.BannerState
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
import kotlinx.android.synthetic.main.fragment_home_detail.*
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo
@ -64,7 +68,10 @@ class HomeDetailFragment @Inject constructor(
private val alertManager: PopupAlertManager,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
private val vectorPreferences: VectorPreferences
) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory {
) : VectorBaseFragment<FragmentHomeDetailBinding>(),
KeysBackupBanner.Delegate,
ActiveCallView.Callback,
ServerBackupStatusViewModel.Factory {
private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
@ -73,7 +80,9 @@ class HomeDetailFragment @Inject constructor(
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
private lateinit var sharedCallActionViewModel: SharedActiveCallViewModel
override fun getLayoutResId() = R.layout.fragment_home_detail
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDetailBinding {
return FragmentHomeDetailBinding.inflate(inflater, container, false)
}
private val activeCallViewHolder = ActiveCallViewHolder()
@ -89,7 +98,7 @@ class HomeDetailFragment @Inject constructor(
withState(viewModel) {
// Update the navigation view if needed (for when we restore the tabs)
bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
}
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
@ -132,8 +141,8 @@ class HomeDetailFragment @Inject constructor(
}
private fun checkNotificationTabStatus() {
val wasVisible = bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
val wasVisible = views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
if (wasVisible && !vectorPreferences.labAddNotificationTab()) {
// As we hide it check if it's not the current item!
withState(viewModel) {
@ -156,7 +165,7 @@ class HomeDetailFragment @Inject constructor(
).apply {
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
contentAction = Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity)
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)
?.navigator
?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
unknownDeviceDetectorSharedViewModel.handle(
@ -184,7 +193,7 @@ class HomeDetailFragment @Inject constructor(
).apply {
colorInt = ContextCompat.getColor(requireActivity(), R.color.riotx_accent)
contentAction = Runnable {
(weakCurrentActivity?.get() as? VectorBaseActivity)?.let {
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
// mark as ignored to avoid showing it again
unknownDeviceDetectorSharedViewModel.handle(
UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
@ -204,7 +213,7 @@ class HomeDetailFragment @Inject constructor(
private fun onGroupChange(groupSummary: GroupSummary?) {
groupSummary?.let {
// Use GlideApp with activity context to avoid the glideRequests to be paused
avatarRenderer.render(it.toMatrixItem(), groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
avatarRenderer.render(it.toMatrixItem(), views.groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
}
}
@ -212,20 +221,20 @@ class HomeDetailFragment @Inject constructor(
serverBackupStatusViewModel
.subscribe(this) {
when (val banState = it.bannerState.invoke()) {
is BannerState.Setup -> homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
BannerState.BackingUp -> homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
null,
BannerState.Hidden -> homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
}
}
homeKeysBackupBanner.delegate = this
views.homeKeysBackupBanner.delegate = this
}
private fun setupActiveCallView() {
activeCallViewHolder.bind(
activeCallPiP,
activeCallView,
activeCallPiPWrap,
views.activeCallPiP,
views.activeCallView,
views.activeCallPiPWrap,
this
)
}
@ -233,17 +242,17 @@ class HomeDetailFragment @Inject constructor(
private fun setupToolbar() {
val parentActivity = vectorBaseActivity
if (parentActivity is ToolbarConfigurable) {
parentActivity.configure(groupToolbar)
parentActivity.configure(views.groupToolbar)
}
groupToolbar.title = ""
groupToolbarAvatarImageView.debouncedClicks {
views.groupToolbar.title = ""
views.groupToolbarAvatarImageView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
}
}
private fun setupBottomNavigationView() {
bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
bottomNavigationView.setOnNavigationItemSelectedListener {
views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
views.bottomNavigationView.setOnNavigationItemSelectedListener {
val displayMode = when (it.itemId) {
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
@ -266,7 +275,7 @@ class HomeDetailFragment @Inject constructor(
}
private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
groupToolbarTitleView.setText(displayMode.titleRes)
views.groupToolbarTitleView.setText(displayMode.titleRes)
updateSelectedFragment(displayMode)
}
@ -302,10 +311,10 @@ class HomeDetailFragment @Inject constructor(
override fun invalidate() = withState(viewModel) {
Timber.v(it.toString())
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
syncStateView.render(it.syncState)
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
views.syncStateView.render(it.syncState)
}
private fun BadgeDrawable.render(count: Int, highlight: Boolean) {

View file

@ -17,7 +17,9 @@
package im.vector.app.features.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
@ -27,12 +29,14 @@ import im.vector.app.core.extensions.observeK
import im.vector.app.core.extensions.replaceChildFragment
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentHomeDrawerBinding
import im.vector.app.features.grouplist.GroupListFragment
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity
import im.vector.app.features.usercode.UserCodeActivity
import im.vector.app.features.workers.signout.SignOutUiWorker
import kotlinx.android.synthetic.main.fragment_home_drawer.*
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
@ -41,11 +45,13 @@ class HomeDrawerFragment @Inject constructor(
private val session: Session,
private val vectorPreferences: VectorPreferences,
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment() {
) : VectorBaseFragment<FragmentHomeDrawerBinding>() {
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
override fun getLayoutResId() = R.layout.fragment_home_drawer
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentHomeDrawerBinding {
return FragmentHomeDrawerBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -58,40 +64,40 @@ class HomeDrawerFragment @Inject constructor(
session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser ->
val user = optionalUser?.getOrNull()
if (user != null) {
avatarRenderer.render(user.toMatrixItem(), homeDrawerHeaderAvatarView)
homeDrawerUsernameView.text = user.displayName
homeDrawerUserIdView.text = user.userId
avatarRenderer.render(user.toMatrixItem(), views.homeDrawerHeaderAvatarView)
views.homeDrawerUsernameView.text = user.displayName
views.homeDrawerUserIdView.text = user.userId
}
}
// Profile
homeDrawerHeader.debouncedClicks {
views.homeDrawerHeader.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
navigator.openSettings(requireActivity(), directAccess = VectorSettingsActivity.EXTRA_DIRECT_ACCESS_GENERAL)
}
// Settings
homeDrawerHeaderSettingsView.debouncedClicks {
views.homeDrawerHeaderSettingsView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
navigator.openSettings(requireActivity())
}
// Sign out
homeDrawerHeaderSignoutView.debouncedClicks {
views.homeDrawerHeaderSignoutView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
SignOutUiWorker(requireActivity()).perform()
}
homeDrawerQRCodeButton.debouncedClicks {
views.homeDrawerQRCodeButton.debouncedClicks {
UserCodeActivity.newIntent(requireContext(), sharedActionViewModel.session.myUserId).let {
val options =
ActivityOptionsCompat.makeSceneTransitionAnimation(
requireActivity(),
homeDrawerHeaderAvatarView,
ViewCompat.getTransitionName(homeDrawerHeaderAvatarView) ?: ""
views.homeDrawerHeaderAvatarView,
ViewCompat.getTransitionName(views.homeDrawerHeaderAvatarView) ?: ""
)
startActivity(it, options.toBundle())
}
}
homeDrawerInviteFriendButton.debouncedClicks {
views.homeDrawerInviteFriendButton.debouncedClicks {
session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
val text = getString(R.string.invite_friends_text, permalink)
@ -106,8 +112,8 @@ class HomeDrawerFragment @Inject constructor(
}
// Debug menu
homeDrawerHeaderDebugView.isVisible = BuildConfig.DEBUG && vectorPreferences.developerMode()
homeDrawerHeaderDebugView.debouncedClicks {
views.homeDrawerHeaderDebugView.isVisible = BuildConfig.DEBUG && vectorPreferences.developerMode()
views.homeDrawerHeaderDebugView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
navigator.openDebug(requireActivity())
}

View file

@ -18,20 +18,26 @@ package im.vector.app.features.home
import android.graphics.drawable.AnimationDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import im.vector.app.R
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_loading.*
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentLoadingBinding
import javax.inject.Inject
class LoadingFragment @Inject constructor() : VectorBaseFragment() {
class LoadingFragment @Inject constructor() : VectorBaseFragment<FragmentLoadingBinding>() {
override fun getLayoutResId() = R.layout.fragment_loading
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoadingBinding {
return FragmentLoadingBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val background = animatedLogoImageView.background
val background = views.animatedLogoImageView.background
if (background is AnimationDrawable) {
background.start()
}

View file

@ -17,27 +17,34 @@
package im.vector.app.features.home.room.breadcrumbs
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentBreadcrumbsBinding
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.features.home.room.detail.RoomDetailSharedAction
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
import kotlinx.android.synthetic.main.fragment_breadcrumbs.*
import javax.inject.Inject
class BreadcrumbsFragment @Inject constructor(
private val breadcrumbsController: BreadcrumbsController,
val breadcrumbsViewModelFactory: BreadcrumbsViewModel.Factory
) : VectorBaseFragment(), BreadcrumbsController.Listener {
) : VectorBaseFragment<FragmentBreadcrumbsBinding>(),
BreadcrumbsController.Listener {
private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
private val breadcrumbsViewModel: BreadcrumbsViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_breadcrumbs
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBreadcrumbsBinding {
return FragmentBreadcrumbsBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -46,13 +53,13 @@ class BreadcrumbsFragment @Inject constructor(
}
override fun onDestroyView() {
breadcrumbsRecyclerView.cleanup()
views.breadcrumbsRecyclerView.cleanup()
breadcrumbsController.listener = null
super.onDestroyView()
}
private fun setupRecyclerView() {
breadcrumbsRecyclerView.configureWith(breadcrumbsController, BreadcrumbsAnimator(), hasFixedSize = false)
views.breadcrumbsRecyclerView.configureWith(breadcrumbsController, BreadcrumbsAnimator(), hasFixedSize = false)
breadcrumbsController.listener = this
}
@ -67,6 +74,6 @@ class BreadcrumbsFragment @Inject constructor(
}
fun scrollToTop() {
breadcrumbsRecyclerView.scrollToPosition(0)
views.breadcrumbsRecyclerView.scrollToPosition(0)
}
}

View file

@ -37,8 +37,8 @@ import im.vector.app.features.room.RequireActiveMembershipViewModel
import im.vector.app.features.room.RequireActiveMembershipViewState
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewModel
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionViewState
import kotlinx.android.synthetic.main.activity_room_detail.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import javax.inject.Inject
class RoomDetailActivity :

View file

@ -167,10 +167,10 @@ import im.vector.app.features.widgets.WidgetKind
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.*
import kotlinx.android.synthetic.main.composer_layout.view.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import kotlinx.parcelize.Parcelize
import nl.dionsegijn.konfetti.models.Shape
import nl.dionsegijn.konfetti.models.Size
import org.billcarsonfr.jsonviewer.JSonViewerDialog

View file

@ -31,7 +31,7 @@ import androidx.transition.Transition
import androidx.transition.TransitionManager
import androidx.transition.TransitionSet
import im.vector.app.R
import kotlinx.android.synthetic.main.composer_layout.view.*
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
/**

View file

@ -18,7 +18,9 @@ package im.vector.app.features.home.room.detail.readreceipts
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.args
import im.vector.app.R
@ -26,11 +28,13 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding
import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
@Parcelize
@ -41,7 +45,9 @@ data class DisplayReadReceiptArgs(
/**
* Bottom sheet displaying list of read receipts for a given event ordered by descending timestamp
*/
class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), DisplayReadReceiptsController.Listener {
class DisplayReadReceiptsBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
DisplayReadReceiptsController.Listener {
@Inject lateinit var epoxyController: DisplayReadReceiptsController
@ -53,19 +59,21 @@ class DisplayReadReceiptsBottomSheet : VectorBaseBottomSheetDialogFragment(), Di
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false)
bottomSheetTitle.text = getString(R.string.seen_by)
views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false)
views.bottomSheetTitle.text = getString(R.string.seen_by)
epoxyController.listener = this
epoxyController.setData(displayReadReceiptArgs.readReceipts)
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
epoxyController.listener = null
super.onDestroyView()
}

View file

@ -19,22 +19,23 @@ package im.vector.app.features.home.room.detail.search
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.widget.SearchView
import com.airbnb.mvrx.MvRx
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.VectorBaseActivity
import kotlinx.android.synthetic.main.activity_search.*
import im.vector.app.databinding.ActivitySearchBinding
class SearchActivity : VectorBaseActivity() {
class SearchActivity : VectorBaseActivity<ActivitySearchBinding>() {
private val searchFragment: SearchFragment?
get() {
return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? SearchFragment
}
override fun getLayoutRes() = R.layout.activity_search
override fun getBinding() = ActivitySearchBinding.inflate(layoutInflater)
override fun injectWith(injector: ScreenComponent) {
super.injectWith(injector)
@ -43,7 +44,7 @@ class SearchActivity : VectorBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
configureToolbar(searchToolbar)
configureToolbar(views.searchToolbar)
}
override fun initUiAndData() {
@ -51,7 +52,7 @@ class SearchActivity : VectorBaseActivity() {
val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return
addFragment(R.id.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG)
}
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
searchFragment?.search(query)
return true
@ -62,7 +63,7 @@ class SearchActivity : VectorBaseActivity() {
}
})
// Open the keyboard immediately
searchView.requestFocus()
views.searchView.requestFocus()
}
companion object {

View file

@ -18,7 +18,9 @@ package im.vector.app.features.home.room.detail.search
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.airbnb.mvrx.Fail
@ -34,8 +36,10 @@ import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.trackItemsVisibilityChange
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_search.*
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentSearchBinding
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.events.model.Event
import javax.inject.Inject
@ -47,32 +51,36 @@ data class SearchArgs(
class SearchFragment @Inject constructor(
val viewModelFactory: SearchViewModel.Factory,
private val controller: SearchResultController
) : VectorBaseFragment(), StateView.EventCallback, SearchResultController.Listener {
) : VectorBaseFragment<FragmentSearchBinding>(),
StateView.EventCallback,
SearchResultController.Listener {
private val fragmentArgs: SearchArgs by args()
private val searchViewModel: SearchViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_search
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSearchBinding {
return FragmentSearchBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
stateView.contentView = searchResultRecycler
stateView.eventCallback = this
views.stateView.contentView = views.searchResultRecycler
views.stateView.eventCallback = this
configureRecyclerView()
}
private fun configureRecyclerView() {
searchResultRecycler.trackItemsVisibilityChange()
searchResultRecycler.configureWith(controller, showDivider = false)
(searchResultRecycler.layoutManager as? LinearLayoutManager)?.stackFromEnd = true
views.searchResultRecycler.trackItemsVisibilityChange()
views.searchResultRecycler.configureWith(controller, showDivider = false)
(views.searchResultRecycler.layoutManager as? LinearLayoutManager)?.stackFromEnd = true
controller.listener = this
}
override fun onDestroy() {
super.onDestroy()
searchResultRecycler?.cleanup()
views.searchResultRecycler?.cleanup()
controller.listener = null
}
@ -80,20 +88,20 @@ class SearchFragment @Inject constructor(
if (state.searchResult.isNullOrEmpty()) {
when (state.asyncSearchRequest) {
is Loading -> {
stateView.state = StateView.State.Loading
views.stateView.state = StateView.State.Loading
}
is Fail -> {
stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error))
views.stateView.state = StateView.State.Error(errorFormatter.toHumanReadable(state.asyncSearchRequest.error))
}
is Success -> {
stateView.state = StateView.State.Empty(
views.stateView.state = StateView.State.Empty(
title = getString(R.string.search_no_results),
image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_search_no_results))
}
}
} else {
controller.setData(state)
stateView.state = StateView.State.Content
views.stateView.state = StateView.State.Content
}
}

View file

@ -16,7 +16,9 @@
package im.vector.app.features.home.room.detail.timeline.action
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
@ -24,14 +26,17 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import kotlinx.android.synthetic.main.bottom_sheet_generic_list.*
import javax.inject.Inject
/**
* Bottom sheet fragment that shows a message preview with list of contextual actions
*/
class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), MessageActionsEpoxyController.MessageActionsEpoxyControllerListener {
class MessageActionsBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
MessageActionsEpoxyController.MessageActionsEpoxyControllerListener {
@Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory
@Inject lateinit var messageActionsEpoxyController: MessageActionsEpoxyController
@ -46,17 +51,19 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
return BottomSheetGenericListBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
bottomSheetRecyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true)
views.bottomSheetRecyclerView.configureWith(messageActionsEpoxyController, hasFixedSize = false, disableItemAnimation = true)
messageActionsEpoxyController.listener = this
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
super.onDestroyView()
}
@ -76,8 +83,8 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), Message
if (eventAction is EventSharedAction.ReportContent) {
// Toggle report menu
// Enable item animation
if (bottomSheetRecyclerView.itemAnimator == null) {
bottomSheetRecyclerView.itemAnimator = MessageActionsAnimator()
if (views.bottomSheetRecyclerView.itemAnimator == null) {
views.bottomSheetRecyclerView.itemAnimator = MessageActionsAnimator()
}
viewModel.handle(MessageActionsAction.ToggleReportMenu)
} else {

View file

@ -18,7 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.action
import android.os.Parcelable
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
@Parcelize
data class TimelineEventFragmentArgs(

View file

@ -16,7 +16,9 @@
package im.vector.app.features.home.room.detail.timeline.edithistory
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -25,16 +27,19 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding
import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import im.vector.app.features.html.EventHtmlRenderer
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
import javax.inject.Inject
/**
* Bottom sheet displaying list of edits for a given event ordered by timestamp
*/
class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() {
class ViewEditHistoryBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>() {
private val viewModel: ViewEditHistoryViewModel by fragmentViewModel(ViewEditHistoryViewModel::class)
@ -49,19 +54,21 @@ class ViewEditHistoryBottomSheet : VectorBaseBottomSheetDialogFragment() {
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomSheetRecyclerView.configureWith(
views.bottomSheetRecyclerView.configureWith(
epoxyController,
showDivider = true,
hasFixedSize = false)
bottomSheetTitle.text = context?.getString(R.string.message_edits)
views.bottomSheetTitle.text = context?.getString(R.string.message_edits)
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
super.onDestroyView()
}

View file

@ -17,7 +17,7 @@
package im.vector.app.features.home.room.detail.timeline.item
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.session.room.VerificationState

View file

@ -23,7 +23,7 @@ import android.widget.LinearLayout
import androidx.core.content.withStyledAttributes
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import kotlinx.android.synthetic.main.item_timeline_event_poll_result_item.view.*
class PollResultLineView @JvmOverloads constructor(
context: Context,

View file

@ -17,7 +17,9 @@
package im.vector.app.features.home.room.detail.timeline.reactions
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -26,17 +28,21 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding
import im.vector.app.features.home.room.detail.timeline.action.EventSharedAction
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
import javax.inject.Inject
/**
* Bottom sheet displaying list of reactions for a given event ordered by timestamp
*/
class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReactionsEpoxyController.Listener {
class ViewReactionsBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
ViewReactionsEpoxyController.Listener {
private val viewModel: ViewReactionsViewModel by fragmentViewModel(ViewReactionsViewModel::class)
@ -49,18 +55,20 @@ class ViewReactionsBottomSheet : VectorBaseBottomSheetDialogFragment(), ViewReac
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true)
bottomSheetTitle.text = context?.getString(R.string.reactions)
views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false, showDivider = true)
views.bottomSheetTitle.text = context?.getString(R.string.reactions)
epoxyController.listener = this
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
epoxyController.listener = null
super.onDestroyView()
}

View file

@ -25,7 +25,7 @@ import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.media.ImageContentRenderer
import kotlinx.android.synthetic.main.url_preview.view.*
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.media.PreviewUrlData

View file

@ -21,7 +21,7 @@ import android.util.AttributeSet
import android.view.View
import android.widget.RelativeLayout
import im.vector.app.R
import kotlinx.android.synthetic.main.view_room_widgets_banner.view.*
import org.matrix.android.sdk.api.session.widgets.model.Widget
class RoomWidgetsBannerView @JvmOverloads constructor(

View file

@ -17,7 +17,9 @@
package im.vector.app.features.home.room.detail.widget
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
@ -26,18 +28,22 @@ import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.databinding.BottomSheetGenericListWithTitleBinding
import im.vector.app.features.home.room.detail.RoomDetailAction
import im.vector.app.features.home.room.detail.RoomDetailViewModel
import im.vector.app.features.home.room.detail.RoomDetailViewState
import im.vector.app.features.navigation.Navigator
import kotlinx.android.synthetic.main.bottom_sheet_generic_list_with_title.*
import org.matrix.android.sdk.api.session.widgets.model.Widget
import javax.inject.Inject
/**
* Bottom sheet displaying active widgets in a room
*/
class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidgetsController.Listener {
class RoomWidgetsBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListWithTitleBinding>(),
RoomWidgetsController.Listener {
@Inject lateinit var epoxyController: RoomWidgetsController
@Inject lateinit var colorProvider: ColorProvider
@ -49,14 +55,16 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list_with_title
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListWithTitleBinding {
return BottomSheetGenericListWithTitleBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false)
bottomSheetTitle.text = getString(R.string.active_widgets_title)
bottomSheetTitle.textSize = 20f
bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
views.bottomSheetRecyclerView.configureWith(epoxyController, hasFixedSize = false)
views.bottomSheetTitle.text = getString(R.string.active_widgets_title)
views.bottomSheetTitle.textSize = 20f
views.bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.riotx_text_primary))
epoxyController.listener = this
roomDetailViewModel.asyncSubscribe(this, RoomDetailViewState::activeRoomWidgets) {
epoxyController.setData(it)
@ -64,7 +72,7 @@ class RoomWidgetsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomWidget
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.bottomSheetRecyclerView.cleanup()
epoxyController.listener = null
super.onDestroyView()
}

View file

@ -19,24 +19,26 @@ package im.vector.app.features.home.room.filtered
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.widget.SearchView
import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivityFilteredRoomsBinding
import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.home.room.list.RoomListFragment
import im.vector.app.features.home.room.list.RoomListParams
import kotlinx.android.synthetic.main.activity_filtered_rooms.*
class FilteredRoomsActivity : VectorBaseActivity() {
class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>() {
private val roomListFragment: RoomListFragment?
get() {
return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? RoomListFragment
}
override fun getLayoutRes() = R.layout.activity_filtered_rooms
override fun getBinding() = ActivityFilteredRoomsBinding.inflate(layoutInflater)
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
@ -44,12 +46,12 @@ class FilteredRoomsActivity : VectorBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
configureToolbar(filteredRoomsToolbar)
configureToolbar(views.filteredRoomsToolbar)
if (isFirstCreation()) {
val params = RoomListParams(RoomListDisplayMode.FILTERED)
replaceFragment(R.id.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG)
}
filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
views.filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return true
}
@ -60,7 +62,7 @@ class FilteredRoomsActivity : VectorBaseActivity() {
}
})
// Open the keyboard immediately
filteredRoomsSearchView.requestFocus()
views.filteredRoomsSearchView.requestFocus()
}
companion object {

View file

@ -18,9 +18,11 @@ package im.vector.app.features.home.room.list
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
@ -40,6 +42,8 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.OnBackPressed
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.databinding.FragmentRoomListBinding
import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
@ -47,8 +51,8 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
import im.vector.app.features.home.room.list.widget.NotifsFabMenuView
import im.vector.app.features.notifications.NotificationDrawerManager
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_list.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@ -66,7 +70,10 @@ class RoomListFragment @Inject constructor(
val roomListViewModelFactory: RoomListViewModel.Factory,
private val notificationDrawerManager: NotificationDrawerManager,
private val sharedViewPool: RecyclerView.RecycledViewPool
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, NotifsFabMenuView.Listener {
) : VectorBaseFragment<FragmentRoomListBinding>(),
RoomSummaryController.Listener,
OnBackPressed,
NotifsFabMenuView.Listener {
private var modelBuildListener: OnModelBuildFinishedListener? = null
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
@ -74,7 +81,9 @@ class RoomListFragment @Inject constructor(
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
private lateinit var stateRestorer: LayoutManagerStateRestorer
override fun getLayoutResId() = R.layout.fragment_room_list
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding {
return FragmentRoomListBinding.inflate(inflater, container, false)
}
private var hasUnreadRooms = false

View file

@ -18,7 +18,9 @@ package im.vector.app.features.home.room.list.actions
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
@ -27,9 +29,10 @@ import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetGenericListBinding
import im.vector.app.features.navigation.Navigator
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.bottom_sheet_generic_list.*
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
@Parcelize
@ -47,7 +50,9 @@ data class RoomListActionsArgs(
/**
* Bottom sheet fragment that shows room information with list of contextual actions
*/
class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), RoomListQuickActionsEpoxyController.Listener {
class RoomListQuickActionsBottomSheet :
VectorBaseBottomSheetDialogFragment<BottomSheetGenericListBinding>(),
RoomListQuickActionsEpoxyController.Listener {
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
@Inject lateinit var sharedViewPool: RecyclerView.RecycledViewPool
@ -63,17 +68,19 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
injector.inject(this)
}
override fun getLayoutResId() = R.layout.bottom_sheet_generic_list
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetGenericListBinding {
return BottomSheetGenericListBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
views.views.bottomSheetRecyclerView.configureWith(roomListActionsEpoxyController, viewPool = sharedViewPool, hasFixedSize = false, disableItemAnimation = true)
roomListActionsEpoxyController.listener = this
}
override fun onDestroyView() {
bottomSheetRecyclerView.cleanup()
views.views.bottomSheetRecyclerView.cleanup()
roomListActionsEpoxyController.listener = null
super.onDestroyView()
}

View file

@ -22,7 +22,7 @@ import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.isVisible
import com.google.android.material.floatingactionbutton.FloatingActionButton
import im.vector.app.R
import kotlinx.android.synthetic.main.motion_notifs_fab_menu_merge.view.*
class NotifsFabMenuView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : MotionLayout(context, attrs, defStyleAttr) {

View file

@ -45,8 +45,8 @@ import im.vector.app.features.userdirectory.UserListSharedAction
import im.vector.app.features.userdirectory.UserListSharedActionViewModel
import im.vector.app.features.userdirectory.UserListViewModel
import im.vector.app.features.userdirectory.UserListViewState
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity.*
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.failure.Failure
import java.net.HttpURLConnection
import javax.inject.Inject

View file

@ -19,13 +19,15 @@ package im.vector.app.features.invite
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import im.vector.app.R
import im.vector.app.core.di.HasScreenInjector
import im.vector.app.core.platform.ButtonStateView
import im.vector.app.features.home.AvatarRenderer
import kotlinx.android.synthetic.main.vector_invite_view.view.*
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.util.toMatrixItem
@ -44,6 +46,13 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib
SMALL
}
private val inviteAvatarView: ImageView
private val inviteLabelView: TextView
private val inviteNameView: TextView
private val inviteIdentifierView: TextView
private val inviteAcceptView: ButtonStateView
private val inviteRejectView: ButtonStateView
@Inject lateinit var avatarRenderer: AvatarRenderer
var callback: Callback? = null
@ -52,6 +61,7 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib
context.injector().inject(this)
}
View.inflate(context, R.layout.vector_invite_view, this)
inviteAcceptView = findViewById(R.id.inviteAcceptView)
inviteAcceptView.callback = object : ButtonStateView.Callback {
override fun onButtonClicked() {
callback?.onAcceptInvite()
@ -62,6 +72,7 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib
}
}
inviteRejectView = findViewById(R.id.inviteRejectView)
inviteRejectView.callback = object : ButtonStateView.Callback {
override fun onButtonClicked() {
callback?.onRejectInvite()
@ -71,6 +82,11 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib
callback?.onRejectInvite()
}
}
inviteAvatarView = findViewById(R.id.inviteAvatarView)
inviteLabelView = findViewById(R.id.inviteLabelView)
inviteNameView = findViewById(R.id.inviteNameView)
inviteIdentifierView = findViewById(R.id.inviteIdentifierView)
}
fun render(sender: RoomMemberSummary, mode: Mode = Mode.LARGE, changeMembershipState: ChangeMembershipState) {

Some files were not shown because too many files have changed in this diff Show more