mirror of
https://github.com/nextcloud/talk-android
synced 2025-03-12 10:32:36 +00:00
Initial mention implementation
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
d877fab0f7
commit
fce49d717e
@ -151,6 +151,7 @@ dependencies {
|
|||||||
implementation 'com.github.wooplr:Spotlight:1.2.3'
|
implementation 'com.github.wooplr:Spotlight:1.2.3'
|
||||||
|
|
||||||
implementation 'com.github.stfalcon:chatkit:0.2.2'
|
implementation 'com.github.stfalcon:chatkit:0.2.2'
|
||||||
|
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
||||||
|
|
||||||
implementation 'com.github.Kennyc1012:BottomSheet:2.4.0'
|
implementation 'com.github.Kennyc1012:BottomSheet:2.4.0'
|
||||||
implementation 'eu.davidea:flipview:1.1.3'
|
implementation 'eu.davidea:flipview:1.1.3'
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.adapters.items;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl;
|
||||||
|
import com.bumptech.glide.load.model.LazyHeaders;
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
|
||||||
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
|
import com.nextcloud.talk.utils.glide.GlideApp;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||||
|
import eu.davidea.flexibleadapter.items.IFilterable;
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible;
|
||||||
|
|
||||||
|
public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
|
||||||
|
implements IFilterable<String> {
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
private String displayName;
|
||||||
|
private UserEntity currentUser;
|
||||||
|
|
||||||
|
public MentionAutocompleteItem(String userId, String displayName, UserEntity currentUser) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.currentUser = currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof MentionAutocompleteItem) {
|
||||||
|
MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
|
||||||
|
return (userId.equals(inItem.userId) && displayName.equals(inItem.displayName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutRes() {
|
||||||
|
return R.layout.rv_item_mention;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserItem.UserItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
|
||||||
|
return new UserItem.UserItemViewHolder(view, adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, UserItem.UserItemViewHolder holder, int position, List<Object> payloads) {
|
||||||
|
holder.contactDisplayName.setText(displayName);
|
||||||
|
holder.contactMentionId.setText("@" + userId);
|
||||||
|
|
||||||
|
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
|
||||||
|
userId, false), new LazyHeaders.Builder()
|
||||||
|
.setHeader("Accept", "image/*")
|
||||||
|
.setHeader("User-Agent", ApiUtils.getUserAgent())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
int avatarSize = Math.round(NextcloudTalkApplication
|
||||||
|
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
|
||||||
|
|
||||||
|
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
|
||||||
|
.asBitmap()
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
|
.load(glideUrl)
|
||||||
|
.centerInside()
|
||||||
|
.override(avatarSize, avatarSize)
|
||||||
|
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
|
||||||
|
.into(holder.avatarFlipView.getFrontImageView());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(String constraint) {
|
||||||
|
return userId != null && StringUtils.containsIgnoreCase(userId, constraint);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
@ -161,6 +163,8 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
|
|||||||
public TextView contactDisplayName;
|
public TextView contactDisplayName;
|
||||||
@BindView(R.id.avatar_flip_view)
|
@BindView(R.id.avatar_flip_view)
|
||||||
public FlipView avatarFlipView;
|
public FlipView avatarFlipView;
|
||||||
|
@Nullable @BindView(R.id.secondary_text)
|
||||||
|
public TextView contactMentionId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
|
@ -27,6 +27,7 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
|
|||||||
import com.nextcloud.talk.models.json.chat.ChatOverall;
|
import com.nextcloud.talk.models.json.chat.ChatOverall;
|
||||||
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
||||||
import com.nextcloud.talk.models.json.generic.Status;
|
import com.nextcloud.talk.models.json.generic.Status;
|
||||||
|
import com.nextcloud.talk.models.json.mention.MentionOverall;
|
||||||
import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
|
import com.nextcloud.talk.models.json.participants.AddParticipantOverall;
|
||||||
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
|
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
|
||||||
import com.nextcloud.talk.models.json.push.PushRegistrationOverall;
|
import com.nextcloud.talk.models.json.push.PushRegistrationOverall;
|
||||||
@ -49,6 +50,7 @@ import retrofit2.http.GET;
|
|||||||
import retrofit2.http.Header;
|
import retrofit2.http.Header;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
import retrofit2.http.PUT;
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Query;
|
||||||
import retrofit2.http.QueryMap;
|
import retrofit2.http.QueryMap;
|
||||||
import retrofit2.http.Url;
|
import retrofit2.http.Url;
|
||||||
|
|
||||||
@ -282,4 +284,10 @@ public interface NcApi {
|
|||||||
@FieldMap Map<String, String> fields);
|
@FieldMap Map<String, String> fields);
|
||||||
|
|
||||||
|
|
||||||
|
//@Headers("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
|
||||||
|
@GET
|
||||||
|
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
|
||||||
|
@Url String url, @Query("search") String query,
|
||||||
|
@Nullable @Query("limit") Integer limit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.callbacks;
|
||||||
|
|
||||||
|
import android.text.Editable;
|
||||||
|
|
||||||
|
import com.nextcloud.talk.models.json.mention.Mention;
|
||||||
|
import com.otaliastudios.autocomplete.AutocompleteCallback;
|
||||||
|
import com.otaliastudios.autocomplete.CharPolicy;
|
||||||
|
|
||||||
|
public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> {
|
||||||
|
@Override
|
||||||
|
public boolean onPopupItemClicked(Editable editable, Mention item) {
|
||||||
|
int[] range = CharPolicy.getQueryRange(editable);
|
||||||
|
if (range == null) return false;
|
||||||
|
int start = range[0];
|
||||||
|
int end = range[1];
|
||||||
|
String replacement = item.getId() + " ";
|
||||||
|
editable.replace(start, end, replacement);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPopupVisibilityChanged(boolean shown) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,9 @@ package com.nextcloud.talk.controllers;
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
@ -32,6 +35,7 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.bluelinelabs.conductor.RouterTransaction;
|
import com.bluelinelabs.conductor.RouterTransaction;
|
||||||
@ -44,6 +48,7 @@ import com.nextcloud.talk.activities.CallActivity;
|
|||||||
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder;
|
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder;
|
||||||
import com.nextcloud.talk.api.NcApi;
|
import com.nextcloud.talk.api.NcApi;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.callbacks.MentionAutocompleteCallback;
|
||||||
import com.nextcloud.talk.controllers.base.BaseController;
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
import com.nextcloud.talk.models.database.UserEntity;
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.models.json.call.Call;
|
import com.nextcloud.talk.models.json.call.Call;
|
||||||
@ -51,10 +56,16 @@ import com.nextcloud.talk.models.json.call.CallOverall;
|
|||||||
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
||||||
import com.nextcloud.talk.models.json.chat.ChatOverall;
|
import com.nextcloud.talk.models.json.chat.ChatOverall;
|
||||||
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
||||||
|
import com.nextcloud.talk.models.json.mention.Mention;
|
||||||
|
import com.nextcloud.talk.presenters.MentionAutocompletePresenter;
|
||||||
import com.nextcloud.talk.utils.ApiUtils;
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
import com.nextcloud.talk.utils.glide.GlideApp;
|
import com.nextcloud.talk.utils.glide.GlideApp;
|
||||||
|
import com.otaliastudios.autocomplete.Autocomplete;
|
||||||
|
import com.otaliastudios.autocomplete.AutocompleteCallback;
|
||||||
|
import com.otaliastudios.autocomplete.AutocompletePresenter;
|
||||||
|
import com.otaliastudios.autocomplete.CharPolicy;
|
||||||
import com.stfalcon.chatkit.commons.ImageLoader;
|
import com.stfalcon.chatkit.commons.ImageLoader;
|
||||||
import com.stfalcon.chatkit.messages.MessageInput;
|
import com.stfalcon.chatkit.messages.MessageInput;
|
||||||
import com.stfalcon.chatkit.messages.MessagesList;
|
import com.stfalcon.chatkit.messages.MessagesList;
|
||||||
@ -106,6 +117,15 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
private MessagesListAdapter<ChatMessage> adapter;
|
private MessagesListAdapter<ChatMessage> adapter;
|
||||||
private Menu globalMenu;
|
private Menu globalMenu;
|
||||||
|
|
||||||
|
private Autocomplete mentionAutocomplete;
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
- format mentions
|
||||||
|
- copy message
|
||||||
|
- autocomplete nicks
|
||||||
|
- check push notifications
|
||||||
|
- new conversation handling
|
||||||
|
*/
|
||||||
public ChatController(Bundle args) {
|
public ChatController(Bundle args) {
|
||||||
super(args);
|
super(args);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
@ -155,6 +175,10 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
adapter.setDateHeadersFormatter(this::format);
|
adapter.setDateHeadersFormatter(this::format);
|
||||||
//adapter.enableSelectionMode(this);
|
//adapter.enableSelectionMode(this);
|
||||||
|
|
||||||
|
|
||||||
|
setupMentionAutocomplete();
|
||||||
|
|
||||||
|
messageInput.getInputEditText().setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||||
messageInput.setInputListener(input -> {
|
messageInput.setInputListener(input -> {
|
||||||
sendMessage(input.toString());
|
sendMessage(input.toString());
|
||||||
return true;
|
return true;
|
||||||
@ -165,6 +189,21 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupMentionAutocomplete() {
|
||||||
|
float elevation = 6f;
|
||||||
|
Drawable backgroundDrawable = new ColorDrawable(Color.WHITE);
|
||||||
|
AutocompletePresenter<Mention> presenter = new MentionAutocompletePresenter(getApplicationContext(), roomToken);
|
||||||
|
AutocompleteCallback<Mention> callback = new MentionAutocompleteCallback();
|
||||||
|
|
||||||
|
mentionAutocomplete = Autocomplete.<Mention>on(messageInput.getInputEditText())
|
||||||
|
.with(elevation)
|
||||||
|
.with(backgroundDrawable)
|
||||||
|
.with(new CharPolicy('@'))
|
||||||
|
.with(presenter)
|
||||||
|
.with(callback)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttach(@NonNull View view) {
|
protected void onAttach(@NonNull View view) {
|
||||||
super.onAttach(view);
|
super.onAttach(view);
|
||||||
|
@ -27,12 +27,14 @@ import org.parceler.Parcel;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Parcel
|
@Parcel
|
||||||
@JsonObject
|
@JsonObject
|
||||||
public class ChatOCS extends GenericOCS {
|
public class ChatOCS extends GenericOCS {
|
||||||
@JsonField(name = "data")
|
@Nullable @JsonField(name = "data")
|
||||||
List<ChatMessage> data;
|
List<ChatMessage> data;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
@Parcel
|
@Parcel
|
||||||
@Data
|
@Data
|
||||||
@JsonObject
|
@JsonObject(serializeNullObjects = true)
|
||||||
public class GenericMeta {
|
public class GenericMeta {
|
||||||
@JsonField(name = "status")
|
@JsonField(name = "status")
|
||||||
String status;
|
String status;
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.nextcloud.talk.models.json.mention;
|
||||||
|
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
|
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
@Data
|
||||||
|
@JsonObject
|
||||||
|
public class Mention {
|
||||||
|
@JsonField(name = "id")
|
||||||
|
String id;
|
||||||
|
|
||||||
|
@JsonField(name = "label")
|
||||||
|
String label;
|
||||||
|
|
||||||
|
// type of user (guests or users)
|
||||||
|
@JsonField(name = "source")
|
||||||
|
String source;
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.nextcloud.talk.models.json.mention;
|
||||||
|
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOCS;
|
||||||
|
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Parcel
|
||||||
|
@JsonObject
|
||||||
|
public class MentionOCS extends GenericOCS {
|
||||||
|
@JsonField(name = "data")
|
||||||
|
List<Mention> data;
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.nextcloud.talk.models.json.mention;
|
||||||
|
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
|
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Parcel
|
||||||
|
@JsonObject
|
||||||
|
public class MentionOverall {
|
||||||
|
@JsonField(name = "ocs")
|
||||||
|
MentionOCS ocs;
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.presenters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.nextcloud.talk.adapters.items.MentionAutocompleteItem;
|
||||||
|
import com.nextcloud.talk.api.NcApi;
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
|
import com.nextcloud.talk.models.json.mention.Mention;
|
||||||
|
import com.nextcloud.talk.models.json.mention.MentionOverall;
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
|
import com.otaliastudios.autocomplete.RecyclerViewPresenter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||||
|
import io.reactivex.Observer;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
|
public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention> implements FlexibleAdapter.OnItemClickListener {
|
||||||
|
@Inject
|
||||||
|
NcApi ncApi;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserUtils userUtils;
|
||||||
|
|
||||||
|
private FlexibleAdapter<AbstractFlexibleItem> adapter;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private String roomToken;
|
||||||
|
private List<AbstractFlexibleItem> userItemList = new ArrayList<>();
|
||||||
|
|
||||||
|
public MentionAutocompletePresenter(Context context) {
|
||||||
|
super(context);
|
||||||
|
this.context = context;
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MentionAutocompletePresenter(Context context, String roomToken) {
|
||||||
|
super(context);
|
||||||
|
this.roomToken = roomToken;
|
||||||
|
this.context = context;
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RecyclerView.Adapter instantiateAdapter() {
|
||||||
|
adapter = new FlexibleAdapter<>(userItemList, context, true);
|
||||||
|
adapter.addListener(this);
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onQuery(@Nullable CharSequence query) {
|
||||||
|
if (query != null && query.length() > 0) {
|
||||||
|
UserEntity currentUser = userUtils.getCurrentUser();
|
||||||
|
|
||||||
|
ncApi.getMentionAutocompleteSuggestions(ApiUtils.getCredentials(currentUser.getUserId(), currentUser
|
||||||
|
.getToken()), ApiUtils.getUrlForMentionSuggestions(currentUser.getBaseUrl(), roomToken),
|
||||||
|
query.toString(), null)
|
||||||
|
.subscribeOn(Schedulers.newThread())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(3)
|
||||||
|
.subscribe(new Observer<MentionOverall>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(Disposable d) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(MentionOverall mentionOverall) {
|
||||||
|
List<Mention> mentionsList = mentionOverall.getOcs().getData();
|
||||||
|
userItemList = new ArrayList<>();
|
||||||
|
if (mentionsList.size() == 1 && mentionsList.get(0).getId().equals(query.toString())) {
|
||||||
|
adapter.updateDataSet(userItemList, false);
|
||||||
|
clearRecycledPool();
|
||||||
|
} else {
|
||||||
|
for (Mention mention : mentionsList) {
|
||||||
|
userItemList.add(new MentionAutocompleteItem(mention.getId(), mention
|
||||||
|
.getLabel(), currentUser));
|
||||||
|
}
|
||||||
|
adapter.updateDataSet(userItemList, true);
|
||||||
|
clearRecycledPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
|
userItemList = new ArrayList<>();
|
||||||
|
adapter.updateDataSet(userItemList, false);
|
||||||
|
clearRecycledPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
userItemList = new ArrayList<>();
|
||||||
|
adapter.updateDataSet(userItemList, false);
|
||||||
|
clearRecycledPool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearRecycledPool() {
|
||||||
|
if (getRecyclerView() != null) {
|
||||||
|
getRecyclerView().getRecycledViewPool().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onItemClick(View view, int position) {
|
||||||
|
Mention mention = new Mention();
|
||||||
|
MentionAutocompleteItem mentionAutocompleteItem = (MentionAutocompleteItem) userItemList.get(position);
|
||||||
|
mention.setId(mentionAutocompleteItem.getUserId());
|
||||||
|
mention.setLabel(mentionAutocompleteItem.getDisplayName());
|
||||||
|
mention.setSource("users");
|
||||||
|
dispatchClick(mention);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -130,6 +130,10 @@ public class ApiUtils {
|
|||||||
return baseUrl + ocsApiVersion + spreedApiVersion + "/chat/" + token;
|
return baseUrl + ocsApiVersion + spreedApiVersion + "/chat/" + token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getUrlForMentionSuggestions(String baseUrl, String token) {
|
||||||
|
return getUrlForChat(baseUrl, token) + "/mentions";
|
||||||
|
}
|
||||||
|
|
||||||
public static String getUrlForSignaling(String baseUrl, @Nullable String token) {
|
public static String getUrlForSignaling(String baseUrl, @Nullable String token) {
|
||||||
String signalingUrl = baseUrl + ocsApiVersion + spreedApiVersion + "/signaling";
|
String signalingUrl = baseUrl + ocsApiVersion + spreedApiVersion + "/signaling";
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
|
@ -245,8 +245,7 @@ public class UserUtils {
|
|||||||
|
|
||||||
return dataStore.upsert(user)
|
return dataStore.upsert(user)
|
||||||
.toObservable()
|
.toObservable()
|
||||||
.subscribeOn(Schedulers.newThread())
|
.subscribeOn(Schedulers.newThread());
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
78
app/src/main/res/layout/rv_item_mention.xml
Normal file
78
app/src/main/res/layout/rv_item_mention.xml
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ @author Andy Scherzinger
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic
|
||||||
|
~ Copyright (C) 2017 Andy Scherzinger
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/item_height"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/frame_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="@dimen/activity_horizontal_margin">
|
||||||
|
|
||||||
|
<com.nextcloud.talk.utils.MagicFlipView
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/avatar_flip_view"
|
||||||
|
android:layout_width="@dimen/avatar_size"
|
||||||
|
android:layout_height="@dimen/avatar_size"
|
||||||
|
app:animationDuration="170"
|
||||||
|
app:checked="false"
|
||||||
|
app:enableInitialAnimation="false"
|
||||||
|
app:rearBackgroundColor="@color/colorPrimary"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linear_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginStart="@dimen/margin_between_elements"
|
||||||
|
android:layout_toEndOf="@id/frame_layout"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
tools:text="Call item text"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/secondary_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="A week ago"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
Loading…
Reference in New Issue
Block a user