Browse Source

add open conversations to search

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 3 years ago
parent
commit
1de2261426

+ 19 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/CallItem.java

@@ -49,19 +49,27 @@ import butterknife.ButterKnife;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
+import eu.davidea.flexibleadapter.items.ISectionable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
-public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable<String> {
+public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements ISectionable<CallItem.RoomItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
 
     private Conversation conversation;
     private UserEntity userEntity;
+    private GenericTextHeaderItem header;
 
     public CallItem(Conversation conversation, UserEntity userEntity) {
         this.conversation = conversation;
         this.userEntity = userEntity;
     }
 
+    public CallItem(Conversation conversation, UserEntity userEntity, GenericTextHeaderItem genericTextHeaderItem) {
+        this.conversation = conversation;
+        this.userEntity = userEntity;
+        this.header = genericTextHeaderItem;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof CallItem) {
@@ -168,6 +176,16 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
                 Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
     }
 
+    @Override
+    public GenericTextHeaderItem getHeader() {
+        return header;
+    }
+
+    @Override
+    public void setHeader(GenericTextHeaderItem header) {
+        this.header = header;
+    }
+
     static class RoomItemViewHolder extends FlexibleViewHolder {
 
         @BindView(R.id.name_text)

+ 21 - 2
app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java

@@ -61,22 +61,31 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
+import eu.davidea.flexibleadapter.items.ISectionable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
 
-public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
+public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements ISectionable<ConversationItem.ConversationItemViewHolder, GenericTextHeaderItem>,
         IFilterable<String> {
 
 
     private Conversation conversation;
     private UserEntity userEntity;
     private Context context;
+    private GenericTextHeaderItem header;
+
+    public ConversationItem(Conversation conversation, UserEntity userEntity, Context activityContext) {
+        this.conversation = conversation;
+        this.userEntity = userEntity;
+        this.context = activityContext;
+    }
 
     public ConversationItem(Conversation conversation, UserEntity userEntity,
-                            Context activityContext) {
+                            Context activityContext, GenericTextHeaderItem genericTextHeaderItem) {
         this.conversation = conversation;
         this.userEntity = userEntity;
         this.context = activityContext;
+        this.header = genericTextHeaderItem;
     }
 
     @Override
@@ -286,6 +295,16 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
     }
 
+    @Override
+    public GenericTextHeaderItem getHeader() {
+        return header;
+    }
+
+    @Override
+    public void setHeader(GenericTextHeaderItem header) {
+        this.header = header;
+    }
+
     static class ConversationItemViewHolder extends FlexibleViewHolder {
         @BindView(R.id.dialogAvatar)
         SimpleDraweeView dialogAvatar;

+ 7 - 0
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -436,4 +436,11 @@ public interface NcApi {
     Observable<GenericOverall> setChatReadMarker(@Header("Authorization") String authorization,
                                                  @Url String url,
                                                  @Field("lastReadMessage") int lastReadMessage);
+
+    /*
+    Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /listed-room
+    */
+    @GET
+    Observable<RoomsOverall> getOpenConversations(@Header("Authorization") String authorization, @Url String url);
+
 }

+ 148 - 45
app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java

@@ -66,6 +66,7 @@ import com.nextcloud.talk.R;
 import com.nextcloud.talk.activities.MainActivity;
 import com.nextcloud.talk.adapters.items.CallItem;
 import com.nextcloud.talk.adapters.items.ConversationItem;
+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;
@@ -106,6 +107,7 @@ import org.parceler.Parcels;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Objects;
 
@@ -178,8 +180,11 @@ public class ConversationsListController extends BaseController implements Searc
 
     private UserEntity currentUser;
     private Disposable roomsQueryDisposable;
+    private Disposable openConversationsQueryDisposable;
     private FlexibleAdapter<AbstractFlexibleItem> adapter;
     private List<AbstractFlexibleItem> callItems = new ArrayList<>();
+    private List<AbstractFlexibleItem> callItemsWithHeader = new ArrayList<>();
+    private List<AbstractFlexibleItem> searchableCallItems = new ArrayList<>();
 
     private BottomSheet bottomSheet;
     private MenuItem searchItem;
@@ -212,6 +217,8 @@ public class ConversationsListController extends BaseController implements Searc
 
     private SmoothScrollLinearLayoutManager layoutManager;
 
+    private HashMap<String, GenericTextHeaderItem> callHeaderItems = new HashMap<>();
+
     public ConversationsListController(Bundle bundle) {
         super();
         setHasOptionsMenu(true);
@@ -400,11 +407,20 @@ public class ConversationsListController extends BaseController implements Searc
             searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
                 @Override
                 public boolean onMenuItemActionExpand(MenuItem item) {
+                    adapter.setHeadersShown(true);
+                    adapter.updateDataSet(searchableCallItems, false);
+                    adapter.showAllHeaders();
+                    swipeRefreshLayout.setEnabled(false);
                     return true;
                 }
 
                 @Override
                 public boolean onMenuItemActionCollapse(MenuItem item) {
+                    adapter.setHeadersShown(false);
+                    adapter.updateDataSet(callItems, false);
+                    adapter.hideAllHeaders();
+                    swipeRefreshLayout.setEnabled(true);
+
                     searchView.onActionViewCollapsed();
                     MainActivity activity = (MainActivity) getActivity();
                     if (activity != null) {
@@ -462,6 +478,7 @@ public class ConversationsListController extends BaseController implements Searc
         isRefreshing = true;
 
         callItems = new ArrayList<>();
+        callItemsWithHeader = new ArrayList<>();
 
         int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[]{ApiUtils.APIv4, ApiUtils.APIv3, 1});
 
@@ -494,69 +511,68 @@ public class ConversationsListController extends BaseController implements Searc
                         }
                     }
 
-                    Conversation conversation;
-                    for (int i = 0; i < roomsOverall.getOcs().getData().size(); i++) {
-                        conversation = roomsOverall.getOcs().getData().get(i);
-
+                    for (Conversation conversation : roomsOverall.getOcs().getData()) {
                         if (bundle.containsKey(BundleKeys.INSTANCE.getKEY_FORWARD_HIDE_SOURCE_ROOM()) && conversation.roomId.equals(bundle.getString(
                             BundleKeys.INSTANCE.getKEY_FORWARD_HIDE_SOURCE_ROOM()))) {
                             continue;
                         }
 
+                        String headerTitle;
+
+                        headerTitle = getResources().getString(R.string.conversations);
+
+                        GenericTextHeaderItem genericTextHeaderItem;
+                        if (!callHeaderItems.containsKey(headerTitle)) {
+                            genericTextHeaderItem = new GenericTextHeaderItem(headerTitle);
+                            callHeaderItems.put(headerTitle, genericTextHeaderItem);
+                        }
+
                         if (shouldUseLastMessageLayout) {
                             if (getActivity() != null) {
-                                ConversationItem conversationItem = new ConversationItem(conversation
-                                        , currentUser, getActivity());
+                                ConversationItem conversationItem = new ConversationItem(
+                                    conversation,
+                                    currentUser,
+                                    getActivity());
                                 callItems.add(conversationItem);
+
+                                ConversationItem conversationItemWithHeader = new ConversationItem(
+                                    conversation,
+                                    currentUser,
+                                    getActivity(),
+                                    callHeaderItems.get(headerTitle));
+
+                                callItemsWithHeader.add(conversationItemWithHeader);
                             }
                         } else {
-                            CallItem callItem = new CallItem(conversation, currentUser);
+                            CallItem callItem = new CallItem(
+                                conversation,
+                                currentUser);
                             callItems.add(callItem);
+
+                            CallItem callItemWithHeader = new CallItem(
+                                conversation,
+                                currentUser,
+                                callHeaderItems.get(headerTitle));
+
+                            callItemsWithHeader.add(callItemWithHeader);
                         }
                     }
 
-                    if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")) {
-                        Collections.sort(callItems, (o1, o2) -> {
-                            Conversation conversation1 = ((ConversationItem) o1).getModel();
-                            Conversation conversation2 = ((ConversationItem) o2).getModel();
-                            return new CompareToBuilder()
-                                    .append(conversation2.isFavorite(), conversation1.isFavorite())
-                                    .append(conversation2.getLastActivity(), conversation1.getLastActivity())
-                                    .toComparison();
-                        });
-                    } else {
-                        Collections.sort(callItems, (callItem, t1) ->
-                                Long.compare(((CallItem) t1).getModel().getLastPing(),
-                                             ((CallItem) callItem).getModel().getLastPing()));
-                    }
+                    sortConversations(callItems);
+                    sortConversations(callItemsWithHeader);
 
                     adapter.updateDataSet(callItems, false);
+
                     new Handler().postDelayed(this::checkToShowUnreadBubble, UNREAD_BUBBLE_DELAY);
 
+                    fetchOpenConversations(apiVersion);
+
                     if (swipeRefreshLayout != null) {
                         swipeRefreshLayout.setRefreshing(false);
                     }
 
                 }, throwable -> {
-                    if (throwable instanceof HttpException) {
-                        HttpException exception = (HttpException) throwable;
-                        switch (exception.code()) {
-                            case 401:
-                                if (getParentController() != null && getParentController().getRouter() != null) {
-                                    Log.d(TAG, "Starting reauth webview via getParentController()");
-                                    getParentController().getRouter().pushController((RouterTransaction.with
-                                            (new WebViewLoginController(currentUser.getBaseUrl(), true))
-                                            .pushChangeHandler(new VerticalChangeHandler())
-                                            .popChangeHandler(new VerticalChangeHandler())));
-                                } else {
-                                    Log.d(TAG, "Starting reauth webview via ConversationsListController");
-                                    showUnauthorizedDialog();
-                                }
-                                break;
-                            default:
-                                break;
-                        }
-                    }
+                    handleHttpExceptions(throwable);
                     if (swipeRefreshLayout != null) {
                         swipeRefreshLayout.setRefreshing(false);
                     }
@@ -580,6 +596,94 @@ public class ConversationsListController extends BaseController implements Searc
                 });
     }
 
+    private void sortConversations(List<AbstractFlexibleItem> callItems) {
+        if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")) {
+            Collections.sort(callItems, (o1, o2) -> {
+                Conversation conversation1 = ((ConversationItem) o1).getModel();
+                Conversation conversation2 = ((ConversationItem) o2).getModel();
+                return new CompareToBuilder()
+                        .append(conversation2.isFavorite(), conversation1.isFavorite())
+                        .append(conversation2.getLastActivity(), conversation1.getLastActivity())
+                        .toComparison();
+            });
+        } else {
+            Collections.sort(callItems, (callItem, t1) ->
+                    Long.compare(((CallItem) t1).getModel().getLastPing(),
+                                 ((CallItem) callItem).getModel().getLastPing()));
+        }
+    }
+
+    private void fetchOpenConversations(int apiVersion){
+        searchableCallItems.clear();
+        searchableCallItems.addAll(callItemsWithHeader);
+
+        if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "listable-rooms")) {
+            List<AbstractFlexibleItem> openConversationItems = new ArrayList<>();
+
+            openConversationsQueryDisposable = ncApi.getOpenConversations(
+                credentials,
+                ApiUtils.getUrlForOpenConversations(apiVersion, currentUser.getBaseUrl()))
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(roomsOverall -> {
+
+                    for (Conversation conversation : roomsOverall.getOcs().getData()) {
+                        String headerTitle = getResources().getString(R.string.openConversations);
+
+                        GenericTextHeaderItem genericTextHeaderItem;
+                        if (!callHeaderItems.containsKey(headerTitle)) {
+                            genericTextHeaderItem = new GenericTextHeaderItem(headerTitle);
+                            callHeaderItems.put(headerTitle, genericTextHeaderItem);
+                        }
+
+
+                        if (shouldUseLastMessageLayout) {
+                            if (getActivity() != null) {
+                                ConversationItem conversationItem = new ConversationItem(conversation
+                                    , currentUser, getActivity(), callHeaderItems.get(headerTitle));
+                                openConversationItems.add(conversationItem);
+                            }
+                        } else {
+                            CallItem callItem = new CallItem(conversation, currentUser, callHeaderItems.get(headerTitle));
+                            openConversationItems.add(callItem);
+                        }
+                    }
+
+                    searchableCallItems.addAll(openConversationItems);
+
+                }, throwable -> {
+                    handleHttpExceptions(throwable);
+                    dispose(openConversationsQueryDisposable);
+                }, () -> {
+                    dispose(openConversationsQueryDisposable);
+                });
+        } else {
+            Log.d(TAG, "no open conversations fetched because of missing capability");
+        }
+    }
+
+    private void handleHttpExceptions(Throwable throwable) {
+        if (throwable instanceof HttpException) {
+            HttpException exception = (HttpException) throwable;
+            switch (exception.code()) {
+                case 401:
+                    if (getParentController() != null && getParentController().getRouter() != null) {
+                        Log.d(TAG, "Starting reauth webview via getParentController()");
+                        getParentController().getRouter().pushController((RouterTransaction.with
+                            (new WebViewLoginController(currentUser.getBaseUrl(), true))
+                            .pushChangeHandler(new VerticalChangeHandler())
+                            .popChangeHandler(new VerticalChangeHandler())));
+                    } else {
+                        Log.d(TAG, "Starting reauth webview via ConversationsListController");
+                        showUnauthorizedDialog();
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
     private void prepareViews() {
         layoutManager = new SmoothScrollLinearLayoutManager(Objects.requireNonNull(getActivity()));
         recyclerView.setLayoutManager(layoutManager);
@@ -671,6 +775,10 @@ public class ConversationsListController extends BaseController implements Searc
                 roomsQueryDisposable != null && !roomsQueryDisposable.isDisposed()) {
             roomsQueryDisposable.dispose();
             roomsQueryDisposable = null;
+        } else if (disposable == null &&
+            openConversationsQueryDisposable != null && !openConversationsQueryDisposable.isDisposed()) {
+            openConversationsQueryDisposable.dispose();
+            openConversationsQueryDisposable = null;
         }
     }
 
@@ -716,11 +824,6 @@ public class ConversationsListController extends BaseController implements Searc
                 adapter.filterItems(300);
             }
         }
-
-        if (swipeRefreshLayout != null) {
-            swipeRefreshLayout.setEnabled(!adapter.hasFilter());
-        }
-
         return true;
     }
 

+ 4 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -275,6 +275,10 @@ public class ApiUtils {
         return getUrlForSignaling(version, baseUrl) + "/" + token;
     }
 
+    public static String getUrlForOpenConversations(int version, String baseUrl) {
+        return getUrlForApi(version, baseUrl) + "/listed-room";
+    }
+
     public static RetrofitBucket getRetrofitBucketForCreateRoom(int version, String baseUrl, String roomType,
                                                                 @Nullable String source,
                                                                 @Nullable String invite,

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -273,6 +273,8 @@
 
     <!-- Conversations List-->
     <string name="nc_new_mention">Unread mentions</string>
+    <string name="conversations">Conversations</string>
+    <string name="openConversations">Open conversations</string>
 
     <!-- Chat -->
     <string name="nc_hint_enter_a_message">Enter a message…</string>
@@ -492,4 +494,5 @@
     <string name="take_photo_send">Send</string>
     <string name="take_photo_error_deleting_picture">Error taking picture</string>
     <string name="take_photo_permission">Taking a photo is not possible without permissions</string>
+
 </resources>