Wenn die softwareseitige Tastatur öffnet, wird nur noch zu Position 0 gescrollt, wenn man da drauf oder drunter ist mit der unteren Kante des Textfeldes für die Nachricht.
This commit is contained in:
@@ -33,8 +33,8 @@ android {
|
||||
applicationId "de.beyondsoft.ownchat"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 27
|
||||
versionCode 16
|
||||
versionName "1.16"
|
||||
versionCode 18
|
||||
versionName "1.18"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
public Completable update(Iterable<Message> items, Specification specification) {
|
||||
final RealmWrapper realmWrapper = new RealmWrapper();
|
||||
MessageByIdSpecification realmSpecification = (MessageByIdSpecification) specification;
|
||||
|
||||
return Observable.from(items)
|
||||
.doOnSubscribe(() -> {
|
||||
realmWrapper.realm = mRealmProvider.provide();
|
||||
@@ -114,6 +115,7 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
public Observable<List<Message>> updateMessages(Iterable<Message> items, Specification specification) {
|
||||
final RealmWrapper realmWrapper = new RealmWrapper();
|
||||
MessageByIdSpecification realmSpecification = (MessageByIdSpecification) specification;
|
||||
|
||||
return Observable.from(items)
|
||||
.flatMapIterable((Func1<Message, Iterable<Message>>) message -> items)
|
||||
.map(mToRealmMapper::from)
|
||||
@@ -147,6 +149,7 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
public Completable remove(Specification specification) {
|
||||
RealmWrapper realmWrapper = new RealmWrapper();
|
||||
MessageByIdSpecification realmSpecification = (MessageByIdSpecification) specification;
|
||||
|
||||
return Observable.fromCallable(() -> realmSpecification.toRealmQuery(realmWrapper.realm).findFirst())
|
||||
.doOnSubscribe(() -> {
|
||||
realmWrapper.realm = mRealmProvider.provide();
|
||||
@@ -167,10 +170,8 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
@Override
|
||||
public Completable removeAll() {
|
||||
RealmWrapper realmWrapper = new RealmWrapper();
|
||||
return Observable.fromCallable((Callable<Void>) () -> {
|
||||
realmWrapper.realm.delete(MessageRealm.class);
|
||||
return null;
|
||||
})
|
||||
|
||||
return Observable.fromCallable((Callable<Void>) () -> { realmWrapper.realm.delete(MessageRealm.class); return null; })
|
||||
.doOnSubscribe(() -> {
|
||||
realmWrapper.realm = mRealmProvider.provide();
|
||||
realmWrapper.realm.beginTransaction();
|
||||
@@ -191,6 +192,7 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
RealmWrapper realmWrapper = new RealmWrapper();
|
||||
MessageByIdSpecification realmSpecification = (MessageByIdSpecification) specification;
|
||||
((MessageByIdSpecification) specification).setMessageId(id);
|
||||
|
||||
return Observable.fromCallable(() -> realmSpecification.toRealmQuery(realmWrapper.realm).findFirst())
|
||||
.map(mToMessageMapper::from)
|
||||
.doOnSubscribe(() -> {
|
||||
@@ -211,6 +213,7 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
public Observable<List<Message>> queryForAll(Specification specification) {
|
||||
RealmWrapper realmWrapper = new RealmWrapper();
|
||||
RealmSpecification<MessageRealm> realmSpecification = (RealmSpecification) specification;
|
||||
|
||||
return Observable.fromCallable(() -> realmSpecification.toRealmQuery(realmWrapper.realm)
|
||||
.findAll()
|
||||
.sort(MessageRealm.CREATED_AT, Sort.DESCENDING))
|
||||
@@ -230,5 +233,4 @@ public class MessageRealmRepository implements Repository<Message> {
|
||||
realmWrapper.realm.close();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public class MessageRealm extends RealmObject {
|
||||
public static final String CREATED_AT = "createdAt";
|
||||
public static final String USER_ID = "userId";
|
||||
public static final String MESSAGE = "message";
|
||||
public static final String FILENAME = "filename";
|
||||
|
||||
@PrimaryKey
|
||||
private String uniqueId;
|
||||
|
||||
@@ -23,8 +23,12 @@ public class MessagesByGroupAndSearchTextSpecification implements RealmSpecifica
|
||||
@Override
|
||||
public RealmQuery<MessageRealm> toRealmQuery(Realm realm) {
|
||||
return realm.where(MessageRealm.class)
|
||||
.contains(MessageRealm.MESSAGE, mSearchText, Case.INSENSITIVE)
|
||||
.equalTo(MessageRealm.GROUP_ID, mGroupId)
|
||||
.equalTo(MessageRealm.USER_ID, mUserId);
|
||||
.equalTo(MessageRealm.USER_ID, mUserId)
|
||||
.beginGroup()
|
||||
.contains(MessageRealm.MESSAGE, mSearchText, Case.INSENSITIVE)
|
||||
.or()
|
||||
.contains(MessageRealm.FILENAME, mSearchText, Case.INSENSITIVE)
|
||||
.endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import de.beyondsoft.ownchat.filepicker.models.Document;
|
||||
import de.beyondsoft.ownchat.filepicker.models.FileType;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.MediaStoreHelper;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.TabLayoutHelper;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.Utils;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.FilePickerUtils;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
@@ -146,6 +146,6 @@ public class DocPickerFragment extends BaseFragment {
|
||||
private ArrayList<Document> filterDocuments(final String[] type, List<Document> documents) {
|
||||
final Predicate<Document> docType = document -> document.isThisType(type);
|
||||
|
||||
return new ArrayList<>(Utils.filter(new HashSet<>(documents),docType));
|
||||
return new ArrayList<>(FilePickerUtils.filter(new HashSet<>(documents),docType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.beyondsoft.ownchat.filepicker.models;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import de.beyondsoft.ownchat.filepicker.utils.Utils;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.FilePickerUtils;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
@@ -42,7 +42,7 @@ public class BaseFile implements Parcelable {
|
||||
|
||||
public boolean isImage() {
|
||||
String[] types = {"jpg","jpeg","png","gif"};
|
||||
return Utils.contains(types, this.path);
|
||||
return FilePickerUtils.contains(types, this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,7 +2,7 @@ package de.beyondsoft.ownchat.filepicker.models;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.beyondsoft.ownchat.filepicker.utils.Utils;
|
||||
import de.beyondsoft.ownchat.filepicker.utils.FilePickerUtils;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
@@ -78,7 +78,7 @@ public class Document extends BaseFile {
|
||||
|
||||
public boolean isThisType(String[] types)
|
||||
{
|
||||
return Utils.contains(types, this.path);
|
||||
return FilePickerUtils.contains(types, this.path);
|
||||
}
|
||||
|
||||
public FileType getFileType()
|
||||
|
||||
@@ -12,18 +12,16 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
*/
|
||||
|
||||
public class Utils {
|
||||
public class FilePickerUtils {
|
||||
public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) {
|
||||
Collection<T> result = new ArrayList<T>();
|
||||
for (T element: target) {
|
||||
if (predicate.apply(element)) {
|
||||
Collection<T> result = new ArrayList<>();
|
||||
|
||||
for(T element : target) {
|
||||
if(predicate.apply(element)) {
|
||||
result.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -31,15 +29,16 @@ public class Utils {
|
||||
String name = file.getName();
|
||||
try {
|
||||
return name.substring(name.lastIndexOf(".") + 1);
|
||||
} catch (Exception e) {
|
||||
} catch(Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean contains(String[] types, String path) {
|
||||
for (String string : types) {
|
||||
if (path.toLowerCase().endsWith(string)) return true;
|
||||
for(String string : types) {
|
||||
if(path.toLowerCase().endsWith(string)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -59,15 +58,14 @@ public class Utils {
|
||||
widthHeight[WIDTH_INDEX] = size.x;
|
||||
widthHeight[HEIGHT_INDEX] = size.y;
|
||||
|
||||
if (!isScreenSizeRetrieved(widthHeight)) {
|
||||
if(!isScreenSizeRetrieved(widthHeight)) {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
display.getMetrics(metrics);
|
||||
widthHeight[0] = metrics.widthPixels;
|
||||
widthHeight[1] = metrics.heightPixels;
|
||||
}
|
||||
|
||||
// Last defense. Use deprecated API that was introduced in lower than API 13
|
||||
if (!isScreenSizeRetrieved(widthHeight)) {
|
||||
if(!isScreenSizeRetrieved(widthHeight)) {
|
||||
widthHeight[0] = display.getWidth(); // deprecated
|
||||
widthHeight[1] = display.getHeight(); // deprecated
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package de.beyondsoft.ownchat.filepicker.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.beyondsoft.ownchat.R;
|
||||
import de.beyondsoft.ownchat.filepicker.FilePickerConst;
|
||||
|
||||
/**
|
||||
* Created by Lyndon on 26-Oct-2017.
|
||||
*/
|
||||
|
||||
public class FileUtils {
|
||||
public static int getTypeDrawable(String path) {
|
||||
return R.drawable.document;
|
||||
}
|
||||
|
||||
public static FilePickerConst.FILE_TYPE getFileType(String path) {
|
||||
String fileExtension = Utils.getFileExtension(new File(path));
|
||||
if(TextUtils.isEmpty(fileExtension)) {
|
||||
return FilePickerConst.FILE_TYPE.UNKNOWN;
|
||||
}
|
||||
|
||||
if(isExcelFile(path)) {
|
||||
return FilePickerConst.FILE_TYPE.EXCEL;
|
||||
}
|
||||
|
||||
if(isDocFile(path)) {
|
||||
return FilePickerConst.FILE_TYPE.WORD;
|
||||
}
|
||||
|
||||
if(isPPTFile(path)) {
|
||||
return FilePickerConst.FILE_TYPE.PPT;
|
||||
}
|
||||
|
||||
if(isPDFFile(path)) {
|
||||
return FilePickerConst.FILE_TYPE.PDF;
|
||||
}
|
||||
|
||||
if(isTxtFile(path)) {
|
||||
return FilePickerConst.FILE_TYPE.TXT;
|
||||
} else {
|
||||
return FilePickerConst.FILE_TYPE.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isExcelFile(String path) {
|
||||
String[] types = {"xls","xlsx"};
|
||||
return Utils.contains(types, path);
|
||||
}
|
||||
|
||||
public static boolean isDocFile(String path) {
|
||||
String[] types = {"doc","docx", "dot","dotx"};
|
||||
return Utils.contains(types, path);
|
||||
}
|
||||
|
||||
public static boolean isPPTFile(String path) {
|
||||
String[] types = {"ppt","pptx"};
|
||||
return Utils.contains(types, path);
|
||||
}
|
||||
|
||||
public static boolean isPDFFile(String path) {
|
||||
String[] types = {"pdf"};
|
||||
return Utils.contains(types, path);
|
||||
}
|
||||
|
||||
public static boolean isTxtFile(String path) {
|
||||
String[] types = {"txt"};
|
||||
return Utils.contains(types, path);
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,8 @@ import android.view.ViewTreeObserver;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -71,6 +73,7 @@ import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -174,6 +177,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
private Rect mDialogContainer;
|
||||
private int mInitialLeft = 0;
|
||||
private int mInitialMarginLeft = 0;
|
||||
private int mCurrentVisibleItemPosition = -1;
|
||||
|
||||
@Inject
|
||||
@Named(AppPrefsConstants.CHAT_OPENED)
|
||||
@@ -193,12 +197,20 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mSendMessageImageView.setEnabled(false);
|
||||
InjectionHelper.getChatComponent(this).inject(this);
|
||||
mBaseChatAdapter = getAdapter();
|
||||
mEmptyLayout.setOnTryAgainClickListener(v -> mCallback.fetchMoreMessagesByGroupId());
|
||||
|
||||
mEmptyLayout.setOnTryAgainClickListener(v -> {
|
||||
mCallback.fetchMoreMessagesByGroupId();
|
||||
});
|
||||
|
||||
setupRecyclerView();
|
||||
|
||||
EmojIconActions emojiIcon = new EmojIconActions(this, mCoordinatorLayout, mChatMessageEmojiEditText, mEmojiButton);
|
||||
emojiIcon.ShowEmojIcon();
|
||||
|
||||
mChatMessageEmojiEditText.setOnClickListener(view -> {
|
||||
mCurrentVisibleItemPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition();
|
||||
});
|
||||
|
||||
showLoading();
|
||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
|
||||
@@ -218,10 +230,14 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mEndlessScrollListener = new EndlessScrollListener(VISIBLE_THRESHOLD, linearLayoutManager) {
|
||||
@Override
|
||||
public boolean onLoad() {
|
||||
if(mCallback == null || mCallback.isLoading()) {
|
||||
if(mCallback == null || mCallback.isLoading() || mIsSearching || mIsJumpingToMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsJumpingToMessage = false;
|
||||
|
||||
Log.e("SCROLLING_LOG", "Fetching messages in onLoad");
|
||||
|
||||
mCallback.fetchMoreMessagesByGroupId();
|
||||
return true;
|
||||
}
|
||||
@@ -253,15 +269,26 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
@Override
|
||||
public void messagesLoaded(ArrayList<Message> messages, boolean isFirstPage) {
|
||||
if(isFirstPage) {
|
||||
Log.d("SCROLLING_LOG", "messagesLoaded with first page");
|
||||
|
||||
mEndlessScrollListener.reset();
|
||||
mBaseChatAdapter.setMessages(messages);
|
||||
mRecyclerView.scrollToPosition(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("SCROLLING_LOG", "messagesLoaded");
|
||||
|
||||
mBaseChatAdapter.addMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messagesLoaded(ArrayList<Message> messages) {
|
||||
mEndlessScrollListener.reset();
|
||||
mBaseChatAdapter.setMessages(messages);
|
||||
}
|
||||
|
||||
private void shareFile(boolean isFile) {
|
||||
mIsComingFromSharingActivity.set(false);
|
||||
|
||||
@@ -336,7 +363,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
|
||||
@Override
|
||||
public void hideMessagesLoading() {
|
||||
isSearching = false;
|
||||
mIsSearching = false;
|
||||
|
||||
mBaseChatAdapter.setLoading(false);
|
||||
|
||||
@@ -695,6 +722,35 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mCallback.resendMessage(message, !TextUtils.isEmpty(message.filePath) ? getContentResolver().getType(Uri.parse(message.filePath)) : "");
|
||||
}
|
||||
|
||||
private boolean mIsJumpingToMessage;
|
||||
@Override
|
||||
public void jumpToMessage(Message message) {
|
||||
if(mChatSearchView.isIconified()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mChatPresenter.isAttached()) {
|
||||
mChatPresenter.attachView(this);
|
||||
}
|
||||
|
||||
Log.i("SCROLLING_LOG", "Jumping to message");
|
||||
mCallback.loadMessagesInContext(mGroup.id, message.createdAt, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollToMessage(Message message) {
|
||||
try {
|
||||
final int position = mBaseChatAdapter.getPosition(message);
|
||||
|
||||
mIsJumpingToMessage = true;
|
||||
|
||||
Log.i("SCROLLING_LOG", "About to scroll to position " + position);
|
||||
mRecyclerView.postDelayed(() -> mRecyclerView.smoothScrollToPosition(position), 350);
|
||||
} catch(Exception e) {
|
||||
Log.e("SCROLL_TO_MESSAGE", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaType getMediaType(Uri fileUri) {
|
||||
return MediaType.parse(getContentResolver().getType(fileUri));
|
||||
@@ -777,6 +833,8 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
|
||||
@Override
|
||||
public void addOneMessage(Message message) {
|
||||
Log.i("SCROLLING_LOG", "Adding message '" + message.message + "'");
|
||||
|
||||
mBaseChatAdapter.addMessage(message);
|
||||
|
||||
if(mEndlessScrollListener.getVisibleItem() == 0) {
|
||||
@@ -812,32 +870,39 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
}
|
||||
}
|
||||
|
||||
static int mAppHeight;
|
||||
private ViewTreeObserver.OnGlobalLayoutListener mKeyboardListener = new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
|
||||
private boolean mKeyboardShown = false;
|
||||
private int mPreviousHeight;
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
Rect r = new Rect();
|
||||
getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
|
||||
int screenHeight = getWindow().getDecorView().getHeight();
|
||||
int newHeight = mRecyclerView.getHeight();
|
||||
|
||||
// r.bottom is the position above soft keypad or device button.
|
||||
// if keypad is shown, the r.bottom is smaller than that before.
|
||||
int keypadHeight = screenHeight - r.bottom;
|
||||
if(mPreviousHeight == newHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(keypadHeight > screenHeight * 0.15 && !mKeyboardShown) { // 0.15 ratio is perhaps enough to determine keypad height.
|
||||
// keyboard is opened
|
||||
mRecyclerView.scrollToPosition(0);
|
||||
mKeyboardShown = true;
|
||||
} else {
|
||||
mKeyboardShown = false;
|
||||
mPreviousHeight = newHeight;
|
||||
|
||||
if(newHeight >= mAppHeight) {
|
||||
mAppHeight = newHeight;
|
||||
}
|
||||
|
||||
if(newHeight != 0) {
|
||||
if(mAppHeight > newHeight && mCurrentVisibleItemPosition <= 0) {
|
||||
mRecyclerView.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if(!mChatSearchView.isIconified()) {
|
||||
closeSearchView();
|
||||
return;
|
||||
}
|
||||
|
||||
mIsComingFromSharingActivity.set(false);
|
||||
mSelectedFilePath.delete();
|
||||
|
||||
@@ -866,20 +931,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSearching = false;
|
||||
|
||||
private String mSearchText;
|
||||
|
||||
@Override
|
||||
public String getSearchText() {
|
||||
return mSearchText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSearchText() {
|
||||
mSearchText = null;
|
||||
isSearching = false;
|
||||
}
|
||||
public boolean mIsSearching = false;
|
||||
|
||||
@Override
|
||||
public void showEmptySearchResultMessage(String text) {
|
||||
@@ -888,12 +940,12 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mEmptyLayout.setEmptyText(emptyText);
|
||||
mEmptyLayout.showEmpty();
|
||||
|
||||
isSearching = false;
|
||||
mIsSearching = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
if(isSearching && !TextUtils.isEmpty(newText)) {
|
||||
if(mIsSearching && !TextUtils.isEmpty(newText)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -906,14 +958,13 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mCallback.resetMessages();
|
||||
}
|
||||
|
||||
isSearching = true;
|
||||
mIsSearching = true;
|
||||
|
||||
if(TextUtils.isEmpty(newText)) {
|
||||
loadMessages();
|
||||
} else {
|
||||
mSearchText = newText;
|
||||
mBaseChatAdapter.setMessages(new ArrayList<>());
|
||||
|
||||
messagesLoaded(new ArrayList<>(), true);
|
||||
loadSearchResult(newText);
|
||||
}
|
||||
}, 300);
|
||||
@@ -927,4 +978,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
|
||||
mChatSearchView.setIconified(false);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void closeSearchView();
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
@@ -41,10 +42,11 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
|
||||
private long mUserId;
|
||||
|
||||
final ArrayList<Message> mMessages = new ArrayList<>();
|
||||
final ArrayList<Message> mMessages = new ArrayList<>();
|
||||
private final List<Integer> mDatePositions = new ArrayList<>();
|
||||
final List<Date> mDateList = new ArrayList<>();
|
||||
final List<Integer> mPositionOffset = new ArrayList<>();
|
||||
final List<Date> mDateList = new ArrayList<>();
|
||||
final List<Integer> mPositionOffset = new ArrayList<>();
|
||||
|
||||
private boolean mIsLoading;
|
||||
private int mLastOffset = 0;
|
||||
private Calendar mCurrentDay;
|
||||
@@ -64,6 +66,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
mDatePositions.clear();
|
||||
mDateList.clear();
|
||||
mPositionOffset.clear();
|
||||
|
||||
mIsLoading = false;
|
||||
mLastOffset = 0;
|
||||
mCurrentDay = Calendar.getInstance();
|
||||
@@ -80,6 +83,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
for(int i = 1; i < messageSize; i++) {
|
||||
mCurrentDay.setTimeInMillis(messages.get(i).createdAt);
|
||||
mLastDay.setTimeInMillis(messages.get(i - 1).createdAt);
|
||||
|
||||
if(mCurrentDay.get(Calendar.DAY_OF_YEAR) != mLastDay.get(Calendar.DAY_OF_YEAR)) {
|
||||
mDatePositions.add(i + mLastOffset);
|
||||
mPositionOffset.add(0);
|
||||
@@ -92,6 +96,12 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
}
|
||||
|
||||
mMessages.addAll(messages);
|
||||
|
||||
String[] messageTexts = new String[mMessages.size()];
|
||||
for(int i = 0; i < messageTexts.length; i++) {
|
||||
messageTexts[i] = mMessages.get(i).message;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -103,6 +113,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
int currentMessagesCount = mMessages.size();
|
||||
int lastOffsetBeforeParsing = mLastOffset;
|
||||
int datesInserted = 0;
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(messages.get(0).createdAt);
|
||||
|
||||
@@ -219,6 +230,25 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
}
|
||||
}
|
||||
|
||||
public int getPosition(Message message) {
|
||||
Log.d("MESSAGE_SCROLL", "message id: " + message.id);
|
||||
|
||||
int position = 0;
|
||||
|
||||
for(int i = 0; i < mMessages.size(); i++) {
|
||||
if(message.equals(mMessages.get(i))) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("MESSAGE_SCROLL", "position: " + position + "; offset: " + mPositionOffset.get(position));
|
||||
|
||||
position += mPositionOffset.get(position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mMessages.size() + mLastOffset + (mIsLoading ? 1 : 0);
|
||||
@@ -252,8 +282,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
return LOADING_TYPE;
|
||||
}
|
||||
|
||||
return mMessages.get(position - mPositionOffset.get(position)).senderId == mUserId ?
|
||||
RIGHT_CHAT_TYPE : LEFT_CHAT_TYPE;
|
||||
return mMessages.get(position - mPositionOffset.get(position)).senderId == mUserId ? RIGHT_CHAT_TYPE : LEFT_CHAT_TYPE;
|
||||
}
|
||||
|
||||
void setMessageClickListener(MessageClickListener messageClickListener) {
|
||||
@@ -405,11 +434,29 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
@BindView(R.id.chat_item_file_name)
|
||||
TextView filenameTextView;
|
||||
|
||||
@BindView(R.id.chat_item_container)
|
||||
RelativeLayout chatItemContainer;
|
||||
|
||||
MessageViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
@Optional
|
||||
@OnClick(R.id.chat_item_container)
|
||||
void jumpToMessage() {
|
||||
int currentPosition = getAdapterPosition();
|
||||
|
||||
int position = currentPosition - mPositionOffset.get(currentPosition);
|
||||
if(position >= mMessages.size()) {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
Message messageToJumpTo = mMessages.get(position);
|
||||
|
||||
mMessageClickListener.jumpToMessage(messageToJumpTo);
|
||||
}
|
||||
|
||||
@Optional
|
||||
@OnClick(R.id.chat_item_sending_failed)
|
||||
void retrySendingClicked() {
|
||||
@@ -471,5 +518,7 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||
void localFileClicked(Uri uri);
|
||||
|
||||
void resendMessage(Message message);
|
||||
|
||||
void jumpToMessage(Message message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import retrofit2.Retrofit;
|
||||
|
||||
/**
|
||||
* Created by imarneanu on 3/1/17.
|
||||
*/
|
||||
@Module
|
||||
public class ChatModule {
|
||||
|
||||
|
||||
@@ -303,17 +303,21 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
private void loadMessagesFromDBByGroupId() {
|
||||
MessageByGroupIdSpecification messageByGroupIdSpecification = new MessageByGroupIdSpecification(mUserIdPreference.get());
|
||||
messageByGroupIdSpecification.setGroupId(mGroupId);
|
||||
|
||||
mMessageRealmRepository.queryForAll(messageByGroupIdSpecification)
|
||||
.map(ArrayList::new)
|
||||
.compose(RxUtils.provideDefaultTransformer())
|
||||
.subscribe(this::loadMessagesFromDBSuccessful, this::loadMessagesError);
|
||||
}
|
||||
|
||||
private String mText;
|
||||
public void searchMessagesFromDBByGroupIdAndText(long groupId, String text) {
|
||||
MessagesByGroupAndSearchTextSpecification messagesByGroupAndSearchTextSpecification = new MessagesByGroupAndSearchTextSpecification(mUserIdPreference.get());
|
||||
messagesByGroupAndSearchTextSpecification.setGroupId(groupId);
|
||||
messagesByGroupAndSearchTextSpecification.setSearchText(text);
|
||||
|
||||
mText = text;
|
||||
|
||||
mMessageRealmRepository.queryForAll(messagesByGroupAndSearchTextSpecification)
|
||||
.map(ArrayList::new)
|
||||
.compose(RxUtils.provideDefaultTransformer())
|
||||
@@ -332,14 +336,9 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
getView().hideLoading();
|
||||
getView().hideMessagesLoading();
|
||||
|
||||
String searchText = getView().getSearchText();
|
||||
|
||||
getView().resetSearchText();
|
||||
|
||||
if(!mMessages.isEmpty()) {
|
||||
int endOffset = mOffset + LIMIT > mMessages.size() ? mMessages.size() : mOffset + LIMIT;
|
||||
if(mOffset > endOffset) {
|
||||
Log.i("", "");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -373,7 +372,92 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
return;
|
||||
}
|
||||
|
||||
getView().showEmptySearchResultMessage(searchText);
|
||||
getView().showEmptySearchResultMessage(mText);
|
||||
}
|
||||
|
||||
private Message mMessageToScrollTo;
|
||||
public void loadMessagesInContext(long groupId, long createdAt, Message messageToScrollTo) {
|
||||
MessageByGroupIdSpecification messageByGroupIdSpecification = new MessageByGroupIdSpecification(mUserIdPreference.get());
|
||||
messageByGroupIdSpecification.setGroupId(groupId);
|
||||
|
||||
mMessageToScrollTo = messageToScrollTo;
|
||||
|
||||
mMessageRealmRepository.queryForAll(messageByGroupIdSpecification)
|
||||
.map(ArrayList::new)
|
||||
.compose(RxUtils.provideDefaultTransformer())
|
||||
.subscribe(this::loadMessagesInContextSuccessful, this::loadMessagesError);
|
||||
}
|
||||
|
||||
private void loadMessagesInContextSuccessful(ArrayList<Message> messages) {
|
||||
if(!isAttached()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.w("SCROLLING_LOG" ,"Count of messages loaded: " + messages.size());
|
||||
|
||||
mMessages.clear();
|
||||
mMessages.addAll(messages);
|
||||
mLoading = false;
|
||||
|
||||
getView().hideLoading();
|
||||
getView().hideMessagesLoading();
|
||||
|
||||
if(!mMessages.isEmpty()) {
|
||||
int tempLimit = (LIMIT - 1) / 2;
|
||||
|
||||
int position = 0;
|
||||
mOffset = 0;
|
||||
for(Message message : mMessages) {
|
||||
if(message.equals(mMessageToScrollTo)) {
|
||||
position = mMessages.indexOf(message);
|
||||
}
|
||||
}
|
||||
|
||||
mOffset = position < tempLimit ? 0 : position - tempLimit;
|
||||
|
||||
int endOffset = mOffset + LIMIT > mMessages.size() ? mMessages.size() : mOffset + LIMIT;
|
||||
|
||||
if(mOffset > endOffset) {
|
||||
return;
|
||||
}
|
||||
|
||||
double pos = (double) position;
|
||||
double lim = (double) LIMIT;
|
||||
|
||||
mPage = (int) Math.ceil(pos / lim);
|
||||
boolean isFirstPage = mPage == FIRST_PAGE;
|
||||
|
||||
getView().messagesLoaded(new ArrayList<>(mMessages.subList(mOffset, endOffset)));
|
||||
|
||||
if(isFirstPage && mSystemUtils.isNetworkUnavailable()) {
|
||||
Message firstMessage = mMessages.get(0);
|
||||
Message message = new Message(firstMessage.id,
|
||||
firstMessage.groupId,
|
||||
firstMessage.createdAt / 1000,
|
||||
firstMessage.message,
|
||||
firstMessage.filePath,
|
||||
firstMessage.smallerImage,
|
||||
firstMessage.originalFilename,
|
||||
firstMessage.uri,
|
||||
firstMessage.senderId,
|
||||
firstMessage.senderName,
|
||||
firstMessage.senderAvatar,
|
||||
firstMessage.status,
|
||||
true,
|
||||
firstMessage.userId,
|
||||
firstMessage.fileDownloaded);
|
||||
storeGroupLocally(mGroupId, message);
|
||||
}
|
||||
|
||||
//mPage++;
|
||||
mOffset += LIMIT;
|
||||
|
||||
getView().scrollToMessage(mMessageToScrollTo);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
getView().showEmptyMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,6 +477,9 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
|
||||
if(!mMessages.isEmpty()) {
|
||||
int endOffset = mOffset + LIMIT > mMessages.size() ? mMessages.size() : mOffset + LIMIT;
|
||||
|
||||
LogFetchingInformation(mOffset, endOffset, LIMIT, mMessages.size());
|
||||
|
||||
if(mOffset > endOffset) {
|
||||
return;
|
||||
}
|
||||
@@ -447,6 +534,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
public void fetchMoreMessagesByGroupId() {
|
||||
if(mMessages.size() < 25) {
|
||||
getView().hideMessagesLoading();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -461,6 +549,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
if(mSystemUtils.isNetworkUnavailable()) {
|
||||
loadMessagesFromDBByGroupId();
|
||||
getView().showError(R.string.error_no_internet_connection);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1160,4 +1249,20 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
|
||||
private static String generateRandomId() {
|
||||
return "_" + new Random().nextInt();
|
||||
}
|
||||
|
||||
private static void LogFetchingInformation(int offset, int endOffset, int limit, int messageCollectionSize) {
|
||||
Log.i("FETCHING_INFORMATION", "\n-" +
|
||||
"\nOffset: " + offset +
|
||||
"\nEnd offset: " + endOffset +
|
||||
"\nNumber of messages: " + messageCollectionSize +
|
||||
"\nLimit: " + limit +
|
||||
"\noffset > end offset: " + (offset > endOffset)
|
||||
);
|
||||
}
|
||||
|
||||
private static void LogMessageCollection(List<Message> messages) {
|
||||
for(int i = 0; i < messages.size(); i++) {
|
||||
Log.d("MESSAGES_LOG", String.format("%03d", i) + " " + messages.get(i).id + ": " + (messages.get(i).message == null ? messages.get(i).originalFilename : messages.get(i).message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,14 @@ import java.util.ArrayList;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
|
||||
/**
|
||||
* Created by Rares Teodorescu on 21/02/2017.
|
||||
*/
|
||||
interface ChatView extends MVPView {
|
||||
|
||||
void setCallback(Callback callback);
|
||||
|
||||
void messagesLoaded(ArrayList<Message> messages, boolean isFirstPage);
|
||||
|
||||
void messagesLoaded(ArrayList<Message> messages);
|
||||
|
||||
void showLoading();
|
||||
|
||||
void hideLoading();
|
||||
@@ -57,11 +56,10 @@ interface ChatView extends MVPView {
|
||||
|
||||
void showEmptySearchResultMessage(String searchText);
|
||||
|
||||
String getSearchText();
|
||||
|
||||
void resetSearchText();
|
||||
void scrollToMessage(Message message);
|
||||
|
||||
interface Callback {
|
||||
void loadMessagesInContext(long groupId, long createdAt, Message messageToExclude);
|
||||
|
||||
void loadMessagesFromServerByGroupId(long groupId);
|
||||
|
||||
|
||||
@@ -195,4 +195,11 @@ public class GroupChatActivity extends BaseChatActivity {
|
||||
|
||||
cancelNotification();
|
||||
}
|
||||
|
||||
public void closeSearchView() {
|
||||
mGroupMembersTextView.setVisibility(View.VISIBLE);
|
||||
mGroupTitleTextView.setVisibility(View.VISIBLE);
|
||||
mChatImageView.setVisibility(View.VISIBLE);
|
||||
mChatSearchView.setIconified(true);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,8 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
@@ -201,4 +199,10 @@ public class SingleChatActivity extends BaseChatActivity {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void closeSearchView() {
|
||||
mSingleChatTitleTextView.setVisibility(View.VISIBLE);
|
||||
mChatImageView.setVisibility(View.VISIBLE);
|
||||
mChatSearchView.setIconified(true);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import de.beyondsoft.ownchat.model.Message;
|
||||
import de.beyondsoft.ownchat.utils.DateUtils;
|
||||
import de.beyondsoft.ownchat.utils.ui.ViewUtils;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -19,8 +20,9 @@ class SingleChatAdapter extends BaseChatAdapter {
|
||||
super(userId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
if(viewType == LEFT_CHAT_TYPE) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_chat_left, parent, false);
|
||||
|
||||
@@ -49,7 +51,7 @@ class SingleChatAdapter extends BaseChatAdapter {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||
int viewType = getItemViewType(position);
|
||||
switch(viewType) {
|
||||
case LOADING_TYPE:
|
||||
@@ -91,5 +93,4 @@ class SingleChatAdapter extends BaseChatAdapter {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package de.beyondsoft.ownchat.utils;
|
||||
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
|
||||
public abstract class EndlessScrollListener extends RecyclerView.OnScrollListener {
|
||||
|
||||
private int mPreviousTotal = 0;
|
||||
private int mVisibleThreshold = 5;
|
||||
private int mVisibleThreshold;
|
||||
private boolean mLoading = false;
|
||||
private final LinearLayoutManager mLayoutManager;
|
||||
private int mVisibleItem;
|
||||
@@ -37,6 +38,8 @@ public abstract class EndlessScrollListener extends RecyclerView.OnScrollListene
|
||||
return;
|
||||
}
|
||||
|
||||
Log.e("SCROLLING_LOG", "Scrolling " + (dy < 0 ? "up" : "down"));
|
||||
|
||||
recyclerView.post(() -> {
|
||||
if(!mLoading && (totalItemCount - visibleItemCount) <= (mVisibleItem + mVisibleThreshold)) {
|
||||
mLoading = onLoad();
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package de.beyondsoft.ownchat.utils.ui;
|
||||
|
||||
import de.beyondsoft.ownchat.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
@@ -13,12 +10,8 @@ import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import de.beyondsoft.ownchat.R;
|
||||
|
||||
/**
|
||||
* Helper methods for view related classes
|
||||
* <p>
|
||||
* Created by BoldijarPaul on 03/08/16.
|
||||
*/
|
||||
public abstract class ViewUtils {
|
||||
|
||||
private ViewUtils() {
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
tools:src="@drawable/avatar" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/chat_item_container"
|
||||
style="@style/LeftChatItemRelativeLayout"
|
||||
android:padding="7dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_toEndOf="@id/chat_item_contact_image"
|
||||
>
|
||||
android:padding="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chat_item_time"
|
||||
@@ -38,7 +38,7 @@
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp"
|
||||
tools:text="Sasha Grey | 15:23"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/chat_item_file"
|
||||
@@ -70,14 +70,13 @@
|
||||
android:id="@+id/chat_item_progress"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="90dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@id/chat_item_time"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:visibility="gone"
|
||||
custom:donut_finished_color="@color/colorDefault"
|
||||
custom:donut_text_color="@color/colorBlack"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<hani.momanii.supernova_emoji_library.Helper.EmojiconTextView
|
||||
android:id="@+id/chat_item_message"
|
||||
|
||||
@@ -22,12 +22,13 @@
|
||||
tools:src="@drawable/avatar" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/chat_item_container"
|
||||
style="@style/RightChatItemRelativeLayout"
|
||||
android:padding="7dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_toEndOf="@id/chat_item_contact_image">
|
||||
android:layout_toEndOf="@id/chat_item_contact_image"
|
||||
android:padding="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chat_item_sending_failed"
|
||||
@@ -53,7 +54,7 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_toEndOf="@+id/chat_item_time"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/chat_item_message_status"
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/chat_item_container"
|
||||
style="@style/LeftChatItemRelativeLayout"
|
||||
android:padding="7dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chat_item_time"
|
||||
@@ -59,7 +60,7 @@
|
||||
android:visibility="gone"
|
||||
custom:donut_finished_color="@color/colorDefault"
|
||||
custom:donut_text_color="@color/colorBlack"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<hani.momanii.supernova_emoji_library.Helper.EmojiconTextView
|
||||
android:id="@+id/chat_item_message"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
android:paddingStart="0dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/chat_item_container"
|
||||
style="@style/RightChatItemRelativeLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -46,7 +47,6 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/chat_item_message_status"
|
||||
tools:src="@drawable/delivered"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/chat_item_time"
|
||||
@@ -55,8 +55,8 @@
|
||||
android:layout_toEndOf="@+id/chat_item_time"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
tools:src="@drawable/delivered"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chat_item_time"
|
||||
@@ -93,7 +93,7 @@
|
||||
android:visibility="gone"
|
||||
custom:donut_finished_color="@color/colorWhite"
|
||||
custom:donut_text_color="@color/colorWhite"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chat_item_file_name"
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
<item name="android:textColorPrimary">@color/colorBlack</item>
|
||||
<!--This line changes the color of icons in toolbar (back, overflow menu icons)-->
|
||||
<item name="android:textColorSecondary">@color/colorBlack</item>
|
||||
<item name="colorAccent">@color/colorBlack</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user