Migrate to ViewBindings (#1072) - WIP
This commit is contained in:
parent
706736273c
commit
dba65dcd22
|
@ -172,3 +172,6 @@ getSystemService\(Context
|
||||||
|
|
||||||
### Use DefaultSharedPreferences.getInstance() instead for better performance
|
### Use DefaultSharedPreferences.getInstance() instead for better performance
|
||||||
PreferenceManager\.getDefaultSharedPreferences==2
|
PreferenceManager\.getDefaultSharedPreferences==2
|
||||||
|
|
||||||
|
### Use ViewBindings
|
||||||
|
findViewById
|
||||||
|
|
|
@ -24,26 +24,27 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
import im.vector.app.databinding.ActivityTestMaterialThemeBinding
|
||||||
|
|
||||||
// Rendering is not the same with VectorBaseActivity
|
// Rendering is not the same with VectorBaseActivity
|
||||||
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_test_material_theme)
|
val views = ActivityTestMaterialThemeBinding.inflate(layoutInflater)
|
||||||
|
setContentView(views.root)
|
||||||
|
|
||||||
debugShowSnackbar.setOnClickListener {
|
views.debugShowSnackbar.setOnClickListener {
|
||||||
Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT)
|
Snackbar.make(views.debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT)
|
||||||
.setAction("Action") { }
|
.setAction("Action") { }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowToast.setOnClickListener {
|
views.debugShowToast.setOnClickListener {
|
||||||
toast("Toast")
|
toast("Toast")
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowDialog.setOnClickListener {
|
views.debugShowDialog.setOnClickListener {
|
||||||
AlertDialog.Builder(this)
|
AlertDialog.Builder(this)
|
||||||
.setMessage("Dialog content")
|
.setMessage("Dialog content")
|
||||||
.setIcon(R.drawable.ic_settings_x)
|
.setIcon(R.drawable.ic_settings_x)
|
||||||
|
@ -53,7 +54,7 @@ abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
debugShowBottomSheet.setOnClickListener {
|
views.debugShowBottomSheet.setOnClickListener {
|
||||||
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,16 @@ import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ActivityTestLinkifyBinding
|
||||||
|
import im.vector.app.databinding.ActivityTestMaterialThemeBinding
|
||||||
|
|
||||||
class TestLinkifyActivity : AppCompatActivity() {
|
class TestLinkifyActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_test_linkify)
|
val views = ActivityTestLinkifyBinding.inflate(layoutInflater)
|
||||||
|
setContentView(views.root)
|
||||||
test_linkify_content_view.removeAllViews()
|
views.testLinkifyContentView.removeAllViews()
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
||||||
|
@ -79,7 +80,7 @@ class TestLinkifyActivity : AppCompatActivity() {
|
||||||
)
|
)
|
||||||
.forEach { textContent ->
|
.forEach { textContent ->
|
||||||
val item = LayoutInflater.from(this)
|
val item = LayoutInflater.from(this)
|
||||||
.inflate(R.layout.item_test_linkify, test_linkify_content_view, false)
|
.inflate(R.layout.item_test_linkify, views.testLinkifyContentView, false)
|
||||||
|
|
||||||
item.findViewById<TextView>(R.id.test_linkify_auto_text)
|
item.findViewById<TextView>(R.id.test_linkify_auto_text)
|
||||||
?.apply {
|
?.apply {
|
||||||
|
@ -115,7 +116,7 @@ class TestLinkifyActivity : AppCompatActivity() {
|
||||||
// TODO Call VectorLinkify.addLinks(text)
|
// TODO Call VectorLinkify.addLinks(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
test_linkify_content_view.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
views.testLinkifyContentView.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,18 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||||
import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis
|
import org.matrix.android.sdk.api.crypto.getAllVerificationEmojis
|
||||||
|
|
||||||
|
|
||||||
class DebugSasEmojiActivity : AppCompatActivity() {
|
class DebugSasEmojiActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var views: FragmentGenericRecyclerBinding
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.fragment_generic_recycler)
|
views = FragmentGenericRecyclerBinding.inflate(layoutInflater)
|
||||||
|
setContentView(views.root)
|
||||||
val controller = SasEmojiController()
|
val controller = SasEmojiController()
|
||||||
views.genericRecyclerView.configureWith(controller)
|
views.genericRecyclerView.configureWith(controller)
|
||||||
controller.setData(SasState(getAllVerificationEmojis()))
|
controller.setData(SasState(getAllVerificationEmojis()))
|
||||||
|
|
|
@ -21,7 +21,7 @@ import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogConfirmationWithReasonBinding
|
||||||
|
|
||||||
object ConfirmationDialogBuilder {
|
object ConfirmationDialogBuilder {
|
||||||
|
|
||||||
|
@ -33,25 +33,26 @@ object ConfirmationDialogBuilder {
|
||||||
@StringRes reasonHintRes: Int,
|
@StringRes reasonHintRes: Int,
|
||||||
confirmation: (String?) -> Unit) {
|
confirmation: (String?) -> Unit) {
|
||||||
val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null)
|
val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null)
|
||||||
layout.dialogConfirmationText.setText(confirmationRes)
|
val views = DialogConfirmationWithReasonBinding.bind(layout)
|
||||||
|
views.dialogConfirmationText.setText(confirmationRes)
|
||||||
|
|
||||||
layout.dialogReasonCheck.isVisible = askForReason
|
views.dialogReasonCheck.isVisible = askForReason
|
||||||
layout.dialogReasonTextInputLayout.isVisible = askForReason
|
views.dialogReasonTextInputLayout.isVisible = askForReason
|
||||||
|
|
||||||
layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked ->
|
views.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked ->
|
||||||
layout.dialogReasonTextInputLayout.isEnabled = isChecked
|
views.dialogReasonTextInputLayout.isEnabled = isChecked
|
||||||
}
|
}
|
||||||
if (askForReason && reasonHintRes != 0) {
|
if (askForReason && reasonHintRes != 0) {
|
||||||
layout.dialogReasonInput.setHint(reasonHintRes)
|
views.dialogReasonInput.setHint(reasonHintRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
.setTitle(titleRes)
|
.setTitle(titleRes)
|
||||||
.setView(layout)
|
.setView(layout)
|
||||||
.setPositiveButton(positiveRes) { _, _ ->
|
.setPositiveButton(positiveRes) { _, _ ->
|
||||||
val reason = layout.dialogReasonInput.text.toString()
|
val reason = views.dialogReasonInput.text.toString()
|
||||||
.takeIf { askForReason }
|
.takeIf { askForReason }
|
||||||
?.takeIf { layout.dialogReasonCheck.isChecked }
|
?.takeIf { views.dialogReasonCheck.isChecked }
|
||||||
?.takeIf { it.isNotBlank() }
|
?.takeIf { it.isNotBlank() }
|
||||||
confirmation(reason)
|
confirmation(reason)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.google.android.material.textfield.TextInputLayout
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.SimpleTextWatcher
|
import im.vector.app.core.platform.SimpleTextWatcher
|
||||||
|
import im.vector.app.databinding.DialogExportE2eKeysBinding
|
||||||
|
|
||||||
class ExportKeysDialog {
|
class ExportKeysDialog {
|
||||||
|
|
||||||
|
@ -33,48 +34,45 @@ class ExportKeysDialog {
|
||||||
|
|
||||||
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
||||||
|
val views = DialogExportE2eKeysBinding.bind(dialogLayout)
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.encryption_export_room_keys)
|
.setTitle(R.string.encryption_export_room_keys)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
|
|
||||||
val passPhrase1EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEt)
|
|
||||||
val passPhrase2EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEtConfirm)
|
|
||||||
val passPhrase2Til = dialogLayout.findViewById<TextInputLayout>(R.id.exportDialogTilConfirm)
|
|
||||||
val exportButton = dialogLayout.findViewById<Button>(R.id.exportDialogSubmit)
|
|
||||||
val textWatcher = object : SimpleTextWatcher() {
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
when {
|
when {
|
||||||
passPhrase1EditText.text.isNullOrEmpty() -> {
|
views.exportDialogEt.text.isNullOrEmpty() -> {
|
||||||
exportButton.isEnabled = false
|
views.exportDialogSubmit.isEnabled = false
|
||||||
passPhrase2Til.error = null
|
views.exportDialogTilConfirm.error = null
|
||||||
}
|
}
|
||||||
passPhrase1EditText.text.toString() == passPhrase2EditText.text.toString() -> {
|
views.exportDialogEt.text.toString() == views.exportDialogEtConfirm.text.toString() -> {
|
||||||
exportButton.isEnabled = true
|
views.exportDialogSubmit.isEnabled = true
|
||||||
passPhrase2Til.error = null
|
views.exportDialogTilConfirm.error = null
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
exportButton.isEnabled = false
|
views.exportDialogSubmit.isEnabled = false
|
||||||
passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
views.exportDialogTilConfirm.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
passPhrase1EditText.addTextChangedListener(textWatcher)
|
views.exportDialogEt.addTextChangedListener(textWatcher)
|
||||||
passPhrase2EditText.addTextChangedListener(textWatcher)
|
views.exportDialogEtConfirm.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
||||||
showPassword.setOnClickListener {
|
showPassword.setOnClickListener {
|
||||||
passwordVisible = !passwordVisible
|
passwordVisible = !passwordVisible
|
||||||
passPhrase1EditText.showPassword(passwordVisible)
|
views.exportDialogEt.showPassword(passwordVisible)
|
||||||
passPhrase2EditText.showPassword(passwordVisible)
|
views.exportDialogEtConfirm.showPassword(passwordVisible)
|
||||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
val exportDialog = builder.show()
|
val exportDialog = builder.show()
|
||||||
|
|
||||||
exportButton.setOnClickListener {
|
views.exportDialogSubmit.setOnClickListener {
|
||||||
exportKeyDialogListener.onPassphrase(passPhrase1EditText.text.toString())
|
exportKeyDialogListener.onPassphrase(views.exportDialogEt.text.toString())
|
||||||
|
|
||||||
exportDialog.dismiss()
|
exportDialog.dismiss()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
package im.vector.app.core.dialogs
|
package im.vector.app.core.dialogs
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogDeviceVerifyBinding
|
||||||
import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
|
import org.matrix.android.sdk.api.extensions.getFingerprintHumanReadable
|
||||||
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ object ManuallyVerifyDialog {
|
||||||
|
|
||||||
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
||||||
|
val views = DialogDeviceVerifyBinding.bind(dialogLayout)
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.cross_signing_verify_by_text)
|
.setTitle(R.string.cross_signing_verify_by_text)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
|
@ -35,17 +36,9 @@ object ManuallyVerifyDialog {
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
|
||||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_name)?.let {
|
views.encryptedDeviceInfoDeviceName.text = cryptoDeviceInfo.displayName()
|
||||||
it.text = cryptoDeviceInfo.displayName()
|
views.encryptedDeviceInfoDeviceId.text = cryptoDeviceInfo.deviceId
|
||||||
}
|
views.encryptedDeviceInfoDeviceKey.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
||||||
|
|
||||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_id)?.let {
|
|
||||||
it.text = cryptoDeviceInfo.deviceId
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_key)?.let {
|
|
||||||
it.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.show()
|
builder.show()
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.extensions.showPassword
|
import im.vector.app.core.extensions.showPassword
|
||||||
import im.vector.app.core.platform.SimpleTextWatcher
|
import im.vector.app.core.platform.SimpleTextWatcher
|
||||||
|
import im.vector.app.databinding.DialogPromptPasswordBinding
|
||||||
|
|
||||||
class PromptPasswordDialog {
|
class PromptPasswordDialog {
|
||||||
|
|
||||||
|
@ -35,20 +36,18 @@ class PromptPasswordDialog {
|
||||||
|
|
||||||
fun show(activity: Activity, listener: (String) -> Unit) {
|
fun show(activity: Activity, listener: (String) -> Unit) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
||||||
|
val views = DialogPromptPasswordBinding.bind(dialogLayout)
|
||||||
val passwordTil = dialogLayout.findViewById<TextInputLayout>(R.id.promptPasswordTil)
|
|
||||||
val passwordEditText = dialogLayout.findViewById<TextInputEditText>(R.id.promptPassword)
|
|
||||||
val textWatcher = object : SimpleTextWatcher() {
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
passwordTil.error = null
|
views.promptPasswordTil.error = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
passwordEditText.addTextChangedListener(textWatcher)
|
views.promptPassword.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal)
|
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal)
|
||||||
showPassword.setOnClickListener {
|
showPassword.setOnClickListener {
|
||||||
passwordVisible = !passwordVisible
|
passwordVisible = !passwordVisible
|
||||||
passwordEditText.showPassword(passwordVisible)
|
views.promptPassword.showPassword(passwordVisible)
|
||||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,10 +72,10 @@ class PromptPasswordDialog {
|
||||||
setOnShowListener {
|
setOnShowListener {
|
||||||
getButton(AlertDialog.BUTTON_POSITIVE)
|
getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
if (passwordEditText.text.toString().isEmpty()) {
|
if (views.promptPassword.text.toString().isEmpty()) {
|
||||||
passwordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
views.promptPasswordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||||
} else {
|
} else {
|
||||||
listener.invoke(passwordEditText.text.toString())
|
listener.invoke(views.promptPassword.text.toString())
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogRecoveryKeySavedInfoBinding
|
||||||
import me.gujun.android.span.image
|
import me.gujun.android.span.image
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
|
|
||||||
|
@ -30,10 +31,9 @@ class KeepItSafeDialog {
|
||||||
|
|
||||||
fun show(activity: Activity) {
|
fun show(activity: Activity) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_recovery_key_saved_info, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_recovery_key_saved_info, null)
|
||||||
|
val views = DialogRecoveryKeySavedInfoBinding.bind(dialogLayout)
|
||||||
|
|
||||||
val descriptionText = dialogLayout.findViewById<TextView>(R.id.keepItSafeText)
|
views.keepItSafeText.text = span {
|
||||||
|
|
||||||
descriptionText.text = span {
|
|
||||||
span {
|
span {
|
||||||
image(ContextCompat.getDrawable(activity, R.drawable.ic_check_on)!!)
|
image(ContextCompat.getDrawable(activity, R.drawable.ic_check_on)!!)
|
||||||
+" "
|
+" "
|
||||||
|
|
|
@ -35,6 +35,7 @@ import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
@ -113,6 +114,7 @@ import im.vector.app.core.utils.saveMedia
|
||||||
import im.vector.app.core.utils.shareMedia
|
import im.vector.app.core.utils.shareMedia
|
||||||
import im.vector.app.core.utils.shareText
|
import im.vector.app.core.utils.shareText
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
import im.vector.app.databinding.FragmentRoomDetailBinding
|
||||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView
|
import im.vector.app.features.attachments.AttachmentTypeSelectorView
|
||||||
import im.vector.app.features.attachments.AttachmentsHelper
|
import im.vector.app.features.attachments.AttachmentsHelper
|
||||||
import im.vector.app.features.attachments.ContactAttachment
|
import im.vector.app.features.attachments.ContactAttachment
|
||||||
|
@ -232,7 +234,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
|
||||||
private val pillsPostProcessorFactory: PillsPostProcessor.Factory
|
private val pillsPostProcessorFactory: PillsPostProcessor.Factory
|
||||||
) :
|
) :
|
||||||
VectorBaseFragment(),
|
VectorBaseFragment<FragmentRoomDetailBinding>(),
|
||||||
TimelineEventController.Callback,
|
TimelineEventController.Callback,
|
||||||
VectorInviteView.Callback,
|
VectorInviteView.Callback,
|
||||||
JumpToReadMarkerView.Callback,
|
JumpToReadMarkerView.Callback,
|
||||||
|
@ -278,7 +280,9 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
||||||
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback
|
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_room_detail
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomDetailBinding {
|
||||||
|
return FragmentRoomDetailBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getMenuRes() = R.menu.menu_timeline
|
override fun getMenuRes() = R.menu.menu_timeline
|
||||||
|
|
||||||
|
@ -303,7 +307,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
sharedCallActionViewModel = activityViewModelProvider.get(SharedActiveCallViewModel::class.java)
|
sharedCallActionViewModel = activityViewModelProvider.get(SharedActiveCallViewModel::class.java)
|
||||||
attachmentsHelper = AttachmentsHelper(requireContext(), this).register()
|
attachmentsHelper = AttachmentsHelper(requireContext(), this).register()
|
||||||
keyboardStateUtils = KeyboardStateUtils(requireActivity())
|
keyboardStateUtils = KeyboardStateUtils(requireActivity())
|
||||||
setupToolbar(roomToolbar)
|
setupToolbar(views.roomToolbar)
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
setupComposer()
|
setupComposer()
|
||||||
setupInviteView()
|
setupInviteView()
|
||||||
|
@ -314,7 +318,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
setupConfBannerView()
|
setupConfBannerView()
|
||||||
setupEmojiPopup()
|
setupEmojiPopup()
|
||||||
|
|
||||||
roomToolbarContentView.debouncedClicks {
|
views.roomToolbarContentView.debouncedClicks {
|
||||||
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
navigator.openRoomProfile(requireActivity(), roomDetailArgs.roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +353,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
roomDetailViewModel.selectSubscribe(RoomDetailViewState::syncState) { syncState ->
|
roomDetailViewModel.selectSubscribe(RoomDetailViewState::syncState) { syncState ->
|
||||||
syncStateView.render(syncState)
|
views.syncStateView.render(syncState)
|
||||||
}
|
}
|
||||||
|
|
||||||
roomDetailViewModel.observeViewEvents {
|
roomDetailViewModel.observeViewEvents {
|
||||||
|
@ -396,8 +400,8 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private fun handleChatEffect(chatEffect: ChatEffect) {
|
private fun handleChatEffect(chatEffect: ChatEffect) {
|
||||||
when (chatEffect) {
|
when (chatEffect) {
|
||||||
ChatEffect.CONFETTI -> {
|
ChatEffect.CONFETTI -> {
|
||||||
viewKonfetti.isVisible = true
|
views.viewKonfetti.isVisible = true
|
||||||
viewKonfetti.build()
|
views.viewKonfetti.build()
|
||||||
.addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
|
.addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
|
||||||
.setDirection(0.0, 359.0)
|
.setDirection(0.0, 359.0)
|
||||||
.setSpeed(2f, 5f)
|
.setSpeed(2f, 5f)
|
||||||
|
@ -405,20 +409,20 @@ class RoomDetailFragment @Inject constructor(
|
||||||
.setTimeToLive(2000L)
|
.setTimeToLive(2000L)
|
||||||
.addShapes(Shape.Square, Shape.Circle)
|
.addShapes(Shape.Square, Shape.Circle)
|
||||||
.addSizes(Size(12))
|
.addSizes(Size(12))
|
||||||
.setPosition(-50f, viewKonfetti.width + 50f, -50f, -50f)
|
.setPosition(-50f, views.viewKonfetti.width + 50f, -50f, -50f)
|
||||||
.streamFor(150, 3000L)
|
.streamFor(150, 3000L)
|
||||||
}
|
}
|
||||||
ChatEffect.SNOW -> {
|
ChatEffect.SNOW -> {
|
||||||
viewSnowFall.isVisible = true
|
views.viewSnowFall.isVisible = true
|
||||||
viewSnowFall.restartFalling()
|
views.viewSnowFall.restartFalling()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun handleStopChatEffects() {
|
private fun handleStopChatEffects() {
|
||||||
TransitionManager.beginDelayedTransition(rootConstraintLayout)
|
TransitionManager.beginDelayedTransition(views.rootConstraintLayout)
|
||||||
viewSnowFall.isVisible = false
|
views.viewSnowFall.isVisible = false
|
||||||
// when gone the effect is a bit buggy
|
// when gone the effect is a bit buggy
|
||||||
viewKonfetti.isInvisible = true
|
views.viewKonfetti.isInvisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onImageReady(uri: Uri?) {
|
override fun onImageReady(uri: Uri?) {
|
||||||
|
@ -486,7 +490,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupConfBannerView() {
|
private fun setupConfBannerView() {
|
||||||
activeConferenceView.callback = object : ActiveConferenceView.Callback {
|
views.activeConferenceView.callback = object : ActiveConferenceView.Callback {
|
||||||
override fun onTapJoinAudio(jitsiWidget: Widget) {
|
override fun onTapJoinAudio(jitsiWidget: Widget) {
|
||||||
// need to check if allowed first
|
// need to check if allowed first
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(
|
roomDetailViewModel.handle(RoomDetailAction.EnsureNativeWidgetAllowed(
|
||||||
|
@ -513,13 +517,13 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private fun setupEmojiPopup() {
|
private fun setupEmojiPopup() {
|
||||||
val emojiPopup = EmojiPopup
|
val emojiPopup = EmojiPopup
|
||||||
.Builder
|
.Builder
|
||||||
.fromRootView(rootConstraintLayout)
|
.fromRootView(views.rootConstraintLayout)
|
||||||
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
|
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
|
||||||
.setOnEmojiPopupShownListener { composerLayout?.composerEmojiButton?.setImageResource(R.drawable.ic_keyboard) }
|
.setOnEmojiPopupShownListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_keyboard) }
|
||||||
.setOnEmojiPopupDismissListener { composerLayout?.composerEmojiButton?.setImageResource(R.drawable.ic_insert_emoji) }
|
.setOnEmojiPopupDismissListener { views.composerLayout.views.composerEmojiButton.setImageResource(R.drawable.ic_insert_emoji) }
|
||||||
.build(composerLayout.composerEditText)
|
.build(views.composerLayout.views.composerEditText)
|
||||||
|
|
||||||
composerLayout.composerEmojiButton.debouncedClicks {
|
views.composerLayout.views.composerEmojiButton.debouncedClicks {
|
||||||
emojiPopup.toggle()
|
emojiPopup.toggle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,11 +589,11 @@ class RoomDetailFragment @Inject constructor(
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
timelineEventController.callback = null
|
timelineEventController.callback = null
|
||||||
timelineEventController.removeModelBuildListener(modelBuildListener)
|
timelineEventController.removeModelBuildListener(modelBuildListener)
|
||||||
activeCallView.callback = null
|
views.activeCallView.callback = null
|
||||||
modelBuildListener = null
|
modelBuildListener = null
|
||||||
autoCompleter.clear()
|
autoCompleter.clear()
|
||||||
debouncer.cancelAll()
|
debouncer.cancelAll()
|
||||||
timelineRecyclerView.cleanup()
|
views.timelineRecyclerView.cleanup()
|
||||||
|
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -601,10 +605,10 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupJumpToBottomView() {
|
private fun setupJumpToBottomView() {
|
||||||
jumpToBottomView.visibility = View.INVISIBLE
|
views.jumpToBottomView.visibility = View.INVISIBLE
|
||||||
jumpToBottomView.debouncedClicks {
|
views.jumpToBottomView.debouncedClicks {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
|
roomDetailViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
|
||||||
jumpToBottomView.visibility = View.INVISIBLE
|
views.jumpToBottomView.visibility = View.INVISIBLE
|
||||||
if (!roomDetailViewModel.timeline.isLive) {
|
if (!roomDetailViewModel.timeline.isLive) {
|
||||||
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
|
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
|
||||||
roomDetailViewModel.timeline.restartWithEventId(null)
|
roomDetailViewModel.timeline.restartWithEventId(null)
|
||||||
|
@ -614,22 +618,22 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
|
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
|
||||||
jumpToBottomView,
|
views.jumpToBottomView,
|
||||||
debouncer,
|
debouncer,
|
||||||
timelineRecyclerView,
|
views.timelineRecyclerView,
|
||||||
layoutManager
|
layoutManager
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupJumpToReadMarkerView() {
|
private fun setupJumpToReadMarkerView() {
|
||||||
jumpToReadMarkerView.callback = this
|
views.jumpToReadMarkerView.callback = this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupActiveCallView() {
|
private fun setupActiveCallView() {
|
||||||
activeCallViewHolder.bind(
|
activeCallViewHolder.bind(
|
||||||
activeCallPiP,
|
views.activeCallPiP,
|
||||||
activeCallView,
|
views.activeCallView,
|
||||||
activeCallPiPWrap,
|
views.activeCallPiPWrap,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -639,7 +643,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
if (scrollPosition == null) {
|
if (scrollPosition == null) {
|
||||||
scrollOnHighlightedEventCallback.scheduleScrollTo(action.eventId)
|
scrollOnHighlightedEventCallback.scheduleScrollTo(action.eventId)
|
||||||
} else {
|
} else {
|
||||||
timelineRecyclerView.stopScroll()
|
views.timelineRecyclerView.stopScroll()
|
||||||
layoutManager.scrollToPosition(scrollPosition)
|
layoutManager.scrollToPosition(scrollPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,7 +683,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNotificationView() {
|
private fun setupNotificationView() {
|
||||||
notificationAreaView.delegate = object : NotificationAreaView.Delegate {
|
views.notificationAreaView.delegate = object : NotificationAreaView.Delegate {
|
||||||
override fun onTombstoneEventClicked(tombstoneEvent: Event) {
|
override fun onTombstoneEventClicked(tombstoneEvent: Event) {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.HandleTombstoneEvent(tombstoneEvent))
|
roomDetailViewModel.handle(RoomDetailAction.HandleTombstoneEvent(tombstoneEvent))
|
||||||
}
|
}
|
||||||
|
@ -906,10 +910,10 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
private fun renderRegularMode(text: String) {
|
private fun renderRegularMode(text: String) {
|
||||||
autoCompleter.exitSpecialMode()
|
autoCompleter.exitSpecialMode()
|
||||||
composerLayout.collapse()
|
views.composerLayout.collapse()
|
||||||
|
|
||||||
updateComposerText(text)
|
updateComposerText(text)
|
||||||
composerLayout.sendButton.contentDescription = getString(R.string.send)
|
views.composerLayout.views.sendButton.contentDescription = getString(R.string.send)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderSpecialMode(event: TimelineEvent,
|
private fun renderSpecialMode(event: TimelineEvent,
|
||||||
|
@ -918,7 +922,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
defaultContent: String) {
|
defaultContent: String) {
|
||||||
autoCompleter.enterSpecialMode()
|
autoCompleter.enterSpecialMode()
|
||||||
// switch to expanded bar
|
// switch to expanded bar
|
||||||
composerLayout.composerRelatedMessageTitle.apply {
|
views.composerLayout.views.composerRelatedMessageTitle.apply {
|
||||||
text = event.senderInfo.disambiguatedDisplayName
|
text = event.senderInfo.disambiguatedDisplayName
|
||||||
setTextColor(matrixItemColorProvider.getColor(MatrixItem.UserItem(event.root.senderId ?: "@")))
|
setTextColor(matrixItemColorProvider.getColor(MatrixItem.UserItem(event.root.senderId ?: "@")))
|
||||||
}
|
}
|
||||||
|
@ -931,16 +935,16 @@ class RoomDetailFragment @Inject constructor(
|
||||||
val document = parser.parse(messageContent.formattedBody ?: messageContent.body)
|
val document = parser.parse(messageContent.formattedBody ?: messageContent.body)
|
||||||
formattedBody = eventHtmlRenderer.render(document, pillsPostProcessor)
|
formattedBody = eventHtmlRenderer.render(document, pillsPostProcessor)
|
||||||
}
|
}
|
||||||
composerLayout.composerRelatedMessageContent.text = (formattedBody ?: nonFormattedBody)
|
views.composerLayout.views.composerRelatedMessageContent.text = (formattedBody ?: nonFormattedBody)
|
||||||
|
|
||||||
updateComposerText(defaultContent)
|
updateComposerText(defaultContent)
|
||||||
|
|
||||||
composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes))
|
views.composerLayout.views.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes))
|
||||||
composerLayout.sendButton.contentDescription = getString(descriptionRes)
|
views.composerLayout.views.sendButton.contentDescription = getString(descriptionRes)
|
||||||
|
|
||||||
avatarRenderer.render(event.senderInfo.toMatrixItem(), composerLayout.composerRelatedMessageAvatar)
|
avatarRenderer.render(event.senderInfo.toMatrixItem(), views.composerLayout.views.composerRelatedMessageAvatar)
|
||||||
|
|
||||||
composerLayout.expand {
|
views.composerLayout.expand {
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
// need to do it here also when not using quick reply
|
// need to do it here also when not using quick reply
|
||||||
focusComposerAndShowKeyboard()
|
focusComposerAndShowKeyboard()
|
||||||
|
@ -951,11 +955,10 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
private fun updateComposerText(text: String) {
|
private fun updateComposerText(text: String) {
|
||||||
// Do not update if this is the same text to avoid the cursor to move
|
// Do not update if this is the same text to avoid the cursor to move
|
||||||
if (text != composerLayout.composerEditText.text.toString()) {
|
if (text != views.composerLayout.text.toString()) {
|
||||||
// Ignore update to avoid saving a draft
|
// Ignore update to avoid saving a draft
|
||||||
composerLayout.composerEditText.setText(text)
|
views.composerLayout.views.composerEditText.setText(text)
|
||||||
composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text?.length
|
views.composerLayout.views.composerEditText.setSelection(views.composerLayout.text?.length ?: 0)
|
||||||
?: 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -982,7 +985,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
notificationDrawerManager.setCurrentRoom(null)
|
notificationDrawerManager.setCurrentRoom(null)
|
||||||
|
|
||||||
roomDetailViewModel.handle(RoomDetailAction.SaveDraft(composerLayout.composerEditText.text.toString()))
|
roomDetailViewModel.handle(RoomDetailAction.SaveDraft(views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val attachmentFileActivityResultLauncher = registerStartForActivityResult {
|
private val attachmentFileActivityResultLauncher = registerStartForActivityResult {
|
||||||
|
@ -1050,14 +1053,14 @@ class RoomDetailFragment @Inject constructor(
|
||||||
timelineEventController.callback = this
|
timelineEventController.callback = this
|
||||||
timelineEventController.timeline = roomDetailViewModel.timeline
|
timelineEventController.timeline = roomDetailViewModel.timeline
|
||||||
|
|
||||||
timelineRecyclerView.trackItemsVisibilityChange()
|
views.timelineRecyclerView.trackItemsVisibilityChange()
|
||||||
layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
|
layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
|
||||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||||
scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager, timelineEventController)
|
scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager, timelineEventController)
|
||||||
scrollOnHighlightedEventCallback = ScrollOnHighlightedEventCallback(timelineRecyclerView, layoutManager, timelineEventController)
|
scrollOnHighlightedEventCallback = ScrollOnHighlightedEventCallback(views.timelineRecyclerView, layoutManager, timelineEventController)
|
||||||
timelineRecyclerView.layoutManager = layoutManager
|
views.timelineRecyclerView.layoutManager = layoutManager
|
||||||
timelineRecyclerView.itemAnimator = null
|
views.timelineRecyclerView.itemAnimator = null
|
||||||
timelineRecyclerView.setHasFixedSize(true)
|
views.timelineRecyclerView.setHasFixedSize(true)
|
||||||
modelBuildListener = OnModelBuildFinishedListener {
|
modelBuildListener = OnModelBuildFinishedListener {
|
||||||
it.dispatchTo(stateRestorer)
|
it.dispatchTo(stateRestorer)
|
||||||
it.dispatchTo(scrollOnNewMessageCallback)
|
it.dispatchTo(scrollOnNewMessageCallback)
|
||||||
|
@ -1066,14 +1069,14 @@ class RoomDetailFragment @Inject constructor(
|
||||||
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
|
jumpToBottomViewVisibilityManager.maybeShowJumpToBottomViewVisibilityWithDelay()
|
||||||
}
|
}
|
||||||
timelineEventController.addModelBuildListener(modelBuildListener)
|
timelineEventController.addModelBuildListener(modelBuildListener)
|
||||||
timelineRecyclerView.adapter = timelineEventController.adapter
|
views.timelineRecyclerView.adapter = timelineEventController.adapter
|
||||||
|
|
||||||
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
||||||
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
||||||
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
|
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
|
||||||
(model as? AbsMessageItem)?.attributes?.informationData?.let {
|
(model as? AbsMessageItem)?.attributes?.informationData?.let {
|
||||||
val eventId = it.eventId
|
val eventId = it.eventId
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(eventId, composerLayout.composerEditText.text.toString()))
|
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(eventId, views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,9 +1099,9 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler)
|
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler)
|
||||||
val touchHelper = ItemTouchHelper(swipeCallback)
|
val touchHelper = ItemTouchHelper(swipeCallback)
|
||||||
touchHelper.attachToRecyclerView(timelineRecyclerView)
|
touchHelper.attachToRecyclerView(views.timelineRecyclerView)
|
||||||
}
|
}
|
||||||
timelineRecyclerView.addGlidePreloader(
|
views.timelineRecyclerView.addGlidePreloader(
|
||||||
epoxyController = timelineEventController,
|
epoxyController = timelineEventController,
|
||||||
requestManager = GlideApp.with(this),
|
requestManager = GlideApp.with(this),
|
||||||
preloader = glidePreloader { requestManager, epoxyModel: MessageImageVideoItem, _ ->
|
preloader = glidePreloader { requestManager, epoxyModel: MessageImageVideoItem, _ ->
|
||||||
|
@ -1111,7 +1114,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateJumpToReadMarkerViewVisibility() {
|
private fun updateJumpToReadMarkerViewVisibility() {
|
||||||
jumpToReadMarkerView?.post {
|
views.jumpToReadMarkerView?.post {
|
||||||
withState(roomDetailViewModel) {
|
withState(roomDetailViewModel) {
|
||||||
val showJumpToUnreadBanner = when (it.unreadState) {
|
val showJumpToUnreadBanner = when (it.unreadState) {
|
||||||
UnreadState.Unknown,
|
UnreadState.Unknown,
|
||||||
|
@ -1131,13 +1134,13 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jumpToReadMarkerView?.isVisible = showJumpToUnreadBanner
|
views.jumpToReadMarkerView?.isVisible = showJumpToUnreadBanner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComposer() {
|
private fun setupComposer() {
|
||||||
val composerEditText = composerLayout.composerEditText
|
val composerEditText = views.composerLayout.views.composerEditText
|
||||||
autoCompleter.setup(composerEditText)
|
autoCompleter.setup(composerEditText)
|
||||||
|
|
||||||
observerUserTyping()
|
observerUserTyping()
|
||||||
|
@ -1164,12 +1167,12 @@ class RoomDetailFragment @Inject constructor(
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
composerLayout.callback = object : TextComposerView.Callback {
|
views.composerLayout.callback = object : TextComposerView.Callback {
|
||||||
override fun onAddAttachment() {
|
override fun onAddAttachment() {
|
||||||
if (!::attachmentTypeSelector.isInitialized) {
|
if (!::attachmentTypeSelector.isInitialized) {
|
||||||
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@RoomDetailFragment)
|
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@RoomDetailFragment)
|
||||||
}
|
}
|
||||||
attachmentTypeSelector.show(composerLayout.attachmentButton, keyboardStateUtils.isKeyboardShowing)
|
attachmentTypeSelector.show(views.composerLayout.views.attachmentButton, keyboardStateUtils.isKeyboardShowing)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSendMessage(text: CharSequence) {
|
override fun onSendMessage(text: CharSequence) {
|
||||||
|
@ -1177,7 +1180,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCloseRelatedMessage() {
|
override fun onCloseRelatedMessage() {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnterRegularMode(composerLayout.text.toString(), false))
|
roomDetailViewModel.handle(RoomDetailAction.EnterRegularMode(views.composerLayout.text.toString(), false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||||
|
@ -1193,14 +1196,14 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
// We collapse ASAP, if not there will be a slight anoying delay
|
// We collapse ASAP, if not there will be a slight anoying delay
|
||||||
composerLayout.collapse(true)
|
views.composerLayout.collapse(true)
|
||||||
lockSendButton = true
|
lockSendButton = true
|
||||||
roomDetailViewModel.handle(RoomDetailAction.SendMessage(text, vectorPreferences.isMarkdownEnabled()))
|
roomDetailViewModel.handle(RoomDetailAction.SendMessage(text, vectorPreferences.isMarkdownEnabled()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observerUserTyping() {
|
private fun observerUserTyping() {
|
||||||
composerLayout.composerEditText.textChanges()
|
views.composerLayout.views.composerEditText.textChanges()
|
||||||
.skipInitialValue()
|
.skipInitialValue()
|
||||||
.debounce(300, TimeUnit.MILLISECONDS)
|
.debounce(300, TimeUnit.MILLISECONDS)
|
||||||
.map { it.isNotEmpty() }
|
.map { it.isNotEmpty() }
|
||||||
|
@ -1221,39 +1224,39 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupInviteView() {
|
private fun setupInviteView() {
|
||||||
inviteView.callback = this
|
views.inviteView.callback = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(roomDetailViewModel) { state ->
|
override fun invalidate() = withState(roomDetailViewModel) { state ->
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
val summary = state.asyncRoomSummary()
|
val summary = state.asyncRoomSummary()
|
||||||
renderToolbar(summary, state.typingMessage)
|
renderToolbar(summary, state.typingMessage)
|
||||||
activeConferenceView.render(state)
|
views.activeConferenceView.render(state)
|
||||||
val inviter = state.asyncInviter()
|
val inviter = state.asyncInviter()
|
||||||
if (summary?.membership == Membership.JOIN) {
|
if (summary?.membership == Membership.JOIN) {
|
||||||
jumpToBottomView.count = summary.notificationCount
|
views.jumpToBottomView.count = summary.notificationCount
|
||||||
jumpToBottomView.drawBadge = summary.hasUnreadMessages
|
views.jumpToBottomView.drawBadge = summary.hasUnreadMessages
|
||||||
scrollOnHighlightedEventCallback.timeline = roomDetailViewModel.timeline
|
scrollOnHighlightedEventCallback.timeline = roomDetailViewModel.timeline
|
||||||
timelineEventController.update(state)
|
timelineEventController.update(state)
|
||||||
inviteView.visibility = View.GONE
|
views.inviteView.visibility = View.GONE
|
||||||
if (state.tombstoneEvent == null) {
|
if (state.tombstoneEvent == null) {
|
||||||
if (state.canSendMessage) {
|
if (state.canSendMessage) {
|
||||||
composerLayout.visibility = View.VISIBLE
|
views.composerLayout.visibility = View.VISIBLE
|
||||||
composerLayout.setRoomEncrypted(summary.isEncrypted, summary.roomEncryptionTrustLevel)
|
views.composerLayout.setRoomEncrypted(summary.isEncrypted, summary.roomEncryptionTrustLevel)
|
||||||
notificationAreaView.render(NotificationAreaView.State.Hidden)
|
views.notificationAreaView.render(NotificationAreaView.State.Hidden)
|
||||||
} else {
|
} else {
|
||||||
composerLayout.visibility = View.GONE
|
views.composerLayout.visibility = View.GONE
|
||||||
notificationAreaView.render(NotificationAreaView.State.NoPermissionToPost)
|
views.notificationAreaView.render(NotificationAreaView.State.NoPermissionToPost)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
composerLayout.visibility = View.GONE
|
views.composerLayout.visibility = View.GONE
|
||||||
notificationAreaView.render(NotificationAreaView.State.Tombstone(state.tombstoneEvent))
|
views.notificationAreaView.render(NotificationAreaView.State.Tombstone(state.tombstoneEvent))
|
||||||
}
|
}
|
||||||
} else if (summary?.membership == Membership.INVITE && inviter != null) {
|
} else if (summary?.membership == Membership.INVITE && inviter != null) {
|
||||||
inviteView.visibility = View.VISIBLE
|
views.inviteView.visibility = View.VISIBLE
|
||||||
inviteView.render(inviter, VectorInviteView.Mode.LARGE, state.changeMembershipState)
|
views.inviteView.render(inviter, VectorInviteView.Mode.LARGE, state.changeMembershipState)
|
||||||
// Intercept click event
|
// Intercept click event
|
||||||
inviteView.setOnClickListener { }
|
views.inviteView.setOnClickListener { }
|
||||||
} else if (state.asyncInviter.complete) {
|
} else if (state.asyncInviter.complete) {
|
||||||
vectorBaseActivity.finish()
|
vectorBaseActivity.finish()
|
||||||
}
|
}
|
||||||
|
@ -1261,14 +1264,14 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
private fun renderToolbar(roomSummary: RoomSummary?, typingMessage: String?) {
|
private fun renderToolbar(roomSummary: RoomSummary?, typingMessage: String?) {
|
||||||
if (roomSummary == null) {
|
if (roomSummary == null) {
|
||||||
roomToolbarContentView.isClickable = false
|
views.roomToolbarContentView.isClickable = false
|
||||||
} else {
|
} else {
|
||||||
roomToolbarContentView.isClickable = roomSummary.membership == Membership.JOIN
|
views.roomToolbarContentView.isClickable = roomSummary.membership == Membership.JOIN
|
||||||
roomToolbarTitleView.text = roomSummary.displayName
|
views.roomToolbarTitleView.text = roomSummary.displayName
|
||||||
avatarRenderer.render(roomSummary.toMatrixItem(), roomToolbarAvatarImageView)
|
avatarRenderer.render(roomSummary.toMatrixItem(), views.roomToolbarAvatarImageView)
|
||||||
|
|
||||||
renderSubTitle(typingMessage, roomSummary.topic)
|
renderSubTitle(typingMessage, roomSummary.topic)
|
||||||
roomToolbarDecorationImageView.let {
|
views.roomToolbarDecorationImageView.let {
|
||||||
it.setImageResource(roomSummary.roomEncryptionTrustLevel.toImageRes())
|
it.setImageResource(roomSummary.roomEncryptionTrustLevel.toImageRes())
|
||||||
it.isVisible = roomSummary.roomEncryptionTrustLevel != null
|
it.isVisible = roomSummary.roomEncryptionTrustLevel != null
|
||||||
}
|
}
|
||||||
|
@ -1278,7 +1281,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private fun renderSubTitle(typingMessage: String?, topic: String) {
|
private fun renderSubTitle(typingMessage: String?, topic: String) {
|
||||||
// TODO Temporary place to put typing data
|
// TODO Temporary place to put typing data
|
||||||
val subtitle = typingMessage?.takeIf { it.isNotBlank() } ?: topic
|
val subtitle = typingMessage?.takeIf { it.isNotBlank() } ?: topic
|
||||||
roomToolbarSubtitleView.apply {
|
views.roomToolbarSubtitleView.apply {
|
||||||
setTextOrHide(subtitle)
|
setTextOrHide(subtitle)
|
||||||
if (typingMessage.isNullOrBlank()) {
|
if (typingMessage.isNullOrBlank()) {
|
||||||
setTextColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_toolbar_secondary_text_color))
|
setTextColor(ThemeUtils.getColor(requireContext(), R.attr.vctr_toolbar_secondary_text_color))
|
||||||
|
@ -1294,9 +1297,11 @@ class RoomDetailFragment @Inject constructor(
|
||||||
when (async) {
|
when (async) {
|
||||||
is Loading -> {
|
is Loading -> {
|
||||||
// TODO Better handling progress
|
// TODO Better handling progress
|
||||||
|
/* TODO BMA Yes, improve that
|
||||||
vectorBaseActivity.showWaitingView()
|
vectorBaseActivity.showWaitingView()
|
||||||
vectorBaseActivity.waitingStatusText.visibility = View.VISIBLE
|
vectorBaseActivity.waitingStatusText.visibility = View.VISIBLE
|
||||||
vectorBaseActivity.waitingStatusText.text = getString(R.string.joining_room)
|
vectorBaseActivity.waitingStatusText.text = getString(R.string.joining_room)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
navigator.openRoom(vectorBaseActivity, async())
|
navigator.openRoom(vectorBaseActivity, async())
|
||||||
|
@ -1544,8 +1549,8 @@ class RoomDetailFragment @Inject constructor(
|
||||||
mediaData = mediaData,
|
mediaData = mediaData,
|
||||||
view = view
|
view = view
|
||||||
) { pairs ->
|
) { pairs ->
|
||||||
pairs.add(Pair(roomToolbar, ViewCompat.getTransitionName(roomToolbar) ?: ""))
|
pairs.add(Pair(views.roomToolbar, ViewCompat.getTransitionName(views.roomToolbar) ?: ""))
|
||||||
pairs.add(Pair(composerLayout, ViewCompat.getTransitionName(composerLayout) ?: ""))
|
pairs.add(Pair(views.composerLayout, ViewCompat.getTransitionName(views.composerLayout) ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1556,8 +1561,8 @@ class RoomDetailFragment @Inject constructor(
|
||||||
mediaData = mediaData,
|
mediaData = mediaData,
|
||||||
view = view
|
view = view
|
||||||
) { pairs ->
|
) { pairs ->
|
||||||
pairs.add(Pair(roomToolbar, ViewCompat.getTransitionName(roomToolbar) ?: ""))
|
pairs.add(Pair(views.roomToolbar, ViewCompat.getTransitionName(views.roomToolbar) ?: ""))
|
||||||
pairs.add(Pair(composerLayout, ViewCompat.getTransitionName(composerLayout) ?: ""))
|
pairs.add(Pair(views.composerLayout, ViewCompat.getTransitionName(views.composerLayout) ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,13 +1790,13 @@ class RoomDetailFragment @Inject constructor(
|
||||||
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
||||||
}
|
}
|
||||||
is EventSharedAction.Edit -> {
|
is EventSharedAction.Edit -> {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnterEditMode(action.eventId, composerLayout.text.toString()))
|
roomDetailViewModel.handle(RoomDetailAction.EnterEditMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
is EventSharedAction.Quote -> {
|
is EventSharedAction.Quote -> {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnterQuoteMode(action.eventId, composerLayout.text.toString()))
|
roomDetailViewModel.handle(RoomDetailAction.EnterQuoteMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
is EventSharedAction.Reply -> {
|
is EventSharedAction.Reply -> {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(action.eventId, composerLayout.text.toString()))
|
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
is EventSharedAction.CopyPermalink -> {
|
is EventSharedAction.CopyPermalink -> {
|
||||||
val permalink = session.permalinkService().createPermalink(roomDetailArgs.roomId, action.eventId)
|
val permalink = session.permalinkService().createPermalink(roomDetailArgs.roomId, action.eventId)
|
||||||
|
@ -1857,13 +1862,13 @@ class RoomDetailFragment @Inject constructor(
|
||||||
*/
|
*/
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun insertUserDisplayNameInTextEditor(userId: String) {
|
private fun insertUserDisplayNameInTextEditor(userId: String) {
|
||||||
val startToCompose = composerLayout.composerEditText.text.isNullOrBlank()
|
val startToCompose = views.composerLayout.text.isNullOrBlank()
|
||||||
|
|
||||||
if (startToCompose
|
if (startToCompose
|
||||||
&& userId == session.myUserId) {
|
&& userId == session.myUserId) {
|
||||||
// Empty composer, current user: start an emote
|
// Empty composer, current user: start an emote
|
||||||
composerLayout.composerEditText.setText(Command.EMOTE.command + " ")
|
views.composerLayout.views.composerEditText.setText(Command.EMOTE.command + " ")
|
||||||
composerLayout.composerEditText.setSelection(Command.EMOTE.length)
|
views.composerLayout.views.composerEditText.setSelection(Command.EMOTE.length)
|
||||||
} else {
|
} else {
|
||||||
val roomMember = roomDetailViewModel.getMember(userId)
|
val roomMember = roomDetailViewModel.getMember(userId)
|
||||||
// TODO move logic outside of fragment
|
// TODO move logic outside of fragment
|
||||||
|
@ -1879,7 +1884,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
MatrixItem.UserItem(userId, displayName, roomMember?.avatarUrl)
|
MatrixItem.UserItem(userId, displayName, roomMember?.avatarUrl)
|
||||||
)
|
)
|
||||||
.also { it.bind(composerLayout.composerEditText) },
|
.also { it.bind(views.composerLayout.views.composerEditText) },
|
||||||
0,
|
0,
|
||||||
displayName.length,
|
displayName.length,
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
@ -1889,11 +1894,11 @@ class RoomDetailFragment @Inject constructor(
|
||||||
if (startToCompose) {
|
if (startToCompose) {
|
||||||
if (displayName.startsWith("/")) {
|
if (displayName.startsWith("/")) {
|
||||||
// Ensure displayName will not be interpreted as a Slash command
|
// Ensure displayName will not be interpreted as a Slash command
|
||||||
composerLayout.composerEditText.append("\\")
|
views.composerLayout.views.composerEditText.append("\\")
|
||||||
}
|
}
|
||||||
composerLayout.composerEditText.append(pill)
|
views.composerLayout.views.composerEditText.append(pill)
|
||||||
} else {
|
} else {
|
||||||
composerLayout.composerEditText.text?.insert(composerLayout.composerEditText.selectionStart, pill)
|
views.composerLayout.views.composerEditText.text?.insert(views.composerLayout.views.composerEditText.selectionStart, pill)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1902,8 +1907,8 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun focusComposerAndShowKeyboard() {
|
private fun focusComposerAndShowKeyboard() {
|
||||||
if (composerLayout.isVisible) {
|
if (views.composerLayout.isVisible) {
|
||||||
composerLayout.composerEditText.showKeyboard(andRequestFocus = true)
|
views.composerLayout.views.composerEditText.showKeyboard(andRequestFocus = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1933,7 +1938,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
// JumpToReadMarkerView.Callback
|
// JumpToReadMarkerView.Callback
|
||||||
|
|
||||||
override fun onJumpToReadMarkerClicked() = withState(roomDetailViewModel) {
|
override fun onJumpToReadMarkerClicked() = withState(roomDetailViewModel) {
|
||||||
jumpToReadMarkerView.isVisible = false
|
views.jumpToReadMarkerView.isVisible = false
|
||||||
if (it.unreadState is UnreadState.HasUnread) {
|
if (it.unreadState is UnreadState.HasUnread) {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.firstUnreadEventId, false))
|
roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(it.unreadState.firstUnreadEventId, false))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,12 @@ import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintSet
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
import androidx.core.text.toSpannable
|
import androidx.core.text.toSpannable
|
||||||
|
@ -31,6 +36,7 @@ import androidx.transition.Transition
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
import androidx.transition.TransitionSet
|
import androidx.transition.TransitionSet
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ComposerLayoutBinding
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||||
|
|
||||||
|
@ -38,7 +44,9 @@ import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||||
* Encapsulate the timeline composer UX.
|
* Encapsulate the timeline composer UX.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class TextComposerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
class TextComposerView @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
|
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
interface Callback : ComposerEditText.Callback {
|
interface Callback : ComposerEditText.Callback {
|
||||||
|
@ -47,6 +55,8 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||||
fun onAddAttachment()
|
fun onAddAttachment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val views: ComposerLayoutBinding
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
|
||||||
private var currentConstraintSetId: Int = -1
|
private var currentConstraintSetId: Int = -1
|
||||||
|
@ -54,27 +64,30 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||||
private val animationDuration = 100L
|
private val animationDuration = 100L
|
||||||
|
|
||||||
val text: Editable?
|
val text: Editable?
|
||||||
get() = composerEditText.text
|
get() = views.composerEditText.text
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.composer_layout, this)
|
inflate(context, R.layout.composer_layout, this)
|
||||||
|
views = ComposerLayoutBinding.bind(this)
|
||||||
|
|
||||||
collapse(false)
|
collapse(false)
|
||||||
composerEditText.callback = object : ComposerEditText.Callback {
|
|
||||||
|
views.composerEditText.callback = object : ComposerEditText.Callback {
|
||||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||||
return callback?.onRichContentSelected(contentUri) ?: false
|
return callback?.onRichContentSelected(contentUri) ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composerRelatedMessageCloseButton.setOnClickListener {
|
views.composerRelatedMessageCloseButton.setOnClickListener {
|
||||||
collapse()
|
collapse()
|
||||||
callback?.onCloseRelatedMessage()
|
callback?.onCloseRelatedMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
sendButton.setOnClickListener {
|
views.sendButton.setOnClickListener {
|
||||||
val textMessage = text?.toSpannable() ?: ""
|
val textMessage = text?.toSpannable() ?: ""
|
||||||
callback?.onSendMessage(textMessage)
|
callback?.onSendMessage(textMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentButton.setOnClickListener {
|
views.attachmentButton.setOnClickListener {
|
||||||
callback?.onAddAttachment()
|
callback?.onAddAttachment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +117,7 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||||
ConstraintSet().also {
|
ConstraintSet().also {
|
||||||
it.clone(context, currentConstraintSetId)
|
it.clone(context, currentConstraintSetId)
|
||||||
// in case shield is hidden, we will have glitch without this
|
// in case shield is hidden, we will have glitch without this
|
||||||
it.getConstraint(R.id.composerShieldImageView).propertySet.visibility = composerShieldImageView.visibility
|
it.getConstraint(R.id.composerShieldImageView).propertySet.visibility = views.composerShieldImageView.visibility
|
||||||
it.applyTo(this)
|
it.applyTo(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,17 +147,17 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||||
|
|
||||||
fun setRoomEncrypted(isEncrypted: Boolean, roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
|
fun setRoomEncrypted(isEncrypted: Boolean, roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
|
||||||
if (isEncrypted) {
|
if (isEncrypted) {
|
||||||
composerEditText.setHint(R.string.room_message_placeholder)
|
views.composerEditText.setHint(R.string.room_message_placeholder)
|
||||||
composerShieldImageView.isVisible = true
|
views.composerShieldImageView.isVisible = true
|
||||||
val shieldRes = when (roomEncryptionTrustLevel) {
|
val shieldRes = when (roomEncryptionTrustLevel) {
|
||||||
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
|
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
|
||||||
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
||||||
else -> R.drawable.ic_shield_black
|
else -> R.drawable.ic_shield_black
|
||||||
}
|
}
|
||||||
composerShieldImageView.setImageResource(shieldRes)
|
views.composerShieldImageView.setImageResource(shieldRes)
|
||||||
} else {
|
} else {
|
||||||
composerEditText.setHint(R.string.room_message_placeholder)
|
views.composerEditText.setHint(R.string.room_message_placeholder)
|
||||||
composerShieldImageView.isVisible = false
|
views.composerShieldImageView.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
|
@ -43,6 +45,7 @@ import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.StateView
|
import im.vector.app.core.platform.StateView
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
|
import im.vector.app.databinding.DialogShareQrCodeBinding
|
||||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||||
|
@ -72,6 +75,14 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
) : VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
) : VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||||
RoomMemberProfileController.Callback {
|
RoomMemberProfileController.Callback {
|
||||||
|
|
||||||
|
private lateinit var memberProfileStateView: StateView
|
||||||
|
private lateinit var memberProfileInfoContainer: View
|
||||||
|
private lateinit var memberProfileDecorationImageView: ImageView
|
||||||
|
private lateinit var memberProfileAvatarView: ImageView
|
||||||
|
private lateinit var memberProfileNameView: TextView
|
||||||
|
private lateinit var memberProfileIdView: TextView
|
||||||
|
private lateinit var memberProfilePowerLevelView: TextView
|
||||||
|
|
||||||
private val fragmentArgs: RoomMemberProfileArgs by args()
|
private val fragmentArgs: RoomMemberProfileArgs by args()
|
||||||
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
private val viewModel: RoomMemberProfileViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
@ -85,27 +96,28 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupToolbar(matrixProfileToolbar)
|
setupToolbar(views.matrixProfileToolbar)
|
||||||
val headerView = matrixProfileHeaderView.let {
|
val headerView = views.matrixProfileHeaderView.let {
|
||||||
it.layoutResource = R.layout.view_stub_room_member_profile_header
|
it.layoutResource = R.layout.view_stub_room_member_profile_header
|
||||||
it.inflate()
|
it.inflate()
|
||||||
}
|
}
|
||||||
|
findHeaderSubViews(headerView)
|
||||||
memberProfileStateView.eventCallback = object : StateView.EventCallback {
|
memberProfileStateView.eventCallback = object : StateView.EventCallback {
|
||||||
override fun onRetryClicked() {
|
override fun onRetryClicked() {
|
||||||
viewModel.handle(RoomMemberProfileAction.RetryFetchingInfo)
|
viewModel.handle(RoomMemberProfileAction.RetryFetchingInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memberProfileStateView.contentView = memberProfileInfoContainer
|
memberProfileStateView.contentView = memberProfileInfoContainer
|
||||||
matrixProfileRecyclerView.configureWith(roomMemberProfileController, hasFixedSize = true, disableItemAnimation = true)
|
views.matrixProfileRecyclerView.configureWith(roomMemberProfileController, hasFixedSize = true, disableItemAnimation = true)
|
||||||
roomMemberProfileController.callback = this
|
roomMemberProfileController.callback = this
|
||||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(headerView,
|
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(headerView,
|
||||||
listOf(
|
listOf(
|
||||||
matrixProfileToolbarAvatarImageView,
|
views.matrixProfileToolbarAvatarImageView,
|
||||||
matrixProfileToolbarTitleView,
|
views.matrixProfileToolbarTitleView,
|
||||||
matrixProfileDecorationToolbarAvatarImageView
|
views.matrixProfileDecorationToolbarAvatarImageView
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
views.matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is RoomMemberProfileViewEvents.Loading -> showLoading(it.message)
|
is RoomMemberProfileViewEvents.Loading -> showLoading(it.message)
|
||||||
|
@ -124,6 +136,16 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
setupLongClicks()
|
setupLongClicks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findHeaderSubViews(headerView: View) {
|
||||||
|
memberProfileStateView = headerView.findViewById(R.id.memberProfileStateView)
|
||||||
|
memberProfileInfoContainer = headerView.findViewById(R.id.memberProfileInfoContainer)
|
||||||
|
memberProfileNameView = headerView.findViewById(R.id.roomProfileNameView)
|
||||||
|
memberProfileIdView = headerView.findViewById(R.id.memberProfileIdView)
|
||||||
|
memberProfileAvatarView = headerView.findViewById(R.id.roomProfileAvatarView)
|
||||||
|
memberProfilePowerLevelView = headerView.findViewById(R.id.memberProfilePowerLevelView)
|
||||||
|
memberProfileDecorationImageView = headerView.findViewById(R.id.roomProfileDecorationImageView)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupLongClicks() {
|
private fun setupLongClicks() {
|
||||||
memberProfileNameView.copyOnLongClick()
|
memberProfileNameView.copyOnLongClick()
|
||||||
memberProfileIdView.copyOnLongClick()
|
memberProfileIdView.copyOnLongClick()
|
||||||
|
@ -171,23 +193,23 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
views.matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
roomMemberProfileController.callback = null
|
roomMemberProfileController.callback = null
|
||||||
appBarStateChangeListener = null
|
appBarStateChangeListener = null
|
||||||
matrixProfileRecyclerView.cleanup()
|
views.matrixProfileRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
when (val asyncUserMatrixItem = state.userMatrixItem) {
|
when (val asyncUserMatrixItem = state.userMatrixItem) {
|
||||||
is Incomplete -> {
|
is Incomplete -> {
|
||||||
matrixProfileToolbarTitleView.text = state.userId
|
views.matrixProfileToolbarTitleView.text = state.userId
|
||||||
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), matrixProfileToolbarAvatarImageView)
|
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), views.matrixProfileToolbarAvatarImageView)
|
||||||
memberProfileStateView.state = StateView.State.Loading
|
memberProfileStateView.state = StateView.State.Loading
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), matrixProfileToolbarAvatarImageView)
|
avatarRenderer.render(MatrixItem.UserItem(state.userId, null, null), views.matrixProfileToolbarAvatarImageView)
|
||||||
matrixProfileToolbarTitleView.text = state.userId
|
views.matrixProfileToolbarTitleView.text = state.userId
|
||||||
val failureMessage = errorFormatter.toHumanReadable(asyncUserMatrixItem.error)
|
val failureMessage = errorFormatter.toHumanReadable(asyncUserMatrixItem.error)
|
||||||
memberProfileStateView.state = StateView.State.Error(failureMessage)
|
memberProfileStateView.state = StateView.State.Error(failureMessage)
|
||||||
}
|
}
|
||||||
|
@ -197,9 +219,9 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
memberProfileIdView.text = userMatrixItem.id
|
memberProfileIdView.text = userMatrixItem.id
|
||||||
val bestName = userMatrixItem.getBestName()
|
val bestName = userMatrixItem.getBestName()
|
||||||
memberProfileNameView.text = bestName
|
memberProfileNameView.text = bestName
|
||||||
matrixProfileToolbarTitleView.text = bestName
|
views.matrixProfileToolbarTitleView.text = bestName
|
||||||
avatarRenderer.render(userMatrixItem, memberProfileAvatarView)
|
avatarRenderer.render(userMatrixItem, memberProfileAvatarView)
|
||||||
avatarRenderer.render(userMatrixItem, matrixProfileToolbarAvatarImageView)
|
avatarRenderer.render(userMatrixItem, views.matrixProfileToolbarAvatarImageView)
|
||||||
|
|
||||||
if (state.isRoomEncrypted) {
|
if (state.isRoomEncrypted) {
|
||||||
memberProfileDecorationImageView.isVisible = true
|
memberProfileDecorationImageView.isVisible = true
|
||||||
|
@ -217,15 +239,15 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
memberProfileDecorationImageView.setImageResource(icon)
|
memberProfileDecorationImageView.setImageResource(icon)
|
||||||
matrixProfileDecorationToolbarAvatarImageView.setImageResource(icon)
|
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(icon)
|
||||||
} else {
|
} else {
|
||||||
// Legacy
|
// Legacy
|
||||||
if (state.allDevicesAreTrusted) {
|
if (state.allDevicesAreTrusted) {
|
||||||
memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_trusted)
|
memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_trusted)
|
||||||
matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_trusted)
|
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_trusted)
|
||||||
} else {
|
} else {
|
||||||
memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_warning)
|
memberProfileDecorationImageView.setImageResource(R.drawable.ic_shield_warning)
|
||||||
matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_warning)
|
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(R.drawable.ic_shield_warning)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -235,7 +257,7 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
memberProfileAvatarView.setOnClickListener { view ->
|
memberProfileAvatarView.setOnClickListener { view ->
|
||||||
onAvatarClicked(view, userMatrixItem)
|
onAvatarClicked(view, userMatrixItem)
|
||||||
}
|
}
|
||||||
matrixProfileToolbarAvatarImageView.setOnClickListener { view ->
|
views.matrixProfileToolbarAvatarImageView.setOnClickListener { view ->
|
||||||
onAvatarClicked(view, userMatrixItem)
|
onAvatarClicked(view, userMatrixItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,8 +324,8 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
|
|
||||||
private fun handleShareRoomMemberProfile(permalink: String) {
|
private fun handleShareRoomMemberProfile(permalink: String) {
|
||||||
val view = layoutInflater.inflate(R.layout.dialog_share_qr_code, null)
|
val view = layoutInflater.inflate(R.layout.dialog_share_qr_code, null)
|
||||||
val qrCode = view.findViewById<im.vector.app.core.ui.views.QrCodeImageView>(R.id.itemShareQrCodeImage)
|
val views = DialogShareQrCodeBinding.bind(view)
|
||||||
qrCode.setData(permalink)
|
views.itemShareQrCodeImage.setData(permalink)
|
||||||
AlertDialog.Builder(requireContext())
|
AlertDialog.Builder(requireContext())
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.setNeutralButton(R.string.ok, null)
|
.setNeutralButton(R.string.ok, null)
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
|
import im.vector.app.databinding.DialogEditPowerLevelBinding
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||||
|
|
||||||
|
@ -30,28 +31,29 @@ object EditPowerLevelDialogs {
|
||||||
|
|
||||||
fun showChoice(activity: Activity, currentRole: Role, listener: (Int) -> Unit) {
|
fun showChoice(activity: Activity, currentRole: Role, listener: (Int) -> Unit) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_edit_power_level, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_edit_power_level, null)
|
||||||
dialogLayout.powerLevelRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
val views = DialogEditPowerLevelBinding.bind(dialogLayout)
|
||||||
dialogLayout.powerLevelCustomEditLayout.isVisible = checkedId == R.id.powerLevelCustomRadio
|
views.powerLevelRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||||
|
views.powerLevelCustomEditLayout.isVisible = checkedId == R.id.powerLevelCustomRadio
|
||||||
}
|
}
|
||||||
dialogLayout.powerLevelCustomEdit.setText(currentRole.value.toString())
|
views.powerLevelCustomEdit.setText(currentRole.value.toString())
|
||||||
|
|
||||||
when (currentRole) {
|
when (currentRole) {
|
||||||
Role.Admin -> dialogLayout.powerLevelAdminRadio.isChecked = true
|
Role.Admin -> views.powerLevelAdminRadio.isChecked = true
|
||||||
Role.Moderator -> dialogLayout.powerLevelModeratorRadio.isChecked = true
|
Role.Moderator -> views.powerLevelModeratorRadio.isChecked = true
|
||||||
Role.Default -> dialogLayout.powerLevelDefaultRadio.isChecked = true
|
Role.Default -> views.powerLevelDefaultRadio.isChecked = true
|
||||||
else -> dialogLayout.powerLevelCustomRadio.isChecked = true
|
else -> views.powerLevelCustomRadio.isChecked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.power_level_edit_title)
|
.setTitle(R.string.power_level_edit_title)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
.setPositiveButton(R.string.edit) { _, _ ->
|
.setPositiveButton(R.string.edit) { _, _ ->
|
||||||
val newValue = when (dialogLayout.powerLevelRadioGroup.checkedRadioButtonId) {
|
val newValue = when (views.powerLevelRadioGroup.checkedRadioButtonId) {
|
||||||
R.id.powerLevelAdminRadio -> Role.Admin.value
|
R.id.powerLevelAdminRadio -> Role.Admin.value
|
||||||
R.id.powerLevelModeratorRadio -> Role.Moderator.value
|
R.id.powerLevelModeratorRadio -> Role.Moderator.value
|
||||||
R.id.powerLevelDefaultRadio -> Role.Default.value
|
R.id.powerLevelDefaultRadio -> Role.Default.value
|
||||||
else -> {
|
else -> {
|
||||||
dialogLayout.powerLevelCustomEdit.text?.toString()?.toInt() ?: currentRole.value
|
views.powerLevelCustomEdit.text?.toString()?.toInt() ?: currentRole.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listener(newValue)
|
listener(newValue)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.core.extensions.addFragment
|
||||||
import im.vector.app.core.extensions.addFragmentToBackstack
|
import im.vector.app.core.extensions.addFragmentToBackstack
|
||||||
import im.vector.app.core.platform.ToolbarConfigurable
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||||
import im.vector.app.features.room.RequireActiveMembershipViewEvents
|
import im.vector.app.features.room.RequireActiveMembershipViewEvents
|
||||||
import im.vector.app.features.room.RequireActiveMembershipViewModel
|
import im.vector.app.features.room.RequireActiveMembershipViewModel
|
||||||
|
@ -41,7 +42,7 @@ import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RoomProfileActivity :
|
class RoomProfileActivity :
|
||||||
VectorBaseActivity(),
|
VectorBaseActivity<ActivitySimpleBinding>(),
|
||||||
ToolbarConfigurable,
|
ToolbarConfigurable,
|
||||||
RequireActiveMembershipViewModel.Factory {
|
RequireActiveMembershipViewModel.Factory {
|
||||||
|
|
||||||
|
@ -81,7 +82,9 @@ class RoomProfileActivity :
|
||||||
injector.inject(this)
|
injector.inject(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLayoutRes() = R.layout.activity_simple
|
override fun getBinding(): ActivitySimpleBinding {
|
||||||
|
return ActivitySimpleBinding.inflate(layoutInflater)
|
||||||
|
}
|
||||||
|
|
||||||
override fun initUiAndData() {
|
override fun initUiAndData() {
|
||||||
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||||
|
|
|
@ -23,6 +23,8 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.app.ActivityOptionsCompat
|
import androidx.core.app.ActivityOptionsCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
|
@ -42,7 +44,6 @@ import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.copyToClipboard
|
import im.vector.app.core.utils.copyToClipboard
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
|
||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.features.crypto.util.toImageRes
|
import im.vector.app.features.crypto.util.toImageRes
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
@ -70,9 +71,15 @@ class RoomProfileFragment @Inject constructor(
|
||||||
private val roomProfileController: RoomProfileController,
|
private val roomProfileController: RoomProfileController,
|
||||||
private val avatarRenderer: AvatarRenderer,
|
private val avatarRenderer: AvatarRenderer,
|
||||||
val roomProfileViewModelFactory: RoomProfileViewModel.Factory
|
val roomProfileViewModelFactory: RoomProfileViewModel.Factory
|
||||||
) : VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
) :
|
||||||
|
VectorBaseFragment<FragmentMatrixProfileBinding>(),
|
||||||
RoomProfileController.Callback {
|
RoomProfileController.Callback {
|
||||||
|
|
||||||
|
private lateinit var roomProfileDecorationImageView: ImageView
|
||||||
|
private lateinit var roomProfileAvatarView: ImageView
|
||||||
|
private lateinit var roomProfileAliasView: TextView
|
||||||
|
private lateinit var roomProfileNameView: TextView
|
||||||
|
|
||||||
private val roomProfileArgs: RoomProfileArgs by args()
|
private val roomProfileArgs: RoomProfileArgs by args()
|
||||||
private lateinit var roomListQuickActionsSharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var roomListQuickActionsSharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
private lateinit var roomProfileSharedActionViewModel: RoomProfileSharedActionViewModel
|
||||||
|
@ -90,20 +97,21 @@ class RoomProfileFragment @Inject constructor(
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
roomListQuickActionsSharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
roomListQuickActionsSharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||||
roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
roomProfileSharedActionViewModel = activityViewModelProvider.get(RoomProfileSharedActionViewModel::class.java)
|
||||||
val headerView = matrixProfileHeaderView.let {
|
val headerView = views.matrixProfileHeaderView.let {
|
||||||
it.layoutResource = R.layout.view_stub_room_profile_header
|
it.layoutResource = R.layout.view_stub_room_profile_header
|
||||||
it.inflate()
|
it.inflate()
|
||||||
}
|
}
|
||||||
|
findHeaderSubViews(headerView)
|
||||||
setupWaitingView()
|
setupWaitingView()
|
||||||
setupToolbar(matrixProfileToolbar)
|
setupToolbar(views.matrixProfileToolbar)
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(
|
appBarStateChangeListener = MatrixItemAppBarStateChangeListener(
|
||||||
headerView,
|
headerView,
|
||||||
listOf(matrixProfileToolbarAvatarImageView,
|
listOf(views.matrixProfileToolbarAvatarImageView,
|
||||||
matrixProfileToolbarTitleView,
|
views. matrixProfileToolbarTitleView,
|
||||||
matrixProfileDecorationToolbarAvatarImageView)
|
views. matrixProfileDecorationToolbarAvatarImageView)
|
||||||
)
|
)
|
||||||
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
views.matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
roomProfileViewModel.observeViewEvents {
|
roomProfileViewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is RoomProfileViewEvents.Loading -> showLoading(it.message)
|
is RoomProfileViewEvents.Loading -> showLoading(it.message)
|
||||||
|
@ -119,9 +127,16 @@ class RoomProfileFragment @Inject constructor(
|
||||||
setupLongClicks()
|
setupLongClicks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findHeaderSubViews(headerView: View) {
|
||||||
|
roomProfileNameView = headerView.findViewById(R.id.roomProfileNameView)
|
||||||
|
roomProfileAliasView = headerView.findViewById(R.id.roomProfileAliasView)
|
||||||
|
roomProfileAvatarView = headerView.findViewById(R.id.roomProfileAvatarView)
|
||||||
|
roomProfileDecorationImageView = headerView.findViewById(R.id.roomProfileDecorationImageView)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupWaitingView() {
|
private fun setupWaitingView() {
|
||||||
waitingStatusText.setText(R.string.please_wait)
|
views.waitingView.waitingStatusText.setText(R.string.please_wait)
|
||||||
waitingStatusText.isVisible = true
|
views.waitingView.waitingStatusText.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupLongClicks() {
|
private fun setupLongClicks() {
|
||||||
|
@ -157,18 +172,18 @@ class RoomProfileFragment @Inject constructor(
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
roomProfileController.callback = this
|
roomProfileController.callback = this
|
||||||
matrixProfileRecyclerView.configureWith(roomProfileController, hasFixedSize = true, disableItemAnimation = true)
|
views.matrixProfileRecyclerView.configureWith(roomProfileController, hasFixedSize = true, disableItemAnimation = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
views.matrixProfileAppBarLayout.removeOnOffsetChangedListener(appBarStateChangeListener)
|
||||||
matrixProfileRecyclerView.cleanup()
|
views.matrixProfileRecyclerView.cleanup()
|
||||||
appBarStateChangeListener = null
|
appBarStateChangeListener = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
override fun invalidate() = withState(roomProfileViewModel) { state ->
|
||||||
waiting_view.isVisible = state.isLoading
|
views.waitingView.root.isVisible = state.isLoading
|
||||||
|
|
||||||
state.roomSummary()?.also {
|
state.roomSummary()?.also {
|
||||||
if (it.membership.isLeft()) {
|
if (it.membership.isLeft()) {
|
||||||
|
@ -176,19 +191,19 @@ class RoomProfileFragment @Inject constructor(
|
||||||
activity?.finish()
|
activity?.finish()
|
||||||
} else {
|
} else {
|
||||||
roomProfileNameView.text = it.displayName
|
roomProfileNameView.text = it.displayName
|
||||||
matrixProfileToolbarTitleView.text = it.displayName
|
views.matrixProfileToolbarTitleView.text = it.displayName
|
||||||
roomProfileAliasView.setTextOrHide(it.canonicalAlias)
|
roomProfileAliasView.setTextOrHide(it.canonicalAlias)
|
||||||
val matrixItem = it.toMatrixItem()
|
val matrixItem = it.toMatrixItem()
|
||||||
avatarRenderer.render(matrixItem, roomProfileAvatarView)
|
avatarRenderer.render(matrixItem, roomProfileAvatarView)
|
||||||
avatarRenderer.render(matrixItem, matrixProfileToolbarAvatarImageView)
|
avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView)
|
||||||
roomProfileDecorationImageView.isVisible = it.roomEncryptionTrustLevel != null
|
roomProfileDecorationImageView.isVisible = it.roomEncryptionTrustLevel != null
|
||||||
roomProfileDecorationImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
roomProfileDecorationImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
||||||
matrixProfileDecorationToolbarAvatarImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
views.matrixProfileDecorationToolbarAvatarImageView.setImageResource(it.roomEncryptionTrustLevel.toImageRes())
|
||||||
|
|
||||||
roomProfileAvatarView.setOnClickListener { view ->
|
roomProfileAvatarView.setOnClickListener { view ->
|
||||||
onAvatarClicked(view, matrixItem)
|
onAvatarClicked(view, matrixItem)
|
||||||
}
|
}
|
||||||
matrixProfileToolbarAvatarImageView.setOnClickListener { view ->
|
views.matrixProfileToolbarAvatarImageView.setOnClickListener { view ->
|
||||||
onAvatarClicked(view, matrixItem)
|
onAvatarClicked(view, matrixItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,29 +61,29 @@ class RoomMemberListFragment @Inject constructor(
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
roomMemberListController.callback = this
|
roomMemberListController.callback = this
|
||||||
setupToolbar(roomSettingsToolbar)
|
setupToolbar(views.roomSettingGeneric.roomSettingsToolbar)
|
||||||
setupSearchView()
|
setupSearchView()
|
||||||
setupInviteUsersButton()
|
setupInviteUsersButton()
|
||||||
views.roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
views.roomSettingGeneric.roomSettingsRecyclerView.configureWith(roomMemberListController, hasFixedSize = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupInviteUsersButton() {
|
private fun setupInviteUsersButton() {
|
||||||
inviteUsersButton.debouncedClicks {
|
views.inviteUsersButton.debouncedClicks {
|
||||||
navigator.openInviteUsersToRoom(requireContext(), roomProfileArgs.roomId)
|
navigator.openInviteUsersToRoom(requireContext(), roomProfileArgs.roomId)
|
||||||
}
|
}
|
||||||
// Hide FAB when list is scrolling
|
// Hide FAB when list is scrolling
|
||||||
views.roomSettingsRecyclerView.addOnScrollListener(
|
views.roomSettingGeneric.roomSettingsRecyclerView.addOnScrollListener(
|
||||||
object : RecyclerView.OnScrollListener() {
|
object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
when (newState) {
|
when (newState) {
|
||||||
RecyclerView.SCROLL_STATE_IDLE -> {
|
RecyclerView.SCROLL_STATE_IDLE -> {
|
||||||
if (withState(viewModel) { it.actionsPermissions.canInvite }) {
|
if (withState(viewModel) { it.actionsPermissions.canInvite }) {
|
||||||
inviteUsersButton.show()
|
views.inviteUsersButton.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RecyclerView.SCROLL_STATE_DRAGGING,
|
RecyclerView.SCROLL_STATE_DRAGGING,
|
||||||
RecyclerView.SCROLL_STATE_SETTLING -> {
|
RecyclerView.SCROLL_STATE_SETTLING -> {
|
||||||
inviteUsersButton.hide()
|
views.inviteUsersButton.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,8 +92,8 @@ class RoomMemberListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupSearchView() {
|
private fun setupSearchView() {
|
||||||
searchView.queryHint = getString(R.string.search_members_hint)
|
views.roomSettingGeneric.searchView.queryHint = getString(R.string.search_members_hint)
|
||||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
views.roomSettingGeneric.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String): Boolean {
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -106,16 +106,16 @@ class RoomMemberListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
views.roomSettingsRecyclerView.cleanup()
|
views.roomSettingGeneric.roomSettingsRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { viewState ->
|
override fun invalidate() = withState(viewModel) { viewState ->
|
||||||
roomMemberListController.setData(viewState)
|
roomMemberListController.setData(viewState)
|
||||||
renderRoomSummary(viewState)
|
renderRoomSummary(viewState)
|
||||||
inviteUsersButton.isVisible = viewState.actionsPermissions.canInvite
|
views.inviteUsersButton.isVisible = viewState.actionsPermissions.canInvite
|
||||||
// Display filter only if there are more than 2 members in this room
|
// Display filter only if there are more than 2 members in this room
|
||||||
searchViewAppBarLayout.isVisible = viewState.roomSummary()?.otherMemberIds.orEmpty().size > 1
|
views.roomSettingGeneric.searchViewAppBarLayout.isVisible = viewState.roomSummary()?.otherMemberIds.orEmpty().size > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRoomMemberClicked(roomMember: RoomMemberSummary) {
|
override fun onRoomMemberClicked(roomMember: RoomMemberSummary) {
|
||||||
|
@ -140,8 +140,8 @@ class RoomMemberListFragment @Inject constructor(
|
||||||
|
|
||||||
private fun renderRoomSummary(state: RoomMemberListViewState) {
|
private fun renderRoomSummary(state: RoomMemberListViewState) {
|
||||||
state.roomSummary()?.let {
|
state.roomSummary()?.let {
|
||||||
roomSettingsToolbarTitleView.text = it.displayName
|
views.roomSettingGeneric.roomSettingsToolbarTitleView.text = it.displayName
|
||||||
avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView)
|
avatarRenderer.render(it.toMatrixItem(), views.roomSettingGeneric.roomSettingsToolbarAvatarImageView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogBackgroundSyncModeBinding
|
||||||
|
|
||||||
class BackgroundSyncModeChooserDialog : DialogFragment() {
|
class BackgroundSyncModeChooserDialog : DialogFragment() {
|
||||||
|
|
||||||
|
@ -31,25 +32,26 @@ class BackgroundSyncModeChooserDialog : DialogFragment() {
|
||||||
val initialMode = BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE))
|
val initialMode = BackgroundSyncMode.fromString(arguments?.getString(ARG_INITIAL_MODE))
|
||||||
|
|
||||||
val view = requireActivity().layoutInflater.inflate(R.layout.dialog_background_sync_mode, null)
|
val view = requireActivity().layoutInflater.inflate(R.layout.dialog_background_sync_mode, null)
|
||||||
|
val views = DialogBackgroundSyncModeBinding.bind(view)
|
||||||
val dialog = AlertDialog.Builder(requireActivity())
|
val dialog = AlertDialog.Builder(requireActivity())
|
||||||
.setTitle(R.string.settings_background_fdroid_sync_mode)
|
.setTitle(R.string.settings_background_fdroid_sync_mode)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.setPositiveButton(R.string.cancel, null)
|
.setPositiveButton(R.string.cancel, null)
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
view.findViewById<View>(R.id.backgroundSyncModeBattery).setOnClickListener {
|
views.backgroundSyncModeBattery.setOnClickListener {
|
||||||
interactionListener
|
interactionListener
|
||||||
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY }
|
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY }
|
||||||
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY)
|
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
view.findViewById<View>(R.id.backgroundSyncModeReal).setOnClickListener {
|
views.backgroundSyncModeReal.setOnClickListener {
|
||||||
interactionListener
|
interactionListener
|
||||||
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME }
|
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME }
|
||||||
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME)
|
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
view.findViewById<View>(R.id.backgroundSyncModeOff).setOnClickListener {
|
views.backgroundSyncModeOff.setOnClickListener {
|
||||||
interactionListener
|
interactionListener
|
||||||
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED }
|
?.takeIf { initialMode != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED }
|
||||||
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED)
|
?.onOptionSelected(BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED)
|
||||||
|
|
|
@ -49,6 +49,7 @@ import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.TextUtils
|
import im.vector.app.core.utils.TextUtils
|
||||||
import im.vector.app.core.utils.getSizeOfFiles
|
import im.vector.app.core.utils.getSizeOfFiles
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
import im.vector.app.databinding.DialogChangePasswordBinding
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
import im.vector.app.features.MainActivityArgs
|
||||||
import im.vector.app.features.workers.signout.SignOutUiWorker
|
import im.vector.app.features.workers.signout.SignOutUiWorker
|
||||||
|
@ -352,25 +353,18 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
private fun onPasswordUpdateClick() {
|
private fun onPasswordUpdateClick() {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
val view: ViewGroup = activity.layoutInflater.inflate(R.layout.dialog_change_password, null) as ViewGroup
|
val view: ViewGroup = activity.layoutInflater.inflate(R.layout.dialog_change_password, null) as ViewGroup
|
||||||
|
val views = DialogChangePasswordBinding.bind(view)
|
||||||
val showPassword: ImageView = view.findViewById(R.id.change_password_show_passwords)
|
|
||||||
val oldPasswordTil: TextInputLayout = view.findViewById(R.id.change_password_old_pwd_til)
|
|
||||||
val oldPasswordText: TextInputEditText = view.findViewById(R.id.change_password_old_pwd_text)
|
|
||||||
val newPasswordText: TextInputEditText = view.findViewById(R.id.change_password_new_pwd_text)
|
|
||||||
val confirmNewPasswordTil: TextInputLayout = view.findViewById(R.id.change_password_confirm_new_pwd_til)
|
|
||||||
val confirmNewPasswordText: TextInputEditText = view.findViewById(R.id.change_password_confirm_new_pwd_text)
|
|
||||||
val changePasswordLoader: View = view.findViewById(R.id.change_password_loader)
|
|
||||||
|
|
||||||
var passwordShown = false
|
var passwordShown = false
|
||||||
|
|
||||||
showPassword.setOnClickListener {
|
views.changePasswordShowPasswords.setOnClickListener {
|
||||||
passwordShown = !passwordShown
|
passwordShown = !passwordShown
|
||||||
|
|
||||||
oldPasswordText.showPassword(passwordShown)
|
views.changePasswordOldPwdText.showPassword(passwordShown)
|
||||||
newPasswordText.showPassword(passwordShown)
|
views.changePasswordNewPwdText.showPassword(passwordShown)
|
||||||
confirmNewPasswordText.showPassword(passwordShown)
|
views.changePasswordConfirmNewPwdText.showPassword(passwordShown)
|
||||||
|
|
||||||
showPassword.setImageResource(if (passwordShown) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.changePasswordShowPasswords.setImageResource(if (passwordShown) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dialog = AlertDialog.Builder(activity)
|
val dialog = AlertDialog.Builder(activity)
|
||||||
|
@ -389,53 +383,53 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
updateButton.isEnabled = false
|
updateButton.isEnabled = false
|
||||||
|
|
||||||
fun updateUi() {
|
fun updateUi() {
|
||||||
val oldPwd = oldPasswordText.text.toString()
|
val oldPwd = views.changePasswordOldPwdText.text.toString()
|
||||||
val newPwd = newPasswordText.text.toString()
|
val newPwd = views.changePasswordNewPwdText.text.toString()
|
||||||
val newConfirmPwd = confirmNewPasswordText.text.toString()
|
val newConfirmPwd = views.changePasswordConfirmNewPwdText.text.toString()
|
||||||
|
|
||||||
updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && newPwd == newConfirmPwd
|
updateButton.isEnabled = oldPwd.isNotEmpty() && newPwd.isNotEmpty() && newPwd == newConfirmPwd
|
||||||
|
|
||||||
if (newPwd.isNotEmpty() && newConfirmPwd.isNotEmpty() && newPwd != newConfirmPwd) {
|
if (newPwd.isNotEmpty() && newConfirmPwd.isNotEmpty() && newPwd != newConfirmPwd) {
|
||||||
confirmNewPasswordTil.error = getString(R.string.passwords_do_not_match)
|
views.changePasswordConfirmNewPwdTil.error = getString(R.string.passwords_do_not_match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
views.changePasswordOldPwdText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
oldPasswordTil.error = null
|
views.changePasswordOldPwdTil.error = null
|
||||||
updateUi()
|
updateUi()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
newPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
views.changePasswordNewPwdText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
confirmNewPasswordTil.error = null
|
views.changePasswordConfirmNewPwdTil.error = null
|
||||||
updateUi()
|
updateUi()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
confirmNewPasswordText.addTextChangedListener(object : SimpleTextWatcher() {
|
views.changePasswordConfirmNewPwdText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
confirmNewPasswordTil.error = null
|
views.changePasswordConfirmNewPwdTil.error = null
|
||||||
updateUi()
|
updateUi()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
fun showPasswordLoadingView(toShow: Boolean) {
|
fun showPasswordLoadingView(toShow: Boolean) {
|
||||||
if (toShow) {
|
if (toShow) {
|
||||||
showPassword.isEnabled = false
|
views.changePasswordShowPasswords.isEnabled = false
|
||||||
oldPasswordText.isEnabled = false
|
views.changePasswordOldPwdText.isEnabled = false
|
||||||
newPasswordText.isEnabled = false
|
views.changePasswordNewPwdText.isEnabled = false
|
||||||
confirmNewPasswordText.isEnabled = false
|
views.changePasswordConfirmNewPwdText.isEnabled = false
|
||||||
changePasswordLoader.isVisible = true
|
views.changePasswordLoader.isVisible = true
|
||||||
updateButton.isEnabled = false
|
updateButton.isEnabled = false
|
||||||
cancelButton.isEnabled = false
|
cancelButton.isEnabled = false
|
||||||
} else {
|
} else {
|
||||||
showPassword.isEnabled = true
|
views.changePasswordShowPasswords.isEnabled = true
|
||||||
oldPasswordText.isEnabled = true
|
views.changePasswordOldPwdText.isEnabled = true
|
||||||
newPasswordText.isEnabled = true
|
views.changePasswordNewPwdText.isEnabled = true
|
||||||
confirmNewPasswordText.isEnabled = true
|
views.changePasswordConfirmNewPwdText.isEnabled = true
|
||||||
changePasswordLoader.isVisible = false
|
views.changePasswordLoader.isVisible = false
|
||||||
updateButton.isEnabled = true
|
updateButton.isEnabled = true
|
||||||
cancelButton.isEnabled = true
|
cancelButton.isEnabled = true
|
||||||
}
|
}
|
||||||
|
@ -444,13 +438,13 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
updateButton.setOnClickListener {
|
updateButton.setOnClickListener {
|
||||||
if (passwordShown) {
|
if (passwordShown) {
|
||||||
// Hide passwords during processing
|
// Hide passwords during processing
|
||||||
showPassword.performClick()
|
views.changePasswordShowPasswords.performClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.hideKeyboard()
|
view.hideKeyboard()
|
||||||
|
|
||||||
val oldPwd = oldPasswordText.text.toString()
|
val oldPwd = views.changePasswordOldPwdText.text.toString()
|
||||||
val newPwd = newPasswordText.text.toString()
|
val newPwd = views.changePasswordNewPwdText.text.toString()
|
||||||
|
|
||||||
showPasswordLoadingView(true)
|
showPasswordLoadingView(true)
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
@ -466,9 +460,9 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
activity.toast(R.string.settings_password_updated)
|
activity.toast(R.string.settings_password_updated)
|
||||||
}, { failure ->
|
}, { failure ->
|
||||||
if (failure.isInvalidPassword()) {
|
if (failure.isInvalidPassword()) {
|
||||||
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
|
views.changePasswordOldPwdTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
|
||||||
} else {
|
} else {
|
||||||
oldPasswordTil.error = getString(R.string.settings_fail_to_update_password)
|
views.changePasswordOldPwdTil.error = getString(R.string.settings_fail_to_update_password)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
@ -63,71 +64,70 @@ class VectorSettingsNotificationsTroubleshootFragment @Inject constructor(
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
val layoutManager = LinearLayoutManager(context)
|
val layoutManager = LinearLayoutManager(context)
|
||||||
troubleshoot_test_recycler_view.layoutManager = layoutManager
|
views.troubleshootTestRecyclerView.layoutManager = layoutManager
|
||||||
|
|
||||||
val dividerItemDecoration = DividerItemDecoration(troubleshoot_test_recycler_view.context,
|
val dividerItemDecoration = DividerItemDecoration(view.context, layoutManager.orientation)
|
||||||
layoutManager.orientation)
|
views.troubleshootTestRecyclerView.addItemDecoration(dividerItemDecoration)
|
||||||
troubleshoot_test_recycler_view.addItemDecoration(dividerItemDecoration)
|
|
||||||
|
|
||||||
troubleshoot_summ_button.debouncedClicks {
|
views.troubleshootSummButton.debouncedClicks {
|
||||||
bugReporter.openBugReportScreen(requireActivity())
|
bugReporter.openBugReportScreen(requireActivity())
|
||||||
}
|
}
|
||||||
|
|
||||||
troubleshoot_run_button.debouncedClicks {
|
views.troubleshootRunButton.debouncedClicks {
|
||||||
testManager?.retry(testStartForActivityResult)
|
testManager?.retry(testStartForActivityResult)
|
||||||
}
|
}
|
||||||
startUI()
|
startUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startUI() {
|
private fun startUI() {
|
||||||
toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_running_status, 0, 0)
|
views.toubleshootSummDescription.text = getString(R.string.settings_troubleshoot_diagnostic_running_status, 0, 0)
|
||||||
testManager = testManagerFactory.create(this)
|
testManager = testManagerFactory.create(this)
|
||||||
testManager?.statusListener = { troubleshootTestManager ->
|
testManager?.statusListener = { troubleshootTestManager ->
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
TransitionManager.beginDelayedTransition(troubleshoot_bottom_view)
|
TransitionManager.beginDelayedTransition(views.troubleshootBottomView)
|
||||||
when (troubleshootTestManager.diagStatus) {
|
when (troubleshootTestManager.diagStatus) {
|
||||||
TroubleshootTest.TestStatus.NOT_STARTED -> {
|
TroubleshootTest.TestStatus.NOT_STARTED -> {
|
||||||
toubleshoot_summ_description.text = ""
|
views.toubleshootSummDescription.text = ""
|
||||||
troubleshoot_summ_button.visibility = View.GONE
|
views.troubleshootSummButton.visibility = View.GONE
|
||||||
troubleshoot_run_button.visibility = View.VISIBLE
|
views.troubleshootRunButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.RUNNING,
|
TroubleshootTest.TestStatus.RUNNING,
|
||||||
TroubleshootTest.TestStatus.WAITING_FOR_USER -> {
|
TroubleshootTest.TestStatus.WAITING_FOR_USER -> {
|
||||||
val size = troubleshootTestManager.testListSize
|
val size = troubleshootTestManager.testListSize
|
||||||
val currentTestIndex = troubleshootTestManager.currentTestIndex
|
val currentTestIndex = troubleshootTestManager.currentTestIndex
|
||||||
toubleshoot_summ_description.text = getString(
|
views.toubleshootSummDescription.text = getString(
|
||||||
R.string.settings_troubleshoot_diagnostic_running_status,
|
R.string.settings_troubleshoot_diagnostic_running_status,
|
||||||
currentTestIndex,
|
currentTestIndex,
|
||||||
size
|
size
|
||||||
)
|
)
|
||||||
troubleshoot_summ_button.visibility = View.GONE
|
views.troubleshootSummButton.visibility = View.GONE
|
||||||
troubleshoot_run_button.visibility = View.GONE
|
views.troubleshootRunButton.visibility = View.GONE
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.FAILED -> {
|
TroubleshootTest.TestStatus.FAILED -> {
|
||||||
// check if there are quick fixes
|
// check if there are quick fixes
|
||||||
val hasQuickFix = testManager?.hasQuickFix().orFalse()
|
val hasQuickFix = testManager?.hasQuickFix().orFalse()
|
||||||
if (hasQuickFix) {
|
if (hasQuickFix) {
|
||||||
toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_with_quickfix)
|
views.toubleshootSummDescription.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_with_quickfix)
|
||||||
} else {
|
} else {
|
||||||
toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_no_quickfix)
|
views.toubleshootSummDescription.text = getString(R.string.settings_troubleshoot_diagnostic_failure_status_no_quickfix)
|
||||||
}
|
}
|
||||||
troubleshoot_summ_button.visibility = View.VISIBLE
|
views.troubleshootSummButton.visibility = View.VISIBLE
|
||||||
troubleshoot_run_button.visibility = View.VISIBLE
|
views.troubleshootRunButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.SUCCESS -> {
|
TroubleshootTest.TestStatus.SUCCESS -> {
|
||||||
toubleshoot_summ_description.text = getString(R.string.settings_troubleshoot_diagnostic_success_status)
|
views.toubleshootSummDescription.text = getString(R.string.settings_troubleshoot_diagnostic_success_status)
|
||||||
troubleshoot_summ_button.visibility = View.VISIBLE
|
views.troubleshootSummButton.visibility = View.VISIBLE
|
||||||
troubleshoot_run_button.visibility = View.VISIBLE
|
views.troubleshootRunButton.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
troubleshoot_test_recycler_view.adapter = testManager?.adapter
|
views.troubleshootTestRecyclerView.adapter = testManager?.adapter
|
||||||
testManager?.runDiagnostic(testStartForActivityResult)
|
testManager?.runDiagnostic(testStartForActivityResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
troubleshoot_test_recycler_view.cleanup()
|
views.troubleshootTestRecyclerView.cleanup()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ import im.vector.app.core.preference.VectorPreferenceCategory
|
||||||
import im.vector.app.core.utils.copyToClipboard
|
import im.vector.app.core.utils.copyToClipboard
|
||||||
import im.vector.app.core.utils.openFileSelection
|
import im.vector.app.core.utils.openFileSelection
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
import im.vector.app.databinding.DialogImportE2eKeysBinding
|
||||||
import im.vector.app.features.crypto.keys.KeysExporter
|
import im.vector.app.features.crypto.keys.KeysExporter
|
||||||
import im.vector.app.features.crypto.keys.KeysImporter
|
import im.vector.app.features.crypto.keys.KeysImporter
|
||||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||||
|
@ -447,42 +448,37 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
||||||
val filename = getFilenameFromUri(appContext, uri)
|
val filename = getFilenameFromUri(appContext, uri)
|
||||||
|
|
||||||
val dialogLayout = thisActivity.layoutInflater.inflate(R.layout.dialog_import_e2e_keys, null)
|
val dialogLayout = thisActivity.layoutInflater.inflate(R.layout.dialog_import_e2e_keys, null)
|
||||||
|
val views = DialogImportE2eKeysBinding.bind(dialogLayout)
|
||||||
val textView = dialogLayout.findViewById<TextView>(R.id.dialog_e2e_keys_passphrase_filename)
|
|
||||||
|
|
||||||
if (filename.isNullOrBlank()) {
|
if (filename.isNullOrBlank()) {
|
||||||
textView.isVisible = false
|
views.dialogE2eKeysPassphraseFilename.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
textView.isVisible = true
|
views.dialogE2eKeysPassphraseFilename.isVisible = true
|
||||||
textView.text = getString(R.string.import_e2e_keys_from_file, filename)
|
views.dialogE2eKeysPassphraseFilename.text = getString(R.string.import_e2e_keys_from_file, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
val builder = AlertDialog.Builder(thisActivity)
|
val builder = AlertDialog.Builder(thisActivity)
|
||||||
.setTitle(R.string.encryption_import_room_keys)
|
.setTitle(R.string.encryption_import_room_keys)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
|
|
||||||
val passPhraseEditText = dialogLayout.findViewById<TextInputEditText>(R.id.dialog_e2e_keys_passphrase_edit_text)
|
|
||||||
val importButton = dialogLayout.findViewById<Button>(R.id.dialog_e2e_keys_import_button)
|
|
||||||
|
|
||||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.importDialogShowPassword)
|
|
||||||
var passwordVisible = false
|
var passwordVisible = false
|
||||||
|
|
||||||
showPassword.setOnClickListener {
|
views.importDialogShowPassword.setOnClickListener {
|
||||||
passwordVisible = !passwordVisible
|
passwordVisible = !passwordVisible
|
||||||
passPhraseEditText.showPassword(passwordVisible)
|
views.dialogE2eKeysPassphraseEditText.showPassword(passwordVisible)
|
||||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.importDialogShowPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
|
|
||||||
passPhraseEditText.addTextChangedListener(object : SimpleTextWatcher() {
|
views.dialogE2eKeysPassphraseEditText.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
importButton.isEnabled = !passPhraseEditText.text.isNullOrEmpty()
|
views.dialogE2eKeysImportButton.isEnabled = !views.dialogE2eKeysPassphraseEditText.text.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
val importDialog = builder.show()
|
val importDialog = builder.show()
|
||||||
|
|
||||||
importButton.setOnClickListener {
|
views.dialogE2eKeysImportButton.setOnClickListener {
|
||||||
val password = passPhraseEditText.text.toString()
|
val password = views.dialogE2eKeysPassphraseEditText.text.toString()
|
||||||
|
|
||||||
displayLoadingView()
|
displayLoadingView()
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.jakewharton.rxbinding3.widget.textChanges
|
import com.jakewharton.rxbinding3.widget.textChanges
|
||||||
|
@ -73,23 +74,23 @@ class DeactivateAccountFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupUi() {
|
private fun setupUi() {
|
||||||
deactivateAccountPassword.textChanges()
|
views.deactivateAccountPassword.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
deactivateAccountPasswordTil.error = null
|
views.deactivateAccountPasswordTil.error = null
|
||||||
deactivateAccountSubmit.isEnabled = it.isNotEmpty()
|
views.deactivateAccountSubmit.isEnabled = it.isNotEmpty()
|
||||||
}
|
}
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupViewListeners() {
|
private fun setupViewListeners() {
|
||||||
deactivateAccountPasswordReveal.setOnClickListener {
|
views.deactivateAccountPasswordReveal.setOnClickListener {
|
||||||
viewModel.handle(DeactivateAccountAction.TogglePassword)
|
viewModel.handle(DeactivateAccountAction.TogglePassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivateAccountSubmit.debouncedClicks {
|
views.deactivateAccountSubmit.debouncedClicks {
|
||||||
viewModel.handle(DeactivateAccountAction.DeactivateAccount(
|
viewModel.handle(DeactivateAccountAction.DeactivateAccount(
|
||||||
deactivateAccountPassword.text.toString(),
|
views.deactivateAccountPassword.text.toString(),
|
||||||
deactivateAccountEraseCheckbox.isChecked))
|
views.deactivateAccountEraseCheckbox.isChecked))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,11 +103,11 @@ class DeactivateAccountFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
DeactivateAccountViewEvents.EmptyPassword -> {
|
DeactivateAccountViewEvents.EmptyPassword -> {
|
||||||
settingsActivity?.ignoreInvalidTokenError = false
|
settingsActivity?.ignoreInvalidTokenError = false
|
||||||
deactivateAccountPasswordTil.error = getString(R.string.error_empty_field_your_password)
|
views.deactivateAccountPasswordTil.error = getString(R.string.error_empty_field_your_password)
|
||||||
}
|
}
|
||||||
DeactivateAccountViewEvents.InvalidPassword -> {
|
DeactivateAccountViewEvents.InvalidPassword -> {
|
||||||
settingsActivity?.ignoreInvalidTokenError = false
|
settingsActivity?.ignoreInvalidTokenError = false
|
||||||
deactivateAccountPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
|
views.deactivateAccountPasswordTil.error = getString(R.string.settings_fail_to_update_password_invalid_current_password)
|
||||||
}
|
}
|
||||||
is DeactivateAccountViewEvents.OtherFailure -> {
|
is DeactivateAccountViewEvents.OtherFailure -> {
|
||||||
settingsActivity?.ignoreInvalidTokenError = false
|
settingsActivity?.ignoreInvalidTokenError = false
|
||||||
|
@ -119,7 +120,7 @@ class DeactivateAccountFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
deactivateAccountPassword.showPassword(state.passwordShown)
|
views.deactivateAccountPassword.showPassword(state.passwordShown)
|
||||||
deactivateAccountPasswordReveal.setImageResource(if (state.passwordShown) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
views.deactivateAccountPasswordReveal.setImageResource(if (state.passwordShown) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ package im.vector.app.features.settings.troubleshoot
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
@ -43,68 +47,73 @@ class NotificationTroubleshootRecyclerViewAdapter(val tests: ArrayList<Troublesh
|
||||||
override fun getItemCount(): Int = tests.size
|
override fun getItemCount(): Int = tests.size
|
||||||
|
|
||||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
private val troubleshootProgressBar = itemView.findViewById<ProgressBar>(R.id.troubleshootProgressBar)
|
||||||
|
private val troubleshootTestTitle = itemView.findViewById<TextView>(R.id.troubleshootTestTitle)
|
||||||
|
private val troubleshootTestDescription = itemView.findViewById<TextView>(R.id.troubleshootTestDescription)
|
||||||
|
private val troubleshootStatusIcon = itemView.findViewById<ImageView>(R.id.troubleshootStatusIcon)
|
||||||
|
private val troubleshootTestButton = itemView.findViewById<Button>(R.id.troubleshootTestButton)
|
||||||
|
|
||||||
fun bind(test: TroubleshootTest) {
|
fun bind(test: TroubleshootTest) {
|
||||||
val context = itemView.context
|
val context = itemView.context
|
||||||
itemView.troubleshootTestTitle.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
|
troubleshootTestTitle.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
|
||||||
itemView.troubleshootTestDescription.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
troubleshootTestDescription.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||||
|
|
||||||
when (test.status) {
|
when (test.status) {
|
||||||
TroubleshootTest.TestStatus.NOT_STARTED -> {
|
TroubleshootTest.TestStatus.NOT_STARTED -> {
|
||||||
itemView.troubleshootTestTitle.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
troubleshootTestTitle.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_secondary))
|
||||||
|
|
||||||
itemView.troubleshootProgressBar.visibility = View.INVISIBLE
|
troubleshootProgressBar.visibility = View.INVISIBLE
|
||||||
itemView.troubleshootStatusIcon.visibility = View.VISIBLE
|
troubleshootStatusIcon.visibility = View.VISIBLE
|
||||||
itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test)
|
troubleshootStatusIcon.setImageResource(R.drawable.unit_test)
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.WAITING_FOR_USER -> {
|
TroubleshootTest.TestStatus.WAITING_FOR_USER -> {
|
||||||
itemView.troubleshootProgressBar.visibility = View.INVISIBLE
|
troubleshootProgressBar.visibility = View.INVISIBLE
|
||||||
itemView.troubleshootStatusIcon.visibility = View.VISIBLE
|
troubleshootStatusIcon.visibility = View.VISIBLE
|
||||||
val infoColor = ContextCompat.getColor(context, R.color.vector_info_color)
|
val infoColor = ContextCompat.getColor(context, R.color.vector_info_color)
|
||||||
val drawable = ContextCompat.getDrawable(itemView.context, R.drawable.ic_notification_privacy_warning)?.apply {
|
val drawable = ContextCompat.getDrawable(itemView.context, R.drawable.ic_notification_privacy_warning)?.apply {
|
||||||
ThemeUtils.tintDrawableWithColor(this, infoColor)
|
ThemeUtils.tintDrawableWithColor(this, infoColor)
|
||||||
}
|
}
|
||||||
itemView.troubleshootStatusIcon.setImageDrawable(drawable)
|
troubleshootStatusIcon.setImageDrawable(drawable)
|
||||||
itemView.troubleshootTestDescription.setTextColor(infoColor)
|
troubleshootTestDescription.setTextColor(infoColor)
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.RUNNING -> {
|
TroubleshootTest.TestStatus.RUNNING -> {
|
||||||
itemView.troubleshootProgressBar.visibility = View.VISIBLE
|
troubleshootProgressBar.visibility = View.VISIBLE
|
||||||
itemView.troubleshootStatusIcon.visibility = View.INVISIBLE
|
troubleshootStatusIcon.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.FAILED -> {
|
TroubleshootTest.TestStatus.FAILED -> {
|
||||||
itemView.troubleshootProgressBar.visibility = View.INVISIBLE
|
troubleshootProgressBar.visibility = View.INVISIBLE
|
||||||
itemView.troubleshootStatusIcon.visibility = View.VISIBLE
|
troubleshootStatusIcon.visibility = View.VISIBLE
|
||||||
itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ko)
|
troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ko)
|
||||||
|
|
||||||
itemView.troubleshootStatusIcon.imageTintList = null
|
troubleshootStatusIcon.imageTintList = null
|
||||||
|
|
||||||
itemView.troubleshootTestDescription.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice))
|
troubleshootTestDescription.setTextColor(ContextCompat.getColor(context, R.color.riotx_notice))
|
||||||
}
|
}
|
||||||
TroubleshootTest.TestStatus.SUCCESS -> {
|
TroubleshootTest.TestStatus.SUCCESS -> {
|
||||||
itemView.troubleshootProgressBar.visibility = View.INVISIBLE
|
troubleshootProgressBar.visibility = View.INVISIBLE
|
||||||
itemView.troubleshootStatusIcon.visibility = View.VISIBLE
|
troubleshootStatusIcon.visibility = View.VISIBLE
|
||||||
itemView.troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ok)
|
troubleshootStatusIcon.setImageResource(R.drawable.unit_test_ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val quickFix = test.quickFix
|
val quickFix = test.quickFix
|
||||||
if (quickFix != null) {
|
if (quickFix != null) {
|
||||||
itemView.troubleshootTestButton.setText(test.quickFix!!.title)
|
troubleshootTestButton.setText(test.quickFix!!.title)
|
||||||
itemView.troubleshootTestButton.setOnClickListener { _ ->
|
troubleshootTestButton.setOnClickListener { _ ->
|
||||||
test.quickFix!!.doFix()
|
test.quickFix!!.doFix()
|
||||||
}
|
}
|
||||||
itemView.troubleshootTestButton.visibility = View.VISIBLE
|
troubleshootTestButton.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
itemView.troubleshootTestButton.visibility = View.GONE
|
troubleshootTestButton.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.troubleshootTestTitle.setText(test.titleResId)
|
troubleshootTestTitle.setText(test.titleResId)
|
||||||
val description = test.description
|
val description = test.description
|
||||||
if (description == null) {
|
if (description == null) {
|
||||||
itemView.troubleshootTestDescription.visibility = View.GONE
|
troubleshootTestDescription.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
itemView.troubleshootTestDescription.visibility = View.VISIBLE
|
troubleshootTestDescription.visibility = View.VISIBLE
|
||||||
itemView.troubleshootTestDescription.text = description
|
troubleshootTestDescription.text = description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
@ -58,10 +59,10 @@ class ReviewTermsFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
termsController.listener = this
|
termsController.listener = this
|
||||||
reviewTermsRecyclerView.configureWith(termsController)
|
views.reviewTermsRecyclerView.configureWith(termsController)
|
||||||
|
|
||||||
reviewTermsAccept.onClick { reviewTermsViewModel.handle(ReviewTermsAction.Accept) }
|
views.reviewTermsAccept.onClick { reviewTermsViewModel.handle(ReviewTermsAction.Accept) }
|
||||||
reviewTermsDecline.onClick { activity?.finish() }
|
views.reviewTermsDecline.onClick { activity?.finish() }
|
||||||
|
|
||||||
reviewTermsViewModel.observeViewEvents {
|
reviewTermsViewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -79,7 +80,7 @@ class ReviewTermsFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
reviewTermsRecyclerView.cleanup()
|
views.reviewTermsRecyclerView.cleanup()
|
||||||
termsController.listener = null
|
termsController.listener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
@ -94,11 +95,11 @@ class ReviewTermsFragment @Inject constructor(
|
||||||
|
|
||||||
when (state.termsList) {
|
when (state.termsList) {
|
||||||
is Loading -> {
|
is Loading -> {
|
||||||
reviewTermsBottomBar.isVisible = false
|
views.reviewTermsBottomBar.isVisible = false
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
reviewTermsBottomBar.isVisible = true
|
views.reviewTermsBottomBar.isVisible = true
|
||||||
reviewTermsAccept.isEnabled = state.termsList.invoke().all { it.accepted }
|
views.reviewTermsAccept.isEnabled = state.termsList.invoke().all { it.accepted }
|
||||||
}
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,11 +57,11 @@ class ScanUserCodeFragment @Inject constructor()
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
userCodeMyCodeButton.debouncedClicks {
|
views.userCodeMyCodeButton.debouncedClicks {
|
||||||
sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW))
|
sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW))
|
||||||
}
|
}
|
||||||
|
|
||||||
userCodeOpenGalleryButton.debouncedClicks {
|
views.userCodeOpenGalleryButton.debouncedClicks {
|
||||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher)
|
MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,11 +94,11 @@ class ScanUserCodeFragment @Inject constructor()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startCamera() {
|
private fun startCamera() {
|
||||||
userCodeScannerView.startCamera()
|
views.userCodeScannerView.startCamera()
|
||||||
userCodeScannerView.setAutoFocus(autoFocus)
|
views.userCodeScannerView.setAutoFocus(autoFocus)
|
||||||
userCodeScannerView.debouncedClicks {
|
views.userCodeScannerView.debouncedClicks {
|
||||||
this.autoFocus = !autoFocus
|
this.autoFocus = !autoFocus
|
||||||
userCodeScannerView.setAutoFocus(autoFocus)
|
views.userCodeScannerView.setAutoFocus(autoFocus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ class ScanUserCodeFragment @Inject constructor()
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
// Register ourselves as a handler for scan results.
|
// Register ourselves as a handler for scan results.
|
||||||
userCodeScannerView.setResultHandler(this)
|
views.userCodeScannerView.setResultHandler(this)
|
||||||
if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) {
|
if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) {
|
||||||
startCamera()
|
startCamera()
|
||||||
}
|
}
|
||||||
|
@ -120,9 +120,9 @@ class ScanUserCodeFragment @Inject constructor()
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
userCodeScannerView.setResultHandler(null)
|
views.userCodeScannerView.setResultHandler(null)
|
||||||
// Stop camera on pause
|
// Stop camera on pause
|
||||||
userCodeScannerView.stopCamera()
|
views.userCodeScannerView.stopCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleResult(result: Result?) {
|
override fun handleResult(result: Result?) {
|
||||||
|
|
|
@ -78,9 +78,9 @@ class WidgetFragment @Inject constructor() :
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
widgetWebView.setupForWidget(this)
|
views.widgetWebView.setupForWidget(this)
|
||||||
if (fragmentArgs.kind.isAdmin()) {
|
if (fragmentArgs.kind.isAdmin()) {
|
||||||
viewModel.getPostAPIMediator().setWebView(widgetWebView)
|
viewModel.getPostAPIMediator().setWebView(views.widgetWebView)
|
||||||
}
|
}
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
Timber.v("Observed view events: $it")
|
Timber.v("Observed view events: $it")
|
||||||
|
@ -114,12 +114,12 @@ class WidgetFragment @Inject constructor() :
|
||||||
if (fragmentArgs.kind.isAdmin()) {
|
if (fragmentArgs.kind.isAdmin()) {
|
||||||
viewModel.getPostAPIMediator().clearWebView()
|
viewModel.getPostAPIMediator().clearWebView()
|
||||||
}
|
}
|
||||||
widgetWebView.clearAfterWidget()
|
views.widgetWebView.clearAfterWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
widgetWebView?.let {
|
views.widgetWebView?.let {
|
||||||
it.resumeTimers()
|
it.resumeTimers()
|
||||||
it.onResume()
|
it.onResume()
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class WidgetFragment @Inject constructor() :
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
widgetWebView?.let {
|
views.widgetWebView?.let {
|
||||||
it.pauseTimers()
|
it.pauseTimers()
|
||||||
it.onPause()
|
it.onPause()
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ class WidgetFragment @Inject constructor() :
|
||||||
return@withState true
|
return@withState true
|
||||||
}
|
}
|
||||||
R.id.action_refresh -> if (state.formattedURL.complete) {
|
R.id.action_refresh -> if (state.formattedURL.complete) {
|
||||||
widgetWebView.reload()
|
views.widgetWebView.reload()
|
||||||
return@withState true
|
return@withState true
|
||||||
}
|
}
|
||||||
R.id.action_widget_open_ext -> if (state.formattedURL.complete) {
|
R.id.action_widget_open_ext -> if (state.formattedURL.complete) {
|
||||||
|
@ -183,8 +183,8 @@ class WidgetFragment @Inject constructor() :
|
||||||
|
|
||||||
override fun onBackPressed(toolbarButton: Boolean): Boolean = withState(viewModel) { state ->
|
override fun onBackPressed(toolbarButton: Boolean): Boolean = withState(viewModel) { state ->
|
||||||
if (state.formattedURL.complete) {
|
if (state.formattedURL.complete) {
|
||||||
if (widgetWebView.canGoBack()) {
|
if (views.widgetWebView.canGoBack()) {
|
||||||
widgetWebView.goBack()
|
views.widgetWebView.goBack()
|
||||||
return@withState true
|
return@withState true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,37 +196,37 @@ class WidgetFragment @Inject constructor() :
|
||||||
when (state.formattedURL) {
|
when (state.formattedURL) {
|
||||||
is Incomplete -> {
|
is Incomplete -> {
|
||||||
setStateError(null)
|
setStateError(null)
|
||||||
widgetWebView.isInvisible = true
|
views.widgetWebView.isInvisible = true
|
||||||
widgetProgressBar.isIndeterminate = true
|
views.widgetProgressBar.isIndeterminate = true
|
||||||
widgetProgressBar.isVisible = true
|
views.widgetProgressBar.isVisible = true
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
setStateError(null)
|
setStateError(null)
|
||||||
when (state.webviewLoadedUrl) {
|
when (state.webviewLoadedUrl) {
|
||||||
Uninitialized -> {
|
Uninitialized -> {
|
||||||
widgetWebView.isInvisible = true
|
views.widgetWebView.isInvisible = true
|
||||||
}
|
}
|
||||||
is Loading -> {
|
is Loading -> {
|
||||||
setStateError(null)
|
setStateError(null)
|
||||||
widgetWebView.isInvisible = false
|
views.widgetWebView.isInvisible = false
|
||||||
widgetProgressBar.isIndeterminate = true
|
views.widgetProgressBar.isIndeterminate = true
|
||||||
widgetProgressBar.isVisible = true
|
views.widgetProgressBar.isVisible = true
|
||||||
}
|
}
|
||||||
is Success -> {
|
is Success -> {
|
||||||
widgetWebView.isInvisible = false
|
views.widgetWebView.isInvisible = false
|
||||||
widgetProgressBar.isVisible = false
|
views.widgetProgressBar.isVisible = false
|
||||||
setStateError(null)
|
setStateError(null)
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
widgetProgressBar.isInvisible = true
|
views.widgetProgressBar.isInvisible = true
|
||||||
setStateError(state.webviewLoadedUrl.error.message)
|
setStateError(state.webviewLoadedUrl.error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Fail -> {
|
is Fail -> {
|
||||||
// we need to show Error
|
// we need to show Error
|
||||||
widgetWebView.isInvisible = true
|
views.widgetWebView.isInvisible = true
|
||||||
widgetProgressBar.isVisible = false
|
views.widgetProgressBar.isVisible = false
|
||||||
setStateError(state.formattedURL.error.message)
|
setStateError(state.formattedURL.error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,19 +282,19 @@ class WidgetFragment @Inject constructor() :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadFormattedUrl(event: WidgetViewEvents.OnURLFormatted) {
|
private fun loadFormattedUrl(event: WidgetViewEvents.OnURLFormatted) {
|
||||||
widgetWebView.clearHistory()
|
views.widgetWebView.clearHistory()
|
||||||
widgetWebView.loadUrl(event.formattedURL)
|
views.widgetWebView.loadUrl(event.formattedURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setStateError(message: String?) {
|
private fun setStateError(message: String?) {
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
widgetErrorLayout.isVisible = false
|
views.widgetErrorLayout.isVisible = false
|
||||||
widgetErrorText.text = null
|
views.widgetErrorText.text = null
|
||||||
} else {
|
} else {
|
||||||
widgetProgressBar.isVisible = false
|
views.widgetProgressBar.isVisible = false
|
||||||
widgetErrorLayout.isVisible = true
|
views.widgetErrorLayout.isVisible = true
|
||||||
widgetWebView.isInvisible = true
|
views.widgetWebView.isInvisible = true
|
||||||
widgetErrorText.text = getString(R.string.room_widget_failed_to_load, message)
|
views.widgetErrorText.text = getString(R.string.room_widget_failed_to_load, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,9 @@ import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
|
@ -31,6 +33,9 @@ class SignOutBottomSheetActionButton @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private val actionIconImageView: ImageView
|
||||||
|
private val actionTitleText: TextView
|
||||||
|
|
||||||
var action: (() -> Unit)? = null
|
var action: (() -> Unit)? = null
|
||||||
|
|
||||||
var title: String? = null
|
var title: String? = null
|
||||||
|
@ -72,9 +77,12 @@ class SignOutBottomSheetActionButton @JvmOverloads constructor(
|
||||||
tint = typedArray.getColor(R.styleable.SignOutBottomSheetActionButton_iconTint, ThemeUtils.getColor(context, android.R.attr.textColor))
|
tint = typedArray.getColor(R.styleable.SignOutBottomSheetActionButton_iconTint, ThemeUtils.getColor(context, android.R.attr.textColor))
|
||||||
textColor = typedArray.getColor(R.styleable.SignOutBottomSheetActionButton_textColor, ThemeUtils.getColor(context, android.R.attr.textColor))
|
textColor = typedArray.getColor(R.styleable.SignOutBottomSheetActionButton_textColor, ThemeUtils.getColor(context, android.R.attr.textColor))
|
||||||
|
|
||||||
|
actionIconImageView = findViewById(R.id.actionIconImageView)
|
||||||
|
actionTitleText = findViewById(R.id.actionTitleText)
|
||||||
|
|
||||||
typedArray.recycle()
|
typedArray.recycle()
|
||||||
|
|
||||||
signedOutActionClickable.setOnClickListener {
|
setOnClickListener {
|
||||||
action?.invoke()
|
action?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<include layout="@layout/fragment_room_setting_generic" />
|
<include
|
||||||
|
android:id="@+id/room_setting_generic"
|
||||||
|
layout="@layout/fragment_room_setting_generic" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/inviteUsersButton"
|
android:id="@+id/inviteUsersButton"
|
||||||
|
|
Loading…
Reference in New Issue