mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 12:09:45 +01:00
parent
013e60af1b
commit
189a73975b
@ -17,8 +17,8 @@ android {
|
||||
targetSdkVersion 28
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 80
|
||||
versionName "3.2.1"
|
||||
versionCode 81
|
||||
versionName "3.2.2"
|
||||
|
||||
flavorDimensions "default"
|
||||
renderscriptTargetApi 19
|
||||
@ -123,7 +123,7 @@ dependencies {
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
|
||||
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
implementation 'androidx.multidex:multidex:2.0.0'
|
||||
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.2"
|
||||
@ -195,7 +195,7 @@ dependencies {
|
||||
|
||||
implementation 'com.github.mario:chatkit:d63d61db95'
|
||||
|
||||
implementation 'com.otaliastudios:autocomplete:1.1.0'
|
||||
implementation 'com.github.natario1:Autocomplete:v1.1.0'
|
||||
|
||||
implementation 'com.github.Kennyc1012:BottomSheet:2.4.1'
|
||||
implementation 'eu.davidea:flipview:1.2.0'
|
||||
|
@ -36,18 +36,14 @@ import android.text.InputFilter;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import autodagger.AutoInjector;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
@ -74,17 +70,13 @@ import com.nextcloud.talk.models.json.rooms.Conversation;
|
||||
import com.nextcloud.talk.models.json.rooms.RoomOverall;
|
||||
import com.nextcloud.talk.models.json.rooms.RoomsOverall;
|
||||
import com.nextcloud.talk.presenters.MentionAutocompletePresenter;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
import com.nextcloud.talk.utils.KeyboardUtils;
|
||||
import com.nextcloud.talk.utils.NotificationUtils;
|
||||
import com.nextcloud.talk.utils.*;
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||
import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder;
|
||||
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.models.IMessage;
|
||||
import com.stfalcon.chatkit.messages.MessageHolders;
|
||||
@ -100,32 +92,19 @@ import com.vanniktech.emoji.listeners.OnEmojiClickListener;
|
||||
import com.vanniktech.emoji.listeners.OnEmojiPopupDismissListener;
|
||||
import com.vanniktech.emoji.listeners.OnEmojiPopupShownListener;
|
||||
import com.webianks.library.PopupBubble;
|
||||
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import autodagger.AutoInjector;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.parceler.Parcels;
|
||||
import retrofit2.HttpException;
|
||||
import retrofit2.Response;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication.class)
|
||||
public class ChatController extends BaseController implements MessagesListAdapter.OnLoadMoreListener,
|
||||
MessagesListAdapter.Formatter<Date>, MessagesListAdapter.OnMessageLongClickListener, MessageHolders.ContentChecker {
|
||||
@ -406,7 +385,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
||||
if (s.length() == 1000) {
|
||||
messageInput.setError(getResources().getString(R.string.nc_limit_hit));
|
||||
} else {
|
||||
messageInput.setError(null);
|
||||
messageInput.setError(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,11 +438,11 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
||||
AutocompletePresenter<Mention> presenter = new MentionAutocompletePresenter(getApplicationContext(), roomToken);
|
||||
AutocompleteCallback<Mention> callback = new MentionAutocompleteCallback();
|
||||
|
||||
if (mentionAutocomplete != null) {
|
||||
if (mentionAutocomplete == null && messageInput != null) {
|
||||
mentionAutocomplete = Autocomplete.<Mention>on(messageInput)
|
||||
.with(elevation)
|
||||
.with(backgroundDrawable)
|
||||
.with(new CharPolicy('@'))
|
||||
.with(new MagicCharPolicy('@'))
|
||||
.with(presenter)
|
||||
.with(callback)
|
||||
.build();
|
||||
|
@ -21,9 +21,10 @@
|
||||
package com.nextcloud.talk.presenters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import autodagger.AutoInjector;
|
||||
import com.nextcloud.talk.adapters.items.MentionAutocompleteItem;
|
||||
import com.nextcloud.talk.api.NcApi;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
@ -33,15 +34,6 @@ 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 androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import autodagger.AutoInjector;
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||
import io.reactivex.Observer;
|
||||
@ -49,6 +41,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication.class)
|
||||
public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention> implements FlexibleAdapter.OnItemClickListener {
|
||||
@Inject
|
||||
@ -90,57 +86,61 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention>
|
||||
|
||||
@Override
|
||||
protected void onQuery(@Nullable CharSequence query) {
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
|
||||
adapter.setFilter(query.toString());
|
||||
ncApi.getMentionAutocompleteSuggestions(ApiUtils.getCredentials(currentUser.getUsername(), 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();
|
||||
|
||||
if (mentionsList.size() == 0) {
|
||||
adapter.clear();
|
||||
} else {
|
||||
List<AbstractFlexibleItem> internalAbstractFlexibleItemList = new ArrayList<>();
|
||||
for (Mention mention : mentionsList) {
|
||||
internalAbstractFlexibleItemList.add(
|
||||
new MentionAutocompleteItem(mention.getId(), mention.getLabel(),
|
||||
currentUser));
|
||||
}
|
||||
|
||||
if (adapter.getItemCount() != 0) {
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
adapter.updateDataSet(internalAbstractFlexibleItemList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
String queryString;
|
||||
if (query != null && query.length() > 1) {
|
||||
queryString = String.valueOf(query.subSequence(1, query.length()));
|
||||
} else {
|
||||
adapter.clear();
|
||||
queryString = "";
|
||||
}
|
||||
|
||||
adapter.setFilter(queryString);
|
||||
ncApi.getMentionAutocompleteSuggestions(ApiUtils.getCredentials(currentUser.getUsername(), currentUser
|
||||
.getToken()), ApiUtils.getUrlForMentionSuggestions(currentUser.getBaseUrl(), roomToken),
|
||||
queryString, 5)
|
||||
.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();
|
||||
|
||||
if (mentionsList.size() == 0) {
|
||||
adapter.clear();
|
||||
} else {
|
||||
List<AbstractFlexibleItem> internalAbstractFlexibleItemList = new ArrayList<>();
|
||||
for (Mention mention : mentionsList) {
|
||||
internalAbstractFlexibleItemList.add(
|
||||
new MentionAutocompleteItem(mention.getId(), mention.getLabel(),
|
||||
currentUser));
|
||||
}
|
||||
|
||||
if (adapter.getItemCount() != 0) {
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
adapter.updateDataSet(internalAbstractFlexibleItemList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onItemClick(View view, int position) {
|
||||
Mention mention = new Mention();
|
||||
|
113
app/src/main/java/com/nextcloud/talk/utils/MagicCharPolicy.java
Normal file
113
app/src/main/java/com/nextcloud/talk/utils/MagicCharPolicy.java
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.otaliastudios.autocomplete.AutocompletePolicy;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MagicCharPolicy implements AutocompletePolicy {
|
||||
|
||||
private final char character;
|
||||
|
||||
public MagicCharPolicy(char character) {
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
private int[] checkText(Spannable text, int cursorPos) {
|
||||
if (text.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int[] span = new int[2];
|
||||
Pattern pattern = Pattern.compile("@.*\\w*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
|
||||
while (matcher.find()) {
|
||||
if (cursorPos >= matcher.start() && cursorPos <= matcher.end()) {
|
||||
span[0] = matcher.start();
|
||||
span[1] = matcher.end();
|
||||
if (text.subSequence(matcher.start(), matcher.end()).charAt(0) == character) {
|
||||
return span;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldShowPopup(Spannable text, int cursorPos) {
|
||||
int[] show = checkText(text, cursorPos);
|
||||
if (show != null) {
|
||||
text.setSpan(new QuerySpan(), show[0], show[1], Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDismissPopup(Spannable text, int cursorPos) {
|
||||
return checkText(text, cursorPos) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getQuery(Spannable text) {
|
||||
QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class);
|
||||
if (span == null || span.length == 0) {
|
||||
// Should never happen.
|
||||
return "";
|
||||
}
|
||||
QuerySpan sp = span[0];
|
||||
return text.subSequence(text.getSpanStart(sp), text.getSpanEnd(sp));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDismiss(Spannable text) {
|
||||
// Remove any span added by shouldShow. Should be useless, but anyway.
|
||||
QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class);
|
||||
for (QuerySpan s : span) {
|
||||
text.removeSpan(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static class QuerySpan {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static int[] getQueryRange(Spannable text) {
|
||||
QuerySpan[] span = text.getSpans(0, text.length(), QuerySpan.class);
|
||||
if (span == null || span.length == 0) return null;
|
||||
if (span.length > 1) {
|
||||
// Do absolutely nothing
|
||||
}
|
||||
QuerySpan sp = span[0];
|
||||
return new int[]{text.getSpanStart(sp), text.getSpanEnd(sp)};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user