Merge pull request #489 from nextcloud/improve-leave-delete

Improve leave delete
This commit is contained in:
Mario Đanić 2019-03-04 15:14:42 +01:00 committed by GitHub
commit 55c4f2ba9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 444 additions and 116 deletions

View File

@ -167,5 +167,4 @@ public final class MainActivity extends BaseActivity implements ActionBarProvide
super.onBackPressed();
}
}
}

View File

@ -176,7 +176,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
context.getResources().getColor(R.color.nc_grey));
holder.dialogLastMessageUserAvatar.setImageDrawable(drawable);
} else if (!conversation.getLastMessage().getActorId().equals(userEntity.getUserId())
&& !conversation.getType().equals(Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
&& !conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
holder.dialogLastMessageUserAvatar.setVisibility(View.VISIBLE);
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getLastMessage().getActorId(), R.dimen.small_item_height), new LazyHeaders.Builder()

View File

@ -193,8 +193,10 @@ public class AccountVerificationController extends BaseController {
}
if (isAccountImport) {
getRouter().pushController(RouterTransaction.with(new WebViewLoginController(baseUrl,
false, username, "")));
getRouter().replaceTopController(RouterTransaction.with(new WebViewLoginController(baseUrl,
false, username, ""))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
checkEverything();
}

View File

@ -410,7 +410,6 @@ public class ChatController extends BaseController implements MessagesListAdapte
private void showConversationInfoScreen() {
Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser);
bundle.putString(BundleKeys.KEY_BASE_URL, conversationUser.getBaseUrl());
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken);
getRouter().pushController((RouterTransaction.with(new ConversationInfoController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())

View File

@ -308,11 +308,11 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} else {
Bundle bundle = new Bundle();
Conversation.RoomType roomType;
Conversation.ConversationType roomType;
if (isPublicCall) {
roomType = Conversation.RoomType.ROOM_PUBLIC_CALL;
roomType = Conversation.ConversationType.ROOM_PUBLIC_CALL;
} else {
roomType = Conversation.RoomType.ROOM_GROUP_CALL;
roomType = Conversation.ConversationType.ROOM_GROUP_CALL;
}
bundle.putParcelable(BundleKeys.KEY_CONVERSATION_TYPE, Parcels.wrap(roomType));

View File

@ -21,6 +21,7 @@
package com.nextcloud.talk.controllers;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
@ -59,6 +60,8 @@ import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferencestorage.DatabaseStorageModule;
import com.vanniktech.emoji.EmojiTextView;
import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
import com.yarolegovich.mp.MaterialChoicePreference;
import com.yarolegovich.mp.MaterialPreferenceCategory;
import com.yarolegovich.mp.MaterialPreferenceScreen;
@ -79,6 +82,8 @@ import java.util.List;
@AutoInjector(NextcloudTalkApplication.class)
public class ConversationInfoController extends BaseController {
private static final int ID_DELETE_CONVERSATION_DIALOG = 0;
@BindView(R.id.notification_settings)
MaterialPreferenceScreen materialPreferenceScreen;
@BindView(R.id.progressBar)
@ -97,12 +102,16 @@ public class ConversationInfoController extends BaseController {
RecyclerView recyclerView;
@BindView(R.id.deleteConversationAction)
MaterialStandardPreference deleteConversationAction;
@BindView(R.id.leaveConversationAction)
MaterialStandardPreference leaveConversationAction;
@BindView(R.id.ownOptions)
MaterialPreferenceCategory ownOptionsCategory;
@Inject
NcApi ncApi;
private String baseUrl;
@Inject
Context context;
private String conversationToken;
private UserEntity conversationUser;
private String credentials;
@ -114,13 +123,14 @@ public class ConversationInfoController extends BaseController {
private FlexibleAdapter<AbstractFlexibleItem> adapter;
private List<AbstractFlexibleItem> recyclerViewItems = new ArrayList<>();
private LovelySaveStateHandler saveStateHandler;
public ConversationInfoController(Bundle args) {
super(args);
setHasOptionsMenu(true);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY);
conversationToken = args.getString(BundleKeys.KEY_ROOM_TOKEN);
baseUrl = args.getString(BundleKeys.KEY_BASE_URL);
credentials = ApiUtils.getCredentials(conversationUser.getUsername(), conversationUser.getToken());
}
@ -143,6 +153,11 @@ public class ConversationInfoController extends BaseController {
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
if (saveStateHandler == null) {
saveStateHandler = new LovelySaveStateHandler();
}
materialPreferenceScreen.setStorageModule(new DatabaseStorageModule(conversationUser, conversationToken));
if (adapter == null) {
fetchRoomInfo();
@ -157,6 +172,55 @@ public class ConversationInfoController extends BaseController {
}
}
private void showLovelyDialog(int dialogId, Bundle savedInstanceState) {
switch (dialogId) {
case ID_DELETE_CONVERSATION_DIALOG:
showDeleteConversationDialog(savedInstanceState);
break;
default:
break;
}
}
private void showDeleteConversationDialog(Bundle savedInstanceState) {
if (getActivity() != null) {
new LovelyStandardDialog(getActivity(), LovelyStandardDialog.ButtonLayout.HORIZONTAL)
.setTopColorRes(R.color.nc_darkRed)
.setIcon(DisplayUtils.getTintedDrawable(context.getResources(),
R.drawable.ic_delete_black_24dp, R.color.white))
.setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed))
.setTitle(R.string.nc_delete_call)
.setMessage(conversation.getDeleteWarningMessage())
.setPositiveButton(R.string.nc_delete, new View.OnClickListener() {
@Override
public void onClick(View v) {
deleteConversation();
}
})
.setNegativeButton(R.string.nc_cancel, null)
.setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler)
.setSavedInstanceState(savedInstanceState)
.show();
}
}
@Override
protected void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
saveStateHandler.saveInstanceState(outState);
super.onSaveViewState(view, outState);
}
@Override
protected void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState);
if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
//Dialog won't be restarted automatically, so we need to call this method.
//Each dialog knows how to restore its state
showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState);
}
}
private void setupAdapter() {
Activity activity;
@ -252,8 +316,7 @@ public class ConversationInfoController extends BaseController {
}
}
@OnClick(R.id.deleteConversationAction)
void deleteConversation() {
private void deleteConversation() {
Data data;
if ((data = getWorkerData()) != null) {
OneTimeWorkRequest deleteConversationWorker =
@ -263,6 +326,11 @@ public class ConversationInfoController extends BaseController {
}
}
@OnClick(R.id.deleteConversationAction)
void deleteConversationClick() {
showDeleteConversationDialog(null);
}
private Data getWorkerData() {
if (!TextUtils.isEmpty(conversationToken) && conversationUser != null) {
Data.Builder data = new Data.Builder();
@ -276,9 +344,8 @@ public class ConversationInfoController extends BaseController {
private void popTwoLastControllers() {
List<RouterTransaction> backstack = getRouter().getBackstack();
backstack.remove(backstack.size() - 2);
backstack = backstack.subList(0, backstack.size() - 2);
getRouter().setBackstack(backstack, new HorizontalChangeHandler());
getRouter().popCurrentController();
}
private void fetchRoomInfo() {
@ -296,7 +363,14 @@ public class ConversationInfoController extends BaseController {
conversation = roomOverall.getOcs().getData();
ownOptionsCategory.setVisibility(View.VISIBLE);
if (!conversation.isDeletable()) {
if (!conversation.canLeave()) {
leaveConversationAction.setVisibility(View.GONE);
} else {
leaveConversationAction.setVisibility(View.VISIBLE);
}
if (!conversation.canModerate()) {
deleteConversationAction.setVisibility(View.GONE);
} else {
deleteConversationAction.setVisibility(View.VISIBLE);
@ -372,7 +446,7 @@ public class ConversationInfoController extends BaseController {
private void setProperNotificationValue(Conversation conversation) {
if (messageNotificationLevel != null) {
if (conversation.getType().equals(Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
if (conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
// hack to see if we get mentioned always or just on mention
if (conversationUser.hasSpreedCapabilityWithName("mention-flag")) {
messageNotificationLevel.setValue("always");

View File

@ -30,6 +30,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.text.InputType;
import android.text.TextUtils;
import android.util.Log;
import android.view.*;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
@ -41,6 +42,9 @@ import androidx.core.view.MenuItemCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import autodagger.AutoInjector;
import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction;
@ -68,6 +72,8 @@ import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController;
import com.nextcloud.talk.events.BottomSheetLockEvent;
import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.events.MoreMenuClickEvent;
import com.nextcloud.talk.interfaces.ConversationMenuInterface;
import com.nextcloud.talk.jobs.DeleteConversationWorker;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.rooms.Conversation;
@ -79,6 +85,8 @@ import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
import eu.davidea.fastscroller.FastScroller;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
@ -101,11 +109,12 @@ import java.util.List;
@AutoInjector(NextcloudTalkApplication.class)
public class ConversationsListController extends BaseController implements SearchView.OnQueryTextListener,
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener, FastScroller
.OnScrollStateChangeListener {
.OnScrollStateChangeListener, ConversationMenuInterface {
public static final String TAG = "ConversationsListController";
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
public static final int ID_DELETE_CONVERSATION_DIALOG = 0;
@Inject
UserUtils userUtils;
@ -116,6 +125,9 @@ public class ConversationsListController extends BaseController implements Searc
@Inject
NcApi ncApi;
@Inject
Context context;
@Inject
AppPreferences appPreferences;
@ -159,6 +171,10 @@ public class ConversationsListController extends BaseController implements Searc
private String lastClickedConversationToken;
private int scrollTo = 0;
private LovelySaveStateHandler saveStateHandler;
private Bundle conversationMenuBundle = null;
public ConversationsListController() {
super();
setHasOptionsMenu(true);
@ -178,6 +194,10 @@ public class ConversationsListController extends BaseController implements Searc
getActionBar().show();
}
if (saveStateHandler == null) {
saveStateHandler = new LovelySaveStateHandler();
}
if (adapter == null) {
adapter = new FlexibleAdapter<>(callItems, getActivity(), true);
} else {
@ -505,16 +525,24 @@ public class ConversationsListController extends BaseController implements Searc
@Override
public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
super.onSaveViewState(view, outState);
saveStateHandler.saveInstanceState(outState);
if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) {
outState.putString(KEY_SEARCH_QUERY, searchView.getQuery().toString());
}
super.onSaveViewState(view, outState);
}
@Override
public void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState);
searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, "");
if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
//Dialog won't be restarted automatically, so we need to call this method.
//Each dialog knows how to restore its state
showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState);
}
}
@Override
@ -584,7 +612,7 @@ public class ConversationsListController extends BaseController implements Searc
if (shouldShowCallMenuController) {
getChildRouter((ViewGroup) view).setRoot(
RouterTransaction.with(new CallMenuController(bundle))
RouterTransaction.with(new CallMenuController(bundle, this))
.popChangeHandler(new VerticalChangeHandler())
.pushChangeHandler(new VerticalChangeHandler()));
} else {
@ -677,7 +705,7 @@ public class ConversationsListController extends BaseController implements Searc
@Subscribe(sticky = true, threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(EventStatus eventStatus) {
if (currentUser != null && eventStatus.getUserId() == currentUser.getId()){
if (currentUser != null && eventStatus.getUserId() == currentUser.getId()) {
switch (eventStatus.getEventType()) {
case CONVERSATION_UPDATE:
if (eventStatus.isAllGood() && !isRefreshing) {
@ -689,4 +717,71 @@ public class ConversationsListController extends BaseController implements Searc
}
}
}
private void showDeleteConversationDialog(Bundle savedInstanceState) {
if (getActivity() != null && conversationMenuBundle != null && currentUser != null && conversationMenuBundle.getLong(BundleKeys.KEY_INTERNAL_USER_ID) == currentUser.getId()) {
Conversation conversation =
Parcels.unwrap(conversationMenuBundle.getParcelable(BundleKeys.KEY_ROOM));
if (conversation != null) {
new LovelyStandardDialog(getActivity(), LovelyStandardDialog.ButtonLayout.HORIZONTAL)
.setTopColorRes(R.color.nc_darkRed)
.setIcon(DisplayUtils.getTintedDrawable(context.getResources(),
R.drawable.ic_delete_black_24dp, R.color.white))
.setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed))
.setTitle(R.string.nc_delete_call)
.setMessage(conversation.getDeleteWarningMessage())
.setPositiveButton(R.string.nc_delete, new View.OnClickListener() {
@Override
public void onClick(View v) {
Data.Builder data = new Data.Builder();
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID,
conversationMenuBundle.getLong(BundleKeys.KEY_INTERNAL_USER_ID));
data.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
conversationMenuBundle = null;
deleteConversation(data.build());
}
})
.setNegativeButton(R.string.nc_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
conversationMenuBundle = null;
}
})
.setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler)
.setSavedInstanceState(savedInstanceState)
.show();
}
}
}
private void deleteConversation(Data data) {
OneTimeWorkRequest deleteConversationWorker =
new OneTimeWorkRequest.Builder(DeleteConversationWorker.class).setInputData(data).build();
WorkManager.getInstance().enqueue(deleteConversationWorker);
}
private void showLovelyDialog(int dialogId, Bundle savedInstanceState) {
switch (dialogId) {
case ID_DELETE_CONVERSATION_DIALOG:
showDeleteConversationDialog(savedInstanceState);
break;
default:
break;
}
}
@Override
public void openLovelyDialogWithIdAndBundle(int dialogId, Bundle bundle) {
conversationMenuBundle = bundle;
switch (dialogId) {
case ID_DELETE_CONVERSATION_DIALOG:
showLovelyDialog(dialogId, null);
break;
default:
break;
}
}
}

View File

@ -62,6 +62,7 @@ import com.nextcloud.talk.jobs.AccountRemovalWorker;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.SecurityUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
@ -70,6 +71,8 @@ import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.preferences.MagicUserInputModule;
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
import com.yarolegovich.mp.*;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@ -178,6 +181,8 @@ public class SettingsController extends BaseController {
@Inject
Context context;
private LovelySaveStateHandler saveStateHandler;
private UserEntity currentUser;
private String credentials;
@ -190,6 +195,8 @@ public class SettingsController extends BaseController {
private Disposable profileQueryDisposable;
private Disposable dbQueryDisposable;
private static final int ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0;
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_settings, container, false);
@ -210,6 +217,10 @@ public class SettingsController extends BaseController {
getCurrentUser();
if (saveStateHandler == null) {
saveStateHandler = new LovelySaveStateHandler();
}
appPreferences.registerProxyTypeListener(proxyTypeChangeListener = new ProxyTypeChangeListener());
appPreferences.registerProxyCredentialsListener(proxyCredentialsChangeListener = new ProxyCredentialsChangeListener());
appPreferences.registerScreenSecurityListener(screenSecurityChangeListener = new ScreenSecurityChangeListener());
@ -302,7 +313,6 @@ public class SettingsController extends BaseController {
.popChangeHandler(new VerticalChangeHandler()));
});
String host = null;
int port = -1;
@ -338,6 +348,78 @@ public class SettingsController extends BaseController {
()));
}
private void showLovelyDialog(int dialogId, Bundle savedInstanceState) {
switch (dialogId) {
case ID_REMOVE_ACCOUNT_WARNING_DIALOG:
showRemoveAccountWarning(savedInstanceState);
break;
default:
break;
}
}
@Override
protected void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
saveStateHandler.saveInstanceState(outState);
super.onSaveViewState(view, outState);
}
@Override
protected void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState);
if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
//Dialog won't be restarted automatically, so we need to call this method.
//Each dialog knows how to restore its state
showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState);
}
}
private void showRemoveAccountWarning(Bundle savedInstanceState) {
if (getActivity() != null) {
new LovelyStandardDialog(getActivity(), LovelyStandardDialog.ButtonLayout.HORIZONTAL)
.setTopColorRes(R.color.nc_darkRed)
.setIcon(DisplayUtils.getTintedDrawable(getResources(),
R.drawable.ic_delete_black_24dp, R.color.white))
.setPositiveButtonColor(context.getResources().getColor(R.color.nc_darkRed))
.setTitle(R.string.nc_settings_remove_account)
.setMessage(R.string.nc_settings_remove_confirmation)
.setPositiveButton(R.string.nc_settings_remove, new View.OnClickListener() {
@Override
public void onClick(View v) {
removeCurrentAccount();
}
})
.setNegativeButton(R.string.nc_cancel, null)
.setInstanceStateHandler(ID_REMOVE_ACCOUNT_WARNING_DIALOG, saveStateHandler)
.setSavedInstanceState(savedInstanceState)
.show();
}
}
private void removeCurrentAccount() {
boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId());
OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build();
WorkManager.getInstance().enqueue(accountRemovalWork);
if (otherUserExists && getView() != null) {
onViewBound(getView());
onAttach(getView());
} else if (!otherUserExists) {
if (getParentController() == null || getParentController().getRouter() == null) {
if (getActivity() != null) {
// Something went very wrong, finish the app
getActivity().finish();
}
} else {
getParentController().getRouter().setRoot(RouterTransaction.with(
new ServerSelectionController())
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
}
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
@ -495,28 +577,7 @@ public class SettingsController extends BaseController {
removeAccountButton.addPreferenceClickListener(view1 -> {
boolean otherUserExists = userUtils.scheduleUserForDeletionWithId(currentUser.getId());
OneTimeWorkRequest accountRemovalWork = new OneTimeWorkRequest.Builder(AccountRemovalWorker.class).build();
WorkManager.getInstance().enqueue(accountRemovalWork);
if (otherUserExists && getView() != null) {
onViewBound(getView());
onAttach(getView());
} else if (!otherUserExists) {
if (getParentController() == null || getParentController().getRouter() == null) {
if (getActivity() != null) {
// Something went very wrong, finish the app
getActivity().finish();
}
} else {
getParentController().getRouter().setRoot(RouterTransaction.with(
new ServerSelectionController())
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
}
}
showLovelyDialog(ID_REMOVE_ACCOUNT_WARNING_DIALOG, null);
});
}

View File

@ -28,8 +28,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import autodagger.AutoInjector;
import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction;
@ -39,8 +43,12 @@ import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.AppItem;
import com.nextcloud.talk.adapters.items.MenuItem;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.ConversationsListController;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.BottomSheetLockEvent;
import com.nextcloud.talk.interfaces.ConversationMenuInterface;
import com.nextcloud.talk.jobs.DeleteConversationWorker;
import com.nextcloud.talk.jobs.LeaveConversationWorker;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.rooms.Conversation;
import com.nextcloud.talk.utils.DisplayUtils;
@ -75,6 +83,9 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
private MenuType menuType;
private Intent shareIntent;
private UserEntity currentUser;
private ConversationMenuInterface conversationMenuInterface;
public CallMenuController(Bundle args) {
super(args);
this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
@ -83,6 +94,15 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
}
}
public CallMenuController(Bundle args, @Nullable ConversationMenuInterface conversationMenuInterface) {
super(args);
this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM));
if (args.containsKey(BundleKeys.KEY_MENU_TYPE)) {
this.menuType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_MENU_TYPE));
}
this.conversationMenuInterface = conversationMenuInterface;
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_call_menu, container, false);
@ -128,12 +148,11 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
menuItems.add(new MenuItem(getResources().getString(R.string.nc_configure_room), 0, null));
}
UserEntity currentUser;
currentUser = userUtils.getCurrentUser();
if (conversation.isFavorite()) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_remove_from_favorites), 97, DisplayUtils.getTintedDrawable(getResources(), R.drawable.ic_star_border_black_24dp, R.color.grey_600)));
} else if ((currentUser = userUtils.getCurrentUser()) != null &&
currentUser.hasSpreedCapabilityWithName("favorites")) {
} else if (currentUser.hasSpreedCapabilityWithName("favorites")) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_add_to_favorites)
, 98, DisplayUtils.getTintedDrawable(getResources(), R.drawable.ic_star_black_24dp, R.color.grey_600)));
}
@ -143,7 +162,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
.ic_pencil_grey600_24dp)));
}
if (conversation.canModerate()) {
if (conversation.canModerate() && !currentUser.hasSpreedCapabilityWithName("locked-one-to-one-rooms")) {
if (!conversation.isPublic()) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_make_call_public), 3, getResources().getDrawable(R.drawable
.ic_link_grey600_24px)));
@ -158,6 +177,9 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
.ic_lock_plus_grey600_24dp)));
}
}
menuItems.add(new MenuItem(getResources().getString(R.string.nc_delete_call), 9, getResources().getDrawable(R.drawable
.ic_delete_grey600_24dp)));
}
if (conversation.isPublic()) {
@ -169,13 +191,11 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
}
}
if (conversation.isDeletable()) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_delete_call), 9, getResources().getDrawable(R.drawable
.ic_delete_grey600_24dp)));
}
if (conversation.canLeave()) {
menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1, getResources().getDrawable(R.drawable
.ic_close_grey600_24dp)));
}
} else if (menuType.equals(MenuType.SHARE)) {
prepareIntent();
List<AppAdapter.AppInfo> appInfoList = ShareUtils.getShareApps(getActivity(), shareIntent, null,
@ -209,6 +229,22 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
}
if (tag > 0) {
if (tag == 1 || tag == 9) {
if (tag == 1) {
Data data;
if ((data = getWorkerData()) != null) {
OneTimeWorkRequest leaveConversationWorker =
new OneTimeWorkRequest.Builder(LeaveConversationWorker.class).setInputData(data).build();
WorkManager.getInstance().enqueue(leaveConversationWorker);
}
} else {
Bundle deleteConversationBundle;
if ((deleteConversationBundle = getDeleteConversationBundle()) != null) {
conversationMenuInterface.openLovelyDialogWithIdAndBundle(ConversationsListController.ID_DELETE_CONVERSATION_DIALOG, deleteConversationBundle);
}
}
eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
} else {
bundle.putInt(BundleKeys.KEY_OPERATION_CODE, tag);
if (tag != 2 && tag != 4 && tag != 6 && tag != 7) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
@ -221,12 +257,13 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
.popChangeHandler(new HorizontalChangeHandler()));
} else {
bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(MenuType.SHARE));
getRouter().pushController(RouterTransaction.with(new CallMenuController(bundle))
getRouter().pushController(RouterTransaction.with(new CallMenuController(bundle, null))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
}
}
}
}
} else if (menuType.equals(MenuType.SHARE) && position != 0) {
AppItem appItem = (AppItem) adapter.getItem(position);
if (appItem != null && getActivity() != null) {
@ -257,4 +294,27 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
public enum MenuType {
REGULAR, SHARE
}
private Data getWorkerData() {
if (!TextUtils.isEmpty(conversation.getToken())) {
Data.Builder data = new Data.Builder();
data.putString(BundleKeys.KEY_ROOM_TOKEN, conversation.getToken());
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUser.getId());
return data.build();
}
return null;
}
private Bundle getDeleteConversationBundle() {
if (!TextUtils.isEmpty(conversation.getToken())) {
Bundle bundle = new Bundle();
bundle.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUser.getId());
bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
return bundle;
}
return null;
}
}

View File

@ -116,7 +116,7 @@ public class OperationsMenuController extends BaseController {
private Disposable disposable;
private Conversation.RoomType conversationType;
private Conversation.ConversationType conversationType;
private ArrayList<String> invitedUsers = new ArrayList<>();
private ArrayList<String> invitedGroups = new ArrayList<>();
@ -184,13 +184,6 @@ public class OperationsMenuController extends BaseController {
}
switch (operationCode) {
case 1:
ncApi.removeSelfFromRoom(credentials, ApiUtils.getUrlForRemoveSelfFromRoom(currentUser.getBaseUrl(), conversation.getToken()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver);
break;
case 2:
ncApi.renameRoom(credentials, ApiUtils.getRoom(currentUser.getBaseUrl(), conversation.getToken()),
conversation.getName())
@ -232,14 +225,6 @@ public class OperationsMenuController extends BaseController {
.retry(1)
.subscribe(operationsObserver);
break;
case 9:
ncApi.deleteRoom(credentials, ApiUtils.getRoom(currentUser.getBaseUrl(),
conversation.getToken()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.retry(1)
.subscribe(operationsObserver);
break;
case 10:
ncApi.getRoom(credentials, ApiUtils.getRoom(baseUrl, conversationToken))
.subscribeOn(Schedulers.newThread())
@ -278,7 +263,7 @@ public class OperationsMenuController extends BaseController {
invite = invitedGroups.get(0);
}
if (conversationType.equals(Conversation.RoomType.ROOM_PUBLIC_CALL) ||
if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL) ||
!currentUser.hasSpreedCapabilityWithName("empty-group-room")) {
retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser.getBaseUrl(),
"3", invite, null);
@ -307,7 +292,7 @@ public class OperationsMenuController extends BaseController {
@Override
public void onNext(RoomOverall roomOverall) {
conversation = roomOverall.getOcs().getData();
if (conversationType.equals(Conversation.RoomType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) {
if (conversationType.equals(Conversation.ConversationType.ROOM_PUBLIC_CALL) && isGroupCallWorkaroundFinal) {
performGroupCallWorkaround(credentials);
} else {
inviteUsersToAConversation();

View File

@ -0,0 +1,27 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 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.interfaces;
import android.os.Bundle;
public interface ConversationMenuInterface {
void openLovelyDialogWithIdAndBundle(int dialogId, Bundle bundle);
}

View File

@ -140,12 +140,12 @@ public class NotificationWorker extends Worker {
Conversation conversation = roomOverall.getOcs().getData();
intent.putExtra(BundleKeys.KEY_ROOM, Parcels.wrap(conversation));
if (conversation.getType().equals(Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL) ||
if (conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) ||
(!TextUtils.isEmpty(conversation.getObjectType()) && "share:password".equals
(conversation.getObjectType()))) {
context.startActivity(intent);
} else {
if (conversation.getType().equals(Conversation.RoomType.ROOM_GROUP_CALL)) {
if (conversation.getType().equals(Conversation.ConversationType.ROOM_GROUP_CALL)) {
conversationType = "group";
} else {
conversationType = "public";

View File

@ -23,23 +23,23 @@ package com.nextcloud.talk.models.json.converters;
import com.bluelinelabs.logansquare.typeconverters.IntBasedTypeConverter;
import com.nextcloud.talk.models.json.rooms.Conversation;
public class EnumRoomTypeConverter extends IntBasedTypeConverter<Conversation.RoomType> {
public class EnumRoomTypeConverter extends IntBasedTypeConverter<Conversation.ConversationType> {
@Override
public Conversation.RoomType getFromInt(int i) {
public Conversation.ConversationType getFromInt(int i) {
switch (i) {
case 1:
return Conversation.RoomType.ROOM_TYPE_ONE_TO_ONE_CALL;
return Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL;
case 2:
return Conversation.RoomType.ROOM_GROUP_CALL;
return Conversation.ConversationType.ROOM_GROUP_CALL;
case 3:
return Conversation.RoomType.ROOM_PUBLIC_CALL;
return Conversation.ConversationType.ROOM_PUBLIC_CALL;
default:
return Conversation.RoomType.DUMMY;
return Conversation.ConversationType.DUMMY;
}
}
@Override
public int convertToInt(Conversation.RoomType object) {
public int convertToInt(Conversation.ConversationType object) {
switch (object) {
case DUMMY:
return 0;

View File

@ -20,8 +20,11 @@
*/
package com.nextcloud.talk.models.json.rooms;
import android.content.res.Resources;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter;
import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
@ -45,7 +48,7 @@ public class Conversation {
@JsonField(name = "displayName")
public String displayName;
@JsonField(name = "type", typeConverter = EnumRoomTypeConverter.class)
public RoomType type;
public ConversationType type;
@JsonField(name = "count")
public long count;
@JsonField(name = "lastPing")
@ -79,7 +82,7 @@ public class Conversation {
NotificationLevel notificationLevel;
public boolean isPublic() {
return (RoomType.ROOM_PUBLIC_CALL.equals(type));
return (ConversationType.ROOM_PUBLIC_CALL.equals(type));
}
public boolean isGuest() {
@ -93,11 +96,24 @@ public class Conversation {
}
public boolean isNameEditable() {
return (canModerate() && !RoomType.ROOM_TYPE_ONE_TO_ONE_CALL.equals(type));
return (canModerate() && !ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL.equals(type));
}
public boolean isDeletable() {
return (canModerate() && ((participants != null && participants.size() > 2) || numberOfGuests > 0));
public boolean canLeave() {
return !canModerate() || (getType() != ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && getParticipants().size() > 1);
}
public String getDeleteWarningMessage() {
Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
if (getType() == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
return String.format(resources.getString(R.string.nc_delete_conversation_one2one),
getDisplayName());
} else if (getParticipants().size() > 1) {
return resources.getString(R.string.nc_delete_conversation_more);
}
return resources.getString(R.string.nc_delete_conversation_default);
}
public enum NotificationLevel {
@ -108,7 +124,7 @@ public class Conversation {
}
@Parcel
public enum RoomType {
public enum ConversationType {
DUMMY,
ROOM_TYPE_ONE_TO_ONE_CALL,
ROOM_GROUP_CALL,

View File

@ -35,5 +35,5 @@ public class RoomPropertiesWebSocketMessage {
String name;
@JsonField(name = "type", typeConverter = EnumRoomTypeConverter.class)
Conversation.RoomType roomType;
Conversation.ConversationType roomType;
}

View File

@ -160,6 +160,7 @@ public class PowerManagerUtils {
}
fullLock.release();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
proximityLock.release();
}
@ -180,6 +181,7 @@ public class PowerManagerUtils {
if (!wifiLock.isHeld()) {
wifiLock.acquire();
}
fullLock.release(
);

View File

@ -62,8 +62,8 @@
android:id="@+id/avatar_image"
android:layout_width="@dimen/avatar_size_big"
android:layout_height="@dimen/avatar_size_big"
apc:roundAsCircle="true"
android:layout_centerHorizontal="true" />
android:layout_centerHorizontal="true"
apc:roundAsCircle="true" />
<com.vanniktech.emoji.EmojiTextView
android:id="@+id/display_name_text"
@ -77,19 +77,19 @@
</com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/otherRoomOptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/conversation_info_name"
android:id="@+id/otherRoomOptions"
android:visibility="gone">
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/favoiteConversationAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_icon="@drawable/ic_star_black_24dp"
apc:mp_icon_tint="@color/grey_600"
apc:mp_title="@string/nc_add_to_favorites"
android:id="@+id/favoriteConversationAction">
apc:mp_title="@string/nc_add_to_favorites">
</com.yarolegovich.mp.MaterialStandardPreference>
@ -121,27 +121,27 @@
</com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory
android:id="@+id/ownOptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/participants_list_category"
android:visibility="gone"
android:id="@+id/ownOptions">
android:visibility="gone">
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/leaveConversationAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_title="@string/nc_leave"
apc:mp_icon="@drawable/ic_exit_to_app_black_24dp"
apc:mp_icon_tint="@color/grey_600"
android:id="@+id/leaveConversationAction" />
apc:mp_title="@string/nc_leave" />
<com.yarolegovich.mp.MaterialStandardPreference
android:id="@+id/deleteConversationAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
apc:mp_title="@string/nc_delete_call"
apc:mp_icon_tint="@color/grey_600"
apc:mp_icon="@drawable/ic_delete_black_24dp"
android:id="@+id/deleteConversationAction" />
apc:mp_icon_tint="@color/grey_600"
apc:mp_title="@string/nc_delete_call" />
</com.yarolegovich.mp.MaterialPreferenceCategory>
</RelativeLayout>

View File

@ -69,6 +69,8 @@
<string name="nc_settings_reauthorize">Reauthorize</string>
<string name="nc_client_cert_setup">Set up client certificate</string>
<string name="nc_client_cert_change">Change client certificate</string>
<string name="nc_settings_remove">Remove</string>
<string name="nc_settings_remove_confirmation">Please confirm your intent to remove the current account.</string>
<string name="nc_settings_remove_account">Remove account</string>
<string name="nc_settings_add_account">Add a new account</string>
<string name="nc_settings_wrong_account">Only current account can be reauthorized</string>
@ -143,6 +145,12 @@
<string name="nc_make_call_public">Make conversation public</string>
<string name="nc_make_call_private">Make conversation private</string>
<string name="nc_delete_call">Delete conversation</string>
<string name="nc_delete">Delete</string>
<string name="nc_delete_conversation_default">Please confirm your intent to remove the conversation.</string>
<string name="nc_delete_conversation_one2one">If you delete the conversation, it will also be
deleted for %1$s.</string>
<string name="nc_delete_conversation_more">If you delete the conversation, it will also be deleted for all other participants.</string>
<string name="nc_new_conversation">New conversation</string>
<string name="nc_join_via_link">Join via link</string>
<string name="nc_join_via_web">Join via web</string>