Merge branch 'master' of ssh://float.beyondsoft.de/git/beyondSoft/Chat

This commit is contained in:
Christian
2017-12-11 14:33:06 +01:00
35 changed files with 454 additions and 198 deletions

View File

@@ -9,7 +9,7 @@ buildscript {
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
classpath 'io.fabric.tools:gradle:1.25.0'
}
}
@@ -34,9 +34,10 @@ android {
applicationId "de.beyondsoft.ownchat"
minSdkVersion 19
targetSdkVersion 26
versionCode 6
versionName "1.6"
versionCode 11
versionName "1.11"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
signingConfigs {
@@ -51,6 +52,7 @@ android {
buildTypes {
debug {
ext.enableCrashlytics = false
minifyEnabled = false
}
release {
@@ -111,7 +113,7 @@ dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.scottyab:secure-preferences-lib:0.1.4'
compile 'com.google.firebase:firebase-messaging:11.4.2'
compile 'com.google.firebase:firebase-messaging:11.6.2'
compile 'hani.momanii.supernova_emoji_library:supernova-emoji-library:0.0.2'
compile 'com.github.lzyzsd:circleprogress:1.2.1'
compile 'org.greenrobot:eventbus:3.0.0'
@@ -136,4 +138,4 @@ task adp2upload(type: Exec, dependsOn: "build") {
commandLine 'upload_build.sh', "-c", "$channel", "-v", "$versionCode", "-p", "android", "-a", "$slug", "-f", "$file", "-i", "$identifier", "-n", "$notes"
}
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.gms.google-services'

View File

@@ -22,6 +22,7 @@ import io.realm.Realm;
public class BewoplanerApplication extends Application {
private ApplicationComponent mApplicationComponent;
private static Context mContext;
@Override
public void onCreate() {
@@ -33,6 +34,8 @@ public class BewoplanerApplication extends Application {
Fabric.with(this, new Crashlytics());
}
mContext = getApplicationContext();
buildGraphAndInject();
MessagingInstanceIdService.setApplicationContext(this);
@@ -69,4 +72,7 @@ public class BewoplanerApplication extends Application {
buildGraphAndInject();
}
public static Context getAppContext() {
return mContext;
}
}

View File

@@ -1,7 +1,11 @@
package de.beyondsoft.ownchat.data.repository;
import android.util.Log;
import de.beyondsoft.ownchat.BewoplanerApplication;
import de.beyondsoft.ownchat.data.repository.mapper.Mapper;
import de.beyondsoft.ownchat.data.repository.models.GroupRealm;
import de.beyondsoft.ownchat.data.repository.models.MessageRealm;
import de.beyondsoft.ownchat.data.repository.models.UserRealm;
import de.beyondsoft.ownchat.data.repository.specifications.GroupByIdSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.RealmSpecification;
@@ -10,15 +14,18 @@ import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.model.User;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.Callable;
import io.realm.RealmList;
import io.realm.RealmResults;
import io.realm.Sort;
import rx.Completable;
import rx.Observable;
import rx.functions.Func1;
/**
* Created by imarneanu on 3/6/17.
@@ -29,9 +36,7 @@ public class GroupRealmRepository implements Repository<Group> {
private final Mapper<Group, GroupRealm> mToRealmMapper;
private final Mapper<GroupRealm, Group> mToGroupMapper;
public GroupRealmRepository(RealmProvider realmProvider,
Mapper<Group, GroupRealm> toRealmMapper,
Mapper<GroupRealm, Group> toMessageMapper) {
public GroupRealmRepository(RealmProvider realmProvider, Mapper<Group, GroupRealm> toRealmMapper, Mapper<GroupRealm, Group> toMessageMapper) {
mRealmProvider = realmProvider;
mToRealmMapper = toRealmMapper;
mToGroupMapper = toMessageMapper;
@@ -70,11 +75,11 @@ public class GroupRealmRepository implements Repository<Group> {
.map(mToRealmMapper::from)
.doOnNext(newGroup -> {
realmSpecification.setGroupId(newGroup.getId());
GroupRealm groupToUpdate =
realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
GroupRealm groupToUpdate = realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
if (groupToUpdate != null) {
newGroup.setUniqueId(groupToUpdate.getUniqueId());
}
realmWrapper.realm.copyToRealmOrUpdate(newGroup);
})
.doOnError(throwable -> {
@@ -91,7 +96,93 @@ public class GroupRealmRepository implements Repository<Group> {
@Override
public Completable update(Iterable<Group> items, Specification specification) {
final RealmWrapper realmWrapper = new RealmWrapper();
GroupByIdSpecification realmSpecification = (GroupByIdSpecification) specification;
ArrayList<Group> newGroups = (ArrayList<Group>) items;
ArrayList<Long> newUserIds = new ArrayList<>();
ArrayList<Long> oldUserIds = new ArrayList<>();
ArrayList<Long> userIdsToDelete = new ArrayList<>();
Long myself = ((GroupByIdSpecification) specification).getUserId();
if(newGroups.size() > 0) {
newUserIds = getUserIdsFromGroups(newGroups, myself);
}
int itemsSize = newGroups.size();
Long[] ids = new Long[itemsSize];
for(int i = 0; i < ids.length; i++) {
ids[i] = newGroups.get(i).id;
}
List<String> filePaths = new ArrayList<>();
boolean hasGroupsToDelete = false;
boolean hasMessagesToDelete = false;
try {
realmWrapper.realm = mRealmProvider.provide();
realmWrapper.realm.beginTransaction();
RealmResults<GroupRealm> allWhoAreNotComingFromTheServer = realmWrapper.realm.where(GroupRealm.class).not().in(GroupRealm.ID, ids).findAll();
RealmResults<MessageRealm> messagesToDelete = realmWrapper.realm.where(MessageRealm.class).not().in(MessageRealm.GROUP_ID, ids).findAll();
RealmResults<GroupRealm> allOldGroups = realmWrapper.realm.where(GroupRealm.class).findAll();
for(GroupRealm groupRealm : allOldGroups) {
for(UserRealm userRealm : groupRealm.getUserIdList()) {
oldUserIds.add(userRealm.getId());
}
}
for(Long id : oldUserIds) {
if(!newUserIds.contains(id) && !Objects.equals(id, myself) && !userIdsToDelete.contains(id)) {
userIdsToDelete.add(id);
}
}
for(MessageRealm mr : messagesToDelete) {
if(mr.isFileDownloaded()) {
filePaths.add(mr.getFilePath());
}
}
hasGroupsToDelete = allWhoAreNotComingFromTheServer.size() > 0;
hasMessagesToDelete = messagesToDelete.size() > 0;
realmWrapper.realm.commitTransaction();
realmWrapper.realm.close();
} catch(Exception e) {
RealmTransactionLog(e.getMessage(), 2);
realmWrapper.realm.cancelTransaction();
realmWrapper.realm.close();
}
if(hasGroupsToDelete) {
removeGroupsByIds(ids);
}
if(userIdsToDelete.size() > 0) {
removeUsersByIds(userIdsToDelete.toArray(new Long[userIdsToDelete.size()]));
}
if(hasMessagesToDelete) {
removeMessagesByGroupIds(ids);
for (String path : filePaths) {
String[] splitFileName = path.split("/");
String fileName = splitFileName[splitFileName.length - 1];
File fileToDelete = new File(BewoplanerApplication.getAppContext().getExternalFilesDir(null), File.separator + fileName);
boolean fileExists = fileToDelete.exists();
if(fileExists) {
fileToDelete.delete();
}
}
}
return Observable.from(items)
.doOnSubscribe(() -> {
realmWrapper.realm = mRealmProvider.provide();
@@ -100,24 +191,24 @@ public class GroupRealmRepository implements Repository<Group> {
.map(mToRealmMapper::from)
.doOnNext(newGroup -> {
realmSpecification.setGroupId(newGroup.getId());
GroupRealm groupToUpdate =
realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
GroupRealm groupToUpdate = realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
if (groupToUpdate != null) {
if (newGroup.getMessage() != null && groupToUpdate.getMessage() != null &&
newGroup.getMessage().getCreatedAt() < groupToUpdate.getMessage().getCreatedAt()) {
if (newGroup.getMessage() != null && groupToUpdate.getMessage() != null && newGroup.getMessage().getCreatedAt() < groupToUpdate.getMessage().getCreatedAt()) {
return;
}
newGroup.setUniqueId(groupToUpdate.getUniqueId());
if (groupToUpdate.getMessage() != null
&& newGroup.getMessage() != null
&& groupToUpdate.getMessage().getUniqueId().equals(newGroup.getMessage().getUniqueId())
&& groupToUpdate.getMessage().isRead()) {
if (groupToUpdate.getMessage() != null && newGroup.getMessage() != null && groupToUpdate.getMessage().getUniqueId().equals(newGroup.getMessage().getUniqueId()) && groupToUpdate.getMessage().isRead()) {
newGroup.getMessage().setRead(true);
}
}
realmWrapper.realm.copyToRealmOrUpdate(newGroup);
})
.doOnError(throwable -> {
RealmTransactionLog(String.format(Locale.getDefault(), "Error while updating groups: %s", throwable.getMessage()), 2);
realmWrapper.realm.cancelTransaction();
realmWrapper.realm.close();
})
@@ -128,6 +219,99 @@ public class GroupRealmRepository implements Repository<Group> {
.toCompletable();
}
private ArrayList<Long> getUserIdsFromGroups(ArrayList<Group> groups, long myself) {
ArrayList<Long> userIds = new ArrayList<>();
for(Group group : groups) {
for(User user : group.users) {
if(user.id == myself) {
continue;
}
userIds.add(user.id);
}
}
return userIds;
}
private void RealmTransactionLog(String message, int mode) {
final String tag = "REALM_TRANSACTION";
switch(mode) {
case 0:
Log.d(tag, message);
break;
case 1:
Log.i(tag, message);
break;
case 2:
Log.e(tag, message);
break;
default:
Log.wtf(tag, message);
break;
}
}
private void removeGroupsByIds(Long[] groupIds) {
final RealmWrapper realmWrapper = new RealmWrapper();
try {
realmWrapper.realm = mRealmProvider.provide();
realmWrapper.realm.beginTransaction();
realmWrapper.realm.where(GroupRealm.class).not().in(GroupRealm.ID, groupIds).findAll().deleteAllFromRealm();
realmWrapper.realm.commitTransaction();
realmWrapper.realm.close();
} catch(Exception e) {
Log.e("REALM_TRANSACTION", "Error while removing groups: " + e.getMessage());
realmWrapper.realm.cancelTransaction();
realmWrapper.realm.close();
}
}
private void removeMessagesByGroupIds(Long[] groupIds) {
final RealmWrapper realmWrapper = new RealmWrapper();
try {
realmWrapper.realm = mRealmProvider.provide();
realmWrapper.realm.beginTransaction();
realmWrapper.realm.where(MessageRealm.class).not().in(MessageRealm.GROUP_ID, groupIds).findAll().deleteAllFromRealm();
realmWrapper.realm.commitTransaction();
realmWrapper.realm.close();
} catch(Exception e) {
Log.e("REALM_TRANSACTION", "Error while removing messages from removed groups: " + e.getMessage());
realmWrapper.realm.cancelTransaction();
realmWrapper.realm.close();
}
}
private void removeUsersByIds(Long[] userIds) {
final RealmWrapper realmWrapper = new RealmWrapper();
try {
realmWrapper.realm = mRealmProvider.provide();
realmWrapper.realm.beginTransaction();
realmWrapper.realm.where(UserRealm.class).in(UserRealm.ID, userIds).findAll().deleteAllFromRealm();
realmWrapper.realm.commitTransaction();
realmWrapper.realm.close();
} catch(Exception e) {
Log.e("REALM_TRANSACTION", "Error while removing users: " + e.getMessage());
realmWrapper.realm.cancelTransaction();
realmWrapper.realm.close();
}
}
@Override
public Completable remove(Specification specification) {
return null;
@@ -136,12 +320,10 @@ public class GroupRealmRepository implements Repository<Group> {
@Override
public Completable removeAll() {
RealmWrapper realmWrapper = new RealmWrapper();
return Observable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
realmWrapper.realm.delete(GroupRealm.class);
return null;
}
return Observable.fromCallable((Callable<Void>) () -> {
realmWrapper.realm.delete(GroupRealm.class);
return null;
})
.doOnSubscribe(() -> {
realmWrapper.realm = mRealmProvider.provide();
@@ -183,15 +365,11 @@ public class GroupRealmRepository implements Repository<Group> {
public Observable<List<Group>> queryForAll(Specification specification) {
RealmWrapper realmWrapper = new RealmWrapper();
RealmSpecification<GroupRealm> realmSpecification = (RealmSpecification) specification;
return Observable.fromCallable(() -> realmSpecification.toRealmQuery(realmWrapper.realm)
.findAllSorted(GroupRealm.CREATED_AT, Sort.DESCENDING))
.flatMapIterable(groupsRealms -> groupsRealms)
.flatMap(new Func1<GroupRealm, Observable<Group>>() {
@Override
public Observable<Group> call(GroupRealm groupRealm) {
return Observable.just(mToGroupMapper.from(groupRealm));
}
})
.flatMap(groupRealm -> Observable.just(mToGroupMapper.from(groupRealm)))
.toList()
.doOnSubscribe(() -> {
realmWrapper.realm = mRealmProvider.provide();
@@ -218,29 +396,33 @@ public class GroupRealmRepository implements Repository<Group> {
.map(mToRealmMapper::from)
.doOnNext(newGroup -> {
realmSpecification.setGroupId(newGroup.getId());
GroupRealm groupToUpdate =
realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
GroupRealm groupToUpdate = realmSpecification.toRealmQuery(realmWrapper.realm).findFirst();
if (groupToUpdate == null) {
return;
}
if (groupToUpdate.getMessage() != null &&
group.lastMessage.createdAt < (groupToUpdate.getMessage().getCreatedAt() / 1000)) {
if (groupToUpdate.getMessage() != null && group.lastMessage.createdAt < (groupToUpdate.getMessage().getCreatedAt() / 1000)) {
return;
}
RealmList<UserRealm> userRealms = groupToUpdate.getUserIdList();
ArrayList<User> users = null;
if (userRealms != null) {
users = new ArrayList<>(userRealms.size());
for (int i = 0, size = userRealms.size(); i < size; i++) {
users.add(User.createFromUserRealm(userRealms.get(i)));
}
}
Message message = group.lastMessage;
if (groupToUpdate.getMessage() != null
&& groupToUpdate.getMessage().getUniqueId().equals(message.getUniqueId())
&& groupToUpdate.getMessage().isRead()) {
if (groupToUpdate.getMessage() != null && groupToUpdate.getMessage().getUniqueId().equals(message.getUniqueId()) && groupToUpdate.getMessage().isRead()) {
message.isRead = true;
}
newGroup = new GroupRealm(groupToUpdate.getId(),
groupToUpdate.getName(),
groupToUpdate.getAvatar(),

View File

@@ -44,11 +44,13 @@ public class GroupRealm extends RealmObject {
this.createdAt = this.message != null ? this.message.getCreatedAt() : 0;
this.onlyEmployees = onlyEmployees;
this.mobile = mobile;
if (userList != null) {
for (User l : userList) {
this.userIdList.add(UserRealm.createFromUser(l));
}
}
this.userId = userId;
this.uniqueId = id + "_" + userId;
}
@@ -61,6 +63,7 @@ public class GroupRealm extends RealmObject {
if (group == null) {
return null;
}
return new GroupRealm(group.id, group.name, group.avatar, group.lastMessage, group.mobile, group.onlyEmployees, group.users, group.userId);
}

View File

@@ -21,6 +21,10 @@ public class GroupByIdSpecification implements RealmSpecification<GroupRealm> {
mGroupId = groupId;
}
public long getUserId() {
return mUserId;
}
@Override
public RealmQuery<GroupRealm> toRealmQuery(Realm realm) {
return realm.where(GroupRealm.class)

View File

@@ -68,6 +68,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
@@ -157,7 +158,13 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
protected EndlessScrollListener mEndlessScrollListener;
protected BaseChatAdapter mBaseChatAdapter;
private Snackbar mSnackbar;
MediaRecorder mMediaRecorder;
private int xDelta;
private String mAudioFilePath;
private Rect mDialogContainer;
private int mInitialLeft = 0;
private int mInitialMarginLeft = 0;
@Inject
@Named(AppPrefsConstants.CHAT_OPENED)
@@ -345,11 +352,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mSendMessageImageView.setEnabled(!TextUtils.isEmpty(editable.toString()) && editable.toString().trim().length() > 0);
}
private int xDelta;
private String mAudioFilePath;
private Rect mRecButtonRightLimit;
private int mMaxMarginRight;
private Rect mDialogContainer;
private void selectFile(int requestCode) {
final String[] zipFileTypes = {".zip", ".rar", ".7z"};
final String[] pdfFileTypes = {".pdf"};
@@ -368,6 +370,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
ImageView attachDocumentImageView = dialog.findViewById(R.id.attachDocumentBtn);
TouchableImageView attachRecordAudioImageView = dialog.findViewById(R.id.attachRecordAudioBtn);
TextView limitTextView = dialog.findViewById(R.id.audioRecordingLimitTextView);
ImageView abortRecordingImageView = dialog.findViewById(R.id.abortRecordingImageView);
attachDocumentImageView.setOnClickListener(v -> {
FilePickerBuilder.getInstance().setMaxCount(1)
@@ -394,17 +397,14 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
dialog.dismiss();
});
dialog.setOnShowListener(dialog1 -> {
mRecButtonRightLimit = ViewUtils.getRectFromView(attachRecordAudioImageView);
mMaxMarginRight = ((GridLayout.LayoutParams) attachRecordAudioImageView.getLayoutParams()).leftMargin;
mDialogContainer = ViewUtils.getRectFromView(dialog.findViewById(R.id.dialogGridLayout));
});
final long duration = (mUploadMaxSize.get() / 256000L) * 1000;
final long duration = ((mUploadMaxSize.get() / 10 * 9) * 8) / (Constants.RECORDING_BIT_RATE_IN_MS / 1000); // 10% Overhead
CountDownTimer countDownTimer = new CountDownTimer(duration, 10) {
@Override
public void onTick(long millisecondsUntilFinished) {
limitTextView.setText(String.format(Locale.getDefault(), "%.2fs", (double) (millisecondsUntilFinished / 1000.0)));
long minutes = TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millisecondsUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisecondsUntilFinished));
limitTextView.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
}
@Override
@@ -416,6 +416,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
attachFromGalleryImageView.setVisibility(View.VISIBLE);
try {
dialog.dismiss();
mMediaRecorder.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
@@ -423,7 +424,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
}
};
// TODO: prevent the image view from moving outside the dialog box
attachRecordAudioImageView.setOnTouchListener((v, event) -> {
try {
attachRecordAudioImageView.performClick();
@@ -435,10 +435,17 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
GridLayout.LayoutParams layoutParams1 = (GridLayout.LayoutParams) v.getLayoutParams();
xDelta = x - layoutParams1.leftMargin;
mInitialMarginLeft = ((GridLayout.LayoutParams) attachRecordAudioImageView.getLayoutParams()).leftMargin;
mDialogContainer = ViewUtils.getRectFromView(dialog.findViewById(R.id.dialogGridLayout));
mInitialLeft = ViewUtils.getRectFromView(attachRecordAudioImageView).left;
attachRecordAudioImageView.setImageResource(R.mipmap.ic_file_dialog_record_audio_pressed);
limitTextView.setVisibility(View.VISIBLE);
attachDocumentImageView.setVisibility(View.INVISIBLE);
attachFromGalleryImageView.setVisibility(View.INVISIBLE);
abortRecordingImageView.setVisibility(View.VISIBLE);
mAudioFilePath = FileUtils.generateAudioRecordingFileName(this);
setupMediaRecorder(mAudioFilePath);
@@ -459,13 +466,41 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
countDownTimer.cancel();
mMediaRecorder.stop();
try {
mMediaRecorder.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
}
Rect recordButtonRect = ViewUtils.getRectFromView(attachRecordAudioImageView);
Rect abortButtonRect = ViewUtils.getRectFromView(abortRecordingImageView);
if(recordButtonRect.intersect(abortButtonRect)) {
if(!TextUtils.isEmpty(mAudioFilePath)) {
File audioFile = new File(mAudioFilePath);
if(audioFile.exists()) {
audioFile.delete();
}
}
dialog.dismiss();
return true;
}
if (!mChatPresenter.isAttached()) {
mChatPresenter.attachView(this);
}
//mCallback.sendFile(Uri.fromFile(new File(mAudioFilePath)), null);
Bundle bundle = new Bundle();
bundle.putString(Constants.FILENAME, mAudioFilePath);
Intent intent = new Intent(this, FileConfirmationActivity.class);
intent.putExtras(bundle);
intent.putExtra(Constants.EXTRA_GROUP, mGroup);
startActivityForResult(intent, 666);
dialog.dismiss();
return true;
@@ -475,9 +510,11 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
int newLeft = x - xDelta;
Log.d("ON_TOUCH", "dialog container left: " + mDialogContainer.left + "; x: " + x + "; limit to the right: " + mMaxMarginRight + "; old margin left: " + layoutParams2.leftMargin);
int nextX = mInitialLeft + newLeft - (mInitialMarginLeft * 2);
if(x > mDialogContainer.left && newLeft < mMaxMarginRight) {
boolean isMovingWithinBounds = nextX >= mDialogContainer.left && newLeft < mInitialMarginLeft;
if(isMovingWithinBounds) {
layoutParams2.leftMargin = newLeft;
layoutParams2.rightMargin = 0;
v.setLayoutParams(layoutParams2);
@@ -486,12 +523,15 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
}
return true;
default:
return true;
}
} catch (Exception e) {
dialog.dismiss();
e.printStackTrace();
return true;
}
return false;
});
dialog.show();
@@ -501,7 +541,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setAudioEncodingBitRate(32000);
mMediaRecorder.setAudioEncodingBitRate(Constants.RECORDING_BIT_RATE_IN_MS);
mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mMediaRecorder.setOutputFile(audioFilePath);
}

View File

@@ -325,26 +325,19 @@ abstract class BaseChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
} else {
viewHolder.filenameTextView.setVisibility(View.GONE);
}
} else if (message.filePath.toLowerCase().endsWith(".png") || message.filePath.toLowerCase().endsWith(".jpg") || message.filePath.toLowerCase().endsWith(".gif")) {
} else {
viewHolder.donutProgress.setVisibility(View.GONE);
viewHolder.fileImageView.setVisibility(View.VISIBLE);
viewHolder.filenameTextView.setVisibility(View.GONE);
viewHolder.fileImageView.setImageDrawable(null);
Log.d("FILE_PATH", message.toString());
Glide.with(viewHolder.fileImageView.getContext())
.load(message.filePath)
.load(TextUtils.isEmpty(message.smallerImage) ? message.filePath : message.smallerImage)
.placeholder(R.drawable.document)
.dontAnimate()
.override(500, 500)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(viewHolder.fileImageView);
} else {
viewHolder.donutProgress.setVisibility(View.GONE);
viewHolder.fileImageView.setVisibility(View.VISIBLE);
viewHolder.filenameTextView.setVisibility(View.VISIBLE);
viewHolder.fileImageView.setImageDrawable(null);
viewHolder.fileImageView.setImageResource(R.drawable.document);
viewHolder.filenameTextView.setText(message.originalFilename);
}
if (!TextUtils.isEmpty(message.message)) {

View File

@@ -4,7 +4,6 @@ import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.responses.MessageResponse;
import de.beyondsoft.ownchat.data.api.responses.MessagesResponse;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.events.GroupUpdatedEvent;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
@@ -27,15 +26,12 @@ import de.beyondsoft.ownchat.utils.rx.RxUtils;
import org.greenrobot.eventbus.EventBus;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -43,6 +39,7 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -59,7 +56,6 @@ import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import static de.beyondsoft.ownchat.data.AppPrefsConstants.USER_ID;
@@ -165,51 +161,48 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
Subscription subscription = mChatService.getMessages(mGroupId, 0)
.compose(RxUtils.provideDefaultTransformer())
.flatMap(new ErrorHandlingResponseConverter<>())
.flatMap(new Func1<MessagesResponse, Observable<List<Message>>>() {
@Override
public Observable<List<Message>> call(MessagesResponse messageResponse) {
if (messageResponse.response.messages == null || messageResponse.response.messages.isEmpty()) {
return Observable.just(null);
}
Message lastMessage = messageResponse.response.messages.get(messageResponse.response.messages.size() - 1);
lastMessage.status = Message.Status.DELIVERED;
lastMessage.isRead = true;
if (!mMessages.contains(lastMessage)) {
long groupId = mGroupId;
resetMessages();
loadMessagesFromServerByGroupId(groupId);
return Observable.just(null);
}
for (int i = 0; i < mMessageToUpdate.size(); i++) {
Pair<Message, String> messageToUpdate = mMessageToUpdate.get(i);
if (isAttached()) {
getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second);
}
}
mMessageToUpdate.clear();
ArrayList<Message> messages = new ArrayList<>();
for (int i = messageResponse.response.messages.size() - 1; i >= 0; i--) {
Message message = messageResponse.response.messages.get(i);
message.status = Message.Status.DELIVERED;
message.isRead = true;
message.userId = mUserIdPreference.get();
if (mMessages.contains(message)) {
continue;
}
messages.add(message);
}
return mMessageRealmRepository.updateMessages(messages, new MessageByIdSpecification(mUserIdPreference.get()));
.flatMap(messageResponse -> {
if (messageResponse.response.messages == null || messageResponse.response.messages.isEmpty()) {
return Observable.just(null);
}
Message lastMessage = messageResponse.response.messages.get(messageResponse.response.messages.size() - 1);
lastMessage.status = Message.Status.DELIVERED;
lastMessage.isRead = true;
if (!mMessages.contains(lastMessage)) {
long groupId1 = mGroupId;
resetMessages();
loadMessagesFromServerByGroupId(groupId1);
return Observable.just(null);
}
for (int i = 0; i < mMessageToUpdate.size(); i++) {
Pair<Message, String> messageToUpdate = mMessageToUpdate.get(i);
if (isAttached()) {
getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second);
}
}
mMessageToUpdate.clear();
ArrayList<Message> messages = new ArrayList<>();
for (int i = messageResponse.response.messages.size() - 1; i >= 0; i--) {
Message message = messageResponse.response.messages.get(i);
message.status = Message.Status.DELIVERED;
message.isRead = true;
message.userId = mUserIdPreference.get();
if (mMessages.contains(message)) {
continue;
}
messages.add(message);
}
return mMessageRealmRepository.updateMessages(messages, new MessageByIdSpecification(mUserIdPreference.get()));
})
.subscribe(this::fetchNewMessagesSuccess, this::fetchNewMessagesError);
addSubscription(subscription);
@@ -418,7 +411,7 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
* Send the file to the server.
*/
@Override
public void sendFile(Uri fileUri, String messageText) {
public void sendFile(final Uri fileUri, String messageText) {
File file = getView().getFile(fileUri);
final String mimeType = FileUtils.getMimeType(file);
@@ -506,11 +499,11 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
storeMessageLocally(newMessage, message.id, false);
storeGroupLocally(mGroupId, message);
if (!isAttached()) {
if(!isAttached()) {
return;
}
if (mSystemUtils.isNetworkUnavailable()) {
if(mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
@@ -526,6 +519,15 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
baseResponse.response.message.isRead = true;
storeMessageLocally(baseResponse.response.message, message.id, false);
storeGroupLocally(mGroupId, baseResponse.response.message);
List<String> splitUriAsList = Arrays.asList(fileUri.toString().split("/"));
if(splitUriAsList.contains(Constants.AUDIO_RECORDINGS_DIR)) {
File f = getView().getFile(fileUri);
if(f != null && f.exists()) {
f.delete();
}
}
}
});
}
@@ -564,14 +566,18 @@ public class ChatPresenter extends MVPAbstractPresenter<ChatView> implements Cha
@Override
public void onError(Throwable e) {
Log.e("ChatPresenter", "downloadFile", e);
if (!isAttached()) {
return;
}
getView().stopItemProgress(itemPosition);
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
}
getView().showError(R.string.error_something_went_wrong);
}

View File

@@ -82,10 +82,12 @@ class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
setLastMessage(group, viewHolder);
int type = getItemViewType(position);
if (type == GROUP_TYPE) {
viewHolder.name.setText(group.name);
viewHolder.name.setTextColor(ContextCompat.getColor(viewHolder.name.getContext(), group.isHelpGroup() ? R.color.colorHelpGroup : R.color.colorTeamGroup));
viewHolder.avatar.setImageResource(group.isHelpGroup() ? R.drawable.avatar_help_group : R.drawable.avatar_team_group);
return;
} else if(!group.onlyEmployees) {
viewHolder.avatar.setImageResource(R.drawable.avatar_help);
@@ -134,6 +136,7 @@ class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (resourceId != 0) {
viewHolder.messageStatusPending.setVisibility(resourceId == -1 ? View.VISIBLE : View.GONE);
if (resourceId != -1) {
viewHolder.messageStatus.setImageResource(group.lastMessage.getStatusResourceId());
} else {
@@ -174,10 +177,12 @@ class ContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@OnClick(R.id.contact_container)
void onClickContact() {
int type = getItemViewType();
if (type == GROUP_TYPE) {
mItemClickListener.onOpenGroupMessage(mGroups.get(getAdapterPosition()));
return;
}
mItemClickListener.onOpenPrivateMessage(mGroups.get(getAdapterPosition()));
}
}

View File

@@ -54,8 +54,7 @@ import butterknife.ButterKnife;
/**
* Created by imarneanu on 2/13/17.
*/
public class ContactsFragment extends BaseFragment
implements ContactsView, ContactsAdapter.OnOpenClickListener, SearchView.OnQueryTextListener {
public class ContactsFragment extends BaseFragment implements ContactsView, ContactsAdapter.OnOpenClickListener, SearchView.OnQueryTextListener {
@BindView(R.id.contacts_recycler_view)
RecyclerView mContactsRecyclerView;
@@ -160,6 +159,7 @@ public class ContactsFragment extends BaseFragment
mSnackbar = Snackbar.make(mCoordinatorLayout, message, Snackbar.LENGTH_LONG);
mSnackbar.setActionTextColor(ContextCompat.getColor(getActivity(), R.color.colorDefault));
}
mSnackbar.setText(message);
mSnackbar.show();
}

View File

@@ -102,6 +102,7 @@ class ContactsPresenter extends MVPAbstractPresenter<ContactsView> implements Co
* Send error messages to view.
*/
private void groupsError(Throwable throwable) {
Log.e("REALM_TRANSACTION", "An error occurred. This message was brought to you by ContactsPresenter");
if (mSystemUtils.isNetworkUnavailable()) {
getView().showError(R.string.error_no_internet_connection);
return;
@@ -161,6 +162,7 @@ class ContactsPresenter extends MVPAbstractPresenter<ContactsView> implements Co
if (!isAttached()) {
return;
}
/**/
getView().hideProgress();
getView().setGroups(groups);
}

View File

@@ -160,9 +160,28 @@ public class FileConfirmationActivity extends AppCompatActivity implements FileC
@OnClick(R.id.chat_toolbar_back_arrow)
void backPressed() {
deleteRecording();
onBackPressed();
}
@Override
public void onBackPressed() {
deleteRecording();
super.onBackPressed();
}
private void deleteRecording() {
if(mSelectedUri.toString().contains(Constants.AUDIO_RECORDINGS_DIR)) {
File audioFile = new File(mSelectedUri.toString());
if(audioFile.exists()) {
audioFile.delete();
}
}
}
@Override
protected void onDestroy() {
InjectionHelper.destroyLoginComponent();

View File

@@ -611,36 +611,37 @@ public class LoginPresenter extends MVPAbstractPresenter<LoginView> implements L
}
private void deleteDataOnCustomerIdChange() {
File dir = mContext.getExternalFilesDir(null);
File dir = mContext.getExternalFilesDir(null);
mGlide.clearMemory();
if (dir != null) {
if (dir.isDirectory()) {
String[] children = dir.list();
if (dir != null) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
dir = new File(Environment.getExternalStorageDirectory(), "BeWoPlaner");
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
}
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
}
} else {
dir = new File(Environment.getExternalStorageDirectory(), "BeWoPlaner");
Realm realm = mRealmProvider.provide();
realm.executeTransaction(realm1 -> realm1.deleteAll());
if (dir.isDirectory()) {
String[] children = dir.list();
for (String aChildren : children) {
//noinspection ResultOfMethodCallIgnored
new File(dir, aChildren).delete();
}
} else {
Log.e("deleteData", dir.getAbsolutePath() + " is not a directory!");
}
}
Realm realm = mRealmProvider.provide();
realm.executeTransaction(realm1 -> realm1.deleteAll());
}
private boolean checkPassword(String password) {

View File

@@ -36,4 +36,6 @@ public interface Constants {
String HAS_OPEN_CHAT = "has_open_chat";
String AUDIO_RECORDINGS_DIR = "audio_recordings";
int RECORDING_BIT_RATE_IN_MS = 32000;
}

View File

@@ -56,17 +56,6 @@ public abstract class ViewUtils {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
public static boolean isInViewInBounds(View view, int x, int y) {
Rect outRect = new Rect();
int[] location = new int[2];
view.getDrawingRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect.contains(x, y);
}
public static Rect getRectFromView(View view) {
Rect outRect = new Rect();
int[] location = new int[2];
@@ -78,4 +67,16 @@ public abstract class ViewUtils {
return outRect;
}
public static Rect getHitRectFromView(View view) {
Rect outRect = new Rect();
int[] location = new int[2];
view.getHitRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect;
}
}

View File

@@ -2,7 +2,7 @@
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dialogGridLayout"
android:layout_width="200dp"
android:layout_width="203dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="false"
@@ -14,14 +14,28 @@
android:orientation="horizontal"
android:rowCount="1">
<ImageView
android:id="@+id/abortRecordingImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="10dp"
android:layout_row="0"
android:adjustViewBounds="false"
android:contentDescription="@null"
android:cropToPadding="false"
android:src="@mipmap/ic_trash_bin"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/audioRecordingLimitTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_columnSpan="2"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="20dp"
android:layout_column="1"
android:layout_gravity="center_vertical"
android:layout_margin="10dp"
android:layout_row="0"
android:textAlignment="center"
android:textColor="@color/colorBlack"

View File

@@ -7,9 +7,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:paddingLeft="40dp"
android:paddingEnd="40dp"
android:paddingRight="0dp"
android:paddingStart="0dp"
android:paddingBottom="0dp">
@@ -26,17 +24,14 @@
android:padding="7dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_toEndOf="@id/chat_item_contact_image"
android:layout_toRightOf="@id/chat_item_contact_image"
>
<TextView
android:id="@+id/chat_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="@color/colorManatee"
android:textSize="10sp"
@@ -46,15 +41,14 @@
<ImageView
android:id="@+id/chat_item_file"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_alignParentLeft="true"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentStart="true"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:scaleType="centerCrop"
android:visibility="gone"
tools:src="@drawable/document"
tools:visibility="visible" />
@@ -64,7 +58,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/chat_item_file"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="@color/colorBlack"
android:visibility="gone"
@@ -77,7 +70,6 @@
android:layout_height="90dp"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="gone"
custom:donut_finished_color="@color/colorDefault"
@@ -90,7 +82,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/chat_item_file_name"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
emojicon:emojiconSize="20sp"
style="@style/BaseChatItemText"

View File

@@ -8,16 +8,13 @@
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:paddingLeft="40dp"
android:paddingEnd="40dp"
android:paddingRight="0dp"
android:paddingStart="0dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/chat_item_contact_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_margin="0dp"
android:contentDescription="@null"
@@ -28,17 +25,14 @@
android:padding="7dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_toEndOf="@id/chat_item_contact_image"
android:layout_toRightOf="@id/chat_item_contact_image">
android:layout_toEndOf="@id/chat_item_contact_image">
<TextView
android:id="@+id/chat_item_sending_failed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/chat_item_message_status"
android:layout_toRightOf="@+id/chat_item_message_status"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
@@ -55,10 +49,8 @@
android:layout_height="15dp"
android:layout_alignBottom="@+id/chat_item_time"
android:layout_alignTop="@+id/chat_item_time"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_toEndOf="@+id/chat_item_time"
android:layout_toRightOf="@+id/chat_item_time"
android:visibility="gone"
tools:visibility="visible"/>
@@ -68,10 +60,8 @@
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/chat_item_time"
android:layout_alignTop="@+id/chat_item_time"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_toEndOf="@+id/chat_item_time"
android:layout_toRightOf="@+id/chat_item_time"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:visibility="gone"
@@ -82,7 +72,6 @@
android:id="@+id/chat_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="@color/colorTimestamp"
android:textSize="10sp"
@@ -92,15 +81,14 @@
<ImageView
android:id="@+id/chat_item_file"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_alignParentLeft="true"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentStart="true"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:scaleType="centerCrop"
android:visibility="gone"
tools:src="@drawable/document"
tools:visibility="visible" />
@@ -109,7 +97,6 @@
android:id="@+id/chat_item_file_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/chat_item_file"
android:textColor="@color/colorBlack"
@@ -121,7 +108,6 @@
android:id="@+id/chat_item_progress"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"
@@ -133,7 +119,6 @@
android:id="@+id/chat_item_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/chat_item_file_name"
android:padding="0dp"

View File

@@ -27,8 +27,8 @@
<ImageView
android:id="@+id/chat_item_file"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"

View File

@@ -70,8 +70,8 @@
<ImageView
android:id="@+id/chat_item_file"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignParentStart="true"
android:layout_below="@id/chat_item_time"
android:layout_marginTop="4dp"

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B