diff options
Diffstat (limited to 'app/src/main/java')
14 files changed, 710 insertions, 347 deletions
diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java index 951592a10..75c55baab 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java @@ -21,6 +21,7 @@ package com.nextcloud.talk.adapters.items; import android.accounts.Account; +import android.net.Uri; import android.view.View; import android.widget.*; import androidx.annotation.Nullable; @@ -106,14 +107,14 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User holder.avatarImageView.setController(null); if (adapter.hasFilter()) { - FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(), + FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(), String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() .getResources().getColor(R.color.colorPrimary)); } else { - holder.contactDisplayName.setText(participant.getName()); + holder.contactDisplayName.setText(participant.getDisplayName()); } - holder.serverUrl.setText(userEntity.getBaseUrl()); + holder.serverUrl.setText((Uri.parse(userEntity.getBaseUrl()).getHost())); if (userEntity != null && userEntity.getBaseUrl() != null && userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) { holder.avatarImageView.setVisibility(View.VISIBLE); @@ -122,7 +123,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User .setOldController(holder.avatarImageView.getController()) .setAutoPlayAnimations(true) .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), - participant.getUserId(), R.dimen.avatar_size), null)) + participant.getActorId(), R.dimen.avatar_size), null)) .build(); holder.avatarImageView.setController(draweeController); @@ -138,8 +139,8 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User @Override public boolean filter(String constraint) { - return participant.getName() != null && - Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getName().trim()).find(); + return participant.getDisplayName() != null && + Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find(); } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java index 9968aab35..c1dfe7bf1 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java @@ -21,7 +21,6 @@ package com.nextcloud.talk.adapters.items; import android.content.res.Resources; -import android.graphics.drawable.BitmapDrawable; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; @@ -150,37 +149,38 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> holder.contactDisplayName.setText(NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)); } - if (TextUtils.isEmpty(participant.getSource()) || participant.getSource().equals("users")) { - if (Participant.ParticipantType.GUEST.equals(participant.getType()) || - Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participant.getType())) { - String displayName = NextcloudTalkApplication.Companion.getSharedApplication() - .getResources().getString(R.string.nc_guest); - - if (!TextUtils.isEmpty(participant.getDisplayName())) { - displayName = participant.getDisplayName(); - } - - DraweeController draweeController = Fresco.newDraweeControllerBuilder() - .setOldController(holder.simpleDraweeView.getController()) - .setAutoPlayAnimations(true) - .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(), - displayName, R.dimen.avatar_size), null)) - .build(); - holder.simpleDraweeView.setController(draweeController); - - } else { + if (participant.getActorType() == Participant.ActorType.GROUPS || "groups".equals(participant.getSource())) { + holder.simpleDraweeView.setImageResource(R.drawable.ic_circular_group); + } else if (participant.getActorType() == Participant.ActorType.EMAILS) { + // FIXME use an email icon + holder.simpleDraweeView.setImageResource(R.drawable.ic_circular_group); + } else if (participant.getActorType() == Participant.ActorType.GUESTS || + Participant.ParticipantType.GUEST.equals(participant.getType()) || + Participant.ParticipantType.GUEST_MODERATOR.equals(participant.getType())) { - DraweeController draweeController = Fresco.newDraweeControllerBuilder() - .setOldController(holder.simpleDraweeView.getController()) - .setAutoPlayAnimations(true) - .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), - participant.getUserId(), R.dimen.avatar_size), null)) - .build(); - holder.simpleDraweeView.setController(draweeController); + String displayName = NextcloudTalkApplication.Companion.getSharedApplication() + .getResources().getString(R.string.nc_guest); + if (!TextUtils.isEmpty(participant.getDisplayName())) { + displayName = participant.getDisplayName(); } - } else if ("groups".equals(participant.getSource())) { - holder.simpleDraweeView.setImageResource(R.drawable.ic_circular_group); + + DraweeController draweeController = Fresco.newDraweeControllerBuilder() + .setOldController(holder.simpleDraweeView.getController()) + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(), + displayName, R.dimen.avatar_size), null)) + .build(); + holder.simpleDraweeView.setController(draweeController); + + } else if (participant.getActorType() == Participant.ActorType.USERS || participant.getSource().equals("users")) { + DraweeController draweeController = Fresco.newDraweeControllerBuilder() + .setOldController(holder.simpleDraweeView.getController()) + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), + participant.getUserId(), R.dimen.avatar_size), null)) + .build(); + holder.simpleDraweeView.setController(draweeController); } Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources(); @@ -246,13 +246,20 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> //userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_owner); //break; case 2: + case 6: // Guest moderator userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_moderator); break; case 3: userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_user); + if (participant.getActorType() == Participant.ActorType.GROUPS) { + userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_group); + } break; case 4: userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest); + if (participant.getActorType() == Participant.ActorType.EMAILS) { + userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_email); + } break; case 5: userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_following_link); diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 2daa2750c..2b16e13dd 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -135,15 +135,27 @@ public interface NcApi { // also used for removing a guest from a conversation + @Deprecated @DELETE Observable<GenericOverall> removeParticipantFromConversation(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId); + @DELETE + Observable<GenericOverall> removeAttendeeFromConversation(@Header("Authorization") String authorization, @Url String url, @Query("attendeeId") Long attendeeId); + + @Deprecated @POST Observable<GenericOverall> promoteUserToModerator(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId); + @Deprecated @DELETE Observable<GenericOverall> demoteModeratorToUser(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId); + @POST + Observable<GenericOverall> promoteAttendeeToModerator(@Header("Authorization") String authorization, @Url String url, @Query("attendeeId") Long attendeeId); + + @DELETE + Observable<GenericOverall> demoteAttendeeFromModerator(@Header("Authorization") String authorization, @Url String url, @Query("attendeeId") Long attendeeId); + /* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/participants/self */ diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java index 89f3555f1..8859e8c40 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java @@ -1273,7 +1273,7 @@ public class CallController extends BaseController { inCallFlag = (int) Participant.ParticipantFlags.IN_CALL_WITH_AUDIO_AND_VIDEO.getValue(); } - int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[] {1}); + int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[] {1}); ncApi.joinCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken), inCallFlag) .subscribeOn(Schedulers.io()) @@ -1558,7 +1558,7 @@ public class CallController extends BaseController { } private void hangupNetworkCalls(boolean shutDownView) { - int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[] {1}); + int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[] {1}); ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken)) .subscribeOn(Schedulers.io()) @@ -1686,7 +1686,7 @@ public class CallController extends BaseController { private void getPeersForCall() { Log.d(TAG, "getPeersForCall"); - int apiVersion = ApiUtils.getConversationApiVersion(conversationUser, new int[] {1}); + int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[] {1}); ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, baseUrl, roomToken)) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java index 8254dc60c..355bafbfb 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java @@ -209,7 +209,7 @@ public class CallNotificationController extends BaseController { } private void checkIfAnyParticipantsRemainInRoom() { - int apiVersion = ApiUtils.getConversationApiVersion(userBeingCalled, new int[] {1}); + int apiVersion = ApiUtils.getCallApiVersion(userBeingCalled, new int[] {1}); ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(apiVersion, userBeingCalled.getBaseUrl(), currentConversation.getToken())) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java index 0e1b1fac0..fc9d2d8ce 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -61,6 +61,7 @@ import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall; import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser; import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.models.json.conversations.RoomOverall; +import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter; import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ConductorRemapping; @@ -508,6 +509,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ Participant participant; List<AbstractFlexibleItem> newUserItemList = new ArrayList<>(); + EnumActorTypeConverter actorTypeConverter = new EnumActorTypeConverter(); try { AutocompleteOverall autocompleteOverall = LoganSquare.parse(responseBody.string(), AutocompleteOverall.class); @@ -516,13 +518,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ for (AutocompleteUser autocompleteUser : autocompleteUsersHashSet) { if (!autocompleteUser.getId().equals(currentUser.getUserId()) && !existingParticipants.contains(autocompleteUser.getId())) { participant = new Participant(); - participant.setUserId(autocompleteUser.getId()); + participant.setActorId(autocompleteUser.getId()); + participant.setActorType(actorTypeConverter.getFromString(autocompleteUser.getSource())); participant.setDisplayName(autocompleteUser.getLabel()); participant.setSource(autocompleteUser.getSource()); String headerTitle; - if (!autocompleteUser.getSource().equals("groups")) { + if (participant.getActorType() != Participant.ActorType.GROUPS) { headerTitle = participant.getDisplayName().substring(0, 1).toUpperCase(); } else { headerTitle = getResources().getString(R.string.nc_groups); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt index 3100500b2..6dee8e4ae 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt @@ -20,11 +20,13 @@ package com.nextcloud.talk.controllers +import android.annotation.SuppressLint import android.content.Context import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.LayoutInflater import android.view.MenuItem import android.view.View @@ -63,6 +65,8 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.Participant +import com.nextcloud.talk.models.json.participants.Participant.ActorType.GROUPS +import com.nextcloud.talk.models.json.participants.Participant.ActorType.USERS import com.nextcloud.talk.models.json.participants.ParticipantsOverall import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils @@ -410,8 +414,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA for (i in participants.indices) { participant = participants[i] userItem = UserItem(participant, conversationUser, null) - userItem.isOnline = !participant.sessionId.equals("0") - if (!TextUtils.isEmpty(participant.userId) && participant.userId == conversationUser!!.userId) { + if (participant.sessionId != null) { + userItem.isOnline = !participant.sessionId.equals("0") + } else { + userItem.isOnline = !participant.sessionIds!!.isEmpty() + } + + if (participant.getActorType() == USERS && participant.getActorId() == conversationUser!!.userId) { ownUserItem = userItem ownUserItem.model.sessionId = "-1" ownUserItem.isOnline = true @@ -444,7 +453,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA var apiVersion = 1 // FIXME Fix API checking with guests? if (conversationUser != null) { - apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(1)) + apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) } ncApi.getPeersForCall( @@ -478,7 +487,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA recyclerViewItems.forEach { val userItem = it as UserItem - existingParticipantsId.add(userItem.model.userId) + if (userItem.model.getActorType() == USERS) { + existingParticipantsId.add(userItem.model.getActorId()) + } } bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true) @@ -572,7 +583,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA leaveConversationAction.visibility = View.VISIBLE } - if (!conversation!!.canModerate(conversationUser)) { + if (!conversation!!.canDelete(conversationUser)) { deleteConversationAction.visibility = View.GONE } else { deleteConversationAction.visibility = View.VISIBLE @@ -685,117 +696,320 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA } } + private fun toggleModeratorStatus(apiVersion: Int, participant: Participant) { + val subscriber = object : Observer<GenericOverall> { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(genericOverall: GenericOverall) { + getListOfParticipants() + } + + @SuppressLint("LongLogTag") + override fun onError(e: Throwable) { + Log.e(TAG, "Error toggling moderator status", e) + } + + override fun onComplete() { + } + } + + if (participant.type == Participant.ParticipantType.MODERATOR || + participant.type == Participant.ParticipantType.GUEST_MODERATOR + ) { + ncApi.demoteAttendeeFromModerator( + credentials, + ApiUtils.getUrlForRoomModerators( + apiVersion, + conversationUser!!.baseUrl, + conversation!!.token + ), + participant.attendeeId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(subscriber) + } else if (participant.type == Participant.ParticipantType.USER || + participant.type == Participant.ParticipantType.GUEST + ) { + ncApi.promoteAttendeeToModerator( + credentials, + ApiUtils.getUrlForRoomModerators( + apiVersion, + conversationUser!!.baseUrl, + conversation!!.token + ), + participant.attendeeId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(subscriber) + } + } + + private fun toggleModeratorStatusLegacy(apiVersion: Int, participant: Participant) { + val subscriber = object : Observer<GenericOverall> { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(genericOverall: GenericOverall) { + getListOfParticipants() + } + + @SuppressLint("LongLogTag") + override fun onError(e: Throwable) { + Log.e(TAG, "Error toggling moderator status", e) + } + + override fun onComplete() { + } + } + + if (participant.type == Participant.ParticipantType.MODERATOR) { + ncApi.demoteModeratorToUser( + credentials, + ApiUtils.getUrlForRoomModerators( + apiVersion, + conversationUser!!.baseUrl, + conversation!!.token + ), + participant.userId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(subscriber) + } else if (participant.type == Participant.ParticipantType.USER) { + ncApi.promoteUserToModerator( + credentials, + ApiUtils.getUrlForRoomModerators( + apiVersion, + conversationUser!!.baseUrl, + conversation!!.token + ), + participant.userId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(subscriber) + } + } + + fun removeAttendeeFromConversation(apiVersion: Int, participant: Participant) { + if (apiVersion >= ApiUtils.APIv4) { + ncApi.removeAttendeeFromConversation( + credentials, + ApiUtils.getUrlForAttendees( + apiVersion, + conversationUser!!.baseUrl, + conversation!!.token + ), + participant.attendeeId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer<GenericOverall> { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(genericOverall: GenericOverall) { + getListOfParticipants() + } + + @SuppressLint("LongLogTag") + override fun onError(e: Throwable) { + Log.e(TAG, "Error removing attendee from conversation", e) + } + + override fun onComplete() { + } + }) + } else { + if (participant.type == Participant.ParticipantType.GUEST || + participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK + ) { + ncApi.removeParticipantFromConversation( + credentials, + ApiUtils.getUrlForRemovingParticipantFromConversation( + conversationUser!!.baseUrl, + conversation!!.token, + true + ), + participant.sessionId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer<GenericOverall> { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(genericOverall: GenericOverall) { + getListOfParticipants() + } + + @SuppressLint("LongLogTag") + override fun onError(e: Throwable) { + Log.e(TAG, "Error removing guest from conversation", e) + } + + override fun onComplete() { + } + }) + } else { + ncApi.removeParticipantFromConversation( + credentials, + ApiUtils.getUrlForRemovingParticipantFromConversation( + conversationUser!!.baseUrl, + conversation!!.token, + false + ), + participant.userId + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer<GenericOverall> { + override fun onSubscribe(d: Disposable) { + } + + override fun onNext(genericOverall: GenericOverall) { + getListOfParticipants() + } + + @SuppressLint("LongLogTag") + override fun onError(e: Throwable) { + Log.e(TAG, "Error removing user from conversation", e) + } + + override fun onComplete() { + } + }) + } + } + } + override fun onItemClick(view: View?, position: Int): Boolean { + if (!conversation!!.canModerate(conversationUser)) { + return true + } + val userItem = adapter?.getItem(position) as UserItem val participant = userItem.model - if (participant.userId != conversationUser!!.userId) { - var items = mutableListOf( - BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)), - BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)), + val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1)) + + if (participant.getActorType() == USERS && participant.getActorId() == conversationUser!!.userId) { + if (participant.attendeePin.isNotEmpty()) { + val items = mutableListOf( + BasicListItemWithImage( + R.drawable.ic_lock_grey600_24px, + context.getString(R.string.nc_attendee_pin, participant.attendeePin) + ) + ) + MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show { + cornerRadius(res = R.dimen.corner_radius) + + title(text = participant.displayName) + listItemsWithImage(items = items) { dialog, index, _ -> + if (index == 0) { + removeAttendeeFromConversation(apiVersion, participant) + } + } + } + } + return true + } + + if (participant.type == Participant.ParticipantType.OWNER) { + // Can not moderate owner + return true + } + + if (participant.getActorType() == GROUPS) { + val items = mutableListOf( BasicListItemWithImage( R.drawable.ic_delete_grey600_24dp, - context.getString(R.string.nc_remove_participant) + context.getString(R.string.nc_remove_group_and_members) ) ) + MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show { + cornerRadius(res = R.dimen.corner_radius) - if (!conversation!!.canModerate(conversationUser)) { - items = mutableListOf() - } else { - if (participant.type == Participant.ParticipantType.MODERATOR || participant.type == Participant.ParticipantType.OWNER) { - items.removeAt(0) - } else if (participant.type == Participant.ParticipantType.USER) { - items.removeAt(1) + title(text = participant.displayName) + listItemsWithImage(items = items) { dialog, index, _ -> + if (index == 0) { + removeAttendeeFromConversation(apiVersion, participant) + } } } + return true + } - if (items.isNotEmpty()) { - MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show { - cornerRadius(res = R.dimen.corner_radius) + var items = mutableListOf( + BasicListItemWithImage( + R.drawable.ic_lock_grey600_24px, + context.getString(R.string.nc_attendee_pin, participant.attendeePin) + ), + BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)), + BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)), + BasicListItemWithImage( + R.drawable.ic_delete_grey600_24dp, + context.getString(R.string.nc_remove_participant) + ) + ) - title(text = participant.displayName) - listItemsWithImage(items = items) { dialog, index, _ -> + if (participant.type == Participant.ParticipantType.MODERATOR || + participant.type == Participant.ParticipantType.GUEST_MODERATOR + ) { + items.removeAt(1) + } else if (participant.type == Participant.ParticipantType.USER || + participant.type == Participant.ParticipantType.GUEST + ) { + items.removeAt(2) + } else { + // Self joined users can not be promoted nor demoted + items.removeAt(2) + items.removeAt(1) + } - val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(1)) + if (participant.attendeePin.isEmpty()) { + items.removeAt(0) + } - if (index == 0) { - if (participant.type == Participant.ParticipantType.MODERATOR) { - ncApi.demoteModeratorToUser( - credentials, - ApiUtils.getUrlForRoomModerators( - apiVersion, - conversationUser.baseUrl, - conversation!!.token - ), - participant.userId - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - getListOfParticipants() - } - } else if (participant.type == Participant.ParticipantType.USER) { - ncApi.promoteUserToModerator( - credentials, - ApiUtils.getUrlForRoomModerators( - apiVersion, - conversationUser.baseUrl, - conversation!!.token - ), - participant.userId - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - getListOfParticipants() - } - } - } else if (index == 1) { - if (participant.type == Participant.ParticipantType.GUEST || - participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK - ) { - ncApi.removeParticipantFromConversation( - credentials, - ApiUtils.getUrlForRemovingParticipantFromConversation( - conversationUser.baseUrl, - conversation!!.token, - true - ), - participant.sessionId - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - getListOfParticipants() - } - } else { - ncApi.removeParticipantFromConversation( - credentials, - ApiUtils.getUrlForRemovingParticipantFromConversation( - conversationUser.baseUrl, - conversation!!.token, - false - ), - participant.userId - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - getListOfParticipants() - // get participants again - } - } + if (items.isNotEmpty()) { + MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show { + cornerRadius(res = R.dimen.corner_radius) + + title(text = participant.displayName) + listItemsWithImage(items = items) { dialog, index, _ -> + var actionToTrigger = index + if (participant.attendeePin.isEmpty()) { + actionToTrigger++ + } + if (participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK) { + actionToTrigger++ + } + + if (actionToTrigger == 0) { + // Pin, nothing to do + } else if (actionToTrigger == 1) { + // Promote/demote + if (apiVersion >= ApiUtils.APIv4) { + toggleModeratorStatus(apiVersion, participant) + } else { + toggleModeratorStatusLegacy(apiVersion, participant) } + } else if (actionToTrigger == 2) { + // Remove from conversation + removeAttendeeFromConversation(apiVersion, participant) } } } } - return true } companion object { + private const val TAG = "ConversationInfoController" private const val ID_DELETE_CONVERSATION_DIALOG = 0 } @@ -804,6 +1018,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA */ class UserItemComparator : Comparator<UserItem> { override fun compare(left: UserItem, right: UserItem): Int { + val leftIsGroup = left.model.actorType == GROUPS + val rightIsGroup = right.model.actorType == GROUPS + if (leftIsGroup != rightIsGroup) { + // Groups below participants + return if (rightIsGroup) { -1 } else { 1 } + } + if (left.isOnline && !right.isOnline) { return -1 } else if (!left.isOnline && right.isOnline) { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java index e725ed838..c07cb4f32 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java @@ -178,17 +178,17 @@ public class SwitchAccountController extends BaseController { for (Object userEntityObject : userUtils.getUsers()) { userEntity = (UserEntity) userEntityObject; if (!userEntity.getCurrent()) { - participant = new Participant(); - participant.setName(userEntity.getDisplayName()); - String userId; - if (userEntity.getUserId() != null) { userId = userEntity.getUserId(); } else { userId = userEntity.getUsername(); } - participant.setUserId(userId); + + participant = new Participant(); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(userId); + participant.setDisplayName(userEntity.getDisplayName()); userItems.add(new AdvancedUserItem(participant, userEntity, null)); } } @@ -203,8 +203,9 @@ public class SwitchAccountController extends BaseController { importAccount = AccountUtils.INSTANCE.getInformationFromAccount(account); participant = new Participant(); - participant.setName(importAccount.getUsername()); - participant.setUserId(importAccount.getUsername()); + participant.setActorType(Participant.ActorType.USERS); + participant.setActorId(importAccount.getUsername()); + participant.setDisplayName(importAccount.getUsername()); userEntity = new UserEntity(); userEntity.setBaseUrl(importAccount.getBaseUrl()); userItems.add(new AdvancedUserItem(participant, userEntity, account)); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java index 23705faa4..69811b8d9 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java @@ -54,7 +54,6 @@ 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.ConductorRemapping; @@ -270,29 +269,20 @@ public class OperationsMenuController extends BaseController { break; case 11: RetrofitBucket retrofitBucket; - boolean isGroupCallWorkaround = false; String invite = null; if (invitedGroups.size() > 0) { invite = invitedGroups.get(0); } - if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL) || - !currentUser.hasSpreedFeatureCapability("empty-group-room")) { + if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL)) { retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(), - "3", invite, conversationName); + "3", invite, conversationName); } else { - String roomType = "2"; - if (!currentUser.hasSpreedFeatureCapability("empty-group-room")) { - isGroupCallWorkaround = true; - roomType = "3"; - } - retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(), - roomType, invite, conversationName); + "2", invite, conversationName); } - final boolean isGroupCallWorkaroundFinal = isGroupCallWorkaround; ncApi.createRoom(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -321,11 +311,7 @@ public class OperationsMenuController extends BaseController { @Override public void onNext(RoomOverall roomOverall) { conversation = roomOverall.getOcs().getData(); - if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) { - performGroupCallWorkaround(credentials); - } else { - inviteUsersToAConversation(); - } + inviteUsersToAConversation(); } @Override @@ -393,40 +379,6 @@ public class OperationsMenuController extends BaseController { } } - private void performGroupCallWorkaround(String credentials) { - int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1}); - - ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(), - conversation.getToken())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .retry(1) - .subscribe(new Observer<GenericOverall>() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(GenericOverall genericOverall) { - inviteUsersToAConversation(); - } - - @Override - public void onError(Throwable e) { - showResultImage(false, false); - dispose(); - } - - @Override - public void onComplete() { - dispose(); - } - }); - - - } - private void showResultImage(boolean everythingOK, boolean isGuestSupportError) { progressBar.setVisibility(View.GONE); @@ -552,7 +504,7 @@ public class OperationsMenuController extends BaseController { localInvitedGroups.remove(0); } - int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {1}); + int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {4, 1}); if (localInvitedUsers.size() > 0 || (localInvitedGroups.size() > 0 && currentUser.hasSpreedFeatureCapability("invite-groups-and-mails"))) { if ((localInvitedGroups.size() > 0 && currentUser.hasSpreedFeatureCapability("invite-groups-and-mails"))) { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java index cf0b6846e..947e9693a 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/AddParticipantsToConversation.java @@ -66,7 +66,7 @@ public class AddParticipantsToConversation extends Worker { String[] selectedGroupIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_GROUPS()); UserEntity user = userUtils.getUserWithInternalId(data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1)); - int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {1}); + int apiVersion = ApiUtils.getConversationApiVersion(user, new int[] {ApiUtils.APIv4, 1}); String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_TOKEN()); String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken()); diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.java b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.java index 882a298c2..9a40f9aa3 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.java @@ -84,9 +84,13 @@ public class Conversation { public int lastReadMessage; @JsonField(name = "callFlag") public int callFlag; + @JsonField(name = "canLeaveConversation") public Boolean canLeaveConversation; + @JsonField(name = "canDeleteConversation") + public Boolean canDeleteConversation; + public boolean isPublic() { return (ConversationType.ROOM_PUBLIC_CALL.equals(type)); } @@ -133,6 +137,15 @@ public class Conversation { (getType() != ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && this.participants.size() > 1); } + public boolean canDelete(UserEntity conversationUser) { + if (canDeleteConversation != null) { + // Available since APIv2 + return canDeleteConversation; + } + // Fallback for APIv1 + return canModerate(conversationUser); + } + public String getRoomId() { return this.roomId; } @@ -314,169 +327,155 @@ public class Conversation { this.callFlag = callFlag; } - public boolean equals(final Object o) { - if (o == this) { + @Override + public boolean equals(Object o) { + if (this == o) { return true; } - if (!(o instanceof Conversation)) { + if (o == null || getClass() != o.getClass()) { + return false; + } + + Conversation that = (Conversation) o; + + if (lastPing != that.lastPing) { return false; } - final Conversation other = (Conversation) o; - if (!other.canEqual((Object) this)) { + if (hasPassword != that.hasPassword) { return false; } - final Object this$roomId = this.getRoomId(); - final Object other$roomId = other.getRoomId(); - if (this$roomId == null ? other$roomId != null : !this$roomId.equals(other$roomId)) { + if (isFavorite != that.isFavorite) { return false; } - final Object this$token = this.getToken(); - final Object other$token = other.getToken(); - if (this$token == null ? other$token != null : !this$token.equals(other$token)) { + if (lastActivity != that.lastActivity) { return false; } - final Object this$name = this.getName(); - final Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) { + if (unreadMessages != that.unreadMessages) { return false; } - final Object this$displayName = this.getDisplayName(); - final Object other$displayName = other.getDisplayName(); - if (this$displayName == null ? other$displayName != null : !this$displayName.equals(other$displayName)) { + if (unreadMention != that.unreadMention) { return false; } - final Object this$type = this.getType(); - final Object other$type = other.getType(); - if (this$type == null ? other$type != null : !this$type.equals(other$type)) { + if (lastReadMessage != that.lastReadMessage) { return false; } - if (this.getLastPing() != other.getLastPing()) { + if (callFlag != that.callFlag) { return false; } - final Object this$participants = this.participants; - final Object other$participants = other.participants; - if (this$participants == null ? other$participants != null : !this$participants.equals(other$participants)) { + if (roomId != null ? !roomId.equals(that.roomId) : that.roomId != null) { return false; } - final Object this$participantType = this.getParticipantType(); - final Object other$participantType = other.getParticipantType(); - if (this$participantType == null ? other$participantType != null : !this$participantType.equals(other$participantType)) { + if (!token.equals(that.token)) { return false; } - if (this.isHasPassword() != other.isHasPassword()) { + if (name != null ? !name.equals(that.name) : that.name != null) { return false; } - final Object this$sessionId = this.getSessionId(); - final Object other$sessionId = other.getSessionId(); - if (this$sessionId == null ? other$sessionId != null : !this$sessionId.equals(other$sessionId)) { + if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) { return false; } - final Object this$password = this.getPassword(); - final Object other$password = other.getPassword(); - if (this$password == null ? other$password != null : !this$password.equals(other$password)) { + if (type != that.type) { return false; } - if (this.isFavorite() != other.isFavorite()) { + if (participants != null ? !participants.equals(that.participants) : that.participants != null) { return false; } - if (this.getLastActivity() != other.getLastActivity()) { + if (participantType != that.participantType) { return false; } - if (this.getUnreadMessages() != other.getUnreadMessages()) { + if (sessionId != null ? !sessionId.equals(that.sessionId) : that.sessionId != null) { return false; } - if (this.isUnreadMention() != other.isUnreadMention()) { + if (password != null ? !password.equals(that.password) : that.password != null) { return false; } - final Object this$lastMessage = this.getLastMessage(); - final Object other$lastMessage = other.getLastMessage(); - if (this$lastMessage == null ? other$lastMessage != null : !this$lastMessage.equals(other$lastMessage)) { + if (lastMessage != null ? !lastMessage.equals(that.lastMessage) : that.lastMessage != null) { return false; } - final Object this$objectType = this.getObjectType(); - final Object other$objectType = other.getObjectType(); - if (this$objectType == null ? other$objectType != null : !this$objectType.equals(other$objectType)) { + if (objectType != null ? !objectType.equals(that.objectType) : that.objectType != null) { return false; } - final Object this$notificationLevel = this.getNotificationLevel(); - final Object other$notificationLevel = other.getNotificationLevel(); - if (this$notificationLevel == null ? other$notificationLevel != null : !this$notificationLevel.equals(other$notificationLevel)) { + if (notificationLevel != that.notificationLevel) { return false; } - final Object this$conversationReadOnlyState = this.getConversationReadOnlyState(); - final Object other$conversationReadOnlyState = other.getConversationReadOnlyState(); - if (this$conversationReadOnlyState == null ? other$conversationReadOnlyState != null : !this$conversationReadOnlyState.equals(other$conversationReadOnlyState)) { + if (conversationReadOnlyState != that.conversationReadOnlyState) { return false; } - final Object this$lobbyState = this.getLobbyState(); - final Object other$lobbyState = other.getLobbyState(); - if (this$lobbyState == null ? other$lobbyState != null : !this$lobbyState.equals(other$lobbyState)) { + if (lobbyState != that.lobbyState) { return false; } - final Object this$lobbyTimer = this.getLobbyTimer(); - final Object other$lobbyTimer = other.getLobbyTimer(); - if (this$lobbyTimer == null ? other$lobbyTimer != null : !this$lobbyTimer.equals(other$lobbyTimer)) { + if (lobbyTimer != null ? !lobbyTimer.equals(that.lobbyTimer) : that.lobbyTimer != null) { return false; } - if (this.getLastReadMessage() != other.getLastReadMessage()) { + if (canLeaveConversation != null ? !canLeaveConversation.equals(that.canLeaveConversation) : that.canLeaveConversation != null) { return false; } - - return this.getCallFlag() == other.getCallFlag(); + return canDeleteConversation != null ? canDeleteConversation.equals(that.canDeleteConversation) : that.canDeleteConversation == null; } protected boolean canEqual(final Object other) { return other instanceof Conversation; } + @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $roomId = this.getRoomId(); - result = result * PRIME + ($roomId == null ? 43 : $roomId.hashCode()); - final Object $token = this.getToken(); - result = result * PRIME + ($token == null ? 43 : $token.hashCode()); - final Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); - final Object $displayName = this.getDisplayName(); - result = result * PRIME + ($displayName == null ? 43 : $displayName.hashCode()); - final Object $type = this.getType(); - result = result * PRIME + ($type == null ? 43 : $type.hashCode()); - final long $lastPing = this.getLastPing(); - result = result * PRIME + (int) ($lastPing >>> 32 ^ $lastPing); - final Object $participants = this.participants; - result = result * PRIME + ($participants == null ? 43 : $participants.hashCode()); - final Object $participantType = this.getParticipantType(); - result = result * PRIME + ($participantType == null ? 43 : $participantType.hashCode()); - result = result * PRIME + (this.isHasPassword() ? 79 : 97); - final Object $sessionId = this.getSessionId(); - result = result * PRIME + ($sessionId == null ? 43 : $sessionId.hashCode()); - final Object $password = this.getPassword(); - result = result * PRIME + ($password == null ? 43 : $password.hashCode()); - result = result * PRIME + (this.isFavorite() ? 79 : 97); - final long $lastActivity = this.getLastActivity(); - result = result * PRIME + (int) ($lastActivity >>> 32 ^ $lastActivity); - result = result * PRIME + this.getUnreadMessages(); - result = result * PRIME + (this.isUnreadMention() ? 79 : 97); - final Object $lastMessage = this.getLastMessage(); - result = result * PRIME + ($lastMessage == null ? 43 : $lastMessage.hashCode()); - final Object $objectType = this.getObjectType(); - result = result * PRIME + ($objectType == null ? 43 : $objectType.hashCode()); - final Object $notificationLevel = this.getNotificationLevel(); - result = result * PRIME + ($notificationLevel == null ? 43 : $notificationLevel.hashCode()); - final Object $conversationReadOnlyState = this.getConversationReadOnlyState(); - result = result * PRIME + ($conversationReadOnlyState == null ? 43 : $conversationReadOnlyState.hashCode()); - final Object $lobbyState = this.getLobbyState(); - result = result * PRIME + ($lobbyState == null ? 43 : $lobbyState.hashCode()); - final Object $lobbyTimer = this.getLobbyTimer(); - result = result * PRIME + ($lobbyTimer == null ? 43 : $lobbyTimer.hashCode()); - result = result * PRIME + this.getLastReadMessage(); - result = result * PRIME + this.getCallFlag(); + int result = roomId != null ? roomId.hashCode() : 0; + result = 31 * result + token.hashCode(); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (displayName != null ? displayName.hashCode() : 0); + result = 31 * result + type.hashCode(); + result = 31 * result + (int) (lastPing ^ (lastPing >>> 32)); + result = 31 * result + (participants != null ? participants.hashCode() : 0); + result = 31 * result + (participantType != null ? participantType.hashCode() : 0); + result = 31 * result + (hasPassword ? 1 : 0); + result = 31 * result + (sessionId != null ? sessionId.hashCode() : 0); + result = 31 * result + (password != null ? password.hashCode() : 0); + result = 31 * result + (isFavorite ? 1 : 0); + result = 31 * result + (int) (lastActivity ^ (lastActivity >>> 32)); + result = 31 * result + unreadMessages; + result = 31 * result + (unreadMention ? 1 : 0); + result = 31 * result + (lastMessage != null ? lastMessage.hashCode() : 0); + result = 31 * result + (objectType != null ? objectType.hashCode() : 0); + result = 31 * result + (notificationLevel != null ? notificationLevel.hashCode() : 0); + result = 31 * result + (conversationReadOnlyState != null ? conversationReadOnlyState.hashCode() : 0); + result = 31 * result + (lobbyState != null ? lobbyState.hashCode() : 0); + result = 31 * result + (lobbyTimer != null ? lobbyTimer.hashCode() : 0); + result = 31 * result + lastReadMessage; + result = 31 * result + callFlag; + result = 31 * result + (canLeaveConversation != null ? canLeaveConversation.hashCode() : 0); + result = 31 * result + (canDeleteConversation != null ? canDeleteConversation.hashCode() : 0); return result; } + @Override public String toString() { - return "Conversation(roomId=" + this.getRoomId() + ", token=" + this.getToken() + ", name=" + this.getName() + ", displayName=" + this.getDisplayName() + ", type=" + this.getType() + ", lastPing=" + this.getLastPing() + ", participants=" + this.participants + ", participantType=" + this.getParticipantType() + ", hasPassword=" + this.isHasPassword() + ", sessionId=" + this.getSessionId() + ", password=" + this.getPassword() + ", isFavorite=" + this.isFavorite() + ", lastActivity=" + this.getLastActivity() + ", unreadMessages=" + this.getUnreadMessages() + ", unreadMention=" + this.isUnreadMention() + ", lastMessage=" + this.getLastMessage() + ", objectType=" + this.getObjectType() + ", notificationLevel=" + this.getNotificationLevel() + ", conversationReadOnlyState=" + this.getConversationReadOnlyState() + ", lobbyState=" + this.getLobbyState() + ", lobbyTimer=" + this.getLobbyTimer() + ", lastReadMessage=" + this.getLastReadMessage() + ", callFlag=" + this.getCallFlag() + ")"; + return "Conversation{" + + "roomId='" + roomId + '\'' + + ", token='" + token + '\'' + + ", name='" + name + '\'' + + ", displayName='" + displayName + '\'' + + ", type=" + type + + ", lastPing=" + lastPing + + ", participants=" + participants + + ", participantType=" + participantType + + ", hasPassword=" + hasPassword + + ", sessionId='" + sessionId + '\'' + + ", password='" + password + '\'' + + ", isFavorite=" + isFavorite + + ", lastActivity=" + lastActivity + + ", unreadMessages=" + unreadMessages + + ", unreadMention=" + unreadMention + + ", lastMessage=" + lastMessage + + ", objectType='" + objectType + '\'' + + ", notificationLevel=" + notificationLevel + + ", conversationReadOnlyState=" + conversationReadOnlyState + + ", lobbyState=" + lobbyState + + ", lobbyTimer=" + lobbyTimer + + ", lastReadMessage=" + lastReadMessage + + ", callFlag=" + callFlag + + ", canLeaveConversation=" + canLeaveConversation + + ", canDeleteConversation=" + canDeleteConversation + + '}'; } public enum NotificationLevel { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumActorTypeConverter.kt b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumActorTypeConverter.kt new file mode 100644 index 000000000..ca7407a36 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/converters/EnumActorTypeConverter.kt @@ -0,0 +1,58 @@ +/* + * Nextcloud Talk application + * + * @author Joas Schilling + * @author Andy Scherzinger + * Copyright (C) 2021 Joas Schilling <coding@schilljs.com> + * Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de> + * + * 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.models.json.converters + +import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter +import com.nextcloud.talk.models.json.participants.Participant +import com.nextcloud.talk.models.json.participants.Participant.ActorType.DUMMY +import com.nextcloud.talk.models.json.participants.Participant.ActorType.EMAILS +import com.nextcloud.talk.models.json.participants.Participant.ActorType.GROUPS +import com.nextcloud.talk.models.json.participants.Participant.ActorType.GUESTS +import com.nextcloud.talk.models.json.participants.Participant.ActorType.USERS + +class EnumActorTypeConverter : StringBasedTypeConverter<Participant.ActorType>() { + override fun getFromString(string: String): Participant.ActorType { + return when (string) { + "emails" -> EMAILS + "groups" -> GROUPS + "guests" -> GUESTS + "users" -> USERS + else -> DUMMY + } + } + + override fun convertToString(`object`: Participant.ActorType?): String { + + if (`object` == null) { + return "" + } + + return when (`object`) { + EMAILS -> "emails" + GROUPS -> "groups" + GUESTS -> "guests" + USERS -> "users" + else -> "" + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java index 5832a0461..71a9db829 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.java @@ -22,21 +22,38 @@ package com.nextcloud.talk.models.json.participants; import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonObject; +import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter; import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter; import com.nextcloud.talk.models.json.converters.ObjectParcelConverter; import org.parceler.Parcel; import org.parceler.ParcelPropertyConverter; +import java.util.Arrays; + @Parcel @JsonObject public class Participant { + @JsonField(name = "attendeeId") + public Long attendeeId; + + @JsonField(name = "actorType", typeConverter = EnumActorTypeConverter.class) + public ActorType actorType; + + @JsonField(name = "actorId") + public String actorId; + + @JsonField(name = "attendeePin") + public String attendeePin; + + @Deprecated @JsonField(name = "userId") public String userId; @JsonField(name = {"type", "participantType"}, typeConverter = EnumParticipantTypeConverter.class) public ParticipantType type; + @Deprecated @JsonField(name = "name") public String name; @@ -46,15 +63,21 @@ public class Participant { @JsonField(name = "lastPing") public long lastPing; + @Deprecated @JsonField(name = "sessionId") public String sessionId; + @JsonField(name = "sessionIds") + public String[] sessionIds; + + @Deprecated @JsonField(name = "roomId") public long roomId; @ParcelPropertyConverter(ObjectParcelConverter.class) @JsonField(name = "inCall") public Object inCall; + public String source; public boolean selected; @@ -76,7 +99,37 @@ public class Participant { return participantFlags; } + public Long getAttendeeId() { + return attendeeId; + } + + public ActorType getActorType() { + if (this.actorType == null) { + if (this.userId != null) { + return ActorType.USERS; + } else { + return ActorType.GUESTS; + } + } + return actorType; + } + + public String getActorId() { + if (this.actorId == null) { + return this.userId; + } + return actorId; + } + + public String getAttendeePin() { + return attendeePin; + } + + @Deprecated public String getUserId() { + if (this.actorType != null && this.actorType == ActorType.USERS) { + return this.actorId; + } return this.userId; } @@ -84,6 +137,7 @@ public class Participant { return this.type; } + @Deprecated public String getName() { return this.name; } @@ -96,10 +150,16 @@ public class Participant { return this.lastPing; } + @Deprecated public String getSessionId() { return this.sessionId; } + public String[] getSessionIds() { + return sessionIds; + } + + @Deprecated public long getRoomId() { return this.roomId; } @@ -116,14 +176,32 @@ public class Participant { return this.selected; } + @Deprecated public void setUserId(String userId) { this.userId = userId; } + public void setAttendeeId(Long attendeeId) { + this.attendeeId = attendeeId; + } + + public void setActorType(ActorType actorType) { + this.actorType = actorType; + } + + public void setActorId(String actorId) { + this.actorId = actorId; + } + + public void setAttendeePin(String attendeePin) { + this.attendeePin = attendeePin; + } + public void setType(ParticipantType type) { this.type = type; } + @Deprecated public void setName(String name) { this.name = name; } @@ -136,10 +214,12 @@ public class Participant { this.lastPing = lastPing; } + @Deprecated public void setSessionId(String sessionId) { this.sessionId = sessionId; } + @Deprecated public void setRoomId(long roomId) { this.roomId = roomId; } @@ -156,93 +236,118 @@ public class Participant { this.selected = selected; } - public boolean equals(final Object o) { - if (o == this) { + public void setSessionIds(String[] sessionIds) { + this.sessionIds = sessionIds; + } + + @Override + public boolean equals(Object o) { + if (this == o) { return true; } - if (!(o instanceof Participant)) { + if (o == null || getClass() != o.getClass()) { return false; } - final Participant other = (Participant) o; - if (!other.canEqual((Object) this)) { + + Participant that = (Participant) o; + + if (lastPing != that.lastPing) { return false; } - final Object this$userId = this.getUserId(); - final Object other$userId = other.getUserId(); - if (this$userId == null ? other$userId != null : !this$userId.equals(other$userId)) { + if (roomId != that.roomId) { return false; } - final Object this$type = this.getType(); - final Object other$type = other.getType(); - if (this$type == null ? other$type != null : !this$type.equals(other$type)) { + if (selected != that.selected) { return false; } - final Object this$name = this.getName(); - final Object other$name = other.getName(); - if (this$name == null ? other$name != null : !this$name.equals(other$name)) { + if (!attendeeId.equals(that.attendeeId)) { return false; } - final Object this$displayName = this.getDisplayName(); - final Object other$displayName = other.getDisplayName(); - if (this$displayName == null ? other$displayName != null : !this$displayName.equals(other$displayName)) { + if (!actorType.equals(that.actorType)) { return false; } - if (this.getLastPing() != other.getLastPing()) { + if (!actorId.equals(that.actorId)) { return false; } - final Object this$sessionId = this.getSessionId(); - final Object other$sessionId = other.getSessionId(); - if (this$sessionId == null ? other$sessionId != null : !this$sessionId.equals(other$sessionId)) { + if (!attendeePin.equals(that.attendeePin)) { return false; } - if (this.getRoomId() != other.getRoomId()) { + if (!userId.equals(that.userId)) { return false; } - final Object this$inCall = this.getInCall(); - final Object other$inCall = other.getInCall(); - if (this$inCall == null ? other$inCall != null : !this$inCall.equals(other$inCall)) { + if (type != that.type) { return false; } - final Object this$source = this.getSource(); - final Object other$source = other.getSource(); - if (this$source == null ? other$source != null : !this$source.equals(other$source)) { + if (!name.equals(that.name)) { return false; } - - return this.isSelected() == other.isSelected(); + if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) { + return false; + } + if (!sessionId.equals(that.sessionId)) { + return false; + } + // Probably incorrect - comparing Object[] arrays with Arrays.equals + if (!Arrays.equals(sessionIds, that.sessionIds)) { + return false; + } + if (inCall != null ? !inCall.equals(that.inCall) : that.inCall != null) { + return false; + } + return source != null ? source.equals(that.source) : that.source == null; } protected boolean canEqual(final Object other) { return other instanceof Participant; } + @Override public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $userId = this.getUserId(); - result = result * PRIME + ($userId == null ? 43 : $userId.hashCode()); - final Object $type = this.getType(); - result = result * PRIME + ($type == null ? 43 : $type.hashCode()); - final Object $name = this.getName(); - result = result * PRIME + ($name == null ? 43 : $name.hashCode()); - final Object $displayName = this.getDisplayName(); - result = result * PRIME + ($displayName == null ? 43 : $displayName.hashCode()); - final long $lastPing = this.getLastPing(); - result = result * PRIME + (int) ($lastPing >>> 32 ^ $lastPing); - final Object $sessionId = this.getSessionId(); - result = result * PRIME + ($sessionId == null ? 43 : $sessionId.hashCode()); - final long $roomId = this.getRoomId(); - result = result * PRIME + (int) ($roomId >>> 32 ^ $roomId); - final Object $inCall = this.getInCall(); - result = result * PRIME + ($inCall == null ? 43 : $inCall.hashCode()); - final Object $source = this.getSource(); - result = result * PRIME + ($source == null ? 43 : $source.hashCode()); - result = result * PRIME + (this.isSelected() ? 79 : 97); + int result = (attendeeId != null ? attendeeId.hashCode() : 0); + result = 31 * result + (actorType != null ? actorType.hashCode() : 0); + result = 31 * result + (actorId != null ? actorId.hashCode() : 0); + result = 31 * result + (attendeePin != null ? attendeePin.hashCode() : 0); + result = 31 * result + (userId != null ? userId.hashCode() : 0); + result = 31 * result + (type != null ? type.hashCode() : 0); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (displayName != null ? displayName.hashCode() : 0); + result = 31 * result + (int) (lastPing ^ (lastPing >>> 32)); + result = 31 * result + (sessionId != null ? sessionId.hashCode() : 0); + result = 31 * result + Arrays.hashCode(sessionIds); + result = 31 * result + (int) (roomId ^ (roomId >>> 32)); + result = 31 * result + (inCall != null ? inCall.hashCode() : 0); + result = 31 * result + (source != null ? source.hashCode() : 0); + result = 31 * result + (selected ? 1 : 0); return result; } + @Override public String toString() { - return "Participant(userId=" + this.getUserId() + ", type=" + this.getType() + ", name=" + this.getName() + ", displayName=" + this.getDisplayName() + ", lastPing=" + this.getLastPing() + ", sessionId=" + this.getSessionId() + ", roomId=" + this.getRoomId() + ", inCall=" + this.getInCall() + ", source=" + this.getSource() + ", selected=" + this.isSelected() + ")"; + return "Participant{" + + "attendeeId=" + attendeeId + + ", actorType='" + actorType + '\'' + + ", actorId='" + actorId + '\'' + + ", attendeePin='" + attendeePin + '\'' + + ", userId='" + userId + '\'' + + ", type=" + type + + ", name='" + name + '\'' + + ", displayName='" + displayName + '\'' + + ", lastPing=" + lastPing + + ", sessionId='" + sessionId + '\'' + + ", sessionIds=" + Arrays.toString(sessionIds) + + ", roomId=" + roomId + + ", inCall=" + inCall + + ", source='" + source + '\'' + + ", selected=" + selected + + '}'; + } + + public enum ActorType { + DUMMY, + EMAILS, + GROUPS, + GUESTS, + USERS, } public enum ParticipantType { diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index 8a037c951..c9e75f1af 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -111,6 +111,10 @@ public class ApiUtils { return baseUrl + ocsApiVersion + "/cloud/capabilities"; } + public static int getCallApiVersion(UserEntity capabilities, int[] versions) throws NoSupportedApiException { + return getConversationApiVersion(capabilities, versions); + } + public static int getConversationApiVersion(UserEntity capabilities, int[] versions) throws NoSupportedApiException { boolean hasApiV4 = false; for (int version : versions) { |