Merge pull request #1922 from nextcloud/bugfix/noid/kotlinConversion5

Migrate OperationsMenuController to kotlin
This commit is contained in:
Andy Scherzinger 2022-05-07 13:29:04 +02:00 committed by GitHub
commit 4c199b1369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 821 additions and 810 deletions

View File

@ -1,808 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.controllers.bottomsheet;
import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_JOIN_ROOM;
import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.ConversationsListFetchDataEvent;
import com.nextcloud.talk.events.OpenConversationEvent;
import com.nextcloud.talk.models.RetrofitBucket;
import com.nextcloud.talk.models.database.CapabilitiesUtil;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.capabilities.Capabilities;
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomOverall;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.NoSupportedApiException;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
import org.greenrobot.eventbus.EventBus;
import org.parceler.Parcels;
import java.io.IOException;
import java.util.ArrayList;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import autodagger.AutoInjector;
import butterknife.BindView;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import retrofit2.HttpException;
import retrofit2.Response;
@AutoInjector(NextcloudTalkApplication.class)
public class OperationsMenuController extends BaseController {
private static final String TAG = "OperationsMenuController";
@BindView(R.id.progress_bar)
ProgressBar progressBar;
@BindView(R.id.result_image_view)
ImageView resultImageView;
@BindView(R.id.result_text_view)
TextView resultsTextView;
@BindView(R.id.ok_button)
Button okButton;
@BindView(R.id.web_button)
Button webButton;
@Inject
NcApi ncApi;
@Inject
UserUtils userUtils;
@Inject
EventBus eventBus;
private ConversationOperationEnum operation;
private Conversation conversation;
private UserEntity currentUser;
private String callPassword;
private String callUrl;
private String baseUrl;
private String conversationToken;
private Disposable disposable;
private Conversation.ConversationType conversationType;
private ArrayList<String> invitedUsers = new ArrayList<>();
private ArrayList<String> invitedGroups = new ArrayList<>();
private Capabilities serverCapabilities;
private String credentials;
private String conversationName;
public OperationsMenuController(Bundle args) {
super(args);
this.operation = (ConversationOperationEnum) args.getSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE());
if (args.containsKey(BundleKeys.INSTANCE.getKEY_ROOM())) {
this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
}
this.callPassword = args.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), "");
this.callUrl = args.getString(BundleKeys.INSTANCE.getKEY_CALL_URL(), "");
if (args.containsKey(BundleKeys.INSTANCE.getKEY_INVITED_PARTICIPANTS())) {
this.invitedUsers = args.getStringArrayList(BundleKeys.INSTANCE.getKEY_INVITED_PARTICIPANTS());
}
if (args.containsKey(BundleKeys.INSTANCE.getKEY_INVITED_GROUP())) {
this.invitedGroups = args.getStringArrayList(BundleKeys.INSTANCE.getKEY_INVITED_GROUP());
}
if (args.containsKey(BundleKeys.INSTANCE.getKEY_CONVERSATION_TYPE())) {
this.conversationType = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_CONVERSATION_TYPE()));
}
if (args.containsKey(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES())) {
this.serverCapabilities = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES()));
}
this.conversationName = args.getString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), "");
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_operations_menu, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
currentUser = userUtils.getCurrentUser();
if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1);
if (callUrl.contains("/index.php")) {
baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php"));
} else {
baseUrl = callUrl.substring(0, callUrl.indexOf("/call"));
}
}
if (!TextUtils.isEmpty(baseUrl) && !baseUrl.equals(currentUser.getBaseUrl())) {
if (serverCapabilities != null) {
try {
useBundledCapabilitiesForGuest();
} catch (IOException e) {
// Fall back to fetching capabilities again
fetchCapabilitiesForGuest();
}
} else {
fetchCapabilitiesForGuest();
}
} else {
processOperation();
}
}
@SuppressLint("LongLogTag")
private void useBundledCapabilitiesForGuest() throws IOException {
currentUser = new UserEntity();
currentUser.setBaseUrl(baseUrl);
currentUser.setUserId("?");
try {
currentUser.setCapabilities(LoganSquare.serialize(serverCapabilities));
} catch (IOException e) {
Log.e("OperationsMenu", "Failed to serialize capabilities");
throw e;
}
try {
checkCapabilities(currentUser);
processOperation();
} catch (NoSupportedApiException e) {
showResultImage(false, false);
Log.d(TAG, "No supported server version found", e);
}
}
@SuppressLint("LongLogTag")
private void fetchCapabilitiesForGuest() {
ncApi.getCapabilities(null, ApiUtils.getUrlForCapabilities(baseUrl))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<CapabilitiesOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@SuppressLint("LongLogTag")
@Override
public void onNext(@io.reactivex.annotations.NonNull CapabilitiesOverall capabilitiesOverall) {
currentUser = new UserEntity();
currentUser.setBaseUrl(baseUrl);
currentUser.setUserId("?");
try {
currentUser.setCapabilities(
LoganSquare
.serialize(
capabilitiesOverall
.getOcs()
.getData()
.getCapabilities()));
} catch (IOException e) {
Log.e("OperationsMenu", "Failed to serialize capabilities");
}
try {
checkCapabilities(currentUser);
processOperation();
} catch (NoSupportedApiException e) {
showResultImage(false, false);
Log.d(TAG, "No supported server version found", e);
}
}
@SuppressLint("LongLogTag")
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
showResultImage(false, false);
Log.e(TAG, "Error fetching capabilities for guest", e);
}
@Override
public void onComplete() {
}
});
}
@SuppressLint("LongLogTag")
private void processOperation() {
RoomOperationsObserver roomOperationsObserver = new RoomOperationsObserver();
GenericOperationsObserver genericOperationsObserver = new GenericOperationsObserver();
if (currentUser == null) {
showResultImage(false, true);
Log.e(TAG, "Ended up in processOperation without a valid currentUser");
return;
}
credentials = ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken());
int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, ApiUtils.APIv1});
int chatApiVersion = ApiUtils.getChatApiVersion(currentUser, new int[] {ApiUtils.APIv1});
switch (operation) {
case OPS_CODE_RENAME_ROOM:
ncApi.renameRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
conversation.getToken()),
conversation.getName())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
break;
case OPS_CODE_MAKE_PUBLIC:
ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
break;
case OPS_CODE_CHANGE_PASSWORD:
case OPS_CODE_CLEAR_PASSWORD:
case OPS_CODE_SET_PASSWORD:
String pass = "";
if (conversation.getPassword() != null) {
pass = conversation.getPassword();
}
ncApi.setPassword(credentials, ApiUtils.getUrlForRoomPassword(apiVersion, currentUser.getBaseUrl(),
conversation.getToken()), pass)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
break;
case OPS_CODE_MAKE_PRIVATE:
ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomPublic(apiVersion,
currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
break;
case OPS_CODE_GET_AND_JOIN_ROOM:
ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
disposable = d;
}
@Override
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
conversation = roomOverall.getOcs().getData();
if (conversation.isHasPassword() && conversation.isGuest()) {
eventBus.post(new ConversationsListFetchDataEvent());
Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl);
try {
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(),
Parcels.wrap(LoganSquare.parse(currentUser.getCapabilities(),
Capabilities.class)));
} catch (IOException e) {
Log.e(TAG, "Failed to parse capabilities for guest");
showResultImage(false, false);
}
bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), OPS_CODE_JOIN_ROOM);
getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (conversation.isGuest()) {
ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion,
baseUrl,
conversationToken), null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(
@io.reactivex.annotations.NonNull Disposable d
) {
}
@Override
public void onNext(
@io.reactivex.annotations.NonNull RoomOverall roomOverall
) {
conversation = roomOverall.getOcs().getData();
initiateConversation();
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
showResultImage(false, false);
dispose();
}
@Override
public void onComplete() {
}
});
} else {
initiateConversation();
}
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
showResultImage(false, false);
dispose();
}
@Override
public void onComplete() {
dispose();
}
});
break;
case OPS_CODE_INVITE_USERS:
RetrofitBucket retrofitBucket;
String invite = null;
if (invitedGroups.size() > 0) {
invite = invitedGroups.get(0);
}
if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL)) {
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
"3", null, invite, conversationName);
} else {
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(),
"2", null, invite, conversationName);
}
ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@Override
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
conversation = roomOverall.getOcs().getData();
ncApi.getRoom(credentials,
ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<RoomOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@Override
public void onNext(
@io.reactivex.annotations.NonNull RoomOverall roomOverall
) {
conversation = roomOverall.getOcs().getData();
inviteUsersToAConversation();
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
showResultImage(false, false);
dispose();
}
@Override
public void onComplete() {
}
});
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
showResultImage(false, false);
dispose();
}
@Override
public void onComplete() {
dispose();
}
});
break;
case OPS_CODE_MARK_AS_READ:
ncApi.setChatReadMarker(credentials,
ApiUtils.getUrlForSetChatReadMarker(chatApiVersion,
currentUser.getBaseUrl(),
conversation.getToken()),
conversation.lastMessage.jsonMessageId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
break;
case OPS_CODE_REMOVE_FAVORITE:
case OPS_CODE_ADD_FAVORITE:
if (operation == OPS_CODE_REMOVE_FAVORITE) {
ncApi.removeConversationFromFavorites(credentials,
ApiUtils.getUrlForRoomFavorite(apiVersion,
currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
} else {
ncApi.addConversationToFavorites(credentials,
ApiUtils.getUrlForRoomFavorite(apiVersion,
currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver);
}
break;
case OPS_CODE_JOIN_ROOM:
ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion,
baseUrl,
conversationToken),
callPassword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(roomOperationsObserver);
break;
default:
break;
}
}
private void showResultImage(boolean everythingOK, boolean isGuestSupportError) {
progressBar.setVisibility(View.GONE);
if (getResources() != null) {
if (everythingOK) {
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(),
R.drawable.ic_check_circle_black_24dp,
R.color.nc_darkGreen));
} else {
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(),
R.drawable.ic_cancel_black_24dp,
R.color.nc_darkRed));
}
}
resultImageView.setVisibility(View.VISIBLE);
if (everythingOK) {
resultsTextView.setText(R.string.nc_all_ok_operation);
} else {
resultsTextView.setTextColor(getResources().getColor(R.color.nc_darkRed));
if (!isGuestSupportError) {
resultsTextView.setText(R.string.nc_failed_to_perform_operation);
} else {
resultsTextView.setText(R.string.nc_failed_signaling_settings);
webButton.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(callUrl));
startActivity(browserIntent);
});
webButton.setVisibility(View.VISIBLE);
}
}
resultsTextView.setVisibility(View.VISIBLE);
if (everythingOK) {
eventBus.post(new ConversationsListFetchDataEvent());
} else {
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(), R.drawable
.ic_cancel_black_24dp, R.color.nc_darkRed));
okButton.setOnClickListener(v -> eventBus.post(new ConversationsListFetchDataEvent()));
okButton.setVisibility(View.VISIBLE);
}
}
private void dispose() {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
disposable = null;
}
@Override
public void onDestroy() {
super.onDestroy();
dispose();
}
private void checkCapabilities(UserEntity currentUser) throws NoSupportedApiException {
ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
ApiUtils.getCallApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1});
ApiUtils.getChatApiVersion(currentUser, new int[] {1});
ApiUtils.getSignalingApiVersion(currentUser, new int[] {ApiUtils.APIv3, 2, 1});
}
private void inviteUsersToAConversation() {
final ArrayList<String> localInvitedUsers = invitedUsers;
final ArrayList<String> localInvitedGroups = invitedGroups;
if (localInvitedGroups.size() > 0) {
localInvitedGroups.remove(0);
}
int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {4, 1});
if (localInvitedUsers.size() > 0 || (localInvitedGroups.size() > 0 &&
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails"))) {
addGroupsToConversation(localInvitedUsers, localInvitedGroups, apiVersion);
addUsersToConversation(localInvitedUsers, localInvitedGroups, apiVersion);
} else {
initiateConversation();
}
}
private void addUsersToConversation(
ArrayList<String> localInvitedUsers,
ArrayList<String> localInvitedGroups,
int apiVersion)
{
RetrofitBucket retrofitBucket;
for (int i = 0; i < localInvitedUsers.size(); i++) {
final String userId = invitedUsers.get(i);
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(apiVersion,
currentUser.getBaseUrl(),
conversation.getToken(),
userId);
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(new Observer<AddParticipantOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@Override
public void onNext(
@io.reactivex.annotations.NonNull AddParticipantOverall addParticipantOverall
) {
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
dispose();
}
@Override
public void onComplete() {
synchronized (localInvitedUsers) {
localInvitedUsers.remove(userId);
}
if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
initiateConversation();
}
dispose();
}
});
}
}
private void addGroupsToConversation(
ArrayList<String> localInvitedUsers,
ArrayList<String> localInvitedGroups,
int apiVersion)
{
RetrofitBucket retrofitBucket;
if ((localInvitedGroups.size() > 0 &&
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails"))) {
for (int i = 0; i < localInvitedGroups.size(); i++) {
final String groupId = localInvitedGroups.get(i);
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipantWithSource(
apiVersion,
currentUser.getBaseUrl(),
conversation.getToken(),
"groups",
groupId
);
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(new Observer<AddParticipantOverall>() {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
}
@Override
public void onNext(
@io.reactivex.annotations.NonNull AddParticipantOverall addParticipantOverall
) {
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
dispose();
}
@Override
public void onComplete() {
synchronized (localInvitedGroups) {
localInvitedGroups.remove(groupId);
}
if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
initiateConversation();
}
dispose();
}
});
}
}
}
private void initiateConversation() {
eventBus.post(new ConversationsListFetchDataEvent());
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken());
bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), conversation.getRoomId());
bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), conversation.getDisplayName());
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser);
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation));
bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword);
eventBus.post(new OpenConversationEvent(conversation, bundle));
}
private void handleObserverError(@io.reactivex.annotations.NonNull Throwable e) {
if (operation != OPS_CODE_JOIN_ROOM || !(e instanceof HttpException)) {
showResultImage(false, false);
} else {
Response<?> response = ((HttpException) e).response();
if (response != null && response.code() == 403) {
ApplicationWideMessageHolder.getInstance().setMessageType(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG);
getRouter().popCurrentController();
} else {
showResultImage(false, false);
}
}
dispose();
}
private class GenericOperationsObserver implements Observer<GenericOverall> {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
disposable = d;
}
@Override
public void onNext(@io.reactivex.annotations.NonNull GenericOverall genericOverall) {
if (operation != OPS_CODE_JOIN_ROOM) {
showResultImage(true, false);
} else {
throw new IllegalArgumentException("Unsupported operation code observed!");
}
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
handleObserverError(e);
}
@Override
public void onComplete() {
dispose();
}
}
private class RoomOperationsObserver implements Observer<RoomOverall> {
@Override
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
disposable = d;
}
@Override
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
conversation = roomOverall.getOcs().getData();
if (operation != OPS_CODE_JOIN_ROOM) {
showResultImage(true, false);
} else {
conversation = roomOverall.getOcs().getData();
initiateConversation();
}
}
@Override
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
handleObserverError(e);
}
@Override
public void onComplete() {
dispose();
}
}
@Override
public AppBarLayoutType getAppBarLayoutType() {
return AppBarLayoutType.SEARCH_BAR;
}
}

View File

@ -0,0 +1,819 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* @author Andy Scherzinger
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.controllers.bottomsheet
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.View
import autodagger.AutoInjector
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.controllers.base.NewBaseController
import com.nextcloud.talk.controllers.util.viewBinding
import com.nextcloud.talk.databinding.ControllerOperationsMenuBinding
import com.nextcloud.talk.events.ConversationsListFetchDataEvent
import com.nextcloud.talk.events.OpenConversationEvent
import com.nextcloud.talk.models.RetrofitBucket
import com.nextcloud.talk.models.database.CapabilitiesUtil
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.capabilities.Capabilities
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericOverall
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.NoSupportedApiException
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_URL
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_PASSWORD
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TYPE
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INVITED_GROUP
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INVITED_PARTICIPANTS
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SERVER_CAPABILITIES
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
import com.nextcloud.talk.utils.database.user.UserUtils
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import org.parceler.Parcels
import retrofit2.HttpException
import java.io.IOException
import java.util.Collections
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class OperationsMenuController(args: Bundle) : NewBaseController(
R.layout.controller_operations_menu,
args
) {
private val binding: ControllerOperationsMenuBinding by viewBinding(ControllerOperationsMenuBinding::bind)
@Inject
lateinit var ncApi: NcApi
@Inject
lateinit var userUtils: UserUtils
@Inject
lateinit var eventBus: EventBus
private val operation: ConversationOperationEnum?
private var conversation: Conversation? = null
private var currentUser: UserEntity? = null
private val callPassword: String
private val callUrl: String
private var baseUrl: String? = null
private var conversationToken: String? = null
private var disposable: Disposable? = null
private var conversationType: ConversationType? = null
private var invitedUsers: ArrayList<String>? = ArrayList()
private var invitedGroups: ArrayList<String>? = ArrayList()
private var serverCapabilities: Capabilities? = null
private var credentials: String? = null
private val conversationName: String
override val appBarLayoutType: AppBarLayoutType
get() = AppBarLayoutType.SEARCH_BAR
override fun onViewBound(view: View) {
super.onViewBound(view)
sharedApplication!!.componentApplication.inject(this)
currentUser = userUtils.currentUser
if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1)
if (callUrl.contains("/index.php")) {
baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php"))
} else {
baseUrl = callUrl.substring(0, callUrl.indexOf("/call"))
}
}
if (!TextUtils.isEmpty(baseUrl) && baseUrl != currentUser!!.baseUrl) {
if (serverCapabilities != null) {
try {
useBundledCapabilitiesForGuest()
} catch (e: IOException) {
// Fall back to fetching capabilities again
fetchCapabilitiesForGuest()
}
} else {
fetchCapabilitiesForGuest()
}
} else {
processOperation()
}
}
@Throws(IOException::class)
private fun useBundledCapabilitiesForGuest() {
currentUser = UserEntity()
currentUser!!.baseUrl = baseUrl
currentUser!!.userId = "?"
try {
currentUser!!.capabilities = LoganSquare.serialize(serverCapabilities)
} catch (e: IOException) {
Log.e("OperationsMenu", "Failed to serialize capabilities")
throw e
}
try {
checkCapabilities(currentUser!!)
processOperation()
} catch (e: NoSupportedApiException) {
showResultImage(everythingOK = false, isGuestSupportError = false)
Log.d(TAG, "No supported server version found", e)
}
}
private fun fetchCapabilitiesForGuest() {
ncApi.getCapabilities(null, ApiUtils.getUrlForCapabilities(baseUrl))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<CapabilitiesOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(capabilitiesOverall: CapabilitiesOverall) {
currentUser = UserEntity()
currentUser!!.baseUrl = baseUrl
currentUser!!.userId = "?"
try {
currentUser!!.capabilities = LoganSquare
.serialize(capabilitiesOverall.ocs!!.data!!.capabilities)
} catch (e: IOException) {
Log.e("OperationsMenu", "Failed to serialize capabilities")
}
try {
checkCapabilities(currentUser!!)
processOperation()
} catch (e: NoSupportedApiException) {
showResultImage(everythingOK = false, isGuestSupportError = false)
Log.d(TAG, "No supported server version found", e)
}
}
override fun onError(e: Throwable) {
showResultImage(everythingOK = false, isGuestSupportError = false)
Log.e(TAG, "Error fetching capabilities for guest", e)
}
override fun onComplete() {
// unused atm
}
})
}
@Suppress("Detekt.ComplexMethod")
private fun processOperation() {
if (currentUser == null) {
showResultImage(everythingOK = false, isGuestSupportError = true)
Log.e(TAG, "Ended up in processOperation without a valid currentUser")
return
}
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
when (operation) {
ConversationOperationEnum.OPS_CODE_RENAME_ROOM -> operationRenameRoom()
ConversationOperationEnum.OPS_CODE_MAKE_PUBLIC -> operationMakePublic()
ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD,
ConversationOperationEnum.OPS_CODE_CLEAR_PASSWORD,
ConversationOperationEnum.OPS_CODE_SET_PASSWORD -> operationChangePassword()
ConversationOperationEnum.OPS_CODE_MAKE_PRIVATE -> operationMakePrivate()
ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM -> operationGetAndJoinRoom()
ConversationOperationEnum.OPS_CODE_INVITE_USERS -> operationInviteUsers()
ConversationOperationEnum.OPS_CODE_MARK_AS_READ -> operationMarkAsRead()
ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE,
ConversationOperationEnum.OPS_CODE_ADD_FAVORITE -> operationToggleFavorite()
ConversationOperationEnum.OPS_CODE_JOIN_ROOM -> operationJoinRoom()
else -> {
}
}
}
private fun apiVersion(): Int {
return ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
}
private fun chatApiVersion(): Int {
return ApiUtils.getChatApiVersion(currentUser, intArrayOf(ApiUtils.APIv1))
}
private fun operationJoinRoom() {
ncApi.joinRoom(
credentials,
ApiUtils.getUrlForParticipantsActive(
apiVersion(),
baseUrl,
conversationToken
),
callPassword
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(RoomOperationsObserver())
}
private fun operationMarkAsRead() {
ncApi.setChatReadMarker(
credentials,
ApiUtils.getUrlForSetChatReadMarker(
chatApiVersion(),
currentUser!!.baseUrl,
conversation!!.getToken()
),
conversation!!.lastMessage.jsonMessageId
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(GenericOperationsObserver())
}
private fun operationMakePrivate() {
ncApi.makeRoomPrivate(
credentials,
ApiUtils.getUrlForRoomPublic(
apiVersion(),
currentUser!!.baseUrl,
conversation!!.getToken()
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(GenericOperationsObserver())
}
private fun operationChangePassword() {
var pass: String? = ""
if (conversation!!.getPassword() != null) {
pass = conversation!!.getPassword()
}
ncApi.setPassword(
credentials,
ApiUtils.getUrlForRoomPassword(
apiVersion(),
currentUser!!.baseUrl,
conversation!!.getToken()
),
pass
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(GenericOperationsObserver())
}
private fun operationMakePublic() {
ncApi.makeRoomPublic(
credentials,
ApiUtils.getUrlForRoomPublic(
apiVersion(),
currentUser!!.baseUrl,
conversation!!.getToken()
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(GenericOperationsObserver())
}
private fun operationRenameRoom() {
ncApi.renameRoom(
credentials,
ApiUtils.getUrlForRoom(
apiVersion(),
currentUser!!.baseUrl,
conversation!!.getToken()
),
conversation!!.getName()
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(GenericOperationsObserver())
}
private fun operationToggleFavorite() {
val genericOperationsObserver = GenericOperationsObserver()
val apiVersion = apiVersion()
if (operation === ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE) {
ncApi.removeConversationFromFavorites(
credentials,
ApiUtils.getUrlForRoomFavorite(
apiVersion,
currentUser!!.baseUrl,
conversation!!.getToken()
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver)
} else {
ncApi.addConversationToFavorites(
credentials,
ApiUtils.getUrlForRoomFavorite(
apiVersion,
currentUser!!.baseUrl,
conversation!!.getToken()
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(genericOperationsObserver)
}
}
private fun operationInviteUsers() {
val retrofitBucket: RetrofitBucket
val apiVersion = apiVersion()
var invite: String? = null
if (invitedGroups!!.size > 0) {
invite = invitedGroups!![0]
}
retrofitBucket = if (conversationType == ConversationType.ROOM_PUBLIC_CALL) {
ApiUtils.getRetrofitBucketForCreateRoom(
apiVersion,
currentUser!!.baseUrl,
"3",
null,
invite,
conversationName
)
} else {
ApiUtils.getRetrofitBucketForCreateRoom(
apiVersion,
currentUser!!.baseUrl,
"2",
null,
invite,
conversationName
)
}
ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(roomOverall: RoomOverall) {
conversation = roomOverall.getOcs().getData()
ncApi.getRoom(
credentials,
ApiUtils.getUrlForRoom(
apiVersion, currentUser!!.baseUrl,
conversation!!.getToken()
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(
roomOverall: RoomOverall
) {
conversation = roomOverall.getOcs().getData()
inviteUsersToAConversation()
}
override fun onError(e: Throwable) {
showResultImage(everythingOK = false, isGuestSupportError = false)
dispose()
}
override fun onComplete() {
// unused atm
}
})
}
override fun onError(e: Throwable) {
showResultImage(everythingOK = false, isGuestSupportError = false)
dispose()
}
override fun onComplete() {
dispose()
}
})
}
private fun operationGetAndJoinRoom() {
val apiVersion = apiVersion()
ncApi.getRoom(
credentials,
ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onNext(roomOverall: RoomOverall) {
conversation = roomOverall.getOcs().getData()
if (conversation!!.isHasPassword && conversation!!.isGuest) {
eventBus.post(ConversationsListFetchDataEvent())
val bundle = Bundle()
bundle.putParcelable(KEY_ROOM, Parcels.wrap(conversation))
bundle.putString(KEY_CALL_URL, callUrl)
try {
bundle.putParcelable(
KEY_SERVER_CAPABILITIES,
Parcels.wrap<Capabilities>(
LoganSquare.parse<Capabilities>(
currentUser!!.capabilities,
Capabilities::class.java
)
)
)
} catch (e: IOException) {
Log.e(TAG, "Failed to parse capabilities for guest")
showResultImage(everythingOK = false, isGuestSupportError = false)
}
bundle.putSerializable(KEY_OPERATION_CODE, ConversationOperationEnum.OPS_CODE_JOIN_ROOM)
router.pushController(
RouterTransaction.with(EntryMenuController(bundle))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else if (conversation!!.isGuest) {
ncApi.joinRoom(
credentials,
ApiUtils.getUrlForParticipantsActive(
apiVersion,
baseUrl,
conversationToken
),
null
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(roomOverall: RoomOverall) {
conversation = roomOverall.getOcs().getData()
initiateConversation()
}
override fun onError(e: Throwable) {
showResultImage(everythingOK = false, isGuestSupportError = false)
dispose()
}
override fun onComplete() {
// unused atm
}
})
} else {
initiateConversation()
}
}
override fun onError(e: Throwable) {
showResultImage(everythingOK = false, isGuestSupportError = false)
dispose()
}
override fun onComplete() {
dispose()
}
})
}
@Suppress("Detekt.TooGenericExceptionCaught")
private fun showResultImage(everythingOK: Boolean, isGuestSupportError: Boolean) {
try {
binding.progressBar.visibility = View.GONE
if (resources != null) {
if (everythingOK) {
binding.resultImageView.setImageDrawable(
DisplayUtils.getTintedDrawable(
resources,
R.drawable.ic_check_circle_black_24dp,
R.color.nc_darkGreen
)
)
} else {
binding.resultImageView.setImageDrawable(
DisplayUtils.getTintedDrawable(
resources,
R.drawable.ic_cancel_black_24dp,
R.color.nc_darkRed
)
)
}
}
binding.resultImageView.visibility = View.VISIBLE
if (everythingOK) {
binding.resultTextView.setText(R.string.nc_all_ok_operation)
} else {
binding.resultTextView.setTextColor(resources!!.getColor(R.color.nc_darkRed))
if (!isGuestSupportError) {
binding.resultTextView.setText(R.string.nc_failed_to_perform_operation)
} else {
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.resultTextView.visibility = View.VISIBLE
if (everythingOK) {
eventBus!!.post(ConversationsListFetchDataEvent())
} else {
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
}
} catch (npe: NullPointerException) {
Log.i(TAG, "Controller already closed", npe)
}
}
private fun dispose() {
if (disposable != null && !disposable!!.isDisposed) {
disposable!!.dispose()
}
disposable = null
}
public override fun onDestroy() {
super.onDestroy()
dispose()
}
@kotlin.Throws(NoSupportedApiException::class)
private fun checkCapabilities(currentUser: UserEntity) {
ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
ApiUtils.getCallApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
ApiUtils.getChatApiVersion(currentUser, intArrayOf(1))
ApiUtils.getSignalingApiVersion(currentUser, intArrayOf(ApiUtils.APIv3, 2, 1))
}
private fun inviteUsersToAConversation() {
val localInvitedUsers = invitedUsers
val localInvitedGroups = invitedGroups
if (localInvitedGroups!!.size > 0) {
localInvitedGroups.removeAt(0)
}
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, API_CONVERSATION_VERSIONS)
if (localInvitedUsers!!.size > 0 || localInvitedGroups.size > 0 &&
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")
) {
addGroupsToConversation(localInvitedUsers, localInvitedGroups, apiVersion)
addUsersToConversation(localInvitedUsers, localInvitedGroups, apiVersion)
} else {
initiateConversation()
}
}
private fun addUsersToConversation(
localInvitedUsers: ArrayList<String>?,
localInvitedGroups: ArrayList<String>?,
apiVersion: Int
) {
var retrofitBucket: RetrofitBucket
for (i in localInvitedUsers!!.indices) {
val userId = invitedUsers!![i]
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(
apiVersion,
currentUser!!.baseUrl,
conversation!!.getToken(),
userId
)
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<AddParticipantOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(addParticipantOverall: AddParticipantOverall) {
// unused atm
}
override fun onError(e: Throwable) {
dispose()
}
override fun onComplete() {
Collections.synchronizedList(localInvitedUsers).remove(userId)
if (localInvitedGroups!!.size == 0 && localInvitedUsers.size == 0) {
initiateConversation()
}
dispose()
}
})
}
}
private fun addGroupsToConversation(
localInvitedUsers: ArrayList<String>?,
localInvitedGroups: ArrayList<String>?,
apiVersion: Int
) {
var retrofitBucket: RetrofitBucket
if (localInvitedGroups!!.size > 0 &&
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")
) {
for (i in localInvitedGroups.indices) {
val groupId = localInvitedGroups[i]
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipantWithSource(
apiVersion,
currentUser!!.baseUrl,
conversation!!.getToken(),
"groups",
groupId
)
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(object : Observer<AddParticipantOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(addParticipantOverall: AddParticipantOverall) {
// unused atm
}
override fun onError(e: Throwable) {
dispose()
}
override fun onComplete() {
Collections.synchronizedList(localInvitedGroups).remove(groupId)
if (localInvitedGroups.size == 0 && localInvitedUsers!!.size == 0) {
initiateConversation()
}
dispose()
}
})
}
}
}
private fun initiateConversation() {
eventBus.post(ConversationsListFetchDataEvent())
val bundle = Bundle()
bundle.putString(KEY_ROOM_TOKEN, conversation!!.getToken())
bundle.putString(KEY_ROOM_ID, conversation!!.getRoomId())
bundle.putString(KEY_CONVERSATION_NAME, conversation!!.getDisplayName())
bundle.putParcelable(KEY_USER_ENTITY, currentUser)
bundle.putParcelable(KEY_ACTIVE_CONVERSATION, Parcels.wrap(conversation))
bundle.putString(KEY_CONVERSATION_PASSWORD, callPassword)
eventBus.post(OpenConversationEvent(conversation, bundle))
}
private fun handleObserverError(e: Throwable) {
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM || e !is HttpException) {
showResultImage(everythingOK = false, isGuestSupportError = false)
} else {
val response = e.response()
if (response != null && response.code() == FORBIDDEN) {
ApplicationWideMessageHolder.getInstance()
.setMessageType(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG)
router.popCurrentController()
} else {
showResultImage(everythingOK = false, isGuestSupportError = false)
}
}
dispose()
}
private inner class GenericOperationsObserver : Observer<GenericOverall> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onNext(genericOverall: GenericOverall) {
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
showResultImage(everythingOK = true, isGuestSupportError = false)
} else {
throw IllegalArgumentException("Unsupported operation code observed!")
}
}
override fun onError(e: Throwable) {
handleObserverError(e)
}
override fun onComplete() {
dispose()
}
}
private inner class RoomOperationsObserver : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onNext(roomOverall: RoomOverall) {
conversation = roomOverall.getOcs().getData()
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
showResultImage(everythingOK = true, isGuestSupportError = false)
} else {
conversation = roomOverall.getOcs().getData()
initiateConversation()
}
}
override fun onError(e: Throwable) {
handleObserverError(e)
}
override fun onComplete() {
dispose()
}
}
companion object {
private const val TAG = "OperationsMenu"
private const val FORBIDDEN = 403
private val API_CONVERSATION_VERSIONS = intArrayOf(4, 1)
}
init {
operation = args.getSerializable(KEY_OPERATION_CODE) as ConversationOperationEnum?
if (args.containsKey(KEY_ROOM)) {
conversation = Parcels.unwrap(args.getParcelable(KEY_ROOM))
}
callPassword = args.getString(KEY_CONVERSATION_PASSWORD, "")
callUrl = args.getString(KEY_CALL_URL, "")
if (args.containsKey(KEY_INVITED_PARTICIPANTS)) {
invitedUsers = args.getStringArrayList(KEY_INVITED_PARTICIPANTS)
}
if (args.containsKey(KEY_INVITED_GROUP)) {
invitedGroups = args.getStringArrayList(KEY_INVITED_GROUP)
}
if (args.containsKey(KEY_CONVERSATION_TYPE)) {
conversationType = Parcels.unwrap(args.getParcelable(KEY_CONVERSATION_TYPE))
}
if (args.containsKey(KEY_SERVER_CAPABILITIES)) {
serverCapabilities = Parcels.unwrap(args.getParcelable(KEY_SERVER_CAPABILITIES))
}
conversationName = args.getString(KEY_CONVERSATION_NAME, "")
}
}

View File

@ -1 +1 @@
411 406

View File

@ -1,2 +1,2 @@
DO NOT TOUCH; GENERATED BY DRONE DO NOT TOUCH; GENERATED BY DRONE
<span class="mdl-layout-title">Lint Report: 1 error and 149 warnings</span> <span class="mdl-layout-title">Lint Report: 1 error and 144 warnings</span>