diff --git a/app/build.gradle b/app/build.gradle index 8dd4275c6..c1b42c427 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -266,7 +266,6 @@ dependencies { implementation 'com.novoda:merlin:1.2.1' - implementation 'com.github.Kennyc1012:BottomSheet:2.4.1' implementation 'com.github.nextcloud:PopupBubble:1.0.6' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt index 1cb242863..ea55052db 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt @@ -304,7 +304,9 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() { } } - override fun onError(e: Throwable) {} + override fun onError(e: Throwable) { + // unused atm + } override fun onComplete() { stopForeground(true) handler.removeCallbacksAndMessages(null) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d6c2e86bc..abbf6b73e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,9 @@ ~ Nextcloud Talk application ~ ~ @author Mario Danic + ~ @author Marcel Hibbe ~ Copyright (C) 2017-2019 Mario Danic + ~ Copyright (C) 2021-2022 Marcel Hibbe ~ ~ 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 @@ -97,7 +99,7 @@ + android:windowSoftInputMode="adjustResize"> diff --git a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt index de8dbf73b..7089d6304 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -246,7 +246,9 @@ class MainActivity : BaseActivity(), ActionBarProvider { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} + override fun onSubscribe(d: Disposable) { + // unused atm + } override fun onNext(roomOverall: RoomOverall) { val bundle = Bundle() bundle.putParcelable(KEY_USER_ENTITY, currentUser) @@ -265,7 +267,9 @@ class MainActivity : BaseActivity(), ActionBarProvider { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} + override fun onSubscribe(d: Disposable) { + // unused atm + } override fun onNext(roomOverall: RoomOverall) { bundle.putParcelable( KEY_ACTIVE_CONVERSATION, @@ -277,13 +281,21 @@ class MainActivity : BaseActivity(), ActionBarProvider { ) } - override fun onError(e: Throwable) {} - override fun onComplete() {} + override fun onError(e: Throwable) { + // unused atm + } + override fun onComplete() { + // unused atm + } }) } - override fun onError(e: Throwable) {} - override fun onComplete() {} + override fun onError(e: Throwable) { + // unused atm + } + override fun onComplete() { + // unused atm + } }) } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index b47f38cbe..6d2af213b 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -149,7 +149,6 @@ import com.nextcloud.talk.utils.ContactUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.ImageEmojiEditText -import com.nextcloud.talk.utils.KeyboardUtils import com.nextcloud.talk.utils.MagicCharPolicy import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.UriUtils @@ -347,6 +346,7 @@ class ChatController(args: Bundle) : } override fun onError(e: Throwable) { + // unused atm } override fun onComplete() { @@ -389,9 +389,11 @@ class ChatController(args: Bundle) : } override fun onError(e: Throwable) { + // unused atm } override fun onComplete() { + // unused atm } }) } @@ -666,6 +668,7 @@ class ChatController(args: Bundle) : } override fun afterTextChanged(s: Editable) { + // unused atm } }) @@ -1262,7 +1265,9 @@ class ChatController(args: Bundle) : UploadAndShareFilesWorker.requestStoragePermission(this) } } - .setNegativeButton(R.string.nc_no) {} + .setNegativeButton(R.string.nc_no) { + // unused atm + } .show() } catch (e: IllegalStateException) { Toast.makeText(context, context?.resources?.getString(R.string.nc_upload_failed), Toast.LENGTH_LONG) @@ -1541,10 +1546,6 @@ class ChatController(args: Bundle) : cancelReply() } - if (activity != null) { - KeyboardUtils(activity, getView(), false) - } - cancelNotificationsForCurrentConversation() if (inConversation) { @@ -1698,9 +1699,11 @@ class ChatController(args: Bundle) : } override fun onError(e: Throwable) { + // unused atm } override fun onComplete() { + // unused atm } }) } else { @@ -1764,7 +1767,9 @@ class ChatController(args: Bundle) : } } - override fun onError(e: Throwable) {} + override fun onError(e: Throwable) { + // unused atm + } override fun onComplete() { dispose() 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 c9dbaf36a..3adbb0903 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java @@ -2,7 +2,9 @@ * Nextcloud Talk application * * @author Mario Danic - * Copyright (C) 2017 Mario Danic (mario@lovelyhq.com) + * @author Marcel Hibbe + * Copyright (C) 2017 Mario Danic + * Copyright (C) 2022 Marcel Hibbe * * 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 @@ -20,12 +22,14 @@ package com.nextcloud.talk.controllers; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_INVITE_USERS; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM; + import android.app.SearchManager; import android.content.Context; import android.graphics.PorterDuff; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.text.InputType; import android.util.Log; import android.view.LayoutInflater; @@ -39,19 +43,14 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; -import com.bluelinelabs.conductor.RouterTransaction; -import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.bluelinelabs.logansquare.LoganSquare; -import com.kennyc.bottomsheet.BottomSheet; import com.nextcloud.talk.R; import com.nextcloud.talk.adapters.items.GenericTextHeaderItem; import com.nextcloud.talk.adapters.items.UserItem; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; -import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController; -import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController; -import com.nextcloud.talk.events.BottomSheetLockEvent; +import com.nextcloud.talk.events.OpenConversationEvent; import com.nextcloud.talk.jobs.AddParticipantsToConversation; import com.nextcloud.talk.models.RetrofitBucket; import com.nextcloud.talk.models.database.CapabilitiesUtil; @@ -62,9 +61,9 @@ 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.ui.dialog.ContactsBottomDialog; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ConductorRemapping; -import com.nextcloud.talk.utils.KeyboardUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.preferences.AppPreferences; @@ -113,7 +112,7 @@ import okhttp3.ResponseBody; @AutoInjector(NextcloudTalkApplication.class) public class ContactsController extends BaseController implements SearchView.OnQueryTextListener, - FlexibleAdapter.OnItemClickListener { + FlexibleAdapter.OnItemClickListener { public static final String TAG = "ContactsController"; @@ -167,8 +166,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ private Disposable cacheQueryDisposable; private FlexibleAdapter adapter; private List contactItems; - private BottomSheet bottomSheet; - private View view; private SmoothScrollLinearLayoutManager layoutManager; @@ -192,6 +189,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ private boolean isAddingParticipantsView; private String conversationToken; + private ContactsBottomDialog contactsBottomDialog; + public ContactsController() { super(); setHasOptionsMenu(true); @@ -266,12 +265,12 @@ public class ContactsController extends BaseController implements SearchView.OnQ private void setupAdapter() { adapter.setNotifyChangeOfUnfilteredItems(true) - .setMode(SelectableAdapter.Mode.MULTI); + .setMode(SelectableAdapter.Mode.MULTI); adapter.setStickyHeaderElevation(5) - .setUnlinkAllItemsOnRemoveHeaders(true) - .setDisplayHeadersAtStartUp(true) - .setStickyHeaders(true); + .setUnlinkAllItemsOnRemoveHeaders(true) + .setDisplayHeadersAtStartUp(true) + .setStickyHeaders(true); adapter.addListener(this); } @@ -294,7 +293,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ userId = selectedUserIds.iterator().next(); } - int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[]{ApiUtils.APIv4, 1}); RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(), roomType, @@ -302,65 +301,65 @@ public class ContactsController extends BaseController implements SearchView.OnQ userId, null); ncApi.createRoom(credentials, - retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { + retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { - } + } - @Override - public void onNext(RoomOverall roomOverall) { - Bundle bundle = new Bundle(); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken()); - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId()); + @Override + public void onNext(RoomOverall roomOverall) { + Bundle bundle = new Bundle(); + bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); + bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken()); + bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId()); - // FIXME once APIv2 or later is used only, the createRoom already returns all the data - ncApi.getRoom(credentials, - ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(), - roomOverall.getOcs().getData().getToken())) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { + // FIXME once APIv2 or later is used only, the createRoom already returns all the data + ncApi.getRoom(credentials, + ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(), + roomOverall.getOcs().getData().getToken())) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { + @Override + public void onSubscribe(Disposable d) { - } + } - @Override - public void onNext(RoomOverall roomOverall) { - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), - Parcels.wrap(roomOverall.getOcs().getData())); + @Override + public void onNext(RoomOverall roomOverall) { + bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), + Parcels.wrap(roomOverall.getOcs().getData())); - ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), - roomOverall.getOcs().getData().getToken(), bundle, true); - } + ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), + roomOverall.getOcs().getData().getToken(), bundle, true); + } - @Override - public void onError(Throwable e) { + @Override + public void onError(Throwable e) { - } + } - @Override - public void onComplete() { + @Override + public void onComplete() { - } - }); - } + } + }); + } - @Override - public void onError(Throwable e) { + @Override + public void onError(Throwable e) { - } + } - @Override - public void onComplete() { - } - }); + @Override + public void onComplete() { + } + }); } else { Bundle bundle = new Bundle(); @@ -382,8 +381,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ bundle.putStringArrayList(BundleKeys.INSTANCE.getKEY_INVITED_GROUP(), groupIdsArray); bundle.putStringArrayList(BundleKeys.INSTANCE.getKEY_INVITED_EMAIL(), emailsArray); bundle.putStringArrayList(BundleKeys.INSTANCE.getKEY_INVITED_CIRCLE(), circleIdsArray); - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 11); - prepareAndShowBottomSheetWithBundle(bundle, true); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), OPS_CODE_INVITE_USERS); + prepareAndShowBottomSheetWithBundle(bundle); } } else { String[] userIdsArray = selectedUserIds.toArray(new String[selectedUserIds.size()]); @@ -400,7 +399,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ data.putStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_CIRCLES(), circleIdsArray); OneTimeWorkRequest addParticipantsToConversationWorker = - new OneTimeWorkRequest.Builder(AddParticipantsToConversation.class).setInputData(data.build()).build(); + new OneTimeWorkRequest.Builder(AddParticipantsToConversation.class).setInputData(data.build()).build(); WorkManager.getInstance().enqueue(addParticipantsToConversationWorker); getRouter().popCurrentController(); @@ -500,186 +499,186 @@ public class ContactsController extends BaseController implements SearchView.OnQ modifiedQueryMap.put("shareTypes[]", shareTypesList); ncApi.getContactsWithSearchParam( - credentials, - retrofitBucket.getUrl(), shareTypesList, modifiedQueryMap) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .retry(3) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - contactsQueryDisposable = d; - } + credentials, + retrofitBucket.getUrl(), shareTypesList, modifiedQueryMap) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .retry(3) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + contactsQueryDisposable = d; + } - @Override - public void onNext(ResponseBody responseBody) { - if (responseBody != null) { - Participant participant; + @Override + public void onNext(ResponseBody responseBody) { + if (responseBody != null) { + Participant participant; - List newUserItemList = new ArrayList<>(); - EnumActorTypeConverter actorTypeConverter = new EnumActorTypeConverter(); + List newUserItemList = new ArrayList<>(); + EnumActorTypeConverter actorTypeConverter = new EnumActorTypeConverter(); - try { - AutocompleteOverall autocompleteOverall = LoganSquare.parse( - responseBody.string(), - AutocompleteOverall.class); - autocompleteUsersHashSet.addAll(autocompleteOverall.getOcs().getData()); + try { + AutocompleteOverall autocompleteOverall = LoganSquare.parse( + responseBody.string(), + AutocompleteOverall.class); + autocompleteUsersHashSet.addAll(autocompleteOverall.getOcs().getData()); - for (AutocompleteUser autocompleteUser : autocompleteUsersHashSet) { - if (!autocompleteUser.getId().equals(currentUser.getUserId()) - && !existingParticipants.contains(autocompleteUser.getId())) { - participant = new Participant(); - participant.setActorId(autocompleteUser.getId()); - participant.setActorType(actorTypeConverter.getFromString(autocompleteUser.getSource())); - participant.setDisplayName(autocompleteUser.getLabel()); - participant.setSource(autocompleteUser.getSource()); + for (AutocompleteUser autocompleteUser : autocompleteUsersHashSet) { + if (!autocompleteUser.getId().equals(currentUser.getUserId()) + && !existingParticipants.contains(autocompleteUser.getId())) { + participant = new Participant(); + participant.setActorId(autocompleteUser.getId()); + participant.setActorType(actorTypeConverter.getFromString(autocompleteUser.getSource())); + participant.setDisplayName(autocompleteUser.getLabel()); + participant.setSource(autocompleteUser.getSource()); - String headerTitle; + String headerTitle; - if (participant.getActorType() == Participant.ActorType.GROUPS) { - headerTitle = getResources().getString(R.string.nc_groups); - } else if (participant.getActorType() == Participant.ActorType.CIRCLES) { - headerTitle = getResources().getString(R.string.nc_circles); - } else { - headerTitle = - participant.getDisplayName().substring(0, 1).toUpperCase(Locale.getDefault()); - } + if (participant.getActorType() == Participant.ActorType.GROUPS) { + headerTitle = getResources().getString(R.string.nc_groups); + } else if (participant.getActorType() == Participant.ActorType.CIRCLES) { + headerTitle = getResources().getString(R.string.nc_circles); + } else { + headerTitle = + participant.getDisplayName().substring(0, 1).toUpperCase(Locale.getDefault()); + } - GenericTextHeaderItem genericTextHeaderItem; - if (!userHeaderItems.containsKey(headerTitle)) { - genericTextHeaderItem = new GenericTextHeaderItem(headerTitle); - userHeaderItems.put(headerTitle, genericTextHeaderItem); - } + GenericTextHeaderItem genericTextHeaderItem; + if (!userHeaderItems.containsKey(headerTitle)) { + genericTextHeaderItem = new GenericTextHeaderItem(headerTitle); + userHeaderItems.put(headerTitle, genericTextHeaderItem); + } - UserItem newContactItem = new UserItem( - participant, - currentUser, - userHeaderItems.get(headerTitle) - ); + UserItem newContactItem = new UserItem( + participant, + currentUser, + userHeaderItems.get(headerTitle) + ); - if (!contactItems.contains(newContactItem)) { - newUserItemList.add(newContactItem); - } + if (!contactItems.contains(newContactItem)) { + newUserItemList.add(newContactItem); } } - } catch (IOException ioe) { - Log.e(TAG, "Parsing response body failed while getting contacts", ioe); + } + } catch (IOException ioe) { + Log.e(TAG, "Parsing response body failed while getting contacts", ioe); + } + + userHeaderItems = new HashMap<>(); + contactItems.addAll(newUserItemList); + + Collections.sort(newUserItemList, (o1, o2) -> { + String firstName; + String secondName; + + if (o1 instanceof UserItem) { + firstName = ((UserItem) o1).getModel().getDisplayName(); + } else { + firstName = ((GenericTextHeaderItem) o1).getModel(); } - userHeaderItems = new HashMap<>(); - contactItems.addAll(newUserItemList); + if (o2 instanceof UserItem) { + secondName = ((UserItem) o2).getModel().getDisplayName(); + } else { + secondName = ((GenericTextHeaderItem) o2).getModel(); + } - Collections.sort(newUserItemList, (o1, o2) -> { - String firstName; - String secondName; - - if (o1 instanceof UserItem) { - firstName = ((UserItem) o1).getModel().getDisplayName(); - } else { - firstName = ((GenericTextHeaderItem) o1).getModel(); - } - - if (o2 instanceof UserItem) { - secondName = ((UserItem) o2).getModel().getDisplayName(); - } else { - secondName = ((GenericTextHeaderItem) o2).getModel(); - } - - if (o1 instanceof UserItem && o2 instanceof UserItem) { - String firstSource = ((UserItem) o1).getModel().getSource(); - String secondSource = ((UserItem) o2).getModel().getSource(); - if (firstSource.equals(secondSource)) { - return firstName.compareToIgnoreCase(secondName); - } - - // First users - if ("users".equals(firstSource)) { - return -1; - } else if ("users".equals(secondSource)) { - return 1; - } - - // Then groups - if ("groups".equals(firstSource)) { - return -1; - } else if ("groups".equals(secondSource)) { - return 1; - } - - // Then circles - if ("circles".equals(firstSource)) { - return -1; - } else if ("circles".equals(secondSource)) { - return 1; - } - - // Otherwise fall back to name sorting + if (o1 instanceof UserItem && o2 instanceof UserItem) { + String firstSource = ((UserItem) o1).getModel().getSource(); + String secondSource = ((UserItem) o2).getModel().getSource(); + if (firstSource.equals(secondSource)) { return firstName.compareToIgnoreCase(secondName); } + // First users + if ("users".equals(firstSource)) { + return -1; + } else if ("users".equals(secondSource)) { + return 1; + } + + // Then groups + if ("groups".equals(firstSource)) { + return -1; + } else if ("groups".equals(secondSource)) { + return 1; + } + + // Then circles + if ("circles".equals(firstSource)) { + return -1; + } else if ("circles".equals(secondSource)) { + return 1; + } + + // Otherwise fall back to name sorting return firstName.compareToIgnoreCase(secondName); - }); + } - Collections.sort(contactItems, (o1, o2) -> { - String firstName; - String secondName; + return firstName.compareToIgnoreCase(secondName); + }); - if (o1 instanceof UserItem) { - firstName = ((UserItem) o1).getModel().getDisplayName(); - } else { - firstName = ((GenericTextHeaderItem) o1).getModel(); - } + Collections.sort(contactItems, (o1, o2) -> { + String firstName; + String secondName; - if (o2 instanceof UserItem) { - secondName = ((UserItem) o2).getModel().getDisplayName(); - } else { - secondName = ((GenericTextHeaderItem) o2).getModel(); - } - - if (o1 instanceof UserItem && o2 instanceof UserItem) { - if ("groups".equals(((UserItem) o1).getModel().getSource()) && "groups".equals(((UserItem) o2).getModel().getSource())) { - return firstName.compareToIgnoreCase(secondName); - } else if ("groups".equals(((UserItem) o1).getModel().getSource())) { - return -1; - } else if ("groups".equals(((UserItem) o2).getModel().getSource())) { - return 1; - } - } - - return firstName.compareToIgnoreCase(secondName); - }); - - if (newUserItemList.size() > 0) { - adapter.updateDataSet(newUserItemList); + if (o1 instanceof UserItem) { + firstName = ((UserItem) o1).getModel().getDisplayName(); } else { - adapter.filterItems(); + firstName = ((GenericTextHeaderItem) o1).getModel(); } - if (swipeRefreshLayout != null) { - swipeRefreshLayout.setRefreshing(false); + if (o2 instanceof UserItem) { + secondName = ((UserItem) o2).getModel().getDisplayName(); + } else { + secondName = ((GenericTextHeaderItem) o2).getModel(); } + + if (o1 instanceof UserItem && o2 instanceof UserItem) { + if ("groups".equals(((UserItem) o1).getModel().getSource()) && "groups".equals(((UserItem) o2).getModel().getSource())) { + return firstName.compareToIgnoreCase(secondName); + } else if ("groups".equals(((UserItem) o1).getModel().getSource())) { + return -1; + } else if ("groups".equals(((UserItem) o2).getModel().getSource())) { + return 1; + } + } + + return firstName.compareToIgnoreCase(secondName); + }); + + if (newUserItemList.size() > 0) { + adapter.updateDataSet(newUserItemList); + } else { + adapter.filterItems(); } - } - @Override - public void onError(Throwable e) { if (swipeRefreshLayout != null) { swipeRefreshLayout.setRefreshing(false); } - dispose(contactsQueryDisposable); } + } - @Override - public void onComplete() { - if (swipeRefreshLayout != null) { - swipeRefreshLayout.setRefreshing(false); - } - dispose(contactsQueryDisposable); - alreadyFetching = false; - - disengageProgressBar(); + @Override + public void onError(Throwable e) { + if (swipeRefreshLayout != null) { + swipeRefreshLayout.setRefreshing(false); } - }); + dispose(contactsQueryDisposable); + } + + @Override + public void onComplete() { + if (swipeRefreshLayout != null) { + swipeRefreshLayout.setRefreshing(false); + } + dispose(contactsQueryDisposable); + alreadyFetching = false; + + disengageProgressBar(); + } + }); } @@ -694,14 +693,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background); joinConversationViaLinkImageView - .getBackground() - .setColorFilter(ResourcesCompat.getColor(getResources(), R.color.colorBackgroundDarker, null), - PorterDuff.Mode.SRC_IN); + .getBackground() + .setColorFilter(ResourcesCompat.getColor(getResources(), R.color.colorBackgroundDarker, null), + PorterDuff.Mode.SRC_IN); publicCallLinkImageView - .getBackground() - .setColorFilter(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null), - PorterDuff.Mode.SRC_IN); + .getBackground() + .setColorFilter(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null), + PorterDuff.Mode.SRC_IN); disengageProgressBar(); } @@ -801,59 +800,21 @@ public class ContactsController extends BaseController implements SearchView.OnQ } } - - - private void prepareAndShowBottomSheetWithBundle(Bundle bundle, boolean showEntrySheet) { - if (view == null) { - view = getActivity().getLayoutInflater().inflate(R.layout.bottom_sheet, null, false); - } - - if (bottomSheet == null) { - bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); - } - - if (showEntrySheet) { - getChildRouter((ViewGroup) view).setRoot( - RouterTransaction.with(new EntryMenuController(bundle)) - .popChangeHandler(new VerticalChangeHandler()) - .pushChangeHandler(new VerticalChangeHandler())); - } else { - getChildRouter((ViewGroup) view).setRoot( - RouterTransaction.with(new OperationsMenuController(bundle)) - .popChangeHandler(new VerticalChangeHandler()) - .pushChangeHandler(new VerticalChangeHandler())); - } - - bottomSheet.setOnShowListener(dialog -> { - if (showEntrySheet) { - new KeyboardUtils(getActivity(), bottomSheet.getLayout(), true); - } else { - eventBus.post(new BottomSheetLockEvent(false, 0, - false, false)); - } - }); - - bottomSheet.setOnDismissListener(dialog -> getActionBar().setDisplayHomeAsUpEnabled(getRouter().getBackstackSize() > 1)); - - bottomSheet.show(); + private void prepareAndShowBottomSheetWithBundle(Bundle bundle) { + // 11: create conversation-enter name for new conversation + // 10: get&join room when enter link + contactsBottomDialog = new ContactsBottomDialog(getActivity(), bundle); + contactsBottomDialog.show(); } + @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(BottomSheetLockEvent bottomSheetLockEvent) { - - if (bottomSheet != null) { - if (!bottomSheetLockEvent.isCancelable()) { - bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable()); - } else { - bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable()); - if (bottomSheet.isShowing() && bottomSheetLockEvent.isCancel()) { - new Handler().postDelayed(() -> { - bottomSheet.setOnCancelListener(null); - bottomSheet.cancel(); - - }, bottomSheetLockEvent.getDelay()); - } - } + public void onMessageEvent(OpenConversationEvent openConversationEvent) { + ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), + openConversationEvent.getConversation().getToken(), + openConversationEvent.getBundle(), true); + if (contactsBottomDialog != null) { + contactsBottomDialog.dismiss(); } } @@ -874,7 +835,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ roomType = "2"; } - int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, 1}); + int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[]{ApiUtils.APIv4, 1}); RetrofitBucket retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(apiVersion, currentUser.getBaseUrl(), @@ -884,40 +845,40 @@ public class ContactsController extends BaseController implements SearchView.OnQ null); ncApi.createRoom(credentials, - retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { + retrofitBucket.getUrl(), retrofitBucket.getQueryMap()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + } + + @Override + public void onNext(RoomOverall roomOverall) { + if (getActivity() != null) { + Bundle bundle = new Bundle(); + bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); + bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken()); + bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId()); + bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), + Parcels.wrap(roomOverall.getOcs().getData())); + + ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), + roomOverall.getOcs().getData().getToken(), bundle, true); } + } - @Override - public void onNext(RoomOverall roomOverall) { - if (getActivity() != null) { - Bundle bundle = new Bundle(); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomOverall.getOcs().getData().getToken()); - bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), roomOverall.getOcs().getData().getRoomId()); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), - Parcels.wrap(roomOverall.getOcs().getData())); + @Override + public void onError(Throwable e) { - ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), - roomOverall.getOcs().getData().getToken(), bundle, true); - } - } + } - @Override - public void onError(Throwable e) { + @Override + public void onComplete() { - } - - @Override - public void onComplete() { - - } - }); + } + }); } else { Participant participant = ((UserItem) adapter.getItem(position)).getModel(); participant.setSelected(!participant.isSelected()); @@ -949,17 +910,17 @@ public class ContactsController extends BaseController implements SearchView.OnQ } if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity") - && !CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") && - "groups".equals(((UserItem) adapter.getItem(position)).getModel().getSource()) && - participant.isSelected() && - adapter.getSelectedItemCount() > 1) { + && !CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") && + "groups".equals(((UserItem) adapter.getItem(position)).getModel().getSource()) && + participant.isSelected() && + adapter.getSelectedItemCount() > 1) { List currentItems = adapter.getCurrentItems(); Participant internalParticipant; for (int i = 0; i < currentItems.size(); i++) { internalParticipant = currentItems.get(i).getModel(); if (internalParticipant.getActorId().equals(participant.getActorId()) && - internalParticipant.getActorType() == Participant.ActorType.GROUPS && - internalParticipant.isSelected()) { + internalParticipant.getActorType() == Participant.ActorType.GROUPS && + internalParticipant.isSelected()) { internalParticipant.setSelected(false); selectedGroupIds.remove(internalParticipant.getActorId()); } @@ -978,9 +939,9 @@ public class ContactsController extends BaseController implements SearchView.OnQ @OnClick(R.id.joinConversationViaLinkRelativeLayout) void joinConversationViaLink() { Bundle bundle = new Bundle(); - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 10); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), OPS_CODE_GET_AND_JOIN_ROOM); - prepareAndShowBottomSheetWithBundle(bundle, true); + prepareAndShowBottomSheetWithBundle(bundle); } @Optional @@ -1002,7 +963,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ if (currentItems.get(i) instanceof UserItem) { internalParticipant = ((UserItem) currentItems.get(i)).getModel(); if (internalParticipant.getActorType() == Participant.ActorType.GROUPS && - internalParticipant.isSelected()) { + internalParticipant.isSelected()) { internalParticipant.setSelected(false); selectedGroupIds.remove(internalParticipant.getActorId()); } 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 e1ffca885..37ab07ee8 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt @@ -287,15 +287,19 @@ class ConversationInfoController(args: Bundle) : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onComplete() { + // unused atm } override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(t: GenericOverall) { + // unused atm } override fun onError(e: Throwable) { + // unused atm } }) } @@ -305,6 +309,7 @@ class ConversationInfoController(args: Bundle) : ID_DELETE_CONVERSATION_DIALOG -> showDeleteConversationDialog(savedInstanceState) ID_CLEAR_CHAT_DIALOG -> showClearHistoryDialog(savedInstanceState) else -> { + // unused atm } } } @@ -444,6 +449,7 @@ class ConversationInfoController(args: Bundle) : } override fun onError(e: Throwable) { + // unused atm } override fun onComplete() { @@ -525,6 +531,7 @@ class ConversationInfoController(args: Bundle) : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -538,6 +545,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } }) } @@ -598,13 +606,13 @@ class ConversationInfoController(args: Bundle) : setupWebinaryView() - if (!conversation!!.canLeave(conversationUser)) { + if (!conversation!!.canLeave()) { binding.leaveConversationAction.visibility = View.GONE } else { binding.leaveConversationAction.visibility = View.VISIBLE } - if (!conversation!!.canDelete(conversationUser)) { + if (!conversation!!.canDelete()) { binding.deleteConversationAction.visibility = View.GONE } else { binding.deleteConversationAction.visibility = View.VISIBLE @@ -647,6 +655,7 @@ class ConversationInfoController(args: Bundle) : } override fun onError(e: Throwable) { + // unused atm } override fun onComplete() { @@ -731,6 +740,7 @@ class ConversationInfoController(args: Bundle) : } else -> { + // unused atm } } } @@ -738,6 +748,7 @@ class ConversationInfoController(args: Bundle) : private fun toggleModeratorStatus(apiVersion: Int, participant: Participant) { val subscriber = object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -750,6 +761,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } } @@ -789,6 +801,7 @@ class ConversationInfoController(args: Bundle) : private fun toggleModeratorStatusLegacy(apiVersion: Int, participant: Participant) { val subscriber = object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -801,6 +814,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } } @@ -848,6 +862,7 @@ class ConversationInfoController(args: Bundle) : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -860,6 +875,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } }) } else { @@ -879,6 +895,7 @@ class ConversationInfoController(args: Bundle) : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -891,6 +908,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } }) } else { @@ -907,6 +925,7 @@ class ConversationInfoController(args: Bundle) : ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(object : Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(genericOverall: GenericOverall) { @@ -919,6 +938,7 @@ class ConversationInfoController(args: Bundle) : } override fun onComplete() { + // unused atm } }) } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java index 40c3cdf49..0c3b5f707 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java @@ -3,8 +3,10 @@ * * @author Mario Danic * @author Andy Scherzinger + * @author Marcel Hibbe * Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de) * Copyright (C) 2017-2020 Mario Danic (mario@lovelyhq.com) + * Copyright (C) 2022 Marcel Hibbe (dev@mhibbe.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 @@ -62,7 +64,7 @@ import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.request.ImageRequest; import com.google.android.material.button.MaterialButton; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.kennyc.bottomsheet.BottomSheet; + import com.nextcloud.talk.R; import com.nextcloud.talk.activities.MainActivity; import com.nextcloud.talk.adapters.items.ConversationItem; @@ -70,11 +72,10 @@ import com.nextcloud.talk.adapters.items.GenericTextHeaderItem; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; -import com.nextcloud.talk.controllers.bottomsheet.CallMenuController; +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum; import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController; -import com.nextcloud.talk.events.BottomSheetLockEvent; +import com.nextcloud.talk.events.ConversationsListFetchDataEvent; import com.nextcloud.talk.events.EventStatus; -import com.nextcloud.talk.events.MoreMenuClickEvent; import com.nextcloud.talk.interfaces.ConversationMenuInterface; import com.nextcloud.talk.jobs.AccountRemovalWorker; import com.nextcloud.talk.jobs.ContactAddressBookWorker; @@ -85,11 +86,11 @@ import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment; +import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ClosedInterfaceImpl; import com.nextcloud.talk.utils.ConductorRemapping; import com.nextcloud.talk.utils.DisplayUtils; -import com.nextcloud.talk.utils.KeyboardUtils; import com.nextcloud.talk.utils.UriUtils; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; @@ -186,7 +187,6 @@ public class ConversationsListController extends BaseController implements Searc private List conversationItemsWithHeader = new ArrayList<>(); private final List searchableConversationItems = new ArrayList<>(); - private BottomSheet bottomSheet; private MenuItem searchItem; private SearchView searchView; private String searchQuery; @@ -218,6 +218,8 @@ public class ConversationsListController extends BaseController implements Searc private HashMap callHeaderItems = new HashMap<>(); + private ConversationsListBottomDialog conversationsListBottomDialog; + public ConversationsListController(Bundle bundle) { super(); setHasOptionsMenu(true); @@ -310,7 +312,7 @@ public class ConversationsListController extends BaseController implements Searc if (getActivity() != null && getActivity() instanceof MainActivity) { loadUserAvatar(((MainActivity) getActivity()).binding.switchAccountButton); } - fetchData(false); + fetchData(); } } @@ -453,6 +455,7 @@ public class ConversationsListController extends BaseController implements Searc return false; } + @Override protected void showSearchOrToolbar() { if (TextUtils.isEmpty(searchQuery)) { super.showSearchOrToolbar(); @@ -469,7 +472,7 @@ public class ConversationsListController extends BaseController implements Searc } @SuppressLint("LongLogTag") - private void fetchData(boolean fromBottomSheet) { + public void fetchData() { dispose(null); isRefreshing = true; @@ -565,15 +568,6 @@ public class ConversationsListController extends BaseController implements Searc swipeRefreshLayout.setRefreshing(false); } - if (fromBottomSheet) { - new Handler().postDelayed(() -> { - bottomSheet.setCancelable(true); - if (bottomSheet.isShowing()) { - bottomSheet.cancel(); - } - }, 2500); - } - isRefreshing = false; }); } @@ -678,7 +672,7 @@ public class ConversationsListController extends BaseController implements Searc return false; }); - swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false)); + swipeRefreshLayout.setOnRefreshListener(() -> fetchData()); swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background); @@ -811,60 +805,6 @@ public class ConversationsListController extends BaseController implements Searc return onQueryTextChange(query); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(BottomSheetLockEvent bottomSheetLockEvent) { - if (bottomSheet != null) { - if (!bottomSheetLockEvent.isCancelable()) { - bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable()); - } else { - if (bottomSheetLockEvent.getDelay() != 0 && bottomSheetLockEvent.isShouldRefreshData()) { - fetchData(true); - } else { - bottomSheet.setCancelable(bottomSheetLockEvent.isCancelable()); - if (bottomSheet.isShowing() && bottomSheetLockEvent.isCancel()) { - bottomSheet.cancel(); - } - } - } - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(MoreMenuClickEvent moreMenuClickEvent) { - Bundle bundle = new Bundle(); - Conversation conversation = moreMenuClickEvent.getConversation(); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_MENU_TYPE(), Parcels.wrap(CallMenuController.MenuType.REGULAR)); - - prepareAndShowBottomSheetWithBundle(bundle, true); - } - - private void prepareAndShowBottomSheetWithBundle(Bundle bundle, boolean shouldShowCallMenuController) { - if (view == null) { - view = getActivity().getLayoutInflater().inflate(R.layout.bottom_sheet, null, false); - } - - if (shouldShowCallMenuController) { - getChildRouter((ViewGroup) view).setRoot( - RouterTransaction.with(new CallMenuController(bundle, this)) - .popChangeHandler(new VerticalChangeHandler()) - .pushChangeHandler(new VerticalChangeHandler())); - } else { - getChildRouter((ViewGroup) view).setRoot( - RouterTransaction.with(new EntryMenuController(bundle)) - .popChangeHandler(new VerticalChangeHandler()) - .pushChangeHandler(new VerticalChangeHandler())); - } - - if (bottomSheet == null) { - bottomSheet = new BottomSheet.Builder(getActivity()).setView(view).create(); - } - - bottomSheet.setOnShowListener(dialog -> new KeyboardUtils(getActivity(), bottomSheet.getLayout(), true)); - bottomSheet.setOnDismissListener(dialog -> showSearchOrToolbar()); - bottomSheet.show(); - } - @Override protected String getTitle() { return getResources().getString(R.string.nc_app_product_name); @@ -950,8 +890,12 @@ public class ConversationsListController extends BaseController implements Searc Object clickedItem = adapter.getItem(position); if (clickedItem != null) { Conversation conversation = ((ConversationItem) clickedItem).getModel(); - MoreMenuClickEvent moreMenuClickEvent = new MoreMenuClickEvent(conversation); - onMessageEvent(moreMenuClickEvent); + conversationsListBottomDialog = new ConversationsListBottomDialog( + getActivity(), + this, + userUtils.getCurrentUser(), + conversation); + conversationsListBottomDialog.show(); } } } @@ -1055,22 +999,13 @@ public class ConversationsListController extends BaseController implements Searc private void openConversation(String textToPaste) { Bundle bundle = new Bundle(); bundle.putParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY(), currentUser); + bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(selectedConversation)); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), selectedConversation.getToken()); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), selectedConversation.getRoomId()); bundle.putString(BundleKeys.INSTANCE.getKEY_SHARED_TEXT(), textToPaste); - if (selectedConversation.hasPassword && selectedConversation.participantType == - Participant.ParticipantType.GUEST || - selectedConversation.participantType == Participant.ParticipantType.USER_FOLLOWING_LINK) { - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99); - prepareAndShowBottomSheetWithBundle(bundle, false); - } else { - currentUser = userUtils.getCurrentUser(); - - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(selectedConversation)); - ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), - selectedConversation.getToken(), bundle, false); - } + ConductorRemapping.INSTANCE.remapChatController(getRouter(), currentUser.getId(), + selectedConversation.getToken(), bundle, false); } @Subscribe(sticky = true, threadMode = ThreadMode.BACKGROUND) @@ -1079,7 +1014,7 @@ public class ConversationsListController extends BaseController implements Searc switch (eventStatus.getEventType()) { case CONVERSATION_UPDATE: if (eventStatus.isAllGood() && !isRefreshing) { - fetchData(false); + fetchData(); } break; default: @@ -1088,6 +1023,17 @@ public class ConversationsListController extends BaseController implements Searc } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(ConversationsListFetchDataEvent conversationsListFetchDataEvent) { + fetchData(); + + new Handler().postDelayed(() -> { + if (conversationsListBottomDialog.isShowing()) { + conversationsListBottomDialog.dismiss(); + } + }, 2500); + } + private void showDeleteConversationDialog(Bundle savedInstanceState) { if (getActivity() != null && conversationMenuBundle != null && currentUser != null && conversationMenuBundle.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID()) == currentUser.getId()) { @@ -1240,7 +1186,6 @@ public class ConversationsListController extends BaseController implements Searc default: break; } - } @Override diff --git a/app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt b/app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt index 1acae2aa3..1226965ac 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt @@ -46,7 +46,9 @@ abstract class ButterKnifeController : Controller { return view } - protected open fun onViewBound(view: View) {} + protected open fun onViewBound(view: View) { + // unused atm + } override fun onDestroyView(view: View) { super.onDestroyView(view) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java deleted file mode 100644 index a958de538..000000000 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.controllers.bottomsheet; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.bluelinelabs.conductor.RouterTransaction; -import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; -import com.kennyc.bottomsheet.adapters.AppAdapter; -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.LeaveConversationWorker; -import com.nextcloud.talk.models.database.CapabilitiesUtil; -import com.nextcloud.talk.models.database.UserEntity; -import com.nextcloud.talk.models.json.conversations.Conversation; -import com.nextcloud.talk.utils.DisplayUtils; -import com.nextcloud.talk.utils.ShareUtils; -import com.nextcloud.talk.utils.bundle.BundleKeys; -import com.nextcloud.talk.utils.database.user.UserUtils; - -import org.greenrobot.eventbus.EventBus; -import org.parceler.Parcel; -import org.parceler.Parcels; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -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 eu.davidea.flexibleadapter.FlexibleAdapter; -import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; -import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; - -@AutoInjector(NextcloudTalkApplication.class) -public class CallMenuController extends BaseController implements FlexibleAdapter.OnItemClickListener { - public static final int ALL_MESSAGES_READ = 0; - @BindView(R.id.recycler_view) - RecyclerView recyclerView; - - @Inject - EventBus eventBus; - - @Inject - UserUtils userUtils; - - @Inject - Context context; - - private Conversation conversation; - private List menuItems; - private FlexibleAdapter adapter; - 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.INSTANCE.getKEY_ROOM())); - if (args.containsKey(BundleKeys.INSTANCE.getKEY_MENU_TYPE())) { - this.menuType = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_MENU_TYPE())); - } - } - - public CallMenuController(Bundle args, @Nullable ConversationMenuInterface conversationMenuInterface) { - super(args); - this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM())); - if (args.containsKey(BundleKeys.INSTANCE.getKEY_MENU_TYPE())) { - this.menuType = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_MENU_TYPE())); - } - this.conversationMenuInterface = conversationMenuInterface; - } - - @Override - @NonNull - protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { - return inflater.inflate(R.layout.controller_call_menu, container, false); - } - - @Override - protected void onViewBound(@NonNull View view) { - super.onViewBound(view); - NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - prepareViews(); - } - - private void prepareViews() { - LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); - recyclerView.setLayoutManager(layoutManager); - recyclerView.setHasFixedSize(true); - - prepareMenu(); - if (adapter == null) { - adapter = new FlexibleAdapter<>(menuItems, getActivity(), false); - } - - adapter.addListener(this); - recyclerView.setAdapter(adapter); - } - - private void prepareIntent() { - shareIntent = new Intent(Intent.ACTION_SEND); - shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_SUBJECT, String.format(getResources().getString(R.string.nc_share_subject), - getResources().getString(R.string.nc_app_product_name))); - } - - private void prepareMenu() { - menuItems = new ArrayList<>(); - - if (menuType.equals(MenuType.REGULAR)) { - if (!TextUtils.isEmpty(conversation.getDisplayName())) { - menuItems.add(new MenuItem(conversation.getDisplayName(), 0, null)); - } else if (!TextUtils.isEmpty(conversation.getName())) { - menuItems.add(new MenuItem(conversation.getName(), 0, null)); - } else { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_configure_room), 0, null)); - } - - 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 (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "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))); - } - - if(conversation.unreadMessages > ALL_MESSAGES_READ && CapabilitiesUtil.canSetChatReadMarker(currentUser)) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_mark_as_read), - 96, - ContextCompat.getDrawable(context, R.drawable.ic_eye))); - } - - if (conversation.isNameEditable(currentUser)) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_rename), - 2, - ContextCompat.getDrawable(context, - R.drawable.ic_pencil_grey600_24dp))); - } - - if (conversation.canModerate(currentUser)) { - if (!conversation.isPublic()) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_make_call_public), - 3, ContextCompat.getDrawable(context, - R.drawable.ic_link_grey600_24px))); - } else { - if (conversation.isHasPassword()) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_change_password), - 4, ContextCompat.getDrawable(context, - R.drawable.ic_lock_grey600_24px))); - menuItems.add(new MenuItem(getResources().getString(R.string.nc_clear_password), - 5, - ContextCompat.getDrawable(context, - R.drawable.ic_lock_open_grey600_24dp))); - } else { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_set_password), - 6, ContextCompat.getDrawable(context, - R.drawable.ic_lock_plus_grey600_24dp))); - } - } - - menuItems.add(new MenuItem(getResources().getString(R.string.nc_delete_call), - 9, ContextCompat.getDrawable(context, - R.drawable.ic_delete_grey600_24dp))); - } - - if (conversation.isPublic()) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_share_link), - 7, ContextCompat.getDrawable(context, - R.drawable.ic_link_grey600_24px))); - if (conversation.canModerate(currentUser)) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_make_call_private), - 8, ContextCompat.getDrawable(context, - R.drawable.ic_group_grey600_24px))); - } - } - - if (conversation.canLeave(currentUser)) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1, - DisplayUtils.getTintedDrawable(getResources(), - R.drawable.ic_exit_to_app_black_24dp, R.color.grey_600) - )); - } - } else if (menuType.equals(MenuType.SHARE)) { - prepareIntent(); - List appInfoList = ShareUtils.getShareApps(getActivity(), shareIntent, null, - null); - menuItems.add(new AppItem(getResources().getString(R.string.nc_share_link_via), - "", - "", - ContextCompat.getDrawable(context, R.drawable.ic_link_grey600_24px))); - if (appInfoList != null) { - for (AppAdapter.AppInfo appInfo : appInfoList) { - menuItems.add(new AppItem(appInfo.title, appInfo.packageName, appInfo.name, appInfo.drawable)); - } - } - } else { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_start_conversation), 0, null)); - menuItems.add(new MenuItem(getResources().getString(R.string.nc_new_conversation), - 1, ContextCompat.getDrawable(context, - R.drawable.ic_add_grey600_24px))); - menuItems.add(new MenuItem(getResources().getString(R.string.nc_join_via_link), - 2, ContextCompat.getDrawable(context, - R.drawable.ic_link_grey600_24px))); - } - } - - @Override - public boolean onItemClick(View view, int position) { - Bundle bundle = new Bundle(); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); - - if (menuType.equals(MenuType.REGULAR)) { - MenuItem menuItem = (MenuItem) adapter.getItem(position); - if (menuItem != null) { - - int tag = menuItem.getTag(); - if (tag == 5) { - conversation.setPassword(""); - } - - 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.INSTANCE.getKEY_OPERATION_CODE(), tag); - if (tag != 2 && tag != 4 && tag != 6 && tag != 7) { - eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); - getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) - .pushChangeHandler(new HorizontalChangeHandler()) - .popChangeHandler(new HorizontalChangeHandler())); - } else if (tag != 7) { - getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) - .pushChangeHandler(new HorizontalChangeHandler()) - .popChangeHandler(new HorizontalChangeHandler())); - } else { - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_MENU_TYPE(), Parcels.wrap(MenuType.SHARE)); - 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) { - if (!conversation.hasPassword) { - shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(), null, - userUtils, conversation)); - Intent intent = new Intent(shareIntent); - intent.setComponent(new ComponentName(appItem.getPackageName(), appItem.getName())); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); - getActivity().startActivity(intent); - } else { - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 7); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SHARE_INTENT(), Parcels.wrap(shareIntent)); - bundle.putString(BundleKeys.INSTANCE.getKEY_APP_ITEM_PACKAGE_NAME(), appItem.getPackageName()); - bundle.putString(BundleKeys.INSTANCE.getKEY_APP_ITEM_NAME(), appItem.getName()); - getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) - .pushChangeHandler(new HorizontalChangeHandler()) - .popChangeHandler(new HorizontalChangeHandler())); - } - } - } - - return true; - } - - private Data getWorkerData() { - if (!TextUtils.isEmpty(conversation.getToken())) { - Data.Builder data = new Data.Builder(); - data.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken()); - data.putLong(BundleKeys.INSTANCE.getKEY_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.INSTANCE.getKEY_INTERNAL_USER_ID(), currentUser.getId()); - bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); - return bundle; - } - - return null; - } - - @Parcel - public enum MenuType { - REGULAR, SHARE - } -} diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt new file mode 100644 index 000000000..3cd89a8c6 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/ConversationOperationEnum.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * 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 . + */ + +package com.nextcloud.talk.controllers.bottomsheet + +enum class ConversationOperationEnum { + OPS_CODE_RENAME_ROOM, + OPS_CODE_MAKE_PUBLIC, + OPS_CODE_CHANGE_PASSWORD, + OPS_CODE_CLEAR_PASSWORD, + OPS_CODE_SET_PASSWORD, + OPS_CODE_SHARE_LINK, + OPS_CODE_MAKE_PRIVATE, + OPS_CODE_GET_AND_JOIN_ROOM, + OPS_CODE_INVITE_USERS, + OPS_CODE_MARK_AS_READ, + OPS_CODE_REMOVE_FAVORITE, + OPS_CODE_ADD_FAVORITE, + OPS_CODE_JOIN_ROOM +} diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java index e57318f31..cdd15dd88 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java @@ -2,7 +2,9 @@ * Nextcloud Talk application * * @author Mario Danic + * @author Marcel Hibbe * Copyright (C) 2017 Mario Danic + * Copyright (C) 2022 Marcel Hibbe * * 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 @@ -20,6 +22,14 @@ package com.nextcloud.talk.controllers.bottomsheet; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_JOIN_ROOM; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_INVITE_USERS; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SET_PASSWORD; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SHARE_LINK; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM; + import android.content.ComponentName; import android.content.Intent; import android.graphics.PorterDuff; @@ -41,7 +51,6 @@ import com.google.android.material.textfield.TextInputLayout; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; -import com.nextcloud.talk.events.BottomSheetLockEvent; import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.utils.EmojiTextInputEditText; import com.nextcloud.talk.utils.ShareUtils; @@ -86,7 +95,7 @@ public class EntryMenuController extends BaseController { @Inject UserUtils userUtils; - private int operationCode; + private ConversationOperationEnum operation; private Conversation conversation; private Intent shareIntent; private String packageName; @@ -101,7 +110,7 @@ public class EntryMenuController extends BaseController { super(args); originalBundle = args; - this.operationCode = args.getInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE()); + this.operation = (ConversationOperationEnum) args.getSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE()); if (args.containsKey(BundleKeys.INSTANCE.getKEY_ROOM())) { this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM())); } @@ -143,13 +152,12 @@ public class EntryMenuController extends BaseController { @OnClick(R.id.ok_button) public void onProceedButtonClick() { Bundle bundle; - if (operationCode == 99) { - eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + if (operation == OPS_CODE_JOIN_ROOM) { bundle = new Bundle(); bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl); bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), editText.getText().toString()); - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operation); if (originalBundle.containsKey(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES())) { bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(), originalBundle.getParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES())); } @@ -157,20 +165,19 @@ public class EntryMenuController extends BaseController { getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); - } else if (operationCode != 7 && operationCode != 10 && operationCode != 11) { - eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + } else if (operation != OPS_CODE_SHARE_LINK && operation != OPS_CODE_GET_AND_JOIN_ROOM && operation != OPS_CODE_INVITE_USERS) { bundle = new Bundle(); - if (operationCode == 4 || operationCode == 6) { + if (operation == OPS_CODE_CHANGE_PASSWORD || operation == OPS_CODE_SET_PASSWORD) { conversation.setPassword(editText.getText().toString()); } else { conversation.setName(editText.getText().toString()); } bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operation); getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); - } else if (operationCode == 7) { + } else if (operation == OPS_CODE_SHARE_LINK) { if (getActivity() != null) { shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(), editText.getText().toString(), userUtils, conversation)); @@ -178,19 +185,16 @@ public class EntryMenuController extends BaseController { intent.setComponent(new ComponentName(packageName, name)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getActivity().startActivity(intent); - eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); } - } else if (operationCode != 11) { - eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + } else if (operation != OPS_CODE_INVITE_USERS) { bundle = new Bundle(); - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operation); bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), editText.getText().toString()); getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); - } else if (operationCode == 11) { - eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + } else if (operation == OPS_CODE_INVITE_USERS) { originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), editText.getText().toString()); getRouter().pushController(RouterTransaction.with(new OperationsMenuController(originalBundle)) .pushChangeHandler(new HorizontalChangeHandler()) @@ -204,7 +208,7 @@ public class EntryMenuController extends BaseController { super.onViewBound(view); NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - if (conversation != null && operationCode == 2) { + if (conversation != null && operation == OPS_CODE_RENAME_ROOM) { editText.setText(conversation.getName()); } @@ -230,7 +234,7 @@ public class EntryMenuController extends BaseController { @Override public void afterTextChanged(Editable s) { if (!TextUtils.isEmpty(s)) { - if (operationCode == 2) { + if (operation == OPS_CODE_RENAME_ROOM) { if (conversation.getName() == null || !conversation.getName().equals(s.toString())) { if (!proceedButton.isEnabled()) { proceedButton.setEnabled(true); @@ -244,7 +248,7 @@ public class EntryMenuController extends BaseController { } textInputLayout.setError(getResources().getString(R.string.nc_call_name_is_same)); } - } else if (operationCode != 10) { + } else if (operation != OPS_CODE_GET_AND_JOIN_ROOM) { if (!proceedButton.isEnabled()) { proceedButton.setEnabled(true); proceedButton.setAlpha(1.0f); @@ -253,7 +257,6 @@ public class EntryMenuController extends BaseController { } else if ((editText.getText().toString().startsWith("http://") || editText.getText().toString().startsWith("https://")) && editText.getText().toString().contains("/call/")) { - // operation code 10 if (!proceedButton.isEnabled()) { proceedButton.setEnabled(true); proceedButton.setAlpha(1.0f); @@ -277,9 +280,9 @@ public class EntryMenuController extends BaseController { }); String labelText = ""; - switch (operationCode) { - case 11: - case 2: + switch (operation) { + case OPS_CODE_INVITE_USERS: + case OPS_CODE_RENAME_ROOM: labelText = getResources().getString(R.string.nc_call_name); editText.setInputType(InputType.TYPE_CLASS_TEXT); smileyButton.setVisibility(View.VISIBLE); @@ -307,18 +310,18 @@ public class EntryMenuController extends BaseController { }).build(editText); break; - case 4: + case OPS_CODE_CHANGE_PASSWORD: labelText = getResources().getString(R.string.nc_new_password); editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); break; - case 6: - case 7: - case 99: + case OPS_CODE_SET_PASSWORD: + case OPS_CODE_SHARE_LINK: + case OPS_CODE_JOIN_ROOM: // 99 is joining a conversation via password labelText = getResources().getString(R.string.nc_password); editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); break; - case 10: + case OPS_CODE_GET_AND_JOIN_ROOM: labelText = getResources().getString(R.string.nc_conversation_link); editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI); break; @@ -326,7 +329,10 @@ public class EntryMenuController extends BaseController { break; } - if (operationCode == 99 || operationCode == 4 || operationCode == 6 || operationCode == 7) { + if (operation == OPS_CODE_JOIN_ROOM + || operation == OPS_CODE_CHANGE_PASSWORD + || operation == OPS_CODE_SET_PASSWORD + || operation == OPS_CODE_SHARE_LINK) { textInputLayout.setEndIconMode(TextInputLayout.END_ICON_PASSWORD_TOGGLE); } else { textInputLayout.setEndIconMode(TextInputLayout.END_ICON_NONE); @@ -335,4 +341,9 @@ public class EntryMenuController extends BaseController { textInputLayout.setHint(labelText); textInputLayout.requestFocus(); } + + @Override + public AppBarLayoutType getAppBarLayoutType() { + return AppBarLayoutType.SEARCH_BAR; + } } 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 3be1a2537..7b84fed2e 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 @@ -20,6 +20,9 @@ package com.nextcloud.talk.controllers.bottomsheet; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_JOIN_ROOM; +import static com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE; + import android.annotation.SuppressLint; import android.content.Intent; import android.net.Uri; @@ -33,7 +36,6 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import android.widget.Toast; import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; @@ -42,7 +44,8 @@ import com.nextcloud.talk.R; import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; -import com.nextcloud.talk.events.BottomSheetLockEvent; +import com.nextcloud.talk.events.ConversationsListFetchDataEvent; +import com.nextcloud.talk.events.OpenConversationEvent; import com.nextcloud.talk.models.RetrofitBucket; import com.nextcloud.talk.models.database.CapabilitiesUtil; import com.nextcloud.talk.models.database.UserEntity; @@ -53,7 +56,6 @@ 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; import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.NoSupportedApiException; import com.nextcloud.talk.utils.bundle.BundleKeys; @@ -75,7 +77,6 @@ import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import okhttp3.ResponseBody; import retrofit2.HttpException; import retrofit2.Response; @@ -108,7 +109,7 @@ public class OperationsMenuController extends BaseController { @Inject EventBus eventBus; - private int operationCode; + private ConversationOperationEnum operation; private Conversation conversation; private UserEntity currentUser; @@ -130,7 +131,7 @@ public class OperationsMenuController extends BaseController { public OperationsMenuController(Bundle args) { super(args); - this.operationCode = args.getInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE()); + this.operation = (ConversationOperationEnum) args.getSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE()); if (args.containsKey(BundleKeys.INSTANCE.getKEY_ROOM())) { this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM())); } @@ -283,8 +284,8 @@ public class OperationsMenuController extends BaseController { int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {ApiUtils.APIv4, ApiUtils.APIv1}); int chatApiVersion = ApiUtils.getChatApiVersion(currentUser, new int[] {ApiUtils.APIv1}); - switch (operationCode) { - case 2: + switch (operation) { + case OPS_CODE_RENAME_ROOM: ncApi.renameRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, currentUser.getBaseUrl(), conversation.getToken()), conversation.getName()) @@ -293,7 +294,7 @@ public class OperationsMenuController extends BaseController { .retry(1) .subscribe(genericOperationsObserver); break; - case 3: + case OPS_CODE_MAKE_PUBLIC: ncApi.makeRoomPublic(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(), conversation.getToken())) .subscribeOn(Schedulers.io()) @@ -301,9 +302,9 @@ public class OperationsMenuController extends BaseController { .retry(1) .subscribe(genericOperationsObserver); break; - case 4: - case 5: - case 6: + case OPS_CODE_CHANGE_PASSWORD: + case OPS_CODE_CLEAR_PASSWORD: + case OPS_CODE_SET_PASSWORD: String pass = ""; if (conversation.getPassword() != null) { pass = conversation.getPassword(); @@ -315,10 +316,7 @@ public class OperationsMenuController extends BaseController { .retry(1) .subscribe(genericOperationsObserver); break; - case 7: - // Operation 7 is sharing, so we handle this differently - break; - case 8: + case OPS_CODE_MAKE_PRIVATE: ncApi.makeRoomPrivate(credentials, ApiUtils.getUrlForRoomPublic(apiVersion, currentUser.getBaseUrl(), conversation.getToken())) @@ -327,7 +325,7 @@ public class OperationsMenuController extends BaseController { .retry(1) .subscribe(genericOperationsObserver); break; - case 10: + case OPS_CODE_GET_AND_JOIN_ROOM: ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -342,8 +340,7 @@ public class OperationsMenuController extends BaseController { public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) { conversation = roomOverall.getOcs().getData(); if (conversation.isHasPassword() && conversation.isGuest()) { - eventBus.post(new BottomSheetLockEvent(true, 0, - true, false)); + eventBus.post(new ConversationsListFetchDataEvent()); Bundle bundle = new Bundle(); bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl); @@ -355,7 +352,7 @@ public class OperationsMenuController extends BaseController { Log.e(TAG, "Failed to parse capabilities for guest"); showResultImage(false, false); } - bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), 99); + bundle.putSerializable(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), OPS_CODE_JOIN_ROOM); getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) .pushChangeHandler(new HorizontalChangeHandler()) .popChangeHandler(new HorizontalChangeHandler())); @@ -407,7 +404,7 @@ public class OperationsMenuController extends BaseController { } }); break; - case 11: + case OPS_CODE_INVITE_USERS: RetrofitBucket retrofitBucket; String invite = null; @@ -483,7 +480,7 @@ public class OperationsMenuController extends BaseController { }); break; - case 96: + case OPS_CODE_MARK_AS_READ: ncApi.setChatReadMarker(credentials, ApiUtils.getUrlForSetChatReadMarker(chatApiVersion, currentUser.getBaseUrl(), @@ -494,9 +491,9 @@ public class OperationsMenuController extends BaseController { .retry(1) .subscribe(genericOperationsObserver); break; - case 97: - case 98: - if (operationCode == 97) { + case OPS_CODE_REMOVE_FAVORITE: + case OPS_CODE_ADD_FAVORITE: + if (operation == OPS_CODE_REMOVE_FAVORITE) { ncApi.removeConversationFromFavorites(credentials, ApiUtils.getUrlForRoomFavorite(apiVersion, currentUser.getBaseUrl(), @@ -516,7 +513,7 @@ public class OperationsMenuController extends BaseController { .subscribe(genericOperationsObserver); } break; - case 99: + case OPS_CODE_JOIN_ROOM: ncApi.joinRoom(credentials, ApiUtils.getUrlForParticipantsActive(apiVersion, baseUrl, conversationToken), @@ -557,10 +554,8 @@ public class OperationsMenuController extends BaseController { } else { resultsTextView.setText(R.string.nc_failed_signaling_settings); webButton.setOnClickListener(v -> { - eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(callUrl)); startActivity(browserIntent); - new BottomSheetLockEvent(true, 0, false, true); }); webButton.setVisibility(View.VISIBLE); } @@ -568,12 +563,11 @@ public class OperationsMenuController extends BaseController { resultsTextView.setVisibility(View.VISIBLE); if (everythingOK) { - eventBus.post(new BottomSheetLockEvent(true, 2500, true, true)); + eventBus.post(new ConversationsListFetchDataEvent()); } else { resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(), R.drawable .ic_cancel_black_24dp, R.color.nc_darkRed)); - okButton.setOnClickListener(v -> eventBus.post(new BottomSheetLockEvent(true, 0, operationCode != 99 - && operationCode != 10, true))); + okButton.setOnClickListener(v -> eventBus.post(new ConversationsListFetchDataEvent())); okButton.setVisibility(View.VISIBLE); } } @@ -724,8 +718,7 @@ public class OperationsMenuController extends BaseController { } private void initiateConversation(boolean dismissView) { - eventBus.post(new BottomSheetLockEvent(true, 0, - true, true, dismissView)); + eventBus.post(new ConversationsListFetchDataEvent()); Bundle bundle = new Bundle(); bundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), conversation.getToken()); @@ -735,20 +728,15 @@ public class OperationsMenuController extends BaseController { bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ACTIVE_CONVERSATION(), Parcels.wrap(conversation)); bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), callPassword); - if (getParentController() != null) { - ConductorRemapping.INSTANCE.remapChatController(getParentController().getRouter(), currentUser.getId(), - conversation.getToken(), bundle, true); - } + eventBus.post(new OpenConversationEvent(conversation, bundle)); } private void handleObserverError(@io.reactivex.annotations.NonNull Throwable e) { - if (operationCode != 99 || !(e instanceof HttpException)) { + if (operation != OPS_CODE_JOIN_ROOM || !(e instanceof HttpException)) { showResultImage(false, false); } else { Response response = ((HttpException) e).response(); if (response != null && response.code() == 403) { - eventBus.post(new BottomSheetLockEvent(true, 0, false, - false)); ApplicationWideMessageHolder.getInstance().setMessageType(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG); getRouter().popCurrentController(); } else { @@ -767,7 +755,7 @@ public class OperationsMenuController extends BaseController { @Override public void onNext(@io.reactivex.annotations.NonNull GenericOverall genericOverall) { - if (operationCode != 99) { + if (operation != OPS_CODE_JOIN_ROOM) { showResultImage(true, false); } else { throw new IllegalArgumentException("Unsupported operation code observed!"); @@ -795,7 +783,7 @@ public class OperationsMenuController extends BaseController { @Override public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) { conversation = roomOverall.getOcs().getData(); - if (operationCode != 99) { + if (operation != OPS_CODE_JOIN_ROOM) { showResultImage(true, false); } else { conversation = roomOverall.getOcs().getData(); @@ -813,4 +801,9 @@ public class OperationsMenuController extends BaseController { dispose(); } } + + @Override + public AppBarLayoutType getAppBarLayoutType() { + return AppBarLayoutType.SEARCH_BAR; + } } diff --git a/app/src/main/java/com/nextcloud/talk/events/BottomSheetLockEvent.java b/app/src/main/java/com/nextcloud/talk/events/BottomSheetLockEvent.java deleted file mode 100644 index b9c61e487..000000000 --- a/app/src/main/java/com/nextcloud/talk/events/BottomSheetLockEvent.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.events; - -public class BottomSheetLockEvent { - private final boolean cancelable; - private final int delay; - private final boolean shouldRefreshData; - private final boolean cancel; - private boolean dismissView; - - public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData, boolean cancel) { - this.cancelable = cancelable; - this.delay = delay; - this.shouldRefreshData = shouldRefreshData; - this.cancel = cancel; - this.dismissView = true; - } - - public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData, boolean cancel, boolean - dismissView) { - this.cancelable = cancelable; - this.delay = delay; - this.shouldRefreshData = shouldRefreshData; - this.cancel = cancel; - this.dismissView = dismissView; - } - - public boolean isCancelable() { - return this.cancelable; - } - - public int getDelay() { - return this.delay; - } - - public boolean isShouldRefreshData() { - return this.shouldRefreshData; - } - - public boolean isCancel() { - return this.cancel; - } - - public boolean isDismissView() { - return this.dismissView; - } - - public void setDismissView(boolean dismissView) { - this.dismissView = dismissView; - } - - public boolean equals(final Object o) { - if (o == this) { - return true; - } - if (!(o instanceof BottomSheetLockEvent)) { - return false; - } - final BottomSheetLockEvent other = (BottomSheetLockEvent) o; - if (!other.canEqual((Object) this)) { - return false; - } - if (this.isCancelable() != other.isCancelable()) { - return false; - } - if (this.getDelay() != other.getDelay()) { - return false; - } - if (this.isShouldRefreshData() != other.isShouldRefreshData()) { - return false; - } - if (this.isCancel() != other.isCancel()) { - return false; - } - - return this.isDismissView() == other.isDismissView(); - } - - protected boolean canEqual(final Object other) { - return other instanceof BottomSheetLockEvent; - } - - public int hashCode() { - final int PRIME = 59; - int result = 1; - result = result * PRIME + (this.isCancelable() ? 79 : 97); - result = result * PRIME + this.getDelay(); - result = result * PRIME + (this.isShouldRefreshData() ? 79 : 97); - result = result * PRIME + (this.isCancel() ? 79 : 97); - result = result * PRIME + (this.isDismissView() ? 79 : 97); - return result; - } - - public String toString() { - return "BottomSheetLockEvent(cancelable=" + this.isCancelable() + ", delay=" + this.getDelay() + ", shouldRefreshData=" + this.isShouldRefreshData() + ", cancel=" + this.isCancel() + ", dismissView=" + this.isDismissView() + ")"; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/events/ConversationsListFetchDataEvent.kt b/app/src/main/java/com/nextcloud/talk/events/ConversationsListFetchDataEvent.kt new file mode 100644 index 000000000..f69e5d1d4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/events/ConversationsListFetchDataEvent.kt @@ -0,0 +1,23 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * 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 . + */ + +package com.nextcloud.talk.events + +class ConversationsListFetchDataEvent diff --git a/app/src/main/java/com/nextcloud/talk/events/OpenConversationEvent.kt b/app/src/main/java/com/nextcloud/talk/events/OpenConversationEvent.kt new file mode 100644 index 000000000..e1d2e33d8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/events/OpenConversationEvent.kt @@ -0,0 +1,52 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * 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 . + */ + +package com.nextcloud.talk.events + +import android.os.Bundle +import com.nextcloud.talk.models.json.conversations.Conversation + +class OpenConversationEvent { + var conversation: Conversation? = null + var bundle: Bundle? = null + + constructor(conversation: Conversation?, bundle: Bundle?) { + this.conversation = conversation + this.bundle = bundle + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as OpenConversationEvent + + if (conversation != other.conversation) return false + if (bundle != other.bundle) return false + + return true + } + + override fun hashCode(): Int { + var result = conversation?.hashCode() ?: 0 + result = 31 * result + (bundle?.hashCode() ?: 0) + return result + } +} diff --git a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java index 5ddab19f3..826e3b7f8 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java @@ -21,6 +21,8 @@ package com.nextcloud.talk.jobs; import android.content.Context; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.work.Data; import androidx.work.Worker; @@ -48,6 +50,8 @@ import java.net.CookieManager; @AutoInjector(NextcloudTalkApplication.class) public class LeaveConversationWorker extends Worker { + private static String TAG = "LeaveConversationWorker"; + @Inject Retrofit retrofit; @@ -106,7 +110,7 @@ public class LeaveConversationWorker extends Worker { @Override public void onError(Throwable e) { - + Log.e(TAG, "failed to remove self from room", e); } @Override 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 880c37bd1..82e557b29 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 @@ -148,23 +148,12 @@ public class Conversation { return (canModerate(conversationUser) && !ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL.equals(type)); } - public boolean canLeave(UserEntity conversationUser) { - if (canLeaveConversation != null) { - // Available since APIv2 - return canLeaveConversation; - } - // Fallback for APIv1 - return !canModerate(conversationUser) || - (getType() != ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && this.participants.size() > 1); + public boolean canLeave() { + return canLeaveConversation; } - public boolean canDelete(UserEntity conversationUser) { - if (canDeleteConversation != null) { - // Available since APIv2 - return canDeleteConversation; - } - // Fallback for APIv1 - return canModerate(conversationUser); + public boolean canDelete() { + return canDeleteConversation; } public String getRoomId() { diff --git a/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt index d9ed5bb59..54c0611c9 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/bottom/sheet/ProfileBottomSheet.kt @@ -63,6 +63,7 @@ class ProfileBottomSheet(val ncApi: NcApi, val userEntity: UserEntity, val route ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(object : io.reactivex.Observer { override fun onSubscribe(d: Disposable) { + // unused atm } override fun onNext(hoverCardOverall: HoverCardOverall) { @@ -74,6 +75,7 @@ class ProfileBottomSheet(val ncApi: NcApi, val userEntity: UserEntity, val route } override fun onComplete() { + // unused atm } }) } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ContactsBottomDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ContactsBottomDialog.kt new file mode 100644 index 000000000..7ceb934e6 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ContactsBottomDialog.kt @@ -0,0 +1,82 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * 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 . + */ + +package com.nextcloud.talk.ui.dialog + +import android.app.Activity +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import autodagger.AutoInjector +import com.bluelinelabs.conductor.Conductor +import com.bluelinelabs.conductor.Router +import com.bluelinelabs.conductor.RouterTransaction +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.nextcloud.talk.R +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController +import com.nextcloud.talk.databinding.DialogBottomContactsBinding + +@AutoInjector(NextcloudTalkApplication::class) +class ContactsBottomDialog( + val activity: Activity, + val bundle: Bundle +) : BottomSheetDialog(activity, R.style.BottomSheetDialogThemeNoFloating) { + + private var dialogRouter: Router? = null + + private lateinit var binding: DialogBottomContactsBinding + + init { + NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DialogBottomContactsBinding.inflate(layoutInflater) + setContentView(binding.root) + window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + + executeEntryMenuController(bundle) + } + + private fun executeEntryMenuController(bundle: Bundle) { + dialogRouter = Conductor.attachRouter(activity, binding.root, null) + + dialogRouter!!.pushController( + RouterTransaction.with(EntryMenuController(bundle)) + .pushChangeHandler(HorizontalChangeHandler()) + .popChangeHandler(HorizontalChangeHandler()) + ) + } + + override fun onStart() { + super.onStart() + val bottomSheet = findViewById(R.id.design_bottom_sheet) + val behavior = BottomSheetBehavior.from(bottomSheet as View) + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + + companion object { + private const val TAG = "ContactsBottomDialog" + } +} diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt new file mode 100644 index 000000000..ff2b9db97 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/ConversationsListBottomDialog.kt @@ -0,0 +1,318 @@ +/* + * Nextcloud Talk application + * + * @author Marcel Hibbe + * Copyright (C) 2022 Marcel Hibbe + * + * 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 . + */ + +package com.nextcloud.talk.ui.dialog + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.view.ViewGroup +import androidx.work.Data +import androidx.work.OneTimeWorkRequest +import androidx.work.WorkManager +import autodagger.AutoInjector +import com.bluelinelabs.conductor.Conductor +import com.bluelinelabs.conductor.Router +import com.bluelinelabs.conductor.RouterTransaction +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.nextcloud.talk.R +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.controllers.ConversationsListController +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CHANGE_PASSWORD +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_SET_PASSWORD +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_CLEAR_PASSWORD +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PRIVATE +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MAKE_PUBLIC +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM +import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ +import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController +import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController +import com.nextcloud.talk.databinding.DialogConversationOperationsBinding +import com.nextcloud.talk.jobs.LeaveConversationWorker +import com.nextcloud.talk.models.database.CapabilitiesUtil +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.utils.ShareUtils +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import com.nextcloud.talk.utils.database.user.UserUtils +import org.parceler.Parcels +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class ConversationsListBottomDialog( + val activity: Activity, + val controller: ConversationsListController, + val currentUser: UserEntity, + val conversation: Conversation +) : BottomSheetDialog(activity, R.style.BottomSheetDialogThemeNoFloating) { + + private var dialogRouter: Router? = null + + private lateinit var binding: DialogConversationOperationsBinding + + @Inject + @JvmField + var ncApi: NcApi? = null + + @Inject + @JvmField + var userUtils: UserUtils? = null + + init { + NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DialogConversationOperationsBinding.inflate(layoutInflater) + setContentView(binding.root) + window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + + initHeaderDescription() + initItemsVisibility() + initClickListeners() + } + + private fun initHeaderDescription() { + if (!TextUtils.isEmpty(conversation.getDisplayName())) { + binding.conversationOperationHeader.text = conversation.getDisplayName() + } else if (!TextUtils.isEmpty(conversation.getName())) { + binding.conversationOperationHeader.text = conversation.getName() + } + } + + private fun initItemsVisibility() { + val hasFavoritesCapability = CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "favorites") + val canModerate = conversation.canModerate(currentUser) + + binding.conversationOperationRemoveFavorite.visibility = setVisibleIf( + hasFavoritesCapability && conversation.isFavorite() + ) + binding.conversationOperationAddFavorite.visibility = setVisibleIf( + hasFavoritesCapability && !conversation.isFavorite() + ) + + binding.conversationOperationMarkAsRead.visibility = setVisibleIf( + conversation.unreadMessages > 0 && CapabilitiesUtil.canSetChatReadMarker(currentUser) + ) + + binding.conversationOperationRename.visibility = setVisibleIf( + conversation.isNameEditable(currentUser) + ) + + binding.conversationOperationMakePublic.visibility = setVisibleIf( + canModerate && !conversation.isPublic + ) + + binding.conversationOperationChangePassword.visibility = setVisibleIf( + canModerate && conversation.isHasPassword && conversation.isPublic + ) + + binding.conversationOperationClearPassword.visibility = setVisibleIf( + canModerate && conversation.isHasPassword && conversation.isPublic + ) + + binding.conversationOperationSetPassword.visibility = setVisibleIf( + canModerate && !conversation.isHasPassword && conversation.isPublic + ) + + binding.conversationOperationDelete.visibility = setVisibleIf( + canModerate + ) + + binding.conversationOperationShareLink.visibility = setVisibleIf( + conversation.isPublic + ) + + binding.conversationOperationMakePrivate.visibility = setVisibleIf( + conversation.isPublic && canModerate + ) + + binding.conversationOperationLeave.visibility = setVisibleIf( + conversation.canLeave() && + // leaving is by api not possible for the last user with moderator permissions. + // for now, hide this option for all moderators. + !conversation.canModerate(currentUser) + ) + } + + private fun setVisibleIf(boolean: Boolean): Int { + return if (boolean) { + View.VISIBLE + } else { + View.GONE + } + } + + private fun initClickListeners() { + binding.conversationOperationAddFavorite.setOnClickListener { + executeOperationsMenuController(OPS_CODE_ADD_FAVORITE) + } + + binding.conversationOperationRemoveFavorite.setOnClickListener { + executeOperationsMenuController(OPS_CODE_REMOVE_FAVORITE) + } + + binding.conversationOperationLeave.setOnClickListener { + val dataBuilder = Data.Builder() + dataBuilder.putString(KEY_ROOM_TOKEN, conversation.getToken()) + dataBuilder.putLong(KEY_INTERNAL_USER_ID, currentUser.id) + val data = dataBuilder.build() + + val leaveConversationWorker = + OneTimeWorkRequest.Builder(LeaveConversationWorker::class.java).setInputData( + data + ).build() + WorkManager.getInstance().enqueue(leaveConversationWorker) + + dismiss() + } + + binding.conversationOperationDelete.setOnClickListener { + if (!TextUtils.isEmpty(conversation.getToken())) { + val bundle = Bundle() + bundle.putLong(KEY_INTERNAL_USER_ID, currentUser.id) + bundle.putParcelable(KEY_ROOM, Parcels.wrap(conversation)) + + controller.openLovelyDialogWithIdAndBundle( + ConversationsListController.ID_DELETE_CONVERSATION_DIALOG, + bundle + ) + } + + dismiss() + } + + binding.conversationOperationMakePublic.setOnClickListener { + executeOperationsMenuController(OPS_CODE_MAKE_PUBLIC) + } + + binding.conversationOperationMakePrivate.setOnClickListener { + executeOperationsMenuController(OPS_CODE_MAKE_PRIVATE) + } + + binding.conversationOperationChangePassword.setOnClickListener { + executeEntryMenuController(OPS_CODE_CHANGE_PASSWORD) + } + + binding.conversationOperationClearPassword.setOnClickListener { + executeOperationsMenuController(OPS_CODE_CLEAR_PASSWORD) + } + + binding.conversationOperationSetPassword.setOnClickListener { + executeEntryMenuController(OPS_CODE_SET_PASSWORD) + } + + binding.conversationOperationRename.setOnClickListener { + executeEntryMenuController(OPS_CODE_RENAME_ROOM) + } + + binding.conversationOperationMarkAsRead.setOnClickListener { + executeOperationsMenuController(OPS_CODE_MARK_AS_READ) + } + + binding.conversationOperationShareLink.setOnClickListener { + val sendIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + type = "text/plain" + putExtra( + Intent.EXTRA_SUBJECT, + String.format( + activity.resources.getString(R.string.nc_share_subject), + activity.resources.getString(R.string.nc_app_product_name) + ) + ) + // password should not be shared!! + putExtra( + Intent.EXTRA_TEXT, + ShareUtils.getStringForIntent(activity, null, userUtils, conversation) + ) + } + + val shareIntent = Intent.createChooser(sendIntent, null) + activity.startActivity(shareIntent) + + dismiss() + } + } + + private fun executeOperationsMenuController(operation: ConversationOperationEnum) { + val bundle = Bundle() + bundle.putParcelable(KEY_ROOM, Parcels.wrap(conversation)) + bundle.putSerializable(KEY_OPERATION_CODE, operation) + + binding.operationItemsLayout.visibility = View.GONE + + dialogRouter = Conductor.attachRouter(activity, binding.root, null) + + dialogRouter!!.pushController( + RouterTransaction.with(OperationsMenuController(bundle)) + .pushChangeHandler(HorizontalChangeHandler()) + .popChangeHandler(HorizontalChangeHandler()) + ) + + controller.fetchData() + } + + private fun executeEntryMenuController(operation: ConversationOperationEnum) { + val bundle = Bundle() + bundle.putParcelable(KEY_ROOM, Parcels.wrap(conversation)) + bundle.putSerializable(KEY_OPERATION_CODE, operation) + + binding.operationItemsLayout.visibility = View.GONE + + dialogRouter = Conductor.attachRouter(activity, binding.root, null) + + dialogRouter!!.pushController( + + // TODO: refresh conversation list after EntryMenuController finished (throw event? / pass controller + // into EntryMenuController to execute fetch data... ?!) + // for example if you set a password, the dialog items should be refreshed for the next time you open it + // without to manually have to refresh the conversations list + // also see BottomSheetLockEvent ?? + + RouterTransaction.with(EntryMenuController(bundle)) + .pushChangeHandler(HorizontalChangeHandler()) + .popChangeHandler(HorizontalChangeHandler()) + ) + } + + override fun onStart() { + super.onStart() + val bottomSheet = findViewById(R.id.design_bottom_sheet) + val behavior = BottomSheetBehavior.from(bottomSheet as View) + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + + companion object { + private const val TAG = "ConversationOperationDialog" + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/KeyboardUtils.java b/app/src/main/java/com/nextcloud/talk/utils/KeyboardUtils.java deleted file mode 100644 index 5ab0b0138..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/KeyboardUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 Mike Penz All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nextcloud.talk.utils; - -import android.app.Activity; -import android.graphics.Rect; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.inputmethod.InputMethodManager; - -/** - * Created by mikepenz on 14.03.15. - * This class implements a hack to change the layout padding on bottom if the keyboard is shown - * to allow long lists with editTextViews - * Basic idea for this solution found here: http://stackoverflow.com/a/9108219/325479 - */ -public class KeyboardUtils { - private View decorView; - private View contentView; - private boolean isUsedInBottomSheet; - //a small helper to allow showing the editText focus - ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - Rect r = new Rect(); - //r will be populated with the coordinates of your view that area still visible. - decorView.getWindowVisibleDisplayFrame(r); - - //get screen height and calculate the difference with the useable area from the r - int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels; - - int diff = height - r.bottom; - - boolean shouldSetBottomPadding = (isUsedInBottomSheet && diff != 0) || (diff > 0); - - if (shouldSetBottomPadding) { - if (contentView.getPaddingBottom() != diff) { - //set the padding of the contentView for the keyboard - contentView.setPadding(0, 0, 0, diff); - } - } else { - //check if the padding is != initialBottomPadding (if yes reset the padding) - if (contentView.getPaddingBottom() != 0) { - //reset the padding of the contentView - contentView.setPadding(0, 0, 0, 0); - } - } - } - }; - - public KeyboardUtils(Activity act, View contentView, boolean isUsedInBottomSheet) { - this.decorView = act.getWindow().getDecorView(); - this.contentView = contentView; - this.isUsedInBottomSheet = isUsedInBottomSheet; - - decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); - } - - /** - * Helper to hide the keyboard - * - * @param act - */ - public static void hideKeyboard(Activity act) { - if (act != null && act.getCurrentFocus() != null) { - InputMethodManager inputMethodManager = (InputMethodManager) act.getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(act.getCurrentFocus().getWindowToken(), 0); - } - } - - public void enable() { - decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); - } - - public void disable() { - decorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java index 815f26cd3..30f051512 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ShareUtils.java @@ -16,29 +16,19 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * Part of the code in ShareUtils was inspired by BottomSheet under the Apache licence - * located here: https://github.com/Kennyc1012/BottomSheet/blob/master/library/src/main/java/com/kennyc/bottomsheet/BottomSheet.java#L425 */ package com.nextcloud.talk.utils; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; import android.text.TextUtils; -import androidx.annotation.Nullable; -import com.kennyc.bottomsheet.adapters.AppAdapter; + import com.nextcloud.talk.R; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.conversations.Conversation; import com.nextcloud.talk.utils.database.user.UserUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import androidx.annotation.Nullable; public class ShareUtils { @@ -58,49 +48,4 @@ public class ShareUtils { return shareString; } - - public static List getShareApps(Context context, Intent intent, - @Nullable Set appsFilter, @Nullable Set toExclude) { - - if (context == null || intent == null) return null; - - PackageManager manager = context.getPackageManager(); - List apps = manager.queryIntentActivities(intent, 0); - - if (apps != null && !apps.isEmpty()) { - List appResources = new ArrayList<>(apps.size()); - boolean shouldCheckPackages = appsFilter != null && !appsFilter.isEmpty(); - - for (ResolveInfo resolveInfo : apps) { - String packageName = resolveInfo.activityInfo.packageName; - - if (shouldCheckPackages && !appsFilter.contains(packageName)) { - continue; - } - - String title = resolveInfo.loadLabel(manager).toString(); - String name = resolveInfo.activityInfo.name; - Drawable drawable = resolveInfo.loadIcon(manager); - appResources.add(new AppAdapter.AppInfo(title, packageName, name, drawable)); - } - - if (toExclude != null && !toExclude.isEmpty()) { - List toRemove = new ArrayList<>(); - - for (AppAdapter.AppInfo appInfo : appResources) { - if (toExclude.contains(appInfo.packageName)) { - toRemove.add(appInfo); - } - } - - if (!toRemove.isEmpty()) appResources.removeAll(toRemove); - } - - return appResources; - - } - - return null; - } - } diff --git a/app/src/main/res/drawable/ic_mimetype_folder_public.xml b/app/src/main/res/drawable/ic_mimetype_folder_public.xml deleted file mode 100755 index 3daf0ff42..000000000 --- a/app/src/main/res/drawable/ic_mimetype_folder_public.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_mimetype_folder_starred.xml b/app/src/main/res/drawable/ic_mimetype_folder_starred.xml deleted file mode 100755 index e836f7cac..000000000 --- a/app/src/main/res/drawable/ic_mimetype_folder_starred.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/controller_entry_menu.xml b/app/src/main/res/layout/controller_entry_menu.xml index c743fc656..8b0a08bf8 100644 --- a/app/src/main/res/layout/controller_entry_menu.xml +++ b/app/src/main/res/layout/controller_entry_menu.xml @@ -52,7 +52,9 @@ android:layout_marginEnd="@dimen/standard_half_margin" android:layout_toStartOf="@id/smileyButton" app:errorTextAppearance="@style/ErrorAppearance" - app:passwordToggleTint="@color/grey_600"> + app:passwordToggleTint="@color/grey_600" + app:boxStrokeColor="@color/colorPrimary" + app:hintTextColor="@color/colorPrimary"> + android:layout_height="wrap_content"> - - + android:background="@color/bg_bottom_sheet" + android:orientation="vertical" + android:paddingStart="@dimen/standard_padding" + android:paddingEnd="@dimen/standard_padding" + android:paddingBottom="@dimen/standard_half_padding"> - - - - + diff --git a/app/src/main/res/layout/dialog_conversation_operations.xml b/app/src/main/res/layout/dialog_conversation_operations.xml new file mode 100644 index 000000000..16cc0eee9 --- /dev/null +++ b/app/src/main/res/layout/dialog_conversation_operations.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 59b913073..2bcef5826 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -24,6 +24,7 @@ 72dp 56dp + 16sp 48dp 48dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2bef3843a..345a31a82 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -165,8 +165,6 @@ Personal Info - Start a conversation - Configure conversation Leave conversation Delete all messages Do you really want to delete all messages in this conversation? @@ -176,7 +174,6 @@ Change password Clear password Share link - Share link via Make conversation public Make conversation private Delete conversation diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b10c1bedf..89d41e79b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -72,7 +72,7 @@ 12sp - @@ -235,4 +235,9 @@ #ffffff + + diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt index 4a722e9c7..28621d35a 100644 --- a/scripts/analysis/findbugs-results.txt +++ b/scripts/analysis/findbugs-results.txt @@ -1 +1 @@ -552 \ No newline at end of file +542 \ No newline at end of file diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index cd69b2081..437343559 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 1 error and 221 warnings + Lint Report: 1 error and 218 warnings