Skip to content

Commit 6fe1f30

Browse files
authored
Merge pull request #5746 from nextcloud/issue-5721
Fixing UninitializedPropertyAccessException with MessageInputViewModel
2 parents 8bd212f + 42eb0c7 commit 6fe1f30

5 files changed

Lines changed: 63 additions & 54 deletions

File tree

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import androidx.activity.result.ActivityResultLauncher
5656
import androidx.activity.result.PickVisualMediaRequest
5757
import androidx.activity.result.contract.ActivityResultContracts
5858
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
59+
import androidx.activity.viewModels
5960
import androidx.appcompat.app.AlertDialog
6061
import androidx.appcompat.view.ContextThemeWrapper
6162
import androidx.cardview.widget.CardView
@@ -292,7 +293,7 @@ class ChatActivity :
292293

293294
lateinit var conversationInfoViewModel: ConversationInfoViewModel
294295
lateinit var contextChatViewModel: ContextChatViewModel
295-
lateinit var messageInputViewModel: MessageInputViewModel
296+
val messageInputViewModel: MessageInputViewModel by viewModels()
296297

297298
private var chatMenu: Menu? = null
298299

@@ -543,11 +544,6 @@ class ChatActivity :
543544
}
544545

545546
messageInputFragment = getMessageInputFragment()
546-
messageInputViewModel =
547-
ViewModelProvider(this@ChatActivity, viewModelFactory)[
548-
MessageInputViewModel::class
549-
.java
550-
]
551547
messageInputViewModel.setData(chatViewModel.getChatRepository())
552548

553549
initObservers()

app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import androidx.core.view.isVisible
4343
import androidx.core.widget.doAfterTextChanged
4444
import androidx.emoji2.widget.EmojiTextView
4545
import androidx.fragment.app.Fragment
46+
import androidx.fragment.app.activityViewModels
4647
import androidx.lifecycle.Lifecycle
4748
import androidx.lifecycle.LifecycleOwner
4849
import androidx.lifecycle.LiveData
@@ -118,6 +119,7 @@ class MessageInputFragment : Fragment() {
118119
@Inject
119120
lateinit var messageUtils: MessageUtils
120121

122+
private val messageInputViewModel: MessageInputViewModel by activityViewModels()
121123
lateinit var binding: FragmentMessageInputBinding
122124
private lateinit var conversationInternalId: String
123125
private var typedWhileTypingTimerIsRunning: Boolean = false
@@ -206,7 +208,7 @@ class MessageInputFragment : Fragment() {
206208
}
207209
}
208210

209-
chatActivity.messageInputViewModel.getReplyChatMessage.observe(viewLifecycleOwner) { message ->
211+
messageInputViewModel.getReplyChatMessage.observe(viewLifecycleOwner) { message ->
210212
message?.let {
211213
chatActivity.chatViewModel.messageDraft.quotedMessageText = message.text
212214
chatActivity.chatViewModel.messageDraft.quotedDisplayName = message.actorDisplayName
@@ -222,13 +224,13 @@ class MessageInputFragment : Fragment() {
222224

223225
viewLifecycleOwner.lifecycleScope.launch {
224226
repeatOnLifecycle(Lifecycle.State.CREATED) {
225-
chatActivity.messageInputViewModel.getEditChatMessage.collect { message ->
227+
messageInputViewModel.getEditChatMessage.collect { message ->
226228
message?.let { setEditUI(it as ChatMessage) } ?: clearEditUI()
227229
}
228230
}
229231
}
230232

231-
chatActivity.messageInputViewModel.createThreadViewState.observe(viewLifecycleOwner) { state ->
233+
messageInputViewModel.createThreadViewState.observe(viewLifecycleOwner) { state ->
232234
when (state) {
233235
is MessageInputViewModel.CreateThreadStartState ->
234236
binding.fragmentCreateThreadView.createThreadView.visibility = View.GONE
@@ -261,7 +263,7 @@ class MessageInputFragment : Fragment() {
261263
val connectionGained = (!wasOnline && isOnline)
262264
Log.d(TAG, "isOnline: $isOnline\nwasOnline: $wasOnline\nconnectionGained: $connectionGained")
263265
if (connectionGained) {
264-
chatActivity.messageInputViewModel.sendUnsentMessages(
266+
messageInputViewModel.sendUnsentMessages(
265267
chatActivity.conversationUser!!.getCredentials(),
266268
ApiUtils.getUrlForChat(
267269
chatActivity.chatApiVersion,
@@ -274,7 +276,7 @@ class MessageInputFragment : Fragment() {
274276
}.collect()
275277
}
276278

277-
chatActivity.messageInputViewModel.callStartedFlow.observe(viewLifecycleOwner) {
279+
messageInputViewModel.callStartedFlow.observe(viewLifecycleOwner) {
278280
val (message, show) = it
279281
if (show) {
280282
binding.fragmentCallStarted.callAuthorChip.text = message.actorDisplayName
@@ -364,7 +366,7 @@ class MessageInputFragment : Fragment() {
364366
binding.fragmentMessageInputView.messageInput.setSelection(draft.messageCursor)
365367

366368
if (draft.threadTitle?.isNotEmpty() == true) {
367-
chatActivity.messageInputViewModel.startThreadCreation()
369+
messageInputViewModel.startThreadCreation()
368370
}
369371

370372
if (draft.messageText != "") {
@@ -479,7 +481,7 @@ class MessageInputFragment : Fragment() {
479481
replaceMentionChipSpans(editable)
480482
val inputEditText = editable.toString()
481483

482-
val message = chatActivity.messageInputViewModel.getEditChatMessage.value as ChatMessage
484+
val message = messageInputViewModel.getEditChatMessage.value as ChatMessage
483485
if (message.message!!.trim() != inputEditText.trim()) {
484486
if (message.messageParameters != null) {
485487
val editedMessage = messageUtils.processEditMessageParameters(
@@ -566,7 +568,7 @@ class MessageInputFragment : Fragment() {
566568
val base = SystemClock.elapsedRealtime()
567569
voiceRecordStartTime = System.currentTimeMillis()
568570
binding.fragmentMessageInputView.audioRecordDuration.base = base
569-
chatActivity.messageInputViewModel.setRecordingTime(base)
571+
messageInputViewModel.setRecordingTime(base)
570572
binding.fragmentMessageInputView.audioRecordDuration.start()
571573
chatActivity.chatViewModel.startAudioRecording(requireContext(), chatActivity.currentConversation!!)
572574
showRecordAudioUi(true)
@@ -938,7 +940,7 @@ class MessageInputFragment : Fragment() {
938940
}
939941

940942
private fun sendMessage(message: String, sendWithoutNotification: Boolean) {
941-
chatActivity.messageInputViewModel.sendChatMessage(
943+
messageInputViewModel.sendChatMessage(
942944
credentials = chatActivity.conversationUser!!.getCredentials(),
943945
url = ApiUtils.getUrlForChat(
944946
chatActivity.chatApiVersion,
@@ -1004,12 +1006,12 @@ class MessageInputFragment : Fragment() {
10041006
val apiVersion: Int = ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(1))
10051007

10061008
if (message.isTemporary) {
1007-
chatActivity.messageInputViewModel.editTempChatMessage(
1009+
messageInputViewModel.editTempChatMessage(
10081010
message,
10091011
editedMessageText
10101012
)
10111013
} else {
1012-
chatActivity.messageInputViewModel.editChatMessage(
1014+
messageInputViewModel.editChatMessage(
10131015
chatActivity.credentials!!,
10141016
ApiUtils.getUrlForChatMessage(
10151017
apiVersion,
@@ -1044,7 +1046,7 @@ class MessageInputFragment : Fragment() {
10441046
binding.fragmentMessageInputView.inputEditText.setText("")
10451047
binding.fragmentEditView.editMessageView.visibility = View.GONE
10461048
binding.fragmentMessageInputView.attachmentButton.visibility = View.VISIBLE
1047-
chatActivity.messageInputViewModel.edit(null)
1049+
messageInputViewModel.edit(null)
10481050
handleButtonsVisibility()
10491051
}
10501052

@@ -1127,7 +1129,7 @@ class MessageInputFragment : Fragment() {
11271129

11281130
private fun cancelCreateThread() {
11291131
chatActivity.cancelCreateThread()
1130-
chatActivity.messageInputViewModel.stopThreadCreation()
1132+
messageInputViewModel.stopThreadCreation()
11311133
binding.fragmentCreateThreadView.createThreadView.visibility = View.GONE
11321134
}
11331135

app/src/main/java/com/nextcloud/talk/chat/MessageInputVoiceRecordingFragment.kt

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import android.widget.SeekBar
1616
import android.widget.SeekBar.OnSeekBarChangeListener
1717
import androidx.core.content.ContextCompat
1818
import androidx.fragment.app.Fragment
19+
import androidx.fragment.app.activityViewModels
1920
import androidx.lifecycle.lifecycleScope
2021
import autodagger.AutoInjector
2122
import com.nextcloud.android.common.ui.theme.utils.ColorRole
2223
import com.nextcloud.talk.R
2324
import com.nextcloud.talk.application.NextcloudTalkApplication
2425
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
2526
import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager
27+
import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel
2628
import com.nextcloud.talk.databinding.FragmentMessageInputVoiceRecordingBinding
2729
import com.nextcloud.talk.ui.theme.ViewThemeUtils
2830
import kotlinx.coroutines.flow.collect
@@ -43,6 +45,8 @@ class MessageInputVoiceRecordingFragment : Fragment() {
4345
@Inject
4446
lateinit var viewThemeUtils: ViewThemeUtils
4547

48+
private val messageInputViewModel: MessageInputViewModel by activityViewModels()
49+
4650
lateinit var binding: FragmentMessageInputVoiceRecordingBinding
4751
private lateinit var chatActivity: ChatActivity
4852
private var pause = false
@@ -58,48 +62,48 @@ class MessageInputVoiceRecordingFragment : Fragment() {
5862
themeVoiceRecordingView()
5963
initVoiceRecordingView()
6064
initObservers()
61-
this.lifecycle.addObserver(chatActivity.messageInputViewModel)
65+
this.lifecycle.addObserver(messageInputViewModel)
6266
return binding.root
6367
}
6468

6569
override fun onDestroyView() {
6670
super.onDestroyView()
67-
chatActivity.messageInputViewModel.stopMediaPlayer() // if it wasn't stopped already
68-
this.lifecycle.removeObserver(chatActivity.messageInputViewModel)
71+
messageInputViewModel.stopMediaPlayer() // if it wasn't stopped already
72+
this.lifecycle.removeObserver(messageInputViewModel)
6973
}
7074

7175
private fun initObservers() {
72-
chatActivity.messageInputViewModel.startMicInput(requireContext())
73-
chatActivity.messageInputViewModel.micInputAudioObserver.observe(viewLifecycleOwner) {
76+
messageInputViewModel.startMicInput(requireContext())
77+
messageInputViewModel.micInputAudioObserver.observe(viewLifecycleOwner) {
7478
binding.micInputCloud.setRotationSpeed(it.first, it.second)
7579
}
7680

7781
lifecycleScope.launch {
78-
chatActivity.messageInputViewModel.mediaPlayerSeekbarObserver.onEach { progress ->
82+
messageInputViewModel.mediaPlayerSeekbarObserver.onEach { progress ->
7983
if (progress >= SEEK_LIMIT) {
8084
togglePausePlay()
8185
binding.seekbar.progress = 0
82-
} else if (!pause && chatActivity.messageInputViewModel.isVoicePreviewPlaying.value == true) {
86+
} else if (!pause && messageInputViewModel.isVoicePreviewPlaying.value == true) {
8387
binding.seekbar.progress = progress
8488
}
8589
}.collect()
8690
}
8791

88-
chatActivity.messageInputViewModel.getAudioFocusChange.observe(viewLifecycleOwner) { state ->
92+
messageInputViewModel.getAudioFocusChange.observe(viewLifecycleOwner) { state ->
8993
when (state) {
9094
AudioFocusRequestManager.ManagerState.AUDIO_FOCUS_CHANGE_LOSS -> {
91-
if (chatActivity.messageInputViewModel.isVoicePreviewPlaying.value == true) {
92-
chatActivity.messageInputViewModel.stopMediaPlayer()
95+
if (messageInputViewModel.isVoicePreviewPlaying.value == true) {
96+
messageInputViewModel.stopMediaPlayer()
9397
}
9498
}
9599
AudioFocusRequestManager.ManagerState.AUDIO_FOCUS_CHANGE_LOSS_TRANSIENT -> {
96-
if (chatActivity.messageInputViewModel.isVoicePreviewPlaying.value == true) {
97-
chatActivity.messageInputViewModel.pauseMediaPlayer()
100+
if (messageInputViewModel.isVoicePreviewPlaying.value == true) {
101+
messageInputViewModel.pauseMediaPlayer()
98102
}
99103
}
100104
AudioFocusRequestManager.ManagerState.BROADCAST_RECEIVED -> {
101-
if (chatActivity.messageInputViewModel.isVoicePreviewPlaying.value == true) {
102-
chatActivity.messageInputViewModel.pauseMediaPlayer()
105+
if (messageInputViewModel.isVoicePreviewPlaying.value == true) {
106+
messageInputViewModel.pauseMediaPlayer()
103107
}
104108
}
105109
}
@@ -129,13 +133,13 @@ class MessageInputVoiceRecordingFragment : Fragment() {
129133
togglePausePlay()
130134
}
131135

132-
binding.audioRecordDuration.base = chatActivity.messageInputViewModel.getRecordingTime.value ?: 0L
136+
binding.audioRecordDuration.base = messageInputViewModel.getRecordingTime.value ?: 0L
133137
binding.audioRecordDuration.start()
134138

135139
binding.seekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
136140
override fun onProgressChanged(seekbar: SeekBar, progress: Int, fromUser: Boolean) {
137141
if (fromUser) {
138-
chatActivity.messageInputViewModel.seekMediaPlayerTo(progress)
142+
messageInputViewModel.seekMediaPlayerTo(progress)
139143
}
140144
}
141145

@@ -151,23 +155,23 @@ class MessageInputVoiceRecordingFragment : Fragment() {
151155

152156
private fun clear() {
153157
chatActivity.chatViewModel.setVoiceRecordingLocked(false)
154-
chatActivity.messageInputViewModel.stopMicInput()
158+
messageInputViewModel.stopMicInput()
155159
chatActivity.chatViewModel.stopAudioRecording()
156-
chatActivity.messageInputViewModel.stopMediaPlayer()
160+
messageInputViewModel.stopMediaPlayer()
157161
binding.audioRecordDuration.stop()
158162
binding.audioRecordDuration.clearAnimation()
159163
}
160164

161165
private fun togglePreviewVisibility() {
162166
val visibility = binding.voicePreviewContainer.visibility
163167
binding.voicePreviewContainer.visibility = if (visibility == View.VISIBLE) {
164-
chatActivity.messageInputViewModel.stopMediaPlayer()
168+
messageInputViewModel.stopMediaPlayer()
165169
binding.playPauseBtn.icon = ContextCompat.getDrawable(
166170
requireContext(),
167171
R.drawable.ic_baseline_play_arrow_voice_message_24
168172
)
169173
pause = true
170-
chatActivity.messageInputViewModel.startMicInput(requireContext())
174+
messageInputViewModel.startMicInput(requireContext())
171175
chatActivity.chatViewModel.startAudioRecording(requireContext(), chatActivity.currentConversation!!)
172176
binding.audioRecordDuration.visibility = View.VISIBLE
173177
binding.audioRecordDuration.base = SystemClock.elapsedRealtime()
@@ -176,7 +180,7 @@ class MessageInputVoiceRecordingFragment : Fragment() {
176180
} else {
177181
pause = false
178182
binding.seekbar.progress = 0
179-
chatActivity.messageInputViewModel.stopMicInput()
183+
messageInputViewModel.stopMicInput()
180184
chatActivity.chatViewModel.stopAudioRecording()
181185
binding.audioRecordDuration.visibility = View.GONE
182186
binding.audioRecordDuration.stop()
@@ -186,18 +190,18 @@ class MessageInputVoiceRecordingFragment : Fragment() {
186190

187191
private fun togglePausePlay() {
188192
val path = chatActivity.chatViewModel.getCurrentVoiceRecordFile()
189-
if (chatActivity.messageInputViewModel.isVoicePreviewPlaying.value == true) {
193+
if (messageInputViewModel.isVoicePreviewPlaying.value == true) {
190194
binding.playPauseBtn.icon = ContextCompat.getDrawable(
191195
requireContext(),
192196
R.drawable.ic_baseline_play_arrow_voice_message_24
193197
)
194-
chatActivity.messageInputViewModel.stopMediaPlayer()
198+
messageInputViewModel.stopMediaPlayer()
195199
} else {
196200
binding.playPauseBtn.icon = ContextCompat.getDrawable(
197201
requireContext(),
198202
R.drawable.ic_baseline_pause_voice_message_24
199203
)
200-
chatActivity.messageInputViewModel.startMediaPlayer(path)
204+
messageInputViewModel.startMediaPlayer(path)
201205
}
202206
}
203207

app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import androidx.lifecycle.LiveData
1515
import androidx.lifecycle.MutableLiveData
1616
import androidx.lifecycle.ViewModel
1717
import androidx.lifecycle.viewModelScope
18+
import autodagger.AutoInjector
19+
import com.nextcloud.talk.application.NextcloudTalkApplication
1820
import com.nextcloud.talk.chat.data.ChatMessageRepository
1921
import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager
2022
import com.nextcloud.talk.chat.data.io.AudioRecorderManager
@@ -31,11 +33,9 @@ import kotlinx.coroutines.launch
3133
import javax.inject.Inject
3234

3335
@Suppress("Detekt.TooManyFunctions")
34-
class MessageInputViewModel @Inject constructor(
35-
private val audioRecorderManager: AudioRecorderManager,
36-
private val mediaPlayerManager: MediaPlayerManager,
37-
private val audioFocusRequestManager: AudioFocusRequestManager
38-
) : ViewModel(),
36+
@AutoInjector(NextcloudTalkApplication::class)
37+
class MessageInputViewModel :
38+
ViewModel(),
3939
DefaultLifecycleObserver {
4040

4141
enum class LifeCycleFlag {
@@ -44,6 +44,19 @@ class MessageInputViewModel @Inject constructor(
4444
STOPPED
4545
}
4646

47+
init {
48+
NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
49+
}
50+
51+
@Inject
52+
lateinit var audioRecorderManager: AudioRecorderManager
53+
54+
@Inject
55+
lateinit var mediaPlayerManager: MediaPlayerManager
56+
57+
@Inject
58+
lateinit var audioFocusRequestManager: AudioFocusRequestManager
59+
4760
lateinit var chatRepository: ChatMessageRepository
4861
lateinit var currentLifeCycleFlag: LifeCycleFlag
4962
val disposableSet = mutableSetOf<Disposable>()

app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import androidx.lifecycle.ViewModelProvider
1212
import com.nextcloud.talk.account.viewmodels.BrowserLoginActivityViewModel
1313
import com.nextcloud.talk.activities.CallViewModel
1414
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
15-
import com.nextcloud.talk.chat.viewmodels.MessageInputViewModel
1615
import com.nextcloud.talk.chooseaccount.StatusViewModel
1716
import com.nextcloud.talk.contacts.ContactsViewModel
1817
import com.nextcloud.talk.contextchat.ContextChatViewModel
@@ -125,11 +124,6 @@ abstract class ViewModelModule {
125124
@ViewModelKey(ChatViewModel::class)
126125
abstract fun chatViewModel(viewModel: ChatViewModel): ViewModel
127126

128-
@Binds
129-
@IntoMap
130-
@ViewModelKey(MessageInputViewModel::class)
131-
abstract fun messageInputViewModel(viewModel: MessageInputViewModel): ViewModel
132-
133127
@Binds
134128
@IntoMap
135129
@ViewModelKey(ConversationInfoViewModel::class)

0 commit comments

Comments
 (0)