- I did a bunch of UI logic in ChatActivity and view_message_input, mainly in setting up the recording interface
- I created a custom component, MicInputCloud, under the hood it's 3 ovals, with a hole cut in the center for the icon. The ovals are at around 50% opacity, and they each have their own rotations and size changes animated. General rotation speed and colors can be overridden by the activity implementing it.
- I also added a floating action button to activity_chat, to show when the voice recording is locked or not.
- I can replay or pause preview voice recordings before sending or deleting
- Preview voice recording is now smoother and click boxes are bigger and well defined
Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
- Added duration of the voice message playing
- Fixed the seekbar bug, and made it more smoother
Signed-off-by: Julius Linus <julius.linus@nextcloud.com>
Everytime a second attempt was made to enter a call, the connection failed.
How to reproduce:
- Enter the ChatActivity
-> joins the room (so the new session is in the ApplicationWideCurrentRoomHolder)
- Start call
-> in the CallActivity we don't join again and instead execute callOrJoinRoomViaWebSocket()
- Call connection is successful
- Hangup on android
-> the ApplicationWideCurrentRoomHolder gets cleared (so also it's session)
- Staying in the chat and start the call another time
-> When we open CallActivity another time, ApplicationWideCurrentRoomHolder.sessionId is empty.Because of this, in joinRoomAndCall, joinRoom is executed again.
But as we are still in the room and have a session, joinRoom is problematic because on serverside in SignalingController - if there is still a session - it's considered as old.
So Nextcloud now sends a backend message (disinvite) to the external signaling controller that the session (of the first join) was removed.
So the External signaling server removes the session and closes the websocket. (The message for this might be improved, see https://github.com/strukturag/nextcloud-spreed-signaling/issues/512)
As the websocket is now closed, it won't be possible for the android app to send any signaling message anymore. There will just be the connecting screen and the call connection fails.
Solution for now:
ApplicationWideCurrentRoomHolder.getInstance().clear() should not be executed when hanging up, so the session won't be cleared and in the next attempt to start the call the room is not joined again mistakenly.
Instead to clear the `ApplicationWideCurrentRoomHolder`, only
setInCall(false);
setDialing(false);
are set so that the method isNotInCall() in ChatActivity remains working correctly.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
without this change the continue button was broken (no room token -> response 404 for getRoom. But for creating an open conversation getRoom should not be executed at all) and the emoji button was missing
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
reported via gplay:
Exception java.lang.NullPointerException:
at com.nextcloud.talk.profile.ProfileActivity$save$1.onError (ProfileActivity.kt:457)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.checkTerminated (ObservableObserveOn.java:281)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal (ObservableObserveOn.java:172)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run (ObservableObserveOn.java:255)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run (HandlerScheduler.java:124)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:257)
at android.app.ActivityThread.main (ActivityThread.java:8220)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
could happen when using long click on header when using the conversation search
Exception java.lang.ClassCastException:
at com.nextcloud.talk.conversationlist.ConversationsListActivity.onItemLongClick (ConversationsListActivity.kt:1027)
at eu.davidea.viewholders.FlexibleViewHolder.onLongClick (FlexibleViewHolder.java:144)
at android.view.View.performLongClickInternal (View.java:8240)
at android.view.View.performLongClick (View.java:8198)
at android.view.View.performLongClick (View.java:8216)
at android.view.View$CheckForLongPress.run (View.java:30194)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:246)
at android.app.ActivityThread.main (ActivityThread.java:8653)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This does not fix the root cause. So probably position should not be -1 here.
However if it is -1, this commit avoids the following exception and swiping to reply simply won't work.
Exception java.lang.ArrayIndexOutOfBoundsException: length=163; index=-1
at java.util.ArrayList.get (ArrayList.java:439)
at com.nextcloud.talk.chat.ChatActivity$setupSwipeToReply$messageSwipeController$1.showReplyUI (ChatActivity.kt:1144)
at com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback.setTouchListener$lambda$0 (MessageSwipeCallback.kt:137)
at com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback.$r8$lambda$hYMm2zsKL8yVqo4e364Wb8cWEW8
at com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback$$ExternalSyntheticLambda0.onTouch
at android.view.View.dispatchTouchEvent (View.java:15046)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3115)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2788)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:3121)
at android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2802)
at com.android.internal.policy.DecorView.superDispatchTouchEvent (DecorView.java:500)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent (PhoneWindow.java:1912)
at android.app.Activity.dispatchTouchEvent (Activity.java:4299)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent (WindowCallbackWrapper.java:70)
at com.android.internal.policy.DecorView.dispatchTouchEvent (DecorView.java:458)
at android.view.View.dispatchPointerEvent (View.java:15309)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent (ViewRootImpl.java:6778)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:6578)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:6034)
at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:6091)
at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:6057)
at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:6222)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:6065)
at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:6279)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:6038)
at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:6091)
at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:6057)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:6065)
at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:6038)
at android.view.ViewRootImpl.deliverInputEvent (ViewRootImpl.java:9206)
at android.view.ViewRootImpl.doProcessInputEvents (ViewRootImpl.java:9157)
at android.view.ViewRootImpl.enqueueInputEvent (ViewRootImpl.java:9126)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent (ViewRootImpl.java:9329)
at android.view.InputEventReceiver.dispatchInputEvent (InputEventReceiver.java:267)
at android.os.MessageQueue.nativePollOnce
at android.os.MessageQueue.next (MessageQueue.java:335)
at android.os.Looper.loopOnce (Looper.java:161)
at android.os.Looper.loop (Looper.java:288)
at android.app.ActivityThread.main (ActivityThread.java:7918)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
this was temporarily disabled as a workaround because of https://github.com/nextcloud/talk-android/issues/3146
So after screen rotation it could happen that chat was not updated.
Now that the issue is solved, portrait mode will be allowed again
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
handleActionFromContact was not executed in onCreate of the MainActivity which is now fixed by this commit.
+ refactoring some intent handling
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
com.nextcloud.talk2 E Failed to searchContactsByPhoneNumber
java.lang.NullPointerException: Parameter specified as non-null is null: method com.nextcloud.talk.models.json.search.ContactsByNumberOCS.setMap, parameter <set-?>
at com.nextcloud.talk.models.json.search.ContactsByNumberOCS.setMap(Unknown Source:2)
at com.nextcloud.talk.models.json.search.ContactsByNumberOCS$$JsonObjectMapper.parseField(ContactsByNumberOCS$$JsonObjectMapper.java:56)
at com.nextcloud.talk.models.json.search.ContactsByNumberOCS$$JsonObjectMapper.parse(ContactsByNumberOCS$$JsonObjectMapper.java:33)
at com.nextcloud.talk.models.json.search.ContactsByNumberOCS$$JsonObjectMapper.parse(ContactsByNumberOCS$$JsonObjectMapper.java:16)
at com.nextcloud.talk.models.json.search.ContactsByNumberOverall$$JsonObjectMapper.parseField(ContactsByNumberOverall$$JsonObjectMapper.java:40)
at com.nextcloud.talk.models.json.search.ContactsByNumberOverall$$JsonObjectMapper.parse(ContactsByNumberOverall$$JsonObjectMapper.java:30)
at com.nextcloud.talk.models.json.search.ContactsByNumberOverall$$JsonObjectMapper.parse(ContactsByNumberOverall$$JsonObjectMapper.java:13)
at com.bluelinelabs.logansquare.JsonMapper.parse(JsonMapper.java:52)
at com.bluelinelabs.logansquare.LoganSquare.parse(LoganSquare.java:69)
at com.github.aurae.retrofit2.LoganSquareResponseBodyConverter.convert(LoganSquareResponseBodyConverter.java:30)
at com.github.aurae.retrofit2.LoganSquareResponseBodyConverter.convert(LoganSquareResponseBodyConverter.java:16)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46)
at io.reactivex.Observable.subscribe(Observable.java:12284)
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:35)
at io.reactivex.Observable.subscribe(Observable.java:12284)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:608)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Exception java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
at com.google.android.material.internal.ThemeEnforcement.checkTheme (ThemeEnforcement.java:247)
at com.google.android.material.internal.ThemeEnforcement.checkAppCompatTheme (ThemeEnforcement.java:212)
at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme (ThemeEnforcement.java:147)
at com.google.android.material.internal.ThemeEnforcement.obtainTintedStyledAttributes (ThemeEnforcement.java:114)
at com.google.android.material.textfield.TextInputLayout.<init> (TextInputLayout.java:472)
at com.google.android.material.textfield.TextInputLayout.<init> (TextInputLayout.java:451)
at com.google.android.material.textfield.TextInputLayout.<init> (TextInputLayout.java:447)
at com.nextcloud.talk.settings.SettingsActivity.askForPhoneNumber (SettingsActivity.kt:935)
at com.nextcloud.talk.settings.SettingsActivity.access$askForPhoneNumber (SettingsActivity.kt:105)
at com.nextcloud.talk.settings.SettingsActivity$checkForPhoneNumber$1.onNext (SettingsActivity.kt:915)
at com.nextcloud.talk.settings.SettingsActivity$checkForPhoneNumber$1.onNext (SettingsActivity.kt:908)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal (ObservableObserveOn.java:201)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run (ObservableObserveOn.java:255)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run (HandlerScheduler.java:124)
at android.os.Handler.handleCallback (Handler.java:942)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:211)
at android.os.Looper.loop (Looper.java:300)
at android.app.ActivityThread.main (ActivityThread.java:8294)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1028)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
without this fix, it could happen that pullChatMessagesPending remains true after the conversation screen was in background. As a result the check
if (pullChatMessagesPending) {
Log.d(TAG, "pullChatMessages - pullChatMessagesPending is true, exiting")
return
}
in pullChatMessages() always returns without to pull chat messages (so there was even no long-polling anymore).
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
without this fix:
after login the conversation list opened multiple times for the same user when other users already exist
reason:
proceedWithLogin() in AccountVerificationController is called multiple times because for ALL accounts (for (User user : userEntityObjectList)) the workers send their results via eventBus to
AccountVerificationController#onMessageEvent(eventStatus: EventStatus)
So depending on how many accounts exist, the ConversationList was loaded x times.
solution:
if internalAccountId is already the active one, no need to load the conversationList another time.
when there is only one account -> currentUser id and internalAccountId are the same so it would not enter the condition. Thus also allowing it when only one user exists.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
otherwise the list in the ConversationListActivity would handle it which results in unexpected user actions dialog popup
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
The parsed result was without quotes which resulted in error:
Unterminated object at character 21 of [{fromLabel=English (US),
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
sending too much data via intent always is a bad pattern which can lead to TransactionTooLargeException.
When OpenAI translation is enabled, the capabilities contain a ton of translation combinations. These capabilities are contained in 'currentUser' as well in 'selectedConversation'. So, TransactionTooLargeException was thrown.
this PR:
- avoids passing too much data as parcelables in intents (esp. conversation and user)
- introduces MVVM patterns to load required data (esp conversation) from backend (for now via requests, in the future from database first)
- introduces ConversationModel which is created out of the Conversation json model
- loads user data via injection when possible
- creates some quickfixes in ConversationBottomDialog, EntryMenuController and OperationsMenuController.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
# Send start/stop typing
Send "Typing" every 10 sec when there was a change
Send stop typing:
- when input is deleted
- when there was no input during the 10s timer
- when on leaving room
# Receive start/stop typing
Clear typing for participant after 15s if no start typing-message was received.
Use userId instead sessionId to manage typing participants. This ensures participants are not shown multiple times when using multiple devices with the same user (multisession). To get the userId via websocket, SignalingMessageReceiver and WebSocketInstance had to be modified to pass the CallWebSocketMessage in case the signalingMessage.type is related to typing. Not sure if this is the best solution but didn't find any other way.
Typing is not handled when the userId is of the own user (this could happen when using multiple devices)
In case userId is null (which happens for guests), their sessionId is used as key for the typingParticipants map.
# Other
Disable setting for typing indicator when no HPB is used + Avoid crash in chat when no HPB is used.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
this commit fixes bugs from d3056ff2825e53040ca49b86b84f91f73a3eb11c and 1185dcf17a99ca62efd32f8a53c298ec4fd6c4d0
fix onBackPressed handling to use OnBackPressedCallback
remove unnecessary onBackPressedCallback's when they only finished the activity
replaced some finishAffinity methods with finish
...
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Overdraw is expected here to avoid transparency for the typing indicator view. Instead chat message content should be hidden behind the typing indicator view.
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
..."Resource IDs will be non-final by default in Android Gradle Plugin version 8.0, avoid using them as annotation attributes" by using @KeyByString
keys were also wrong by copy&paste and are now fixed
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>