Merge pull request #2694 from nextcloud/bugfix/noid/MakeControllerBindingNullable

avoid crashes with NPEs for bindings
This commit is contained in:
Marcel Hibbe 2023-01-17 08:25:45 +01:00 committed by GitHub
commit 30879dfd49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 903 additions and 927 deletions

View File

@ -80,7 +80,8 @@ class AccountVerificationController(args: Bundle? = null) :
R.layout.controller_account_verification,
args
) {
private val binding: ControllerAccountVerificationBinding by viewBinding(ControllerAccountVerificationBinding::bind)
private val binding: ControllerAccountVerificationBinding? by
viewBinding(ControllerAccountVerificationBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -212,7 +213,7 @@ class AccountVerificationController(args: Bundle? = null) :
} else {
if (activity != null && resources != null) {
activity!!.runOnUiThread {
binding.progressText.setText(
binding?.progressText?.setText(
String.format(
resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
resources!!.getString(R.string.nc_app_product_name)
@ -230,17 +231,14 @@ class AccountVerificationController(args: Bundle? = null) :
override fun onError(e: Throwable) {
if (activity != null && resources != null) {
activity!!.runOnUiThread {
binding.progressText.setText(
String.format(
resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
resources!!.getString(R.string.nc_app_product_name)
)
binding?.progressText?.text = String.format(
resources!!.getString(R.string.nc_nextcloud_talk_app_not_installed),
resources!!.getString(R.string.nc_app_product_name)
)
}
}
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.getInstance().messageType =
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK
)
abortVerification()
}
@ -279,8 +277,8 @@ class AccountVerificationController(args: Bundle? = null) :
registerForPush()
} else {
activity!!.runOnUiThread {
binding.progressText.text =
""" ${binding.progressText.text}
binding?.progressText?.text =
""" ${binding?.progressText?.text}
${resources!!.getString(R.string.nc_push_disabled)}
""".trimIndent()
}
@ -290,8 +288,8 @@ class AccountVerificationController(args: Bundle? = null) :
@SuppressLint("SetTextI18n")
override fun onError(e: Throwable) {
binding.progressText.text =
""" ${binding.progressText.text}
binding?.progressText?.text =
""" ${binding?.progressText?.text}
"""
.trimIndent() + resources!!.getString(R.string.nc_display_name_not_stored)
abortVerification()
@ -331,9 +329,9 @@ class AccountVerificationController(args: Bundle? = null) :
} else {
if (activity != null) {
activity!!.runOnUiThread {
binding.progressText.text =
binding?.progressText?.text =
"""
${binding.progressText.text}
${binding?.progressText?.text}
${resources!!.getString(R.string.nc_display_name_not_fetched)}
""".trimIndent()
}
@ -346,9 +344,9 @@ class AccountVerificationController(args: Bundle? = null) :
override fun onError(e: Throwable) {
if (activity != null) {
activity!!.runOnUiThread {
binding.progressText.text =
binding?.progressText?.text =
"""
${binding.progressText.text}
${binding?.progressText?.text}
${resources!!.getString(R.string.nc_display_name_not_fetched)}
""".trimIndent()
}
@ -380,9 +378,9 @@ class AccountVerificationController(args: Bundle? = null) :
if (eventStatus.eventType == EventStatus.EventType.PUSH_REGISTRATION) {
if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood && activity != null) {
activity!!.runOnUiThread {
binding.progressText.text =
binding?.progressText?.text =
"""
${binding.progressText.text}
${binding?.progressText?.text}
${resources!!.getString(R.string.nc_push_disabled)}
""".trimIndent()
}
@ -392,9 +390,9 @@ class AccountVerificationController(args: Bundle? = null) :
if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
if (activity != null) {
activity!!.runOnUiThread {
binding.progressText.text =
binding?.progressText?.text =
"""
${binding.progressText.text}
${binding?.progressText?.text}
${resources!!.getString(R.string.nc_capabilities_failed)}
""".trimIndent()
}
@ -407,9 +405,9 @@ class AccountVerificationController(args: Bundle? = null) :
if (internalAccountId == eventStatus.userId && !eventStatus.isAllGood) {
if (activity != null) {
activity!!.runOnUiThread {
binding.progressText.text =
binding?.progressText?.text =
"""
${binding.progressText.text}
${binding?.progressText?.text}
${resources!!.getString(R.string.nc_external_server_failed)}
""".trimIndent()
}

View File

@ -213,23 +213,7 @@ import java.util.Locale
import java.util.Objects
import java.util.concurrent.ExecutionException
import javax.inject.Inject
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap
import kotlin.collections.List
import kotlin.collections.MutableList
import kotlin.collections.MutableMap
import kotlin.collections.chunked
import kotlin.collections.indexOfFirst
import kotlin.collections.indices
import kotlin.collections.isNotEmpty
import kotlin.collections.iterator
import kotlin.collections.map
import kotlin.collections.set
import kotlin.collections.toList
import kotlin.collections.toMap
import kotlin.collections.toMutableMap
import kotlin.collections.toTypedArray
import kotlin.math.roundToInt
@AutoInjector(NextcloudTalkApplication::class)
@ -246,7 +230,7 @@ class ChatController(args: Bundle) :
CommonMessageInterface,
PreviewMessageInterface {
private val binding: ControllerChatBinding by viewBinding(ControllerChatBinding::bind)
private val binding: ControllerChatBinding? by viewBinding(ControllerChatBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -435,10 +419,8 @@ class ChatController(args: Bundle) :
}
)
withNullableControllerViewBinding {
val itemTouchHelper = ItemTouchHelper(messageSwipeController)
itemTouchHelper.attachToRecyclerView(binding.messagesListView)
}
val itemTouchHelper = ItemTouchHelper(messageSwipeController)
itemTouchHelper.attachToRecyclerView(binding?.messagesListView)
}
}
@ -541,7 +523,7 @@ class ChatController(args: Bundle) :
var adapterWasNull = false
if (adapter == null) {
binding.progressBar.visibility = View.VISIBLE
binding?.progressBar?.visibility = View.VISIBLE
adapterWasNull = true
@ -651,10 +633,10 @@ class ChatController(args: Bundle) :
this
)
} else {
binding.messagesListView.visibility = View.VISIBLE
binding?.messagesListView?.visibility = View.VISIBLE
}
binding.messagesListView.setAdapter(adapter)
binding?.messagesListView?.setAdapter(adapter)
adapter?.setLoadMoreListener(this)
adapter?.setDateHeadersFormatter { format(it) }
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) }
@ -677,11 +659,11 @@ class ChatController(args: Bundle) :
setupSwipeToReply()
layoutManager = binding.messagesListView.layoutManager as LinearLayoutManager?
layoutManager = binding?.messagesListView?.layoutManager as LinearLayoutManager?
binding.popupBubbleView.setRecyclerView(binding.messagesListView)
binding?.popupBubbleView?.setRecyclerView(binding?.messagesListView)
binding.popupBubbleView.setPopupBubbleListener { context ->
binding?.popupBubbleView?.setPopupBubbleListener { context ->
if (newMessagesCount != 0) {
val scrollPosition = if (newMessagesCount - 1 < 0) {
0
@ -690,18 +672,18 @@ class ChatController(args: Bundle) :
}
Handler().postDelayed(
{
binding.messagesListView.smoothScrollToPosition(scrollPosition)
binding?.messagesListView?.smoothScrollToPosition(scrollPosition)
},
NEW_MESSAGES_POPUP_BUBBLE_DELAY
)
}
}
viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.popupBubbleView)
binding?.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it.popupBubbleView) }
binding.messageInputView.setPadding(0, 0, 0, 0)
binding?.messageInputView?.setPadding(0, 0, 0, 0)
binding.messagesListView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
binding?.messagesListView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
@ -710,8 +692,8 @@ class ChatController(args: Bundle) :
if (layoutManager!!.findFirstCompletelyVisibleItemPosition() < newMessagesCount) {
newMessagesCount = 0
if (binding.popupBubbleView.isShown) {
binding.popupBubbleView.hide()
if (binding?.popupBubbleView?.isShown == true) {
binding?.popupBubbleView?.hide()
}
}
}
@ -723,9 +705,9 @@ class ChatController(args: Bundle) :
val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser)
filters[0] = InputFilter.LengthFilter(lengthFilter)
binding.messageInputView.inputEditText?.filters = filters
binding?.messageInputView?.inputEditText?.filters = filters
binding.messageInputView.inputEditText?.addTextChangedListener(object : TextWatcher {
binding?.messageInputView?.inputEditText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// unused atm
}
@ -734,19 +716,19 @@ class ChatController(args: Bundle) :
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
try {
if (s.length >= lengthFilter) {
binding.messageInputView.inputEditText?.error = String.format(
binding?.messageInputView?.inputEditText?.error = String.format(
Objects.requireNonNull<Resources>(resources).getString(R.string.nc_limit_hit),
lengthFilter.toString()
)
} else {
binding.messageInputView.inputEditText?.error = null
binding?.messageInputView?.inputEditText?.error = null
}
val editable = binding.messageInputView.inputEditText?.editableText
if (editable != null && binding.messageInputView.inputEditText != null) {
val editable = binding?.messageInputView?.inputEditText?.editableText
if (editable != null && binding?.messageInputView?.inputEditText != null) {
val mentionSpans = editable.getSpans(
0,
binding.messageInputView.inputEditText!!.length(),
binding?.messageInputView?.inputEditText!!.length(),
Spans.MentionChipSpan::class.java
)
var mentionSpan: Spans.MentionChipSpan
@ -779,15 +761,15 @@ class ChatController(args: Bundle) :
// Image keyboard support
// See: https://developer.android.com/guide/topics/text/image-keyboard
(binding.messageInputView.inputEditText as ImageEmojiEditText).onCommitContentListener = {
(binding?.messageInputView?.inputEditText as ImageEmojiEditText).onCommitContentListener = {
uploadFile(it.toString(), false)
}
showMicrophoneButton(true)
binding.messageInputView.messageInput.doAfterTextChanged {
binding?.messageInputView?.messageInput?.doAfterTextChanged {
try {
if (binding.messageInputView.messageInput.text.isEmpty()) {
if (binding?.messageInputView?.messageInput?.text?.isEmpty() == true) {
showMicrophoneButton(true)
} else {
showMicrophoneButton(false)
@ -806,7 +788,7 @@ class ChatController(args: Bundle) :
var voiceRecordStartTime = 0L
var voiceRecordEndTime = 0L
binding.messageInputView.recordAudioButton.setOnTouchListener(object : View.OnTouchListener {
binding?.messageInputView?.recordAudioButton?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
view.performClick()
when (event?.action) {
@ -835,7 +817,7 @@ class ChatController(args: Bundle) :
stopAndDiscardAudioRecording()
showRecordAudioUi(false)
binding.messageInputView.slideToCancelDescription.x = sliderInitX
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX
}
MotionEvent.ACTION_UP -> {
Log.d(TAG, "ACTION_UP. stop recording??")
@ -861,7 +843,7 @@ class ChatController(args: Bundle) :
stopAndSendAudioRecording()
}
binding.messageInputView.slideToCancelDescription.x = sliderInitX
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX
}
MotionEvent.ACTION_MOVE -> {
Log.d(TAG, "ACTION_MOVE.")
@ -873,26 +855,26 @@ class ChatController(args: Bundle) :
showRecordAudioUi(true)
if (sliderInitX == 0.0F) {
sliderInitX = binding.messageInputView.slideToCancelDescription.x
sliderInitX = binding?.messageInputView?.slideToCancelDescription?.x!!
}
val movedX: Float = event.x
deltaX = movedX - downX
// only allow slide to left
if (binding.messageInputView.slideToCancelDescription.x > sliderInitX) {
binding.messageInputView.slideToCancelDescription.x = sliderInitX
if (binding?.messageInputView?.slideToCancelDescription?.x!! > sliderInitX) {
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX
}
if (binding.messageInputView.slideToCancelDescription.x < VOICE_RECORD_CANCEL_SLIDER_X) {
if (binding?.messageInputView?.slideToCancelDescription?.x!! < VOICE_RECORD_CANCEL_SLIDER_X) {
Log.d(TAG, "stopping recording because slider was moved to left")
stopAndDiscardAudioRecording()
showRecordAudioUi(false)
binding.messageInputView.slideToCancelDescription.x = sliderInitX
binding?.messageInputView?.slideToCancelDescription?.x = sliderInitX
return true
} else {
binding.messageInputView.slideToCancelDescription.x = binding.messageInputView
.slideToCancelDescription.x + deltaX
binding?.messageInputView?.slideToCancelDescription?.x =
binding?.messageInputView?.slideToCancelDescription?.x!! + deltaX
downX = movedX
}
}
@ -902,26 +884,24 @@ class ChatController(args: Bundle) :
}
})
binding.messageInputView.inputEditText?.setText(sharedText)
binding.messageInputView.setAttachmentsListener {
binding?.messageInputView?.inputEditText?.setText(sharedText)
binding?.messageInputView?.setAttachmentsListener {
activity?.let { AttachmentDialog(it, this).show() }
}
binding.messageInputView.button.setOnClickListener { submitMessage(false) }
binding?.messageInputView?.button?.setOnClickListener { submitMessage(false) }
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
binding.messageInputView.button.setOnLongClickListener {
binding?.messageInputView?.button?.setOnLongClickListener {
showSendButtonMenu()
true
}
}
binding.messageInputView.button.contentDescription = resources?.getString(
R.string
.nc_description_send_message_button
)
binding?.messageInputView?.button?.contentDescription =
resources?.getString(R.string.nc_description_send_message_button)
viewThemeUtils.platform.colorImageView(binding.messageInputView.button)
binding?.messageInputView?.button?.let { viewThemeUtils.platform.colorImageView(it) }
if (currentConversation != null && currentConversation?.roomId != null) {
loadAvatarForStatusBar()
@ -942,7 +922,7 @@ class ChatController(args: Bundle) :
private fun showSendButtonMenu() {
val popupMenu = PopupMenu(
ContextThemeWrapper(view?.context, R.style.ChatSendButtonMenu),
binding.messageInputView.button,
binding?.messageInputView?.button,
Gravity.END
)
popupMenu.inflate(R.menu.chat_send_menu)
@ -1150,23 +1130,23 @@ class ChatController(args: Bundle) :
private fun showRecordAudioUi(show: Boolean) {
if (show) {
binding.messageInputView.microphoneEnabledInfo.visibility = View.VISIBLE
binding.messageInputView.microphoneEnabledInfoBackground.visibility = View.VISIBLE
binding.messageInputView.audioRecordDuration.visibility = View.VISIBLE
binding.messageInputView.slideToCancelDescription.visibility = View.VISIBLE
binding.messageInputView.attachmentButton.visibility = View.GONE
binding.messageInputView.smileyButton.visibility = View.GONE
binding.messageInputView.messageInput.visibility = View.GONE
binding.messageInputView.messageInput.hint = ""
binding?.messageInputView?.microphoneEnabledInfo?.visibility = View.VISIBLE
binding?.messageInputView?.microphoneEnabledInfoBackground?.visibility = View.VISIBLE
binding?.messageInputView?.audioRecordDuration?.visibility = View.VISIBLE
binding?.messageInputView?.slideToCancelDescription?.visibility = View.VISIBLE
binding?.messageInputView?.attachmentButton?.visibility = View.GONE
binding?.messageInputView?.smileyButton?.visibility = View.GONE
binding?.messageInputView?.messageInput?.visibility = View.GONE
binding?.messageInputView?.messageInput?.hint = ""
} else {
binding.messageInputView.microphoneEnabledInfo.visibility = View.GONE
binding.messageInputView.microphoneEnabledInfoBackground.visibility = View.GONE
binding.messageInputView.audioRecordDuration.visibility = View.GONE
binding.messageInputView.slideToCancelDescription.visibility = View.GONE
binding.messageInputView.attachmentButton.visibility = View.VISIBLE
binding.messageInputView.smileyButton.visibility = View.VISIBLE
binding.messageInputView.messageInput.visibility = View.VISIBLE
binding.messageInputView.messageInput.hint =
binding?.messageInputView?.microphoneEnabledInfo?.visibility = View.GONE
binding?.messageInputView?.microphoneEnabledInfoBackground?.visibility = View.GONE
binding?.messageInputView?.audioRecordDuration?.visibility = View.GONE
binding?.messageInputView?.slideToCancelDescription?.visibility = View.GONE
binding?.messageInputView?.attachmentButton?.visibility = View.VISIBLE
binding?.messageInputView?.smileyButton?.visibility = View.VISIBLE
binding?.messageInputView?.messageInput?.visibility = View.VISIBLE
binding?.messageInputView?.messageInput?.hint =
context.resources?.getString(R.string.nc_hint_enter_a_message)
}
}
@ -1179,15 +1159,15 @@ class ChatController(args: Bundle) :
}
private fun startAudioRecording(file: String) {
binding.messageInputView.audioRecordDuration.base = SystemClock.elapsedRealtime()
binding.messageInputView.audioRecordDuration.start()
binding?.messageInputView?.audioRecordDuration?.base = SystemClock.elapsedRealtime()
binding?.messageInputView?.audioRecordDuration?.start()
val animation: Animation = AlphaAnimation(1.0f, 0.0f)
animation.duration = ANIMATION_DURATION
animation.interpolator = LinearInterpolator()
animation.repeatCount = Animation.INFINITE
animation.repeatMode = Animation.REVERSE
binding.messageInputView.microphoneEnabledInfo.startAnimation(animation)
binding?.messageInputView?.microphoneEnabledInfo?.startAnimation(animation)
recorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
@ -1227,8 +1207,8 @@ class ChatController(args: Bundle) :
@Suppress("Detekt.TooGenericExceptionCaught")
private fun stopAudioRecording() {
binding.messageInputView.audioRecordDuration.stop()
binding.messageInputView.microphoneEnabledInfo.clearAnimation()
binding?.messageInputView?.audioRecordDuration?.stop()
binding?.messageInputView?.microphoneEnabledInfo?.clearAnimation()
if (isVoiceRecordingInProgress) {
recorder?.apply {
@ -1301,9 +1281,9 @@ class ChatController(args: Bundle) :
shouldShowLobby() ||
!participantPermissions.hasChatPermission()
) {
binding.messageInputView.visibility = View.GONE
binding?.messageInputView?.visibility = View.GONE
} else {
binding.messageInputView.visibility = View.VISIBLE
binding?.messageInputView?.visibility = View.VISIBLE
}
}
}
@ -1359,10 +1339,10 @@ class ChatController(args: Bundle) :
}
if (shouldShowLobby()) {
binding.lobby.lobbyView.visibility = View.VISIBLE
binding.messagesListView.visibility = View.GONE
binding.messageInputView.visibility = View.GONE
binding.progressBar.visibility = View.GONE
binding?.lobby?.lobbyView?.visibility = View.VISIBLE
binding?.messagesListView?.visibility = View.GONE
binding?.messageInputView?.visibility = View.GONE
binding?.progressBar?.visibility = View.GONE
val sb = StringBuilder()
sb.append(resources!!.getText(R.string.nc_lobby_waiting))
@ -1383,11 +1363,11 @@ class ChatController(args: Bundle) :
}
sb.append(currentConversation!!.description)
binding.lobby.lobbyTextView.text = sb.toString()
binding?.lobby?.lobbyTextView?.text = sb.toString()
} else {
binding.lobby.lobbyView.visibility = View.GONE
binding.messagesListView.visibility = View.VISIBLE
binding.messageInputView.inputEditText?.visibility = View.VISIBLE
binding?.lobby?.lobbyView?.visibility = View.GONE
binding?.messagesListView?.visibility = View.VISIBLE
binding?.messageInputView?.inputEditText?.visibility = View.VISIBLE
if (isFirstMessagesProcessing && pastPreconditionFailed) {
pastPreconditionFailed = false
pullChatMessages(0)
@ -1397,9 +1377,9 @@ class ChatController(args: Bundle) :
}
}
} else {
binding.lobby.lobbyView.visibility = View.GONE
binding.messagesListView.visibility = View.VISIBLE
binding.messageInputView.inputEditText?.visibility = View.VISIBLE
binding?.lobby?.lobbyView?.visibility = View.GONE
binding?.messagesListView?.visibility = View.VISIBLE
binding?.messageInputView?.inputEditText?.visibility = View.VISIBLE
}
}
@ -1461,31 +1441,30 @@ class ChatController(args: Bundle) :
}
}
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(binding.messageInputView.context)
.setTitle(confirmationQuestion)
.setMessage(filenamesWithLineBreaks.toString())
.setPositiveButton(R.string.nc_yes) { _, _ ->
if (UploadAndShareFilesWorker.isStoragePermissionGranted(context)) {
uploadFiles(filesToUpload)
} else {
UploadAndShareFilesWorker.requestStoragePermission(this)
binding?.messageInputView?.context?.let {
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it)
.setTitle(confirmationQuestion)
.setMessage(filenamesWithLineBreaks.toString())
.setPositiveButton(R.string.nc_yes) { _, _ ->
if (UploadAndShareFilesWorker.isStoragePermissionGranted(context)) {
uploadFiles(filesToUpload)
} else {
UploadAndShareFilesWorker.requestStoragePermission(this)
}
}
.setNegativeButton(R.string.nc_no) { _, _ ->
// unused atm
}
}
.setNegativeButton(R.string.nc_no) { _, _ ->
// unused atm
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(
binding.messageInputView.context,
materialAlertDialogBuilder
)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it, materialAlertDialogBuilder)
val dialog = materialAlertDialogBuilder.show()
val dialog = materialAlertDialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
} catch (e: IllegalStateException) {
Toast.makeText(context, context.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG)
.show()
@ -1572,7 +1551,7 @@ class ChatController(args: Bundle) :
it.item is ChatMessage && (it.item as ChatMessage).id == messageId
}
if (position != null && position >= 0) {
binding.messagesListView.smoothScrollToPosition(position)
binding?.messagesListView?.smoothScrollToPosition(position)
} else {
// TODO show error that we don't have that message?
}
@ -1732,12 +1711,12 @@ class ChatController(args: Bundle) :
val callback = MentionAutocompleteCallback(
activity,
conversationUser!!,
binding.messageInputView.inputEditText,
binding?.messageInputView?.inputEditText,
viewThemeUtils
)
if (mentionAutocomplete == null && binding.messageInputView.inputEditText != null) {
mentionAutocomplete = Autocomplete.on<Mention>(binding.messageInputView.inputEditText)
if (mentionAutocomplete == null && binding?.messageInputView?.inputEditText != null) {
mentionAutocomplete = Autocomplete.on<Mention>(binding?.messageInputView?.inputEditText)
.with(elevation)
.with(backgroundDrawable)
.with(MagicCharPolicy('@'))
@ -1773,9 +1752,9 @@ class ChatController(args: Bundle) :
ApplicationWideCurrentRoomHolder.getInstance().currentRoomToken = roomToken
ApplicationWideCurrentRoomHolder.getInstance().userInRoom = conversationUser
val smileyButton = binding.messageInputView.findViewById<ImageButton>(R.id.smileyButton)
val smileyButton = binding?.messageInputView?.findViewById<ImageButton>(R.id.smileyButton)
emojiPopup = binding.messageInputView.inputEditText?.let {
emojiPopup = binding?.messageInputView?.inputEditText?.let {
EmojiPopup(
rootView = view,
editText = it,
@ -1793,7 +1772,7 @@ class ChatController(args: Bundle) :
},
onEmojiClickListener = {
try {
binding.messageInputView.inputEditText?.editableText?.append(" ")
binding?.messageInputView?.inputEditText?.editableText?.append(" ")
} catch (npe: NullPointerException) {
// view binding can be null
// since this is called asynchronously and UI might have been destroyed in the meantime
@ -1807,12 +1786,14 @@ class ChatController(args: Bundle) :
emojiPopup?.toggle()
}
binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.setOnClickListener {
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.setOnClickListener {
cancelReply()
}
viewThemeUtils.platform
.themeImageButton(binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton))
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.let {
viewThemeUtils.platform
.themeImageButton(it)
}
cancelNotificationsForCurrentConversation()
@ -1824,8 +1805,8 @@ class ChatController(args: Bundle) :
}
private fun cancelReply() {
binding.messageInputView.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility = View.GONE
binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
binding?.messageInputView?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility = View.GONE
binding?.messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
}
@Suppress("Detekt.TooGenericExceptionCaught")
@ -2087,8 +2068,8 @@ class ChatController(args: Bundle) :
}
private fun submitMessage(sendWithoutNotification: Boolean) {
if (binding.messageInputView.inputEditText != null) {
val editable = binding.messageInputView.inputEditText!!.editableText
if (binding?.messageInputView?.inputEditText != null) {
val editable = binding?.messageInputView?.inputEditText!!.editableText
val mentionSpans = editable.getSpans(
0,
editable.length,
@ -2104,7 +2085,7 @@ class ChatController(args: Bundle) :
editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@$mentionId")
}
binding.messageInputView.inputEditText?.setText("")
binding?.messageInputView?.inputEditText?.setText("")
val replyMessageId: Int? = view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.tag as Int?
sendMessage(
editable,
@ -2143,11 +2124,11 @@ class ChatController(args: Bundle) :
myFirstMessage = message
try {
if (binding.popupBubbleView.isShown) {
binding.popupBubbleView.hide()
if (binding?.popupBubbleView?.isShown == true) {
binding?.popupBubbleView?.hide()
}
binding.messagesListView.smoothScrollToPosition(0)
binding?.messagesListView?.smoothScrollToPosition(0)
} catch (npe: NullPointerException) {
// view binding can be null
// since this is called asynchronously and UI might have been destroyed in the meantime
@ -2161,11 +2142,11 @@ class ChatController(args: Bundle) :
if (code.toString().startsWith("2")) {
myFirstMessage = message
if (binding.popupBubbleView.isShown) {
binding.popupBubbleView.hide()
if (binding?.popupBubbleView?.isShown == true) {
binding?.popupBubbleView?.hide()
}
binding.messagesListView.smoothScrollToPosition(0)
binding?.messagesListView?.smoothScrollToPosition(0)
}
}
}
@ -2379,7 +2360,7 @@ class ChatController(args: Bundle) :
cancelNotificationsForCurrentConversation()
isFirstMessagesProcessing = false
binding.progressBar.visibility = View.GONE
binding?.progressBar?.visibility = View.GONE
}
historyRead = true
@ -2406,9 +2387,9 @@ class ChatController(args: Bundle) :
cancelNotificationsForCurrentConversation()
isFirstMessagesProcessing = false
binding.progressBar.visibility = View.GONE
binding?.progressBar?.visibility = View.GONE
binding.messagesListView.visibility = View.VISIBLE
binding?.messagesListView?.visibility = View.VISIBLE
}
if (isFromTheFuture) {
@ -2468,7 +2449,7 @@ class ChatController(args: Bundle) :
if (shouldAddNewMessagesNotice && adapter != null) {
layoutManager?.scrollToPositionWithOffset(
adapter!!.getMessagePositionByIdInReverse("-1"),
binding.messagesListView.height / 2
binding?.messagesListView?.height!! / 2
)
}
}
@ -2508,10 +2489,10 @@ class ChatController(args: Bundle) :
private fun modifyMessageCount(shouldAddNewMessagesNotice: Boolean, shouldScroll: Boolean) {
if (!shouldAddNewMessagesNotice && !shouldScroll) {
if (!binding.popupBubbleView.isShown) {
if (!binding?.popupBubbleView?.isShown!!) {
newMessagesCount = 1
binding.popupBubbleView.show()
} else if (binding.popupBubbleView.isShown) {
binding?.popupBubbleView?.show()
} else if (binding?.popupBubbleView?.isShown!!) {
newMessagesCount++
}
} else {
@ -2622,15 +2603,15 @@ class ChatController(args: Bundle) :
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_conversation, menu)
viewThemeUtils.platform.colorToolbarMenuIcon(
binding.messageInputView.context,
menu.findItem(R.id.conversation_voice_call)
)
binding?.messageInputView?.context?.let {
viewThemeUtils.platform.colorToolbarMenuIcon(
it, menu.findItem(R.id.conversation_voice_call)
)
viewThemeUtils.platform.colorToolbarMenuIcon(
binding.messageInputView.context,
menu.findItem(R.id.conversation_video_call)
)
viewThemeUtils.platform.colorToolbarMenuIcon(
it, menu.findItem(R.id.conversation_video_call)
)
}
if (conversationUser?.userId == "?") {
menu.removeItem(R.id.conversation_info)
@ -3148,25 +3129,21 @@ class ChatController(args: Bundle) :
fun replyToMessage(message: IMessage?) {
val chatMessage = message as ChatMessage?
chatMessage?.let {
binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
binding?.messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
View.GONE
binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
binding?.messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
View.VISIBLE
val quotedMessage = binding
.messageInputView
.findViewById<EmojiTextView>(R.id.quotedMessage)
val quotedMessage = binding?.messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)
quotedMessage?.maxLines = 2
quotedMessage?.ellipsize = TextUtils.TruncateAt.END
quotedMessage?.text = it.text
binding.messageInputView.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
binding?.messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
it.actorDisplayName ?: context.getText(R.string.nc_nick_guest)
conversationUser?.let { currentUser ->
val quotedMessageImage = binding
.messageInputView
.findViewById<ImageView>(R.id.quotedMessageImage)
conversationUser?.let {
val quotedMessageImage = binding?.messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)
chatMessage.imageUrl?.let { previewImageUrl ->
quotedMessageImage?.visibility = View.VISIBLE
@ -3184,16 +3161,12 @@ class ChatController(args: Bundle) :
addHeader("Authorization", credentials!!)
}
} ?: run {
binding
.messageInputView
.findViewById<ImageView>(R.id.quotedMessageImage)
?.visibility = View.GONE
binding?.messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
}
}
val quotedChatMessageView = binding
.messageInputView
.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
val quotedChatMessageView =
binding?.messageInputView?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
quotedChatMessageView?.tag = message?.jsonMessageId
quotedChatMessageView?.visibility = View.VISIBLE
}
@ -3201,11 +3174,11 @@ class ChatController(args: Bundle) :
private fun showMicrophoneButton(show: Boolean) {
if (show && CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "voice-message-sharing")) {
binding.messageInputView.messageSendButton.visibility = View.GONE
binding.messageInputView.recordAudioButton.visibility = View.VISIBLE
binding?.messageInputView?.messageSendButton?.visibility = View.GONE
binding?.messageInputView?.recordAudioButton?.visibility = View.VISIBLE
} else {
binding.messageInputView.messageSendButton.visibility = View.VISIBLE
binding.messageInputView.recordAudioButton.visibility = View.GONE
binding?.messageInputView?.messageSendButton?.visibility = View.VISIBLE
binding?.messageInputView?.recordAudioButton?.visibility = View.GONE
}
}
@ -3236,7 +3209,7 @@ class ChatController(args: Bundle) :
}
if (message.reactionsSelf == null) {
message.reactionsSelf = ArrayList<String>()
message.reactionsSelf = ArrayList()
}
var amount = message.reactions!![emoji]
@ -3254,7 +3227,7 @@ class ChatController(args: Bundle) :
}
if (message.reactionsSelf == null) {
message.reactionsSelf = ArrayList<String>()
message.reactionsSelf = ArrayList()
}
var amount = message.reactions!![emoji]

View File

@ -92,7 +92,7 @@ class ContactsController(args: Bundle) :
BaseController(R.layout.controller_contacts_rv),
SearchView.OnQueryTextListener,
FlexibleAdapter.OnItemClickListener {
private val binding: ControllerContactsRvBinding by viewBinding(ControllerContactsRvBinding::bind)
private val binding: ControllerContactsRvBinding? by viewBinding(ControllerContactsRvBinding::bind)
@Inject
lateinit var userManager: UserManager
@ -153,13 +153,13 @@ class ContactsController(args: Bundle) :
toggleConversationPrivacyLayout(!isPublicCall)
}
if (isAddingParticipantsView) {
binding.joinConversationViaLink.joinConversationViaLinkRelativeLayout.visibility = View.GONE
binding.conversationPrivacyToggle.callHeaderLayout.visibility = View.GONE
binding?.joinConversationViaLink?.joinConversationViaLinkRelativeLayout?.visibility = View.GONE
binding?.conversationPrivacyToggle?.callHeaderLayout?.visibility = View.GONE
} else {
binding.joinConversationViaLink.joinConversationViaLinkRelativeLayout.setOnClickListener {
binding?.joinConversationViaLink?.joinConversationViaLinkRelativeLayout?.setOnClickListener {
joinConversationViaLink()
}
binding.conversationPrivacyToggle.callHeaderLayout.setOnClickListener {
binding?.conversationPrivacyToggle?.callHeaderLayout?.setOnClickListener {
toggleCallHeader()
}
}
@ -382,10 +382,12 @@ class ContactsController(args: Bundle) :
super.onPrepareOptionsMenu(menu)
if (searchItem != null) {
viewThemeUtils.platform.colorToolbarMenuIcon(
binding.titleTextView.context,
searchItem!!
)
binding?.titleTextView?.let {
viewThemeUtils.platform.colorToolbarMenuIcon(
it.context,
searchItem!!
)
}
}
checkAndHandleDoneMenuItem()
@ -450,22 +452,16 @@ class ContactsController(args: Bundle) :
adapter?.filterItems()
}
withNullableControllerViewBinding {
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
}
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
}
override fun onError(e: Throwable) {
withNullableControllerViewBinding {
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
}
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
dispose(contactsQueryDisposable)
}
override fun onComplete() {
withNullableControllerViewBinding {
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
}
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
dispose(contactsQueryDisposable)
alreadyFetching = false
disengageProgressBar()
@ -627,31 +623,31 @@ class ContactsController(args: Bundle) :
private fun prepareViews() {
layoutManager = SmoothScrollLinearLayoutManager(activity)
binding.controllerGenericRv.recyclerView.layoutManager = layoutManager
binding.controllerGenericRv.recyclerView.setHasFixedSize(true)
binding.controllerGenericRv.recyclerView.adapter = adapter
binding.controllerGenericRv.swipeRefreshLayout.setOnRefreshListener { fetchData() }
binding?.controllerGenericRv?.recyclerView?.layoutManager = layoutManager
binding?.controllerGenericRv?.recyclerView?.setHasFixedSize(true)
binding?.controllerGenericRv?.recyclerView?.adapter = adapter
binding?.controllerGenericRv?.swipeRefreshLayout?.setOnRefreshListener { fetchData() }
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.controllerGenericRv.swipeRefreshLayout)
binding?.controllerGenericRv?.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it.swipeRefreshLayout) }
binding.joinConversationViaLink.joinConversationViaLinkImageView
.background
.setColorFilter(
binding?.joinConversationViaLink?.joinConversationViaLinkImageView
?.background
?.setColorFilter(
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
PorterDuff.Mode.SRC_IN
)
viewThemeUtils.platform.colorImageViewButton(binding.conversationPrivacyToggle.publicCallLink)
binding?.conversationPrivacyToggle?.let { viewThemeUtils.platform.colorImageViewButton(it.publicCallLink) }
disengageProgressBar()
}
private fun disengageProgressBar() {
if (!alreadyFetching) {
binding.loadingContent.visibility = View.GONE
binding.controllerGenericRv.root.visibility = View.VISIBLE
binding?.loadingContent?.visibility = View.GONE
binding?.controllerGenericRv?.root?.visibility = View.VISIBLE
if (isNewConversationView) {
binding.conversationPrivacyToggle.callHeaderLayout.visibility = View.VISIBLE
binding.joinConversationViaLink.joinConversationViaLinkRelativeLayout.visibility = View.VISIBLE
binding?.conversationPrivacyToggle?.callHeaderLayout?.visibility = View.VISIBLE
binding?.joinConversationViaLink?.joinConversationViaLinkRelativeLayout?.visibility = View.VISIBLE
}
}
}
@ -697,9 +693,7 @@ class ContactsController(args: Bundle) :
adapter?.updateDataSet(contactItems as List<Nothing>?)
}
withNullableControllerViewBinding {
binding.controllerGenericRv.swipeRefreshLayout.isEnabled = !adapter!!.hasFilter()
}
binding?.controllerGenericRv?.swipeRefreshLayout?.isEnabled = !adapter!!.hasFilter()
return true
}
@ -927,25 +921,21 @@ class ContactsController(args: Bundle) :
}
private fun toggleConversationPrivacyLayout(showInitialLayout: Boolean) {
withNullableControllerViewBinding {
if (showInitialLayout) {
binding.conversationPrivacyToggle.initialRelativeLayout.visibility = View.VISIBLE
binding.conversationPrivacyToggle.secondaryRelativeLayout.visibility = View.GONE
} else {
binding.conversationPrivacyToggle.initialRelativeLayout.visibility = View.GONE
binding.conversationPrivacyToggle.secondaryRelativeLayout.visibility = View.VISIBLE
}
if (showInitialLayout) {
binding?.conversationPrivacyToggle?.initialRelativeLayout?.visibility = View.VISIBLE
binding?.conversationPrivacyToggle?.secondaryRelativeLayout?.visibility = View.GONE
} else {
binding?.conversationPrivacyToggle?.initialRelativeLayout?.visibility = View.GONE
binding?.conversationPrivacyToggle?.secondaryRelativeLayout?.visibility = View.VISIBLE
}
}
private fun toggleConversationViaLinkVisibility(isPublicCall: Boolean) {
withNullableControllerViewBinding {
if (isPublicCall) {
binding.joinConversationViaLink.joinConversationViaLinkRelativeLayout.visibility = View.GONE
updateGroupParticipantSelection()
} else {
binding.joinConversationViaLink.joinConversationViaLinkRelativeLayout.visibility = View.VISIBLE
}
if (isPublicCall) {
binding?.joinConversationViaLink?.joinConversationViaLinkRelativeLayout?.visibility = View.GONE
updateGroupParticipantSelection()
} else {
binding?.joinConversationViaLink?.joinConversationViaLinkRelativeLayout?.visibility = View.VISIBLE
}
}

View File

@ -63,9 +63,9 @@ import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
import com.nextcloud.talk.events.EventStatus
import com.nextcloud.talk.extensions.loadAvatar
import com.nextcloud.talk.extensions.loadSystemAvatar
import com.nextcloud.talk.extensions.loadGroupCallAvatar
import com.nextcloud.talk.extensions.loadPublicCallAvatar
import com.nextcloud.talk.extensions.loadSystemAvatar
import com.nextcloud.talk.jobs.DeleteConversationWorker
import com.nextcloud.talk.jobs.LeaveConversationWorker
import com.nextcloud.talk.models.json.conversations.Conversation
@ -107,7 +107,7 @@ class ConversationInfoController(args: Bundle) :
),
FlexibleAdapter.OnItemClickListener {
private val binding: ControllerConversationInfoBinding by viewBinding(ControllerConversationInfoBinding::bind)
private val binding: ControllerConversationInfoBinding? by viewBinding(ControllerConversationInfoBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -173,19 +173,19 @@ class ConversationInfoController(args: Bundle) :
databaseStorageModule = DatabaseStorageModule(conversationUser!!, conversationToken)
}
binding.notificationSettingsView.notificationSettings.setStorageModule(databaseStorageModule)
binding.webinarInfoView.webinarSettings.setStorageModule(databaseStorageModule)
binding.guestAccessView.guestAccessSettings.setStorageModule(databaseStorageModule)
binding?.notificationSettingsView?.notificationSettings?.setStorageModule(databaseStorageModule)
binding?.webinarInfoView?.webinarSettings?.setStorageModule(databaseStorageModule)
binding?.guestAccessView?.guestAccessSettings?.setStorageModule(databaseStorageModule)
binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog() }
binding.leaveConversationAction.setOnClickListener { leaveConversation() }
binding.clearConversationHistory.setOnClickListener { showClearHistoryDialog() }
binding.addParticipantsAction.setOnClickListener { addParticipants() }
binding?.deleteConversationAction?.setOnClickListener { showDeleteConversationDialog() }
binding?.leaveConversationAction?.setOnClickListener { leaveConversation() }
binding?.clearConversationHistory?.setOnClickListener { showClearHistoryDialog() }
binding?.addParticipantsAction?.setOnClickListener { addParticipants() }
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "rich-object-list-media")) {
binding.showSharedItemsAction.setOnClickListener { showSharedItems() }
binding?.showSharedItemsAction?.setOnClickListener { showSharedItems() }
} else {
binding.categorySharedItems.visibility = GONE
binding?.categorySharedItems?.visibility = GONE
}
fetchRoomInfo()
@ -195,19 +195,19 @@ class ConversationInfoController(args: Bundle) :
}
private fun themeSwitchPreferences() {
binding.run {
binding?.run {
listOf(
binding.webinarInfoView.conversationInfoLobby,
binding.notificationSettingsView.callNotifications,
binding.notificationSettingsView.conversationInfoPriorityConversation,
binding.guestAccessView.guestAccessAllowSwitch,
binding.guestAccessView.guestAccessPasswordSwitch
binding?.webinarInfoView?.conversationInfoLobby!!,
binding?.notificationSettingsView?.callNotifications!!,
binding?.notificationSettingsView?.conversationInfoPriorityConversation!!,
binding?.guestAccessView?.guestAccessAllowSwitch!!,
binding?.guestAccessView?.guestAccessPasswordSwitch!!
).forEach(viewThemeUtils.talk::colorSwitchPreference)
}
}
private fun themeCategories() {
binding.run {
binding?.run {
listOf(
conversationInfoName,
conversationDescription,
@ -216,9 +216,9 @@ class ConversationInfoController(args: Bundle) :
ownOptions,
categorySharedItems,
categoryConversationSettings,
binding.guestAccessView.guestAccessCategory,
binding.webinarInfoView.conversationInfoWebinar,
binding.notificationSettingsView.notificationSettingsCategory
binding?.guestAccessView?.guestAccessCategory!!,
binding?.webinarInfoView?.conversationInfoWebinar!!,
binding?.notificationSettingsView?.notificationSettingsCategory!!
).forEach(viewThemeUtils.talk::colorPreferenceCategory)
}
}
@ -237,9 +237,9 @@ class ConversationInfoController(args: Bundle) :
override fun onViewBound(view: View) {
super.onViewBound(view)
binding.addParticipantsAction.visibility = GONE
binding?.addParticipantsAction?.visibility = GONE
viewThemeUtils.platform.colorCircularProgressBar(binding.progressBar)
binding?.progressBar?.let { viewThemeUtils.platform.colorCircularProgressBar(it) }
}
private fun setupWebinaryView() {
@ -247,16 +247,16 @@ class ConversationInfoController(args: Bundle) :
webinaryRoomType(conversation!!) &&
conversation!!.canModerate(conversationUser!!)
) {
binding.webinarInfoView.webinarSettings.visibility = VISIBLE
binding?.webinarInfoView?.webinarSettings?.visibility = VISIBLE
val isLobbyOpenToModeratorsOnly =
conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
(binding?.webinarInfoView?.conversationInfoLobby?.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
.isChecked = isLobbyOpenToModeratorsOnly
reconfigureLobbyTimerView()
binding.webinarInfoView.startTimePreferences.setOnClickListener {
binding?.webinarInfoView?.startTimePreferences?.setOnClickListener {
MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
val currentTimeCalendar = Calendar.getInstance()
if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != 0L) {
@ -277,13 +277,13 @@ class ConversationInfoController(args: Bundle) :
}
}
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
(binding?.webinarInfoView?.conversationInfoLobby?.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
.setOnCheckedChangeListener { _, _ ->
reconfigureLobbyTimerView()
submitLobbyChanges()
}
} else {
binding.webinarInfoView.webinarSettings.visibility = GONE
binding?.webinarInfoView?.webinarSettings?.visibility = GONE
}
}
@ -294,7 +294,7 @@ class ConversationInfoController(args: Bundle) :
private fun reconfigureLobbyTimerView(dateTime: Calendar? = null) {
val isChecked =
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
(binding?.webinarInfoView?.conversationInfoLobby?.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
.isChecked
if (dateTime != null && isChecked) {
@ -313,25 +313,25 @@ class ConversationInfoController(args: Bundle) :
conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE &&
conversation!!.lobbyTimer != 0L
) {
binding.webinarInfoView.startTimePreferences.setSummary(
binding?.webinarInfoView?.startTimePreferences?.setSummary(
dateUtils.getLocalDateTimeStringFromTimestamp(
conversation!!.lobbyTimer!! * DateConstants.SECOND_DIVIDER,
)
)
} else {
binding.webinarInfoView.startTimePreferences.setSummary(R.string.nc_manual)
binding?.webinarInfoView?.startTimePreferences?.setSummary(R.string.nc_manual)
}
if (isChecked) {
binding.webinarInfoView.startTimePreferences.visibility = VISIBLE
binding?.webinarInfoView?.startTimePreferences?.visibility = VISIBLE
} else {
binding.webinarInfoView.startTimePreferences.visibility = GONE
binding?.webinarInfoView?.startTimePreferences?.visibility = GONE
}
}
fun submitLobbyChanges() {
val state = if (
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
(binding?.webinarInfoView?.conversationInfoLobby?.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
.isChecked
) 1 else 0
@ -376,23 +376,30 @@ class ConversationInfoController(args: Bundle) :
private fun showDeleteConversationDialog() {
if (activity != null) {
val dialogBuilder = MaterialAlertDialogBuilder(binding.conversationInfoName.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp))
.setTitle(R.string.nc_delete_call)
.setMessage(R.string.nc_delete_conversation_more)
.setPositiveButton(R.string.nc_delete) { _, _ ->
deleteConversation()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(binding.conversationInfoName.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
binding?.conversationInfoName?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
context, R.drawable.ic_delete_black_24dp
)
)
.setTitle(R.string.nc_delete_call)
.setMessage(R.string.nc_delete_conversation_more)
.setPositiveButton(R.string.nc_delete) { _, _ ->
deleteConversation()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
}
@ -403,9 +410,9 @@ class ConversationInfoController(args: Bundle) :
}
val layoutManager = SmoothScrollLinearLayoutManager(activity)
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter
binding?.recyclerView?.layoutManager = layoutManager
binding?.recyclerView?.setHasFixedSize(true)
binding?.recyclerView?.adapter = adapter
adapter!!.addListener(this)
}
@ -446,7 +453,7 @@ class ConversationInfoController(args: Bundle) :
setupAdapter()
binding.participantsListCategory.visibility = VISIBLE
binding?.participantsListCategory?.visibility = VISIBLE
adapter!!.updateDataSet(userItems)
}
@ -548,23 +555,30 @@ class ConversationInfoController(args: Bundle) :
private fun showClearHistoryDialog() {
if (activity != null) {
val dialogBuilder = MaterialAlertDialogBuilder(binding.conversationInfoName.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp))
.setTitle(R.string.nc_clear_history)
.setMessage(R.string.nc_clear_history_warning)
.setPositiveButton(R.string.nc_delete_all) { _, _ ->
clearHistory()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(binding.conversationInfoName.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
binding?.conversationInfoName?.context?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it)
.setIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
context, R.drawable.ic_delete_black_24dp
)
)
.setTitle(R.string.nc_clear_history)
.setMessage(R.string.nc_clear_history_warning)
.setPositiveButton(R.string.nc_delete_all) { _, _ ->
clearHistory()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
}
@ -638,70 +652,72 @@ class ConversationInfoController(args: Bundle) :
val conversationCopy = conversation
if (conversationCopy!!.canModerate(conversationUser)) {
binding.addParticipantsAction.visibility = VISIBLE
binding?.addParticipantsAction?.visibility = VISIBLE
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "clear-history")) {
binding.clearConversationHistory.visibility = VISIBLE
binding?.clearConversationHistory?.visibility = VISIBLE
} else {
binding.clearConversationHistory.visibility = GONE
binding?.clearConversationHistory?.visibility = GONE
}
} else {
binding.addParticipantsAction.visibility = GONE
binding.clearConversationHistory.visibility = GONE
binding?.addParticipantsAction?.visibility = GONE
binding?.clearConversationHistory?.visibility = GONE
}
if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
binding.ownOptions.visibility = VISIBLE
binding?.ownOptions?.visibility = VISIBLE
setupWebinaryView()
if (!conversation!!.canLeave()) {
binding.leaveConversationAction.visibility = GONE
binding?.leaveConversationAction?.visibility = GONE
} else {
binding.leaveConversationAction.visibility = VISIBLE
binding?.leaveConversationAction?.visibility = VISIBLE
}
if (!conversation!!.canDelete(conversationUser)) {
binding.deleteConversationAction.visibility = GONE
binding?.deleteConversationAction?.visibility = GONE
} else {
binding.deleteConversationAction.visibility = VISIBLE
binding?.deleteConversationAction?.visibility = VISIBLE
}
if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
binding.notificationSettingsView.callNotifications.visibility = GONE
binding?.notificationSettingsView?.callNotifications?.visibility = GONE
}
if (conversation!!.notificationCalls === null) {
binding.notificationSettingsView.callNotifications.visibility = GONE
binding?.notificationSettingsView?.callNotifications?.visibility = GONE
} else {
binding.notificationSettingsView.callNotifications.value =
binding?.notificationSettingsView?.callNotifications?.value =
conversationCopy.notificationCalls == 1
}
getListOfParticipants()
binding.progressBar.visibility = GONE
binding?.progressBar?.visibility = GONE
binding.conversationInfoName.visibility = VISIBLE
binding?.conversationInfoName?.visibility = VISIBLE
binding.displayNameText.text = conversation!!.displayName
binding?.displayNameText?.text = conversation!!.displayName
if (conversation!!.description != null && !conversation!!.description!!.isEmpty()) {
binding.descriptionText.text = conversation!!.description
binding.conversationDescription.visibility = VISIBLE
binding?.descriptionText?.text = conversation!!.description
binding?.conversationDescription?.visibility = VISIBLE
}
loadConversationAvatar()
adjustNotificationLevelUI()
initExpiringMessageOption()
GuestAccessHelper(
this@ConversationInfoController,
binding,
conversation!!,
conversationUser
).setupGuestAccess()
binding?.let {
GuestAccessHelper(
this@ConversationInfoController,
it,
conversation!!,
conversationUser
).setupGuestAccess()
}
binding.notificationSettingsView.notificationSettings.visibility = VISIBLE
binding?.notificationSettingsView?.notificationSettings?.visibility = VISIBLE
}
} catch (npe: NullPointerException) {
// view binding can be null
@ -725,11 +741,11 @@ class ConversationInfoController(args: Bundle) :
CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "message-expiration")
) {
databaseStorageModule?.setMessageExpiration(conversation!!.messageExpiration)
binding.conversationInfoExpireMessages.setStorageModule(databaseStorageModule)
binding.conversationInfoExpireMessages.visibility = View.VISIBLE
binding.conversationInfoExpireMessagesExplanation.visibility = View.VISIBLE
binding?.conversationInfoExpireMessages?.setStorageModule(databaseStorageModule)
binding?.conversationInfoExpireMessages?.visibility = VISIBLE
binding?.conversationInfoExpireMessagesExplanation?.visibility = VISIBLE
} else {
binding.categoryConversationSettings.visibility = View.GONE
binding?.categoryConversationSettings?.visibility = GONE
}
}
@ -739,8 +755,8 @@ class ConversationInfoController(args: Bundle) :
conversationUser != null &&
CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "notification-levels")
) {
binding.notificationSettingsView.conversationInfoMessageNotifications.isEnabled = true
binding.notificationSettingsView.conversationInfoMessageNotifications.alpha = 1.0f
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.isEnabled = true
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.alpha = 1.0f
if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) {
val stringValue: String =
@ -751,13 +767,13 @@ class ConversationInfoController(args: Bundle) :
else -> "mention"
}
binding.notificationSettingsView.conversationInfoMessageNotifications.value = stringValue
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.value = stringValue
} else {
setProperNotificationValue(conversation)
}
} else {
binding.notificationSettingsView.conversationInfoMessageNotifications.isEnabled = false
binding.notificationSettingsView.conversationInfoMessageNotifications.alpha = LOW_EMPHASIS_OPACITY
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.isEnabled = false
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.alpha = LOW_EMPHASIS_OPACITY
setProperNotificationValue(conversation)
}
}
@ -767,28 +783,28 @@ class ConversationInfoController(args: Bundle) :
if (conversation!!.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
// hack to see if we get mentioned always or just on mention
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "mention-flag")) {
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "always"
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.value = "always"
} else {
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "mention"
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.value = "mention"
}
} else {
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "mention"
binding?.notificationSettingsView?.conversationInfoMessageNotifications?.value = "mention"
}
}
private fun loadConversationAvatar() {
when (conversation!!.type) {
Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(conversation!!.name)) {
conversation!!.name?.let { binding.avatarImage.loadAvatar(conversationUser!!, it) }
conversation!!.name?.let { binding?.avatarImage?.loadAvatar(conversationUser!!, it) }
}
Conversation.ConversationType.ROOM_GROUP_CALL -> {
binding.avatarImage.loadGroupCallAvatar(viewThemeUtils)
binding?.avatarImage?.loadGroupCallAvatar(viewThemeUtils)
}
Conversation.ConversationType.ROOM_PUBLIC_CALL -> {
binding.avatarImage.loadPublicCallAvatar(viewThemeUtils)
binding?.avatarImage?.loadPublicCallAvatar(viewThemeUtils)
}
Conversation.ConversationType.ROOM_SYSTEM -> {
binding.avatarImage.loadSystemAvatar()
binding?.avatarImage?.loadSystemAvatar()
}
else -> {

View File

@ -157,7 +157,7 @@ class ConversationsListController(bundle: Bundle) :
@Inject
lateinit var unifiedSearchRepository: UnifiedSearchRepository
private val binding: ControllerConversationsRvBinding by viewBinding(ControllerConversationsRvBinding::bind)
private val binding: ControllerConversationsRvBinding? by viewBinding(ControllerConversationsRvBinding::bind)
override val title: String
get() = resources!!.getString(R.string.nc_app_product_name)
@ -200,7 +200,7 @@ class ConversationsListController(bundle: Bundle) :
if (adapter == null) {
adapter = FlexibleAdapter(conversationItems, activity, true)
} else {
binding.loadingContent.visibility = View.GONE
binding?.loadingContent?.visibility = View.GONE
}
adapter!!.addListener(this)
prepareViews()
@ -409,9 +409,7 @@ class ConversationsListController(bundle: Bundle) :
adapter!!.setHeadersShown(true)
adapter!!.updateDataSet(searchableConversationItems, false)
adapter!!.showAllHeaders()
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isEnabled = false
}
binding?.swipeRefreshLayoutView?.isEnabled = false
return true
}
@ -422,11 +420,9 @@ class ConversationsListController(bundle: Bundle) :
if (searchHelper != null) {
// cancel any pending searches
searchHelper!!.cancelSearch()
binding.swipeRefreshLayoutView.isRefreshing = false
}
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isEnabled = true
binding?.swipeRefreshLayoutView?.isRefreshing = false
}
binding?.swipeRefreshLayoutView?.isEnabled = true
searchView!!.onActionViewCollapsed()
val mainActivity = getActivity() as MainActivity?
if (mainActivity != null) {
@ -441,7 +437,7 @@ class ConversationsListController(bundle: Bundle) :
.resetStatusBar(mainActivity)
}
}
val layoutManager = binding.recyclerView.layoutManager as SmoothScrollLinearLayoutManager?
val layoutManager = binding?.recyclerView?.layoutManager as SmoothScrollLinearLayoutManager?
layoutManager?.scrollToPositionWithOffset(0, 0)
return true
}
@ -503,7 +499,7 @@ class ConversationsListController(bundle: Bundle) :
}
if (adapterWasNull) {
adapterWasNull = false
binding.loadingContent.visibility = View.GONE
binding?.loadingContent?.visibility = View.GONE
}
initOverallLayout(ocs!!.data!!.isNotEmpty())
for (conversation in ocs.data!!) {
@ -514,39 +510,33 @@ class ConversationsListController(bundle: Bundle) :
adapter!!.updateDataSet(conversationItems, false)
Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong())
fetchOpenConversations(apiVersion)
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = false
}
binding?.swipeRefreshLayoutView?.isRefreshing = false
}, { throwable: Throwable ->
handleHttpExceptions(throwable)
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = false
showErrorDialog()
}
binding?.swipeRefreshLayoutView?.isRefreshing = false
showErrorDialog()
dispose(roomsQueryDisposable)
}) {
dispose(roomsQueryDisposable)
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = false
}
binding?.swipeRefreshLayoutView?.isRefreshing = false
isRefreshing = false
}
}
private fun initOverallLayout(isConversationListNotEmpty: Boolean) {
if (isConversationListNotEmpty) {
if (binding.emptyLayout.visibility != View.GONE) {
binding.emptyLayout.visibility = View.GONE
if (binding?.emptyLayout?.visibility != View.GONE) {
binding?.emptyLayout?.visibility = View.GONE
}
if (binding.swipeRefreshLayoutView.visibility != View.VISIBLE) {
binding.swipeRefreshLayoutView.visibility = View.VISIBLE
if (binding?.swipeRefreshLayoutView?.visibility != View.VISIBLE) {
binding?.swipeRefreshLayoutView?.visibility = View.VISIBLE
}
} else {
if (binding.emptyLayout.visibility != View.VISIBLE) {
binding.emptyLayout.visibility = View.VISIBLE
if (binding?.emptyLayout?.visibility != View.VISIBLE) {
binding?.emptyLayout?.visibility = View.VISIBLE
}
if (binding.swipeRefreshLayoutView.visibility != View.GONE) {
binding.swipeRefreshLayoutView.visibility = View.GONE
if (binding?.swipeRefreshLayoutView?.visibility != View.GONE) {
binding?.swipeRefreshLayoutView?.visibility = View.GONE
}
}
}
@ -584,21 +574,24 @@ class ConversationsListController(bundle: Bundle) :
}
private fun showErrorDialog() {
val dialogBuilder = MaterialAlertDialogBuilder(binding.floatingActionButton.context)
.setIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
context,
R.drawable.ic_baseline_error_outline_24dp,
binding?.floatingActionButton?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
context,
R.drawable.ic_baseline_error_outline_24dp,
)
)
.setTitle(R.string.error_loading_chats)
.setCancelable(false)
.setNegativeButton(R.string.close, null)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
.setTitle(R.string.error_loading_chats)
.setCancelable(false)
.setNegativeButton(R.string.close, null)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
private fun sortConversations(conversationItems: MutableList<AbstractFlexibleItem<*>>) {
@ -678,10 +671,10 @@ class ConversationsListController(bundle: Bundle) :
@SuppressLint("ClickableViewAccessibility")
private fun prepareViews() {
layoutManager = SmoothScrollLinearLayoutManager(Objects.requireNonNull(activity))
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
binding?.recyclerView?.layoutManager = layoutManager
binding?.recyclerView?.setHasFixedSize(true)
binding?.recyclerView?.adapter = adapter
binding?.recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
@ -689,21 +682,21 @@ class ConversationsListController(bundle: Bundle) :
}
}
})
binding.recyclerView.setOnTouchListener { v: View, _: MotionEvent? ->
binding?.recyclerView?.setOnTouchListener { v: View, _: MotionEvent? ->
if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
}
false
}
binding.swipeRefreshLayoutView.setOnRefreshListener { fetchRooms() }
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeRefreshLayoutView)
binding.emptyLayout.setOnClickListener { showNewConversationsScreen() }
binding.floatingActionButton.setOnClickListener {
binding?.swipeRefreshLayoutView?.setOnRefreshListener { fetchRooms() }
binding?.swipeRefreshLayoutView?.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it) }
binding?.emptyLayout?.setOnClickListener { showNewConversationsScreen() }
binding?.floatingActionButton?.setOnClickListener {
run(context)
showNewConversationsScreen()
}
viewThemeUtils.material.themeFAB(binding.floatingActionButton)
binding?.floatingActionButton?.let { viewThemeUtils.material.themeFAB(it) }
if (activity != null && activity is MainActivity) {
val activity = activity as MainActivity?
activity!!.binding.switchAccountButton.setOnClickListener {
@ -722,13 +715,13 @@ class ConversationsListController(bundle: Bundle) :
}
}
}
binding.newMentionPopupBubble.hide()
binding.newMentionPopupBubble.setPopupBubbleListener {
binding.recyclerView.smoothScrollToPosition(
binding?.newMentionPopupBubble?.hide()
binding?.newMentionPopupBubble?.setPopupBubbleListener {
binding?.recyclerView?.smoothScrollToPosition(
nextUnreadConversationScrollPosition
)
}
viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.newMentionPopupBubble)
binding?.newMentionPopupBubble?.let { viewThemeUtils.material.colorMaterialButtonPrimaryFilled(it) }
}
@Suppress("Detekt.TooGenericExceptionCaught")
@ -740,14 +733,14 @@ class ConversationsListController(bundle: Bundle) :
val position = adapter!!.getGlobalPositionOf(flexItem)
if (hasUnreadItems(conversation) && position > lastVisibleItem) {
nextUnreadConversationScrollPosition = position
if (!binding.newMentionPopupBubble.isShown) {
binding.newMentionPopupBubble.show()
if (!binding?.newMentionPopupBubble?.isShown!!) {
binding?.newMentionPopupBubble?.show()
}
return
}
}
nextUnreadConversationScrollPosition = 0
binding.newMentionPopupBubble.hide()
binding?.newMentionPopupBubble?.hide()
} catch (e: NullPointerException) {
Log.d(
TAG,
@ -851,9 +844,7 @@ class ConversationsListController(bundle: Bundle) :
@SuppressLint("CheckResult") // handled by helper
private fun startMessageSearch(search: String?) {
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = true
}
binding?.swipeRefreshLayoutView?.isRefreshing = true
searchHelper?.startMessageSearch(search!!)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
@ -866,7 +857,7 @@ class ConversationsListController(bundle: Bundle) :
@SuppressLint("CheckResult") // handled by helper
private fun loadMoreMessages() {
binding.swipeRefreshLayoutView.isRefreshing = true
binding?.swipeRefreshLayoutView?.isRefreshing = true
val observable = searchHelper!!.loadMore()
observable?.observeOn(AndroidSchedulers.mainThread())
?.subscribe({ results: MessageSearchResults -> onMessageSearchResult(results) }) { throwable: Throwable ->
@ -977,24 +968,27 @@ class ConversationsListController(bundle: Bundle) :
selectedConversation!!.displayName
)
}
val dialogBuilder = MaterialAlertDialogBuilder(binding.floatingActionButton.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.upload))
.setTitle(confirmationQuestion)
.setMessage(fileNamesWithLineBreaks.toString())
.setPositiveButton(R.string.nc_yes) { _, _ ->
upload()
openConversation()
}
.setNegativeButton(R.string.nc_no) { _, _ ->
Log.d(TAG, "sharing files aborted, going back to share-to screen")
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
binding?.floatingActionButton?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.upload))
.setTitle(confirmationQuestion)
.setMessage(fileNamesWithLineBreaks.toString())
.setPositiveButton(R.string.nc_yes) { _, _ ->
upload()
openConversation()
}
.setNegativeButton(R.string.nc_no) { _, _ ->
Log.d(TAG, "sharing files aborted, going back to share-to screen")
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
} else {
requestStoragePermission(this@ConversationsListController)
}
@ -1161,33 +1155,36 @@ class ConversationsListController(bundle: Bundle) :
) {
val conversation = Parcels.unwrap<Conversation>(conversationMenuBundle!!.getParcelable(KEY_ROOM))
if (conversation != null) {
val dialogBuilder = MaterialAlertDialogBuilder(binding.floatingActionButton.context)
.setIcon(
viewThemeUtils.dialog
.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp)
)
.setTitle(R.string.nc_delete_call)
.setMessage(R.string.nc_delete_conversation_more)
.setPositiveButton(R.string.nc_delete) { _, _ ->
val data = Data.Builder()
data.putLong(
KEY_INTERNAL_USER_ID,
conversationMenuBundle!!.getLong(KEY_INTERNAL_USER_ID)
binding?.floatingActionButton?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(
viewThemeUtils.dialog
.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp)
)
data.putString(KEY_ROOM_TOKEN, conversation.token)
conversationMenuBundle = null
deleteConversation(data.build())
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
conversationMenuBundle = null
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
.setTitle(R.string.nc_delete_call)
.setMessage(R.string.nc_delete_conversation_more)
.setPositiveButton(R.string.nc_delete) { _, _ ->
val data = Data.Builder()
data.putLong(
KEY_INTERNAL_USER_ID,
conversationMenuBundle!!.getLong(KEY_INTERNAL_USER_ID)
)
data.putString(KEY_ROOM_TOKEN, conversation.token)
conversationMenuBundle = null
deleteConversation(data.build())
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
conversationMenuBundle = null
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
}
}
@ -1198,12 +1195,62 @@ class ConversationsListController(bundle: Bundle) :
private fun showUnauthorizedDialog() {
if (activity != null) {
val dialogBuilder = MaterialAlertDialogBuilder(binding.floatingActionButton.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp))
.setTitle(R.string.nc_dialog_invalid_password)
.setMessage(R.string.nc_dialog_reauth_or_delete)
binding?.floatingActionButton?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
context, R.drawable.ic_delete_black_24dp
)
)
.setTitle(R.string.nc_dialog_invalid_password)
.setMessage(R.string.nc_dialog_reauth_or_delete)
.setCancelable(false)
.setPositiveButton(R.string.nc_delete) { _, _ ->
val otherUserExists = userManager
.scheduleUserForDeletionWithId(currentUser!!.id!!)
.blockingGet()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
WorkManager.getInstance().enqueue(accountRemovalWork)
if (otherUserExists && view != null) {
onViewBound(view!!)
onAttach(view!!)
} else if (!otherUserExists) {
router.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
}
.setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
router.pushController(
RouterTransaction.with(
WebViewLoginController(currentUser!!.baseUrl, true)
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
}
private fun showServerEOLDialog() {
binding?.floatingActionButton?.let {
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_warning_white))
.setTitle(R.string.nc_settings_server_eol_title)
.setMessage(R.string.nc_settings_server_eol)
.setCancelable(false)
.setPositiveButton(R.string.nc_delete) { _, _ ->
.setPositiveButton(R.string.nc_settings_remove_account) { _, _ ->
val otherUserExists = userManager
.scheduleUserForDeletionWithId(currentUser!!.id!!)
.blockingGet()
@ -1214,23 +1261,24 @@ class ConversationsListController(bundle: Bundle) :
onAttach(view!!)
} else if (!otherUserExists) {
router.setRoot(
RouterTransaction.with(ServerSelectionController())
RouterTransaction.with(
ServerSelectionController()
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
}
.setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
router.pushController(
RouterTransaction.with(
WebViewLoginController(currentUser!!.baseUrl, true)
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
.setNegativeButton(R.string.nc_cancel) { _, _ ->
if (userManager.users.blockingGet().isNotEmpty()) {
router.pushController(RouterTransaction.with(SwitchAccountController()))
} else {
activity!!.finishAffinity()
activity!!.finish()
}
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
@ -1239,47 +1287,6 @@ class ConversationsListController(bundle: Bundle) :
}
}
private fun showServerEOLDialog() {
val dialogBuilder = MaterialAlertDialogBuilder(binding.floatingActionButton.context)
.setIcon(viewThemeUtils.dialog.colorMaterialAlertDialogIcon(context, R.drawable.ic_warning_white))
.setTitle(R.string.nc_settings_server_eol_title)
.setMessage(R.string.nc_settings_server_eol)
.setCancelable(false)
.setPositiveButton(R.string.nc_settings_remove_account) { _, _ ->
val otherUserExists = userManager
.scheduleUserForDeletionWithId(currentUser!!.id!!)
.blockingGet()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
WorkManager.getInstance().enqueue(accountRemovalWork)
if (otherUserExists && view != null) {
onViewBound(view!!)
onAttach(view!!)
} else if (!otherUserExists) {
router.setRoot(
RouterTransaction.with(
ServerSelectionController()
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
if (userManager.users.blockingGet().isNotEmpty()) {
router.pushController(RouterTransaction.with(SwitchAccountController()))
} else {
activity!!.finishAffinity()
activity!!.finish()
}
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
private fun deleteConversation(data: Data) {
val deleteConversationWorker =
OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data).build()
@ -1309,20 +1316,16 @@ class ConversationsListController(bundle: Bundle) :
}
// add unified search result at the end of the list
adapter!!.addItems(adapter!!.mainItemCount + adapter!!.scrollableHeaders.size, adapterItems)
binding.recyclerView.scrollToPosition(0)
binding?.recyclerView?.scrollToPosition(0)
}
}
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = false
}
binding?.swipeRefreshLayoutView?.isRefreshing = false
}
private fun onMessageSearchError(throwable: Throwable) {
handleHttpExceptions(throwable)
withNullableControllerViewBinding {
binding.swipeRefreshLayoutView.isRefreshing = false
showErrorDialog()
}
binding?.swipeRefreshLayoutView?.isRefreshing = false
showErrorDialog()
}
companion object {

View File

@ -63,7 +63,7 @@ class GeocodingController(args: Bundle) :
args
),
SearchView.OnQueryTextListener {
private val binding: ControllerGeocodingBinding by viewBinding(ControllerGeocodingBinding::bind)
private val binding: ControllerGeocodingBinding? by viewBinding(ControllerGeocodingBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -94,8 +94,8 @@ class GeocodingController(args: Bundle) :
}
private fun initAdapter(addresses: List<Address>) {
adapter = GeocodingAdapter(binding.geocodingResults.context!!, addresses)
binding.geocodingResults.adapter = adapter
adapter = GeocodingAdapter(binding?.geocodingResults?.context!!, addresses)
binding?.geocodingResults?.adapter = adapter
}
override fun onAttach(view: View) {
@ -110,7 +110,7 @@ class GeocodingController(args: Bundle) :
Log.e(TAG, "search string that was passed to GeocodingController was null or empty")
}
binding.geocodingResults.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
binding?.geocodingResults?.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
val address: Address = adapter.getItem(position) as Address
val listener: GeocodingResultListener? = targetController as GeocodingResultListener?
listener?.receiveChosenGeocodingResult(address.latitude, address.longitude, address.displayName)

View File

@ -90,7 +90,7 @@ class LocationPickerController(args: Bundle) :
SearchView.OnQueryTextListener,
LocationListener,
GeocodingController.GeocodingResultListener {
private val binding: ControllerLocationBinding by viewBinding(ControllerLocationBinding::bind)
private val binding: ControllerLocationBinding? by viewBinding(ControllerLocationBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -164,13 +164,13 @@ class LocationPickerController(args: Bundle) :
override fun onViewBound(view: View) {
setLocationDescription(false, receivedChosenGeocodingResult)
binding.shareLocation.isClickable = false
binding.shareLocation.setOnClickListener {
binding?.shareLocation?.isClickable = false
binding?.shareLocation?.setOnClickListener {
if (readyToShareLocation) {
shareLocation(
binding.map.mapCenter?.latitude,
binding.map.mapCenter?.longitude,
binding.placeName.text.toString()
binding?.map?.mapCenter?.latitude,
binding?.map?.mapCenter?.longitude,
binding?.placeName?.text.toString()
)
} else {
Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
@ -217,8 +217,8 @@ class LocationPickerController(args: Bundle) :
@Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod")
private fun initMap() {
binding.map.setTileSource(TileSourceFactory.MAPNIK)
binding.map.onResume()
binding?.map?.setTileSource(TileSourceFactory.MAPNIK)
binding?.map?.onResume()
locationManager = activity!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
@ -229,12 +229,12 @@ class LocationPickerController(args: Bundle) :
}
val copyrightOverlay = CopyrightOverlay(context)
binding.map.overlays?.add(copyrightOverlay)
binding?.map?.overlays?.add(copyrightOverlay)
binding.map.setMultiTouchControls(true)
binding.map.isTilesScaledToDpi = true
binding?.map?.setMultiTouchControls(true)
binding?.map?.isTilesScaledToDpi = true
locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding.map)
locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding?.map)
locationOverlay.enableMyLocation()
locationOverlay.setPersonHotspot(PERSON_HOT_SPOT_X, PERSON_HOT_SPOT_Y)
locationOverlay.setPersonIcon(
@ -242,9 +242,9 @@ class LocationPickerController(args: Bundle) :
ResourcesCompat.getDrawable(resources!!, R.drawable.current_location_circle, null)
)
)
binding.map.overlays?.add(locationOverlay)
binding?.map?.overlays?.add(locationOverlay)
val mapController = binding.map.controller
val mapController = binding?.map?.controller
if (receivedChosenGeocodingResult) {
mapController?.setZoom(ZOOM_LEVEL_RECEIVED_RESULT)
@ -273,16 +273,16 @@ class LocationPickerController(args: Bundle) :
mapController?.setCenter(GeoPoint(geocodedLat, geocodedLon))
}
binding.centerMapButton.setOnClickListener {
binding?.centerMapButton?.setOnClickListener {
if (myLocation.latitude == COORDINATE_ZERO && myLocation.longitude == COORDINATE_ZERO) {
Toast.makeText(context, context?.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
Toast.makeText(context, context.getString(R.string.nc_location_unknown), Toast.LENGTH_LONG).show()
} else {
mapController?.animateTo(myLocation)
moveToCurrentLocationWasClicked = true
}
}
binding.map.addMapListener(
binding?.map?.addMapListener(
delayedMapListener()
)
}
@ -298,12 +298,12 @@ class LocationPickerController(args: Bundle) :
moveToCurrentLocationWasClicked = false
}
receivedChosenGeocodingResult -> {
binding.shareLocation.isClickable = true
binding?.shareLocation?.isClickable = true
setLocationDescription(isGpsLocation = false, isGeocodedResult = true)
receivedChosenGeocodingResult = false
}
else -> {
binding.shareLocation.isClickable = true
binding?.shareLocation?.isClickable = true
setLocationDescription(isGpsLocation = false, isGeocodedResult = false)
}
}
@ -364,19 +364,19 @@ class LocationPickerController(args: Bundle) :
private fun setLocationDescription(isGpsLocation: Boolean, isGeocodedResult: Boolean) {
when {
isGpsLocation -> {
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_current_location)
binding.placeName.visibility = View.GONE
binding.placeName.text = ""
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_current_location)
binding?.placeName?.visibility = View.GONE
binding?.placeName?.text = ""
}
isGeocodedResult -> {
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
binding.placeName.visibility = View.VISIBLE
binding.placeName.text = geocodedName
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location)
binding?.placeName?.visibility = View.VISIBLE
binding?.placeName?.text = geocodedName
}
else -> {
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
binding.placeName.visibility = View.GONE
binding.placeName.text = ""
binding?.shareLocationDescription?.text = context!!.getText(R.string.nc_share_this_location)
binding?.placeName?.visibility = View.GONE
binding?.placeName?.text = ""
}
}
}

View File

@ -47,7 +47,7 @@ import java.util.concurrent.Executors
@AutoInjector(NextcloudTalkApplication::class)
class LockedController : BaseController(R.layout.controller_locked) {
private val binding: ControllerLockedBinding by viewBinding(ControllerLockedBinding::bind)
private val binding: ControllerLockedBinding? by viewBinding(ControllerLockedBinding::bind)
override val appBarLayoutType: AppBarLayoutType
get() = AppBarLayoutType.EMPTY
@ -60,7 +60,7 @@ class LockedController : BaseController(R.layout.controller_locked) {
override fun onViewBound(view: View) {
super.onViewBound(view)
sharedApplication!!.componentApplication.inject(this)
binding.unlockContainer.setOnClickListener {
binding?.unlockContainer?.setOnClickListener {
unlock()
}
}

View File

@ -96,7 +96,7 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
@Suppress("Detekt.TooManyFunctions")
class ProfileController : BaseController(R.layout.controller_profile) {
private val binding: ControllerProfileBinding by viewBinding(ControllerProfileBinding::bind)
private val binding: ControllerProfileBinding? by viewBinding(ControllerProfileBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -146,11 +146,11 @@ class ProfileController : BaseController(R.layout.controller_profile) {
edit = !edit
if (edit) {
item.setTitle(R.string.save)
binding.emptyList.root.visibility = View.GONE
binding.userinfoList.visibility = View.VISIBLE
binding?.emptyList?.root?.visibility = View.GONE
binding?.userinfoList?.visibility = View.VISIBLE
if (CapabilitiesUtilNew.isAvatarEndpointAvailable(currentUser!!)) {
// TODO later avatar can also be checked via user fields, for now it is in Talk capability
binding.avatarButtons.visibility = View.VISIBLE
binding?.avatarButtons?.visibility = View.VISIBLE
}
ncApi.getEditableUserProfileFields(
ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token),
@ -179,10 +179,10 @@ class ProfileController : BaseController(R.layout.controller_profile) {
})
} else {
item.setTitle(R.string.edit)
binding.avatarButtons.visibility = View.INVISIBLE
binding?.avatarButtons?.visibility = View.INVISIBLE
if (adapter!!.filteredDisplayList.isEmpty()) {
binding.emptyList.root.visibility = View.VISIBLE
binding.userinfoList.visibility = View.GONE
binding?.emptyList?.root?.visibility = View.VISIBLE
binding?.userinfoList?.visibility = View.GONE
}
}
adapter!!.notifyDataSetChanged()
@ -194,14 +194,14 @@ class ProfileController : BaseController(R.layout.controller_profile) {
override fun onAttach(view: View) {
super.onAttach(view)
adapter = UserInfoAdapter(null, viewThemeUtils, this)
binding.userinfoList.adapter = adapter
binding.userinfoList.setItemViewCacheSize(DEFAULT_CACHE_SIZE)
binding?.userinfoList?.adapter = adapter
binding?.userinfoList?.setItemViewCacheSize(DEFAULT_CACHE_SIZE)
currentUser = userManager.currentUser.blockingGet()
val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
binding.avatarUpload.setOnClickListener { sendSelectLocalFileIntent() }
binding.avatarChoose.setOnClickListener { showBrowserScreen() }
binding.avatarCamera.setOnClickListener { checkPermissionAndTakePicture() }
binding.avatarDelete.setOnClickListener {
binding?.avatarUpload?.setOnClickListener { sendSelectLocalFileIntent() }
binding?.avatarChoose?.setOnClickListener { showBrowserScreen() }
binding?.avatarCamera?.setOnClickListener { checkPermissionAndTakePicture() }
binding?.avatarDelete?.setOnClickListener {
ncApi.deleteAvatar(
credentials,
ApiUtils.getUrlForTempAvatar(currentUser!!.baseUrl)
@ -216,7 +216,7 @@ class ProfileController : BaseController(R.layout.controller_profile) {
override fun onNext(genericOverall: GenericOverall) {
DisplayUtils.loadAvatarImage(
currentUser,
binding.avatarImage,
binding?.avatarImage,
true
)
}
@ -230,7 +230,7 @@ class ProfileController : BaseController(R.layout.controller_profile) {
}
})
}
ViewCompat.setTransitionName(binding.avatarImage, "userAvatar.transitionTag")
binding?.avatarImage?.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }
ncApi.getUserProfile(credentials, ApiUtils.getUrlForUserProfile(currentUser!!.baseUrl))
.retry(DEFAULT_RETRIES)
.subscribeOn(Schedulers.io())
@ -262,10 +262,12 @@ class ProfileController : BaseController(R.layout.controller_profile) {
}
private fun colorIcons() {
viewThemeUtils.material.themeFAB(binding.avatarChoose)
viewThemeUtils.material.themeFAB(binding.avatarCamera)
viewThemeUtils.material.themeFAB(binding.avatarUpload)
viewThemeUtils.material.themeFAB(binding.avatarDelete)
binding?.let {
viewThemeUtils.material.themeFAB(it.avatarChoose)
viewThemeUtils.material.themeFAB(it.avatarCamera)
viewThemeUtils.material.themeFAB(it.avatarUpload)
viewThemeUtils.material.themeFAB(it.avatarDelete)
}
}
private fun isAllEmpty(items: Array<String?>): Boolean {
@ -283,13 +285,13 @@ class ProfileController : BaseController(R.layout.controller_profile) {
return
}
if (currentUser!!.baseUrl != null) {
binding.userinfoBaseurl.text = Uri.parse(currentUser!!.baseUrl).host
binding?.userinfoBaseurl?.text = Uri.parse(currentUser!!.baseUrl).host
}
DisplayUtils.loadAvatarImage(currentUser, binding.avatarImage, false)
DisplayUtils.loadAvatarImage(currentUser, binding?.avatarImage, false)
if (!TextUtils.isEmpty(userInfo?.displayName)) {
binding.userinfoFullName.text = userInfo?.displayName
binding?.userinfoFullName?.text = userInfo?.displayName
}
binding.loadingContent.visibility = View.VISIBLE
binding?.loadingContent?.visibility = View.VISIBLE
adapter!!.setData(createUserInfoDetails(userInfo))
if (isAllEmpty(
arrayOf(
@ -302,18 +304,18 @@ class ProfileController : BaseController(R.layout.controller_profile) {
)
)
) {
binding.userinfoList.visibility = View.GONE
binding.loadingContent.visibility = View.GONE
binding.emptyList.root.visibility = View.VISIBLE
binding?.userinfoList?.visibility = View.GONE
binding?.loadingContent?.visibility = View.GONE
binding?.emptyList?.root?.visibility = View.VISIBLE
setErrorMessageForMultiList(
activity!!.getString(R.string.userinfo_no_info_headline),
activity!!.getString(R.string.userinfo_no_info_text),
R.drawable.ic_user
)
} else {
binding.emptyList.root.visibility = View.GONE
binding.loadingContent.visibility = View.GONE
binding.userinfoList.visibility = View.VISIBLE
binding?.emptyList?.root?.visibility = View.GONE
binding?.loadingContent?.visibility = View.GONE
binding?.userinfoList?.visibility = View.VISIBLE
}
// show edit button
@ -354,13 +356,13 @@ class ProfileController : BaseController(R.layout.controller_profile) {
}
try {
binding.emptyList.emptyListViewHeadline.text = headline
binding.emptyList.emptyListViewText.text = message
binding.emptyList.emptyListIcon.setImageResource(errorResource)
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
binding.userinfoList.visibility = View.GONE
binding.loadingContent.visibility = View.GONE
binding?.emptyList?.emptyListViewHeadline?.text = headline
binding?.emptyList?.emptyListViewText?.text = message
binding?.emptyList?.emptyListIcon?.setImageResource(errorResource)
binding?.emptyList?.emptyListIcon?.visibility = View.VISIBLE
binding?.emptyList?.emptyListViewText?.visibility = View.VISIBLE
binding?.userinfoList?.visibility = View.GONE
binding?.loadingContent?.visibility = View.GONE
} catch (npe: NullPointerException) {
// view binding can be null
// since this is called asynchronously and UI might have been destroyed in the meantime
@ -453,7 +455,7 @@ class ProfileController : BaseController(R.layout.controller_profile) {
override fun onNext(userProfileOverall: GenericOverall) {
Log.d(TAG, "Successfully saved: " + item.text + " as " + item.field)
if (item.field == Field.DISPLAYNAME) {
binding.userinfoFullName.text = item.text
binding?.userinfoFullName?.text = item.text
}
}
@ -646,7 +648,7 @@ class ProfileController : BaseController(R.layout.controller_profile) {
}
override fun onNext(genericOverall: GenericOverall) {
DisplayUtils.loadAvatarImage(currentUser, binding.avatarImage, true)
DisplayUtils.loadAvatarImage(currentUser, binding?.avatarImage, true)
}
override fun onError(e: Throwable) {

View File

@ -57,7 +57,7 @@ class RingtoneSelectionController(args: Bundle) :
args
),
FlexibleAdapter.OnItemClickListener {
private val binding: ControllerGenericRvBinding by viewBinding(ControllerGenericRvBinding::bind)
private val binding: ControllerGenericRvBinding? by viewBinding(ControllerGenericRvBinding::bind)
private var adapter: FlexibleAdapter<*>? = null
private var adapterDataObserver: RecyclerView.AdapterDataObserver? = null
@ -89,9 +89,9 @@ class RingtoneSelectionController(args: Bundle) :
private fun prepareViews() {
val layoutManager: RecyclerView.LayoutManager = SmoothScrollLinearLayoutManager(activity)
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter
binding?.recyclerView?.layoutManager = layoutManager
binding?.recyclerView?.setHasFixedSize(true)
binding?.recyclerView?.adapter = adapter
adapterDataObserver = object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
@ -99,7 +99,7 @@ class RingtoneSelectionController(args: Bundle) :
}
}
adapter!!.registerAdapterDataObserver(adapterDataObserver!!)
binding.swipeRefreshLayout.isEnabled = false
binding?.swipeRefreshLayout?.isEnabled = false
}
@SuppressLint("LongLogTag")

View File

@ -63,7 +63,7 @@ import javax.inject.Inject
class ServerSelectionController :
BaseController(R.layout.controller_server_selection) {
private val binding: ControllerServerSelectionBinding by viewBinding(ControllerServerSelectionBinding::bind)
private val binding: ControllerServerSelectionBinding? by viewBinding(ControllerServerSelectionBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -99,14 +99,14 @@ class ServerSelectionController :
actionBar?.hide()
binding.hostUrlInputHelperText.text = String.format(
binding?.hostUrlInputHelperText?.text = String.format(
resources!!.getString(R.string.nc_server_helper_text),
resources!!.getString(R.string.nc_server_product_name)
)
binding.serverEntryTextInputLayout.setEndIconOnClickListener { checkServerAndProceed() }
binding?.serverEntryTextInputLayout?.setEndIconOnClickListener { checkServerAndProceed() }
if (resources!!.getBoolean(R.bool.hide_auth_cert)) {
binding.certTextView.visibility = View.GONE
binding?.certTextView?.visibility = View.GONE
}
val loggedInUsers = userManager.users.blockingGet()
@ -117,21 +117,21 @@ class ServerSelectionController :
} else if (isAbleToShowProviderLink() && loggedInUsers.isEmpty()) {
showVisitProvidersInfo()
} else {
binding.importOrChooseProviderText.visibility = View.INVISIBLE
binding?.importOrChooseProviderText?.visibility = View.INVISIBLE
}
binding.serverEntryTextInputEditText.requestFocus()
binding?.serverEntryTextInputEditText?.requestFocus()
if (!TextUtils.isEmpty(resources!!.getString(R.string.weblogin_url))) {
binding.serverEntryTextInputEditText.setText(resources!!.getString(R.string.weblogin_url))
binding?.serverEntryTextInputEditText?.setText(resources!!.getString(R.string.weblogin_url))
checkServerAndProceed()
}
binding.serverEntryTextInputEditText.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
binding?.serverEntryTextInputEditText?.setOnEditorActionListener { _: TextView?, i: Int, _: KeyEvent? ->
if (i == EditorInfo.IME_ACTION_DONE) {
checkServerAndProceed()
}
false
}
binding.certTextView.setOnClickListener { onCertClick() }
binding?.certTextView?.setOnClickListener { onCertClick() }
}
private fun isAbleToShowProviderLink(): Boolean {
@ -145,25 +145,26 @@ class ServerSelectionController :
)
) {
if (availableAccounts.size > 1) {
binding.importOrChooseProviderText.text = String.format(
binding?.importOrChooseProviderText?.text = String.format(
resources!!.getString(R.string.nc_server_import_accounts),
AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
)
} else {
binding.importOrChooseProviderText.text = String.format(
binding?.importOrChooseProviderText?.text = String.format(
resources!!.getString(R.string.nc_server_import_account),
AccountUtils.getAppNameBasedOnPackage(resources!!.getString(R.string.nc_import_accounts_from))
)
}
} else {
if (availableAccounts.size > 1) {
binding.importOrChooseProviderText.text =
binding?.importOrChooseProviderText?.text =
resources!!.getString(R.string.nc_server_import_accounts_plain)
} else {
binding.importOrChooseProviderText.text = resources!!.getString(R.string.nc_server_import_account_plain)
binding?.importOrChooseProviderText?.text =
resources!!.getString(R.string.nc_server_import_account_plain)
}
}
binding.importOrChooseProviderText.setOnClickListener {
binding?.importOrChooseProviderText?.setOnClickListener {
val bundle = Bundle()
bundle.putBoolean(KEY_IS_ACCOUNT_IMPORT, true)
router.pushController(
@ -177,8 +178,8 @@ class ServerSelectionController :
}
private fun showVisitProvidersInfo() {
binding.importOrChooseProviderText.setText(R.string.nc_get_from_provider)
binding.importOrChooseProviderText.setOnClickListener {
binding?.importOrChooseProviderText?.setText(R.string.nc_get_from_provider)
binding?.importOrChooseProviderText?.setOnClickListener {
val browserIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse(
@ -199,12 +200,12 @@ class ServerSelectionController :
private fun checkServerAndProceed() {
dispose()
try {
var url: String = binding.serverEntryTextInputEditText.text.toString().trim { it <= ' ' }
binding.serverEntryTextInputEditText.isEnabled = false
var url: String = binding?.serverEntryTextInputEditText?.text.toString().trim { it <= ' ' }
binding?.serverEntryTextInputEditText?.isEnabled = false
showserverEntryProgressBar()
if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
binding.importOrChooseProviderText.visibility = View.INVISIBLE
binding.certTextView.visibility = View.INVISIBLE
if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
binding?.importOrChooseProviderText?.visibility = View.INVISIBLE
binding?.certTextView?.visibility = View.INVISIBLE
}
if (url.endsWith("/")) {
url = url.substring(0, url.length - 1)
@ -282,19 +283,19 @@ class ServerSelectionController :
hideserverEntryProgressBar()
}
binding.serverEntryTextInputEditText.isEnabled = true
binding?.serverEntryTextInputEditText?.isEnabled = true
if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
binding.importOrChooseProviderText.visibility = View.VISIBLE
binding.certTextView.visibility = View.VISIBLE
if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
binding?.importOrChooseProviderText?.visibility = View.VISIBLE
binding?.certTextView?.visibility = View.VISIBLE
}
dispose()
}
}) {
hideserverEntryProgressBar()
if (binding.importOrChooseProviderText.visibility != View.INVISIBLE) {
binding.importOrChooseProviderText.visibility = View.VISIBLE
binding.certTextView.visibility = View.VISIBLE
if (binding?.importOrChooseProviderText?.visibility != View.INVISIBLE) {
binding?.importOrChooseProviderText?.visibility = View.VISIBLE
binding?.certTextView?.visibility = View.VISIBLE
}
dispose()
}
@ -305,19 +306,19 @@ class ServerSelectionController :
}
private fun setErrorText(text: String) {
binding.errorText.text = text
binding.errorText.visibility = View.VISIBLE
binding.serverEntryProgressBar.visibility = View.GONE
binding?.errorText?.text = text
binding?.errorText?.visibility = View.VISIBLE
binding?.serverEntryProgressBar?.visibility = View.GONE
}
private fun showserverEntryProgressBar() {
binding.errorText.visibility = View.GONE
binding.serverEntryProgressBar.visibility = View.VISIBLE
binding?.errorText?.visibility = View.GONE
binding?.serverEntryProgressBar?.visibility = View.VISIBLE
}
private fun hideserverEntryProgressBar() {
binding.errorText.visibility = View.GONE
binding.serverEntryProgressBar.visibility = View.INVISIBLE
binding?.errorText?.visibility = View.GONE
binding?.serverEntryProgressBar?.visibility = View.INVISIBLE
}
override fun onAttach(view: View) {
@ -358,9 +359,9 @@ class ServerSelectionController :
activity!!.runOnUiThread {
try {
if (!TextUtils.isEmpty(appPreferences!!.temporaryClientCertAlias)) {
binding.certTextView.setText(R.string.nc_change_cert_auth)
binding?.certTextView?.setText(R.string.nc_change_cert_auth)
} else {
binding.certTextView.setText(R.string.nc_configure_cert_auth)
binding?.certTextView?.setText(R.string.nc_configure_cert_auth)
}
hideserverEntryProgressBar()
} catch (npe: java.lang.NullPointerException) {

View File

@ -106,7 +106,7 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class SettingsController : BaseController(R.layout.controller_settings) {
private val binding: ControllerSettingsBinding by viewBinding(ControllerSettingsBinding::bind)
private val binding: ControllerSettingsBinding? by viewBinding(ControllerSettingsBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -144,7 +144,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
setHasOptionsMenu(true)
sharedApplication!!.componentApplication.inject(this)
ViewCompat.setTransitionName((binding.avatarImage), "userAvatar.transitionTag")
binding?.avatarImage?.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }
getCurrentUser()
@ -154,10 +154,10 @@ class SettingsController : BaseController(R.layout.controller_settings) {
setupLicenceSetting()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
binding.settingsIncognitoKeyboard.visibility = View.GONE
binding?.settingsIncognitoKeyboard?.visibility = View.GONE
}
binding.settingsScreenLock.setSummary(
binding?.settingsScreenLock?.setSummary(
String.format(
Locale.getDefault(),
resources!!.getString(R.string.nc_settings_screen_lock_desc),
@ -167,7 +167,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
setupPrivacyUrl()
setupSourceCodeUrl()
binding.settingsVersion.setSummary("v" + BuildConfig.VERSION_NAME)
binding?.settingsVersion?.setSummary("v" + BuildConfig.VERSION_NAME)
setupSoundSettings()
@ -178,15 +178,15 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private fun setupPhoneBookIntegration() {
if (CapabilitiesUtilNew.isPhoneBookIntegrationAvailable(currentUser!!)) {
binding.settingsPhoneBookIntegration.visibility = View.VISIBLE
binding?.settingsPhoneBookIntegration?.visibility = View.VISIBLE
} else {
binding.settingsPhoneBookIntegration.visibility = View.GONE
binding?.settingsPhoneBookIntegration?.visibility = View.GONE
}
}
private fun setupSoundSettings() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
binding.settingsCallSound.setOnClickListener {
binding?.settingsCallSound?.setOnClickListener {
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
intent.putExtra(
@ -196,7 +196,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
startActivity(intent)
}
binding.settingsMessageSound.setOnClickListener {
binding?.settingsMessageSound?.setOnClickListener {
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
intent.putExtra(
@ -206,7 +206,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
startActivity(intent)
}
} else {
binding.settingsCallSound.setOnClickListener {
binding?.settingsCallSound?.setOnClickListener {
val bundle = Bundle()
bundle.putBoolean(KEY_ARE_CALL_SOUNDS, true)
@ -216,7 +216,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
.popChangeHandler(HorizontalChangeHandler())
)
}
binding.settingsMessageSound.setOnClickListener {
binding?.settingsMessageSound?.setOnClickListener {
val bundle = Bundle()
bundle.putBoolean(KEY_ARE_CALL_SOUNDS, false)
@ -231,7 +231,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private fun setupSourceCodeUrl() {
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_source_code_url))) {
binding.settingsSourceCode.addPreferenceClickListener {
binding?.settingsSourceCode?.addPreferenceClickListener {
startActivity(
Intent(
Intent.ACTION_VIEW,
@ -240,13 +240,13 @@ class SettingsController : BaseController(R.layout.controller_settings) {
)
}
} else {
binding.settingsSourceCode.visibility = View.GONE
binding?.settingsSourceCode?.visibility = View.GONE
}
}
private fun setupPrivacyUrl() {
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_privacy_url))) {
binding.settingsPrivacy.addPreferenceClickListener {
binding?.settingsPrivacy?.addPreferenceClickListener {
startActivity(
Intent(
Intent.ACTION_VIEW,
@ -255,13 +255,13 @@ class SettingsController : BaseController(R.layout.controller_settings) {
)
}
} else {
binding.settingsPrivacy.visibility = View.GONE
binding?.settingsPrivacy?.visibility = View.GONE
}
}
private fun setupLicenceSetting() {
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_gpl3_url))) {
binding.settingsLicence.addPreferenceClickListener {
binding?.settingsLicence?.addPreferenceClickListener {
startActivity(
Intent(
Intent.ACTION_VIEW,
@ -270,15 +270,15 @@ class SettingsController : BaseController(R.layout.controller_settings) {
)
}
} else {
binding.settingsLicence.visibility = View.GONE
binding?.settingsLicence?.visibility = View.GONE
}
}
private fun setupSettingsScreen() {
val listWithIntFields: MutableList<String> = ArrayList()
listWithIntFields.add("proxy_port")
binding.settingsScreen.setUserInputModule(MagicUserInputModule(activity, listWithIntFields))
binding.settingsScreen.setVisibilityController(
binding?.settingsScreen?.setUserInputModule(MagicUserInputModule(activity, listWithIntFields))
binding?.settingsScreen?.setVisibilityController(
R.id.settings_proxy_use_credentials,
Arrays.asList(R.id.settings_proxy_username_edit, R.id.settings_proxy_password_edit),
true
@ -297,7 +297,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
Log.e(TAG, "Failed to create uri")
}
binding.settingsClientCert.addPreferenceClickListener {
binding?.settingsClientCert?.addPreferenceClickListener {
KeyChain.choosePrivateKeyAlias(
activity!!,
{ alias: String? ->
@ -305,9 +305,9 @@ class SettingsController : BaseController(R.layout.controller_settings) {
activity!!.runOnUiThread {
if (finalAlias != null) {
binding.settingsClientCert.setTitle(R.string.nc_client_cert_change)
binding?.settingsClientCert?.setTitle(R.string.nc_client_cert_change)
} else {
binding.settingsClientCert.setTitle(R.string.nc_client_cert_setup)
binding?.settingsClientCert?.setTitle(R.string.nc_client_cert_setup)
}
}
@ -370,27 +370,29 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private fun showRemoveAccountWarning() {
if (activity != null) {
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(binding.messageText.context)
.setTitle(R.string.nc_settings_remove_account)
.setMessage(R.string.nc_settings_remove_confirmation)
.setPositiveButton(R.string.nc_settings_remove) { _, _ ->
removeCurrentAccount()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
binding?.messageText?.context?.let {
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it)
.setTitle(R.string.nc_settings_remove_account)
.setMessage(R.string.nc_settings_remove_confirmation)
.setPositiveButton(R.string.nc_settings_remove) { _, _ ->
removeCurrentAccount()
}
.setNegativeButton(R.string.nc_cancel) { _, _ ->
// unused atm
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(
binding.messageText.context,
materialAlertDialogBuilder
)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(
it,
materialAlertDialogBuilder
)
val dialog = materialAlertDialogBuilder.show()
val dialog = materialAlertDialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
}
}
@ -428,38 +430,38 @@ class SettingsController : BaseController(R.layout.controller_settings) {
actionBar?.show()
dispose(null)
binding.settingsVersion.setOnClickListener {
binding?.settingsVersion?.setOnClickListener {
sendLogs()
}
if (!TextUtils.isEmpty(currentUser!!.clientCertificate)) {
binding.settingsClientCert.setTitle(R.string.nc_client_cert_change)
binding?.settingsClientCert?.setTitle(R.string.nc_client_cert_change)
} else {
binding.settingsClientCert.setTitle(R.string.nc_client_cert_setup)
binding?.settingsClientCert?.setTitle(R.string.nc_client_cert_setup)
}
setupCheckables()
setupScreenLockSetting()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
binding.settingsNotificationsCategory.setTitle(
binding?.settingsNotificationsCategory?.setTitle(
resources!!.getString(R.string.nc_settings_notification_sounds_post_oreo)
)
}
val callRingtoneUri = getCallRingtoneUri(view.context, (appPreferences)!!)
binding.settingsCallSound.setSummary(getRingtoneName(view.context, callRingtoneUri))
binding?.settingsCallSound?.setSummary(getRingtoneName(view.context, callRingtoneUri))
val messageRingtoneUri = getMessageRingtoneUri(view.context, (appPreferences)!!)
binding.settingsMessageSound.setSummary(getRingtoneName(view.context, messageRingtoneUri))
binding?.settingsMessageSound?.setSummary(getRingtoneName(view.context, messageRingtoneUri))
setupProxyTypeSettings()
setupProxyCredentialSettings()
if (currentUser != null) {
binding.baseUrlText.text = Uri.parse(currentUser!!.baseUrl).host
binding?.baseUrlText?.text = Uri.parse(currentUser!!.baseUrl).host
setupServerAgeWarning()
binding.settingsReauthorize.addPreferenceClickListener {
binding?.settingsReauthorize?.addPreferenceClickListener {
router.pushController(
RouterTransaction.with(WebViewLoginController(currentUser!!.baseUrl, true))
.pushChangeHandler(VerticalChangeHandler())
@ -468,19 +470,19 @@ class SettingsController : BaseController(R.layout.controller_settings) {
}
if (currentUser!!.displayName != null) {
binding.displayNameText.text = currentUser!!.displayName
binding?.displayNameText?.text = currentUser!!.displayName
}
DisplayUtils.loadAvatarImage(currentUser, binding.avatarImage, false)
DisplayUtils.loadAvatarImage(currentUser, binding?.avatarImage, false)
setupProfileQueryDisposable()
binding.settingsRemoveAccount.addPreferenceClickListener {
binding?.settingsRemoveAccount?.addPreferenceClickListener {
showRemoveAccountWarning()
}
}
setupMessageView()
binding.avatarContainer.setOnClickListener {
binding?.avatarContainer?.setOnClickListener {
router
.pushController(
RouterTransaction.with(ProfileController())
@ -495,7 +497,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
}
private fun themeSwitchPreferences() {
binding.run {
binding?.run {
listOf(
settingsScreenLock,
settingsScreenSecurity,
@ -508,7 +510,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
}
private fun themeCategories() {
binding.run {
binding?.run {
listOf(
settingsNotificationsCategory,
settingsAboutCategory,
@ -539,54 +541,62 @@ class SettingsController : BaseController(R.layout.controller_settings) {
if (ApplicationWideMessageHolder.getInstance().messageType != null) {
when (ApplicationWideMessageHolder.getInstance().messageType) {
ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED -> {
binding.messageText.setTextColor(
viewThemeUtils.getScheme(binding.messageText.context).primary
)
binding.messageText.text = resources!!.getString(R.string.nc_settings_account_updated)
binding.messageView.visibility = View.VISIBLE
binding?.messageText?.let {
it.setTextColor(
viewThemeUtils.getScheme(it.context).primary
)
it.text = resources!!.getString(R.string.nc_settings_account_updated)
binding?.messageView?.visibility = View.VISIBLE
}
}
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK -> {
binding.messageText.setTextColor(resources!!.getColor(R.color.nc_darkRed))
binding.messageText.text = resources!!.getString(R.string.nc_settings_wrong_account)
binding.messageView.visibility = View.VISIBLE
binding.messageText.setTextColor(
viewThemeUtils.getScheme(binding.messageText.context).primary
)
binding.messageText.text = resources!!.getString(R.string.nc_Server_account_imported)
binding.messageView.visibility = View.VISIBLE
binding?.messageText?.let {
it.setTextColor(resources!!.getColor(R.color.nc_darkRed))
it.text = resources!!.getString(R.string.nc_settings_wrong_account)
binding?.messageView?.visibility = View.VISIBLE
it.setTextColor(
viewThemeUtils.getScheme(it.context).primary
)
it.text = resources!!.getString(R.string.nc_Server_account_imported)
binding?.messageView?.visibility = View.VISIBLE
}
}
ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED -> {
binding.messageText.setTextColor(
viewThemeUtils.getScheme(binding.messageText.context).primary
)
binding.messageText.text = resources!!.getString(R.string.nc_Server_account_imported)
binding.messageView.visibility = View.VISIBLE
binding?.messageText?.let {
it.setTextColor(
viewThemeUtils.getScheme(it.context).primary
)
it.text = resources!!.getString(R.string.nc_Server_account_imported)
binding?.messageView?.visibility = View.VISIBLE
}
}
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT -> {
binding.messageText.setTextColor(resources!!.getColor(R.color.nc_darkRed))
binding.messageText.text = resources!!.getString(R.string.nc_server_failed_to_import_account)
binding.messageView.visibility = View.VISIBLE
binding?.messageText?.let {
it.setTextColor(resources!!.getColor(R.color.nc_darkRed))
it.text = resources!!.getString(R.string.nc_server_failed_to_import_account)
binding?.messageView?.visibility = View.VISIBLE
}
}
else -> binding.messageView.visibility = View.GONE
else -> binding?.messageView?.visibility = View.GONE
}
ApplicationWideMessageHolder.getInstance().setMessageType(null)
binding.messageView.animate()
.translationY(0f)
.alpha(0.0f)
.setDuration(DURATION)
.setStartDelay(START_DELAY)
.setListener(object : AnimatorListenerAdapter() {
ApplicationWideMessageHolder.getInstance().messageType = null
binding?.messageView?.animate()
?.translationY(0f)
?.alpha(0.0f)
?.setDuration(DURATION)
?.setStartDelay(START_DELAY)
?.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
binding.messageView.visibility = View.GONE
binding?.messageView?.visibility = View.GONE
}
})
} else {
binding.messageView.visibility = View.GONE
binding?.messageView?.visibility = View.GONE
}
}
@ -614,7 +624,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
if ((!TextUtils.isEmpty(displayName) && !(displayName == currentUser!!.displayName))) {
currentUser!!.displayName = displayName
userManager.updateOrCreateUser(currentUser!!)
binding.displayNameText.text = currentUser!!.displayName
binding?.displayNameText?.text = currentUser!!.displayName
}
},
{ dispose(profileQueryDisposable) },
@ -625,74 +635,74 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private fun setupServerAgeWarning() {
when {
CapabilitiesUtilNew.isServerEOL(currentUser!!) -> {
binding.serverAgeWarningText.setTextColor(ContextCompat.getColor((context)!!, R.color.nc_darkRed))
binding.serverAgeWarningText.setText(R.string.nc_settings_server_eol)
binding.serverAgeWarningIcon.setColorFilter(
ContextCompat.getColor((context)!!, R.color.nc_darkRed),
binding?.serverAgeWarningText?.setTextColor(ContextCompat.getColor((context)!!, R.color.nc_darkRed))
binding?.serverAgeWarningText?.setText(R.string.nc_settings_server_eol)
binding?.serverAgeWarningIcon?.setColorFilter(
ContextCompat.getColor((context), R.color.nc_darkRed),
PorterDuff.Mode.SRC_IN
)
}
CapabilitiesUtilNew.isServerAlmostEOL(currentUser!!) -> {
binding.serverAgeWarningText.setTextColor(
ContextCompat.getColor((context)!!, R.color.nc_darkYellow)
binding?.serverAgeWarningText?.setTextColor(
ContextCompat.getColor((context), R.color.nc_darkYellow)
)
binding.serverAgeWarningText.setText(R.string.nc_settings_server_almost_eol)
binding.serverAgeWarningIcon.setColorFilter(
ContextCompat.getColor((context)!!, R.color.nc_darkYellow),
binding?.serverAgeWarningText?.setText(R.string.nc_settings_server_almost_eol)
binding?.serverAgeWarningIcon?.setColorFilter(
ContextCompat.getColor((context), R.color.nc_darkYellow),
PorterDuff.Mode.SRC_IN
)
}
else -> {
binding.serverAgeWarningTextCard.visibility = View.GONE
binding?.serverAgeWarningTextCard?.visibility = View.GONE
}
}
}
private fun setupCheckables() {
(binding.settingsScreenSecurity.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsScreenSecurity?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isScreenSecured
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
(binding.settingsIncognitoKeyboard.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsIncognitoKeyboard?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isKeyboardIncognito
}
(binding.settingsIncognitoKeyboard.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsIncognitoKeyboard?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isKeyboardIncognito
if (CapabilitiesUtilNew.isReadStatusAvailable(userManager.currentUser.blockingGet())) {
(binding.settingsReadPrivacy.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsReadPrivacy?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
!CapabilitiesUtilNew.isReadStatusPrivate(currentUser!!)
} else {
binding.settingsReadPrivacy.visibility = View.GONE
binding?.settingsReadPrivacy?.visibility = View.GONE
}
(binding.settingsPhoneBookIntegration.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsPhoneBookIntegration?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isPhoneBookIntegrationEnabled
}
private fun setupScreenLockSetting() {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardSecure) {
binding.settingsScreenLock.isEnabled = true
binding.settingsScreenLockTimeout.isEnabled = true
(binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
binding?.settingsScreenLock?.isEnabled = true
binding?.settingsScreenLockTimeout?.isEnabled = true
(binding?.settingsScreenLock?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isScreenLocked
binding.settingsScreenLockTimeout.isEnabled = appPreferences.isScreenLocked
binding?.settingsScreenLockTimeout?.isEnabled = appPreferences.isScreenLocked
if (appPreferences.isScreenLocked) {
binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
binding?.settingsScreenLockTimeout?.alpha = ENABLED_ALPHA
} else {
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
binding?.settingsScreenLockTimeout?.alpha = DISABLED_ALPHA
}
binding.settingsScreenLock.alpha = ENABLED_ALPHA
binding?.settingsScreenLock?.alpha = ENABLED_ALPHA
} else {
binding.settingsScreenLock.isEnabled = false
binding.settingsScreenLockTimeout.isEnabled = false
binding?.settingsScreenLock?.isEnabled = false
binding?.settingsScreenLockTimeout?.isEnabled = false
appPreferences.removeScreenLock()
appPreferences.removeScreenLockTimeout()
(binding.settingsScreenLock.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = false
binding.settingsScreenLock.alpha = DISABLED_ALPHA
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
(binding?.settingsScreenLock?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked = false
binding?.settingsScreenLock?.alpha = DISABLED_ALPHA
binding?.settingsScreenLockTimeout?.alpha = DISABLED_ALPHA
}
}
@ -710,40 +720,40 @@ class SettingsController : BaseController(R.layout.controller_settings) {
}
private fun hideProxySettings() {
appPreferences?.removeProxyHost()
appPreferences?.removeProxyPort()
appPreferences?.removeProxyCredentials()
appPreferences?.removeProxyUsername()
appPreferences?.removeProxyPassword()
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_host_edit).visibility = View.GONE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_port_edit).visibility = View.GONE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_use_credentials).visibility =
appPreferences.removeProxyHost()
appPreferences.removeProxyPort()
appPreferences.removeProxyCredentials()
appPreferences.removeProxyUsername()
appPreferences.removeProxyPassword()
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_host_edit)?.visibility = View.GONE
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_port_edit)?.visibility = View.GONE
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_use_credentials)?.visibility =
View.GONE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_username_edit).visibility = View.GONE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_password_edit).visibility = View.GONE
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_username_edit)?.visibility = View.GONE
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_password_edit)?.visibility = View.GONE
}
private fun showProxySettings() {
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_host_edit).visibility =
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_host_edit)?.visibility =
View.VISIBLE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_port_edit).visibility =
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_port_edit)?.visibility =
View.VISIBLE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_use_credentials).visibility =
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_use_credentials)?.visibility =
View.VISIBLE
}
private fun showProxyCredentials() {
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_username_edit).visibility =
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_username_edit)?.visibility =
View.VISIBLE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_password_edit).visibility =
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_password_edit)?.visibility =
View.VISIBLE
}
private fun hideProxyCredentials() {
appPreferences?.removeProxyUsername()
appPreferences?.removeProxyPassword()
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_username_edit).visibility = View.GONE
binding.settingsScreen.findViewById<View>(R.id.settings_proxy_password_edit).visibility = View.GONE
appPreferences.removeProxyUsername()
appPreferences.removeProxyPassword()
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_username_edit)?.visibility = View.GONE
binding?.settingsScreen?.findViewById<View>(R.id.settings_proxy_password_edit)?.visibility = View.GONE
}
private fun dispose(disposable: Disposable?) {
@ -784,7 +794,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
checkForPhoneNumber()
} else {
appPreferences.setPhoneBookIntegration(false)
(binding.settingsPhoneBookIntegration.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsPhoneBookIntegration?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
appPreferences.isPhoneBookIntegrationEnabled
Toast.makeText(
context,
@ -802,11 +812,11 @@ class SettingsController : BaseController(R.layout.controller_settings) {
private inner class ScreenLockListener : OnPreferenceValueChangedListener<Boolean> {
override fun onChanged(newValue: Boolean) {
binding.settingsScreenLockTimeout.isEnabled = newValue
binding?.settingsScreenLockTimeout?.isEnabled = newValue
if (newValue) {
binding.settingsScreenLockTimeout.alpha = ENABLED_ALPHA
binding?.settingsScreenLockTimeout?.alpha = ENABLED_ALPHA
} else {
binding.settingsScreenLockTimeout.alpha = DISABLED_ALPHA
binding?.settingsScreenLockTimeout?.alpha = DISABLED_ALPHA
}
}
}
@ -844,11 +854,11 @@ class SettingsController : BaseController(R.layout.controller_settings) {
} else {
when (newValue) {
"HTTP" ->
binding.settingsProxyPortEdit.value = "3128"
binding?.settingsProxyPortEdit?.value = "3128"
"DIRECT" ->
binding.settingsProxyPortEdit.value = "8080"
binding?.settingsProxyPortEdit?.value = "8080"
"SOCKS" ->
binding.settingsProxyPortEdit.value = "1080"
binding?.settingsProxyPortEdit?.value = "1080"
else -> {
}
}
@ -1031,7 +1041,7 @@ class SettingsController : BaseController(R.layout.controller_settings) {
override fun onError(e: Throwable) {
appPreferences.setReadPrivacy(!newValue)
(binding.settingsReadPrivacy.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
(binding?.settingsReadPrivacy?.findViewById<View>(R.id.mp_checkable) as Checkable).isChecked =
!newValue
}

View File

@ -63,7 +63,7 @@ class SwitchAccountController(args: Bundle? = null) :
R.layout.controller_generic_rv,
args
) {
private val binding: ControllerGenericRvBinding by viewBinding(ControllerGenericRvBinding::bind)
private val binding: ControllerGenericRvBinding? by viewBinding(ControllerGenericRvBinding::bind)
@Inject
lateinit var userManager: UserManager
@ -118,7 +118,7 @@ class SwitchAccountController(args: Bundle? = null) :
override fun onViewBound(view: View) {
super.onViewBound(view)
binding.swipeRefreshLayout.isEnabled = false
binding?.swipeRefreshLayout?.isEnabled = false
actionBar?.show()
@ -167,10 +167,10 @@ class SwitchAccountController(args: Bundle? = null) :
private fun prepareViews() {
val layoutManager: LinearLayoutManager = SmoothScrollLinearLayoutManager(activity)
binding.recyclerView.layoutManager = layoutManager
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter
binding.swipeRefreshLayout.isEnabled = false
binding?.recyclerView?.layoutManager = layoutManager
binding?.recyclerView?.setHasFixedSize(true)
binding?.recyclerView?.adapter = adapter
binding?.swipeRefreshLayout?.isEnabled = false
}
private fun reauthorizeFromImport(account: Account?) {

View File

@ -82,7 +82,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
R.layout.controller_web_view_login,
args
) {
private val binding: ControllerWebViewLoginBinding by viewBinding(ControllerWebViewLoginBinding::bind)
private val binding: ControllerWebViewLoginBinding? by viewBinding(ControllerWebViewLoginBinding::bind)
@Inject
lateinit var userManager: UserManager
@ -137,25 +137,25 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
actionBar?.hide()
assembledPrefix = resources!!.getString(R.string.nc_talk_login_scheme) + PROTOCOL_SUFFIX + "login/"
binding.webview.settings.allowFileAccess = false
binding.webview.settings.allowFileAccessFromFileURLs = false
binding.webview.settings.javaScriptEnabled = true
binding.webview.settings.javaScriptCanOpenWindowsAutomatically = false
binding.webview.settings.domStorageEnabled = true
binding.webview.settings.setUserAgentString(webLoginUserAgent)
binding.webview.settings.saveFormData = false
binding.webview.settings.savePassword = false
binding.webview.settings.setRenderPriority(WebSettings.RenderPriority.HIGH)
binding.webview.clearCache(true)
binding.webview.clearFormData()
binding.webview.clearHistory()
binding?.webview?.settings?.allowFileAccess = false
binding?.webview?.settings?.allowFileAccessFromFileURLs = false
binding?.webview?.settings?.javaScriptEnabled = true
binding?.webview?.settings?.javaScriptCanOpenWindowsAutomatically = false
binding?.webview?.settings?.domStorageEnabled = true
binding?.webview?.settings?.setUserAgentString(webLoginUserAgent)
binding?.webview?.settings?.saveFormData = false
binding?.webview?.settings?.savePassword = false
binding?.webview?.settings?.setRenderPriority(WebSettings.RenderPriority.HIGH)
binding?.webview?.clearCache(true)
binding?.webview?.clearFormData()
binding?.webview?.clearHistory()
WebView.clearClientCertPreferences(null)
webViewFidoBridge = WebViewFidoBridge.createInstanceForWebView(activity as AppCompatActivity?, binding.webview)
webViewFidoBridge = WebViewFidoBridge.createInstanceForWebView(activity as AppCompatActivity?, binding?.webview)
CookieSyncManager.createInstance(activity)
android.webkit.CookieManager.getInstance().removeAllCookies(null)
val headers: MutableMap<String, String> = HashMap()
headers.put("OCS-APIRequest", "true")
binding.webview.webViewClient = object : WebViewClient() {
binding?.webview?.webViewClient = object : WebViewClient() {
private var basePageLoaded = false
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
webViewFidoBridge?.delegateShouldInterceptRequest(view, request)
@ -181,24 +181,24 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
try {
loginStep++
if (!basePageLoaded) {
binding.progressBar.visibility = View.GONE
binding.webview.visibility = View.VISIBLE
binding?.progressBar?.visibility = View.GONE
binding?.webview?.visibility = View.VISIBLE
basePageLoaded = true
}
if (!TextUtils.isEmpty(username)) {
if (loginStep == 1) {
binding.webview.loadUrl(
binding?.webview?.loadUrl(
"javascript: {document.getElementsByClassName('login')[0].click(); };"
)
} else if (!automatedLoginAttempted) {
automatedLoginAttempted = true
if (TextUtils.isEmpty(password)) {
binding.webview.loadUrl(
binding?.webview?.loadUrl(
"javascript:var justStore = document.getElementById('user').value = '$username';"
)
} else {
binding.webview.loadUrl(
binding?.webview?.loadUrl(
"javascript: {" +
"document.getElementById('user').value = '" + username + "';" +
"document.getElementById('password').value = '" + password + "';" +
@ -308,7 +308,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
super.onReceivedError(view, errorCode, description, failingUrl)
}
}
binding.webview.loadUrl("$baseUrl/index.php/login/flow", headers)
binding?.webview?.loadUrl("$baseUrl/index.php/login/flow", headers)
}
private fun dispose() {

View File

@ -54,7 +54,6 @@ import com.nextcloud.talk.controllers.ServerSelectionController
import com.nextcloud.talk.controllers.SwitchAccountController
import com.nextcloud.talk.controllers.WebViewLoginController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
import com.nextcloud.talk.controllers.util.ControllerViewBindingDelegate
import com.nextcloud.talk.databinding.ActivityMainBinding
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.DisplayUtils
@ -304,27 +303,6 @@ abstract class BaseController(@LayoutRes var layoutRes: Int, args: Bundle? = nul
}
}
/**
* Mainly intended to be used in async listeners that may be called after the controller has been destroyed.
*
* If you need to use this function to patch a NPE crash, something is wrong in the way that the async calls are
* handled, they should have been cancelled when the controller UI was destroyed (if their only purpose was
* updating UI).
*/
@Suppress("Detekt.TooGenericExceptionCaught")
inline fun withNullableControllerViewBinding(block: () -> Unit) {
try {
block()
} catch (e: NullPointerException) {
// Handle only the exceptions we know about, let everything else pass through
if (e.stackTrace.firstOrNull()?.className == ControllerViewBindingDelegate::class.qualifiedName) {
Log.w("ControllerViewBinding", "Trying to update UI on a null ViewBinding.", e)
} else {
throw e
}
}
}
open val appBarLayoutType: AppBarLayoutType
get() = AppBarLayoutType.TOOLBAR
val searchHint: String

View File

@ -62,7 +62,7 @@ class EntryMenuController(args: Bundle) :
R.layout.controller_entry_menu,
args
) {
private val binding: ControllerEntryMenuBinding by viewBinding(ControllerEntryMenuBinding::bind)
private val binding: ControllerEntryMenuBinding? by viewBinding(ControllerEntryMenuBinding::bind)
@Inject
lateinit var eventBus: EventBus
@ -87,11 +87,11 @@ class EntryMenuController(args: Bundle) :
if (ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG ==
ApplicationWideMessageHolder.getInstance().messageType
) {
binding.textInputLayout.error = resources?.getString(R.string.nc_wrong_password)
ApplicationWideMessageHolder.getInstance().setMessageType(null)
if (binding.okButton.isEnabled) {
binding.okButton.isEnabled = false
binding.okButton.alpha = OPACITY_BUTTON_DISABLED
binding?.textInputLayout?.error = resources?.getString(R.string.nc_wrong_password)
ApplicationWideMessageHolder.getInstance().messageType = null
if (binding?.okButton?.isEnabled == true) {
binding?.okButton?.isEnabled = false
binding?.okButton?.alpha = OPACITY_BUTTON_DISABLED
}
}
}
@ -100,13 +100,13 @@ class EntryMenuController(args: Bundle) :
super.onViewBound(view)
if (conversation != null && operation === ConversationOperationEnum.OPS_CODE_RENAME_ROOM) {
binding.textEdit.setText(conversation!!.name)
binding?.textEdit?.setText(conversation!!.name)
}
binding.textEdit.setOnEditorActionListener { v, actionId, event ->
binding?.textEdit?.setOnEditorActionListener { v, actionId, event ->
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
if (actionId === EditorInfo.IME_ACTION_DONE && binding.okButton.isEnabled) {
binding.okButton.callOnClick()
if (actionId === EditorInfo.IME_ACTION_DONE && binding?.okButton?.isEnabled == true) {
binding?.okButton?.callOnClick()
return@setOnEditorActionListener true
}
false
@ -118,57 +118,59 @@ class EntryMenuController(args: Bundle) :
when (operation) {
ConversationOperationEnum.OPS_CODE_INVITE_USERS, ConversationOperationEnum.OPS_CODE_RENAME_ROOM -> {
labelText = resources!!.getString(R.string.nc_call_name)
binding.textEdit.inputType = InputType.TYPE_CLASS_TEXT
binding.smileyButton.visibility = View.VISIBLE
emojiPopup = EmojiPopup(
rootView = view,
editText = binding.textEdit,
onEmojiPopupShownListener = {
viewThemeUtils.platform.colorImageView(binding.smileyButton)
},
onEmojiPopupDismissListener = {
binding.smileyButton.imageTintList = ColorStateList.valueOf(
ResourcesCompat.getColor(resources!!, R.color.medium_emphasis_text, context.theme)
)
},
onEmojiClickListener = {
binding.textEdit.editableText.append(" ")
}
)
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT
binding?.smileyButton?.visibility = View.VISIBLE
emojiPopup = binding?.let {
EmojiPopup(
rootView = view,
editText = it.textEdit,
onEmojiPopupShownListener = {
viewThemeUtils.platform.colorImageView(it.smileyButton)
},
onEmojiPopupDismissListener = {
it.smileyButton.imageTintList = ColorStateList.valueOf(
ResourcesCompat.getColor(resources!!, R.color.medium_emphasis_text, context.theme)
)
},
onEmojiClickListener = {
binding?.textEdit?.editableText?.append(" ")
}
)
}
}
ConversationOperationEnum.OPS_CODE_JOIN_ROOM -> {
// 99 is joining a conversation via password
labelText = resources!!.getString(R.string.nc_password)
binding.textEdit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM -> {
labelText = resources!!.getString(R.string.nc_conversation_link)
binding.textEdit.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI
}
else -> {
}
}
if (PASSWORD_ENTRY_OPERATIONS.contains(operation)) {
binding.textInputLayout.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
binding?.textInputLayout?.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
} else {
binding.textInputLayout.endIconMode = TextInputLayout.END_ICON_NONE
binding?.textInputLayout?.endIconMode = TextInputLayout.END_ICON_NONE
}
viewThemeUtils.material.colorTextInputLayout(binding.textInputLayout)
viewThemeUtils.material.colorMaterialButtonText(binding.okButton)
binding?.textInputLayout?.let { viewThemeUtils.material.colorTextInputLayout(it) }
binding?.okButton?.let { viewThemeUtils.material.colorMaterialButtonText(it) }
binding.textInputLayout.hint = labelText
binding.textInputLayout.requestFocus()
binding?.textInputLayout?.hint = labelText
binding?.textInputLayout?.requestFocus()
binding.smileyButton.setOnClickListener { onSmileyClick() }
binding.okButton.setOnClickListener { onOkButtonClick() }
binding?.smileyButton?.setOnClickListener { onSmileyClick() }
binding?.okButton?.setOnClickListener { onOkButtonClick() }
}
private fun textEditAddChangedListener() {
binding.textEdit.addTextChangedListener(object : TextWatcher {
binding?.textEdit?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// unused atm
}
@ -181,46 +183,46 @@ class EntryMenuController(args: Bundle) :
if (!TextUtils.isEmpty(s)) {
if (operation === ConversationOperationEnum.OPS_CODE_RENAME_ROOM) {
if (conversation!!.name == null || !conversation!!.name.equals(s.toString())) {
if (!binding.okButton.isEnabled) {
binding.okButton.isEnabled = true
binding.okButton.alpha = OPACITY_ENABLED
if (!binding?.okButton?.isEnabled!!) {
binding?.okButton?.isEnabled = true
binding?.okButton?.alpha = OPACITY_ENABLED
}
binding.textInputLayout.isErrorEnabled = false
binding?.textInputLayout?.isErrorEnabled = false
} else {
if (binding.okButton.isEnabled) {
binding.okButton.isEnabled = false
binding.okButton.alpha = OPACITY_DISABLED
if (binding?.okButton?.isEnabled == true) {
binding?.okButton?.isEnabled = false
binding?.okButton?.alpha = OPACITY_DISABLED
}
binding.textInputLayout.error = resources?.getString(R.string.nc_call_name_is_same)
binding?.textInputLayout?.error = resources?.getString(R.string.nc_call_name_is_same)
}
} else if (operation !== ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM) {
if (!binding.okButton.isEnabled) {
binding.okButton.isEnabled = true
binding.okButton.alpha = OPACITY_ENABLED
if (!binding?.okButton?.isEnabled!!) {
binding?.okButton?.isEnabled = true
binding?.okButton?.alpha = OPACITY_ENABLED
}
binding.textInputLayout.isErrorEnabled = false
binding?.textInputLayout?.isErrorEnabled = false
} else if (
UriUtils.hasHttpProtocollPrefixed(binding.textEdit.text.toString()) &&
binding.textEdit.text.toString().contains("/call/")
UriUtils.hasHttpProtocollPrefixed(binding?.textEdit?.text.toString()) &&
binding?.textEdit?.text.toString().contains("/call/")
) {
if (!binding.okButton.isEnabled) {
binding.okButton.isEnabled = true
binding.okButton.alpha = OPACITY_ENABLED
if (!binding?.okButton?.isEnabled!!) {
binding?.okButton?.isEnabled = true
binding?.okButton?.alpha = OPACITY_ENABLED
}
binding.textInputLayout.isErrorEnabled = false
binding?.textInputLayout?.isErrorEnabled = false
} else {
if (binding.okButton.isEnabled) {
binding.okButton.isEnabled = false
binding.okButton.alpha = OPACITY_DISABLED
if (binding?.okButton?.isEnabled == true) {
binding?.okButton?.isEnabled = false
binding?.okButton?.alpha = OPACITY_DISABLED
}
binding.textInputLayout.error = resources?.getString(R.string.nc_wrong_link)
binding?.textInputLayout?.error = resources?.getString(R.string.nc_wrong_link)
}
} else {
if (binding.okButton.isEnabled) {
binding.okButton.isEnabled = false
binding.okButton.alpha = OPACITY_DISABLED
if (binding?.okButton?.isEnabled == true) {
binding?.okButton?.isEnabled = false
binding?.okButton?.alpha = OPACITY_DISABLED
}
binding.textInputLayout.isErrorEnabled = false
binding?.textInputLayout?.isErrorEnabled = false
}
}
})
@ -238,7 +240,7 @@ class EntryMenuController(args: Bundle) :
operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS
) {
val bundle = Bundle()
conversation!!.name = binding.textEdit.text.toString()
conversation!!.name = binding?.textEdit?.text.toString()
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap<Any>(conversation))
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
router.pushController(
@ -249,14 +251,14 @@ class EntryMenuController(args: Bundle) :
} else if (operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
val bundle = Bundle()
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
bundle.putString(BundleKeys.KEY_CALL_URL, binding.textEdit.text.toString())
bundle.putString(BundleKeys.KEY_CALL_URL, binding?.textEdit?.text.toString())
router.pushController(
RouterTransaction.with(OperationsMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else if (operation === ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME, binding.textEdit.text.toString())
originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME, binding?.textEdit?.text.toString())
router.pushController(
RouterTransaction.with(
OperationsMenuController(
@ -273,12 +275,12 @@ class EntryMenuController(args: Bundle) :
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap<Any>(conversation))
bundle.putString(BundleKeys.KEY_CALL_URL, callUrl)
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, binding.textEdit.text.toString())
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, binding?.textEdit?.text.toString())
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
if (originalBundle.containsKey(BundleKeys.KEY_SERVER_CAPABILITIES)) {
bundle.putParcelable(
BundleKeys.KEY_SERVER_CAPABILITIES,
originalBundle.getParcelable<Parcelable>(BundleKeys.KEY_SERVER_CAPABILITIES)
originalBundle.getParcelable(BundleKeys.KEY_SERVER_CAPABILITIES)
)
}
router.pushController(

View File

@ -83,7 +83,7 @@ class OperationsMenuController(args: Bundle) : BaseController(
R.layout.controller_operations_menu,
args
) {
private val binding: ControllerOperationsMenuBinding by viewBinding(ControllerOperationsMenuBinding::bind)
private val binding: ControllerOperationsMenuBinding? by viewBinding(ControllerOperationsMenuBinding::bind)
@Inject
lateinit var ncApi: NcApi
@ -117,7 +117,7 @@ class OperationsMenuController(args: Bundle) : BaseController(
sharedApplication!!.componentApplication.inject(this)
currentUser = userManager.currentUser.blockingGet()
viewThemeUtils.platform.colorCircularProgressBar(binding.progressBar)
binding?.progressBar?.let { viewThemeUtils.platform.colorCircularProgressBar(it) }
if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1)
@ -476,10 +476,10 @@ class OperationsMenuController(args: Bundle) : BaseController(
@Suppress("Detekt.TooGenericExceptionCaught")
private fun showResultImage(everythingOK: Boolean, isGuestSupportError: Boolean) {
try {
binding.progressBar.visibility = View.GONE
binding?.progressBar?.visibility = View.GONE
if (resources != null) {
if (everythingOK) {
binding.resultImageView.setImageDrawable(
binding?.resultImageView?.setImageDrawable(
DisplayUtils.getTintedDrawable(
resources,
R.drawable.ic_check_circle_black_24dp,
@ -487,7 +487,7 @@ class OperationsMenuController(args: Bundle) : BaseController(
)
)
} else {
binding.resultImageView.setImageDrawable(
binding?.resultImageView?.setImageDrawable(
DisplayUtils.getTintedDrawable(
resources,
R.drawable.ic_cancel_black_24dp,
@ -496,35 +496,35 @@ class OperationsMenuController(args: Bundle) : BaseController(
)
}
}
binding.resultImageView.visibility = View.VISIBLE
binding?.resultImageView?.visibility = View.VISIBLE
if (everythingOK) {
binding.resultTextView.setText(R.string.nc_all_ok_operation)
binding?.resultTextView?.setText(R.string.nc_all_ok_operation)
} else {
binding.resultTextView.setTextColor(resources!!.getColor(R.color.nc_darkRed))
binding?.resultTextView?.setTextColor(resources!!.getColor(R.color.nc_darkRed))
if (!isGuestSupportError) {
binding.resultTextView.setText(R.string.nc_failed_to_perform_operation)
binding?.resultTextView?.setText(R.string.nc_failed_to_perform_operation)
} else {
binding.resultTextView.setText(R.string.nc_failed_signaling_settings)
binding.webButton.setOnClickListener {
binding?.resultTextView?.setText(R.string.nc_failed_signaling_settings)
binding?.webButton?.setOnClickListener {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(callUrl))
startActivity(browserIntent)
}
binding.webButton.visibility = View.VISIBLE
binding?.webButton?.visibility = View.VISIBLE
}
}
binding.resultTextView.visibility = View.VISIBLE
binding?.resultTextView?.visibility = View.VISIBLE
if (everythingOK) {
eventBus!!.post(ConversationsListFetchDataEvent())
eventBus.post(ConversationsListFetchDataEvent())
} else {
binding.resultImageView.setImageDrawable(
binding?.resultImageView?.setImageDrawable(
DisplayUtils.getTintedDrawable(
resources,
R.drawable.ic_cancel_black_24dp,
R.color.nc_darkRed
)
)
binding.okButton.setOnClickListener { v: View? -> eventBus!!.post(ConversationsListFetchDataEvent()) }
binding.okButton.visibility = View.VISIBLE
binding?.okButton?.setOnClickListener { v: View? -> eventBus.post(ConversationsListFetchDataEvent()) }
binding?.okButton?.visibility = View.VISIBLE
}
} catch (npe: NullPointerException) {
Log.i(TAG, "Controller already closed", npe)

View File

@ -31,7 +31,7 @@ fun <T : ViewBinding> Controller.viewBinding(bindingFactory: (View) -> T) =
class ControllerViewBindingDelegate<T : ViewBinding>(
controller: Controller,
private val viewBinder: (View) -> T
) : ReadOnlyProperty<Controller, T>, LifecycleObserver {
) : ReadOnlyProperty<Controller, T?>, LifecycleObserver {
private var binding: T? = null
@ -43,7 +43,10 @@ class ControllerViewBindingDelegate<T : ViewBinding>(
})
}
override fun getValue(thisRef: Controller, property: KProperty<*>): T {
return binding ?: viewBinder(thisRef.view!!).also { binding = it }
override fun getValue(thisRef: Controller, property: KProperty<*>): T? {
if (binding == null) {
binding = thisRef.view?.let { viewBinder(it) }
}
return binding
}
}