From bebbb845c1bacc7e824a405c1f335d2a3d239e2f Mon Sep 17 00:00:00 2001 From: Lyndon Date: Fri, 24 Nov 2017 13:52:05 +0100 Subject: [PATCH] Recording audio file is now supported. --- .../bewoplaner-chat-android/app/build.gradle | 8 +- .../ownchat/page/chat/BaseChatActivity.java | 51 +++++++-- .../ownchat/page/chat/ChatPresenter.java | 106 +++++++++--------- .../beyondsoft/ownchat/utils/Constants.java | 2 + .../ownchat/utils/ui/ViewUtils.java | 23 ++-- .../main/res/layout/dialog_file_chooser.xml | 24 +++- .../app/src/main/res/mipmap-hdpi/ic_abort.png | Bin 0 -> 781 bytes .../main/res/mipmap-hdpi/ic_slide_left.png | Bin 0 -> 250 bytes .../src/main/res/mipmap-hdpi/ic_trash_bin.png | Bin 0 -> 343 bytes .../app/src/main/res/mipmap-mdpi/ic_abort.png | Bin 0 -> 515 bytes .../main/res/mipmap-mdpi/ic_slide_left.png | Bin 0 -> 252 bytes .../src/main/res/mipmap-mdpi/ic_trash_bin.png | Bin 0 -> 289 bytes .../src/main/res/mipmap-xhdpi/ic_abort.png | Bin 0 -> 1163 bytes .../main/res/mipmap-xhdpi/ic_slide_left.png | Bin 0 -> 391 bytes .../main/res/mipmap-xhdpi/ic_trash_bin.png | Bin 0 -> 417 bytes .../src/main/res/mipmap-xxhdpi/ic_abort.png | Bin 0 -> 1796 bytes .../main/res/mipmap-xxhdpi/ic_slide_left.png | Bin 0 -> 550 bytes .../main/res/mipmap-xxhdpi/ic_trash_bin.png | Bin 0 -> 619 bytes .../src/main/res/mipmap-xxxhdpi/ic_abort.png | Bin 0 -> 2658 bytes .../main/res/mipmap-xxxhdpi/ic_slide_left.png | Bin 0 -> 892 bytes .../main/res/mipmap-xxxhdpi/ic_trash_bin.png | Bin 0 -> 865 bytes 21 files changed, 132 insertions(+), 82 deletions(-) create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_abort.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_slide_left.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_trash_bin.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_abort.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_slide_left.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_trash_bin.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_abort.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_slide_left.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_trash_bin.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxhdpi/ic_abort.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxhdpi/ic_slide_left.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxhdpi/ic_trash_bin.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxxhdpi/ic_abort.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxxhdpi/ic_slide_left.png create mode 100644 BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxxhdpi/ic_trash_bin.png diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/build.gradle b/BeWoPlanerChat/bewoplaner-chat-android/app/build.gradle index 31e0fda..713dc76 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/build.gradle +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/build.gradle @@ -34,8 +34,8 @@ android { applicationId "de.beyondsoft.ownchat" minSdkVersion 19 targetSdkVersion 26 - versionCode 6 - versionName "1.6" + versionCode 7 + versionName "1.7" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } @@ -111,7 +111,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.0' 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 +136,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' \ No newline at end of file +apply plugin: 'com.google.gms.google-services' diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/BaseChatActivity.java b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/BaseChatActivity.java index 689d13d..ea65122 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/BaseChatActivity.java +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/BaseChatActivity.java @@ -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; @@ -347,7 +348,6 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha private int xDelta; private String mAudioFilePath; - private Rect mRecButtonRightLimit; private int mMaxMarginRight; private Rect mDialogContainer; private void selectFile(int requestCode) { @@ -368,6 +368,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) @@ -395,16 +396,20 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha }); 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; + Log.d("ON_TOUCH", "Upload max size: " + mUploadMaxSize.get()); + + 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,19 +421,19 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha attachFromGalleryImageView.setVisibility(View.VISIBLE); try { - mMediaRecorder.stop(); + mMediaRecorder.stop(); // TODO: delete } catch (IllegalStateException e) { e.printStackTrace(); } } }; - // TODO: prevent the image view from moving outside the dialog box attachRecordAudioImageView.setOnTouchListener((v, event) -> { try { attachRecordAudioImageView.performClick(); final int x = (int) event.getRawX(); + int test = 0; switch(event.getAction()) { case MotionEvent.ACTION_DOWN: @@ -439,6 +444,7 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha limitTextView.setVisibility(View.VISIBLE); attachDocumentImageView.setVisibility(View.INVISIBLE); attachFromGalleryImageView.setVisibility(View.INVISIBLE); + abortRecordingImageView.setVisibility(View.VISIBLE); mAudioFilePath = FileUtils.generateAudioRecordingFileName(this); setupMediaRecorder(mAudioFilePath); @@ -461,11 +467,34 @@ abstract class BaseChatActivity extends RuntimePermissionActivity implements Cha mMediaRecorder.stop(); + 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 +504,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); + Log.d("ON_TOUCH", "new left margin: " + newLeft); - if(x > mDialogContainer.left && newLeft < mMaxMarginRight) { + int buttonLeft = ViewUtils.getRectFromView(attachRecordAudioImageView).left; + + if(buttonLeft > mDialogContainer.left && newLeft < mMaxMarginRight) { layoutParams2.leftMargin = newLeft; layoutParams2.rightMargin = 0; v.setLayoutParams(layoutParams2); @@ -501,7 +532,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); } diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/ChatPresenter.java b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/ChatPresenter.java index 1cf8098..0c3c1ea 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/ChatPresenter.java +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/page/chat/ChatPresenter.java @@ -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 implements Cha Subscription subscription = mChatService.getMessages(mGroupId, 0) .compose(RxUtils.provideDefaultTransformer()) .flatMap(new ErrorHandlingResponseConverter<>()) - .flatMap(new Func1>>() { - @Override - public Observable> 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 messageToUpdate = mMessageToUpdate.get(i); - - if (isAttached()) { - getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second); - } - } - - mMessageToUpdate.clear(); - ArrayList 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 messageToUpdate = mMessageToUpdate.get(i); + + if (isAttached()) { + getView().lastMessageUpdated(messageToUpdate.first, messageToUpdate.second); + } + } + + mMessageToUpdate.clear(); + ArrayList 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 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 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 implements Cha baseResponse.response.message.isRead = true; storeMessageLocally(baseResponse.response.message, message.id, false); storeGroupLocally(mGroupId, baseResponse.response.message); + + List 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(); + } + } } }); } diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/Constants.java b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/Constants.java index fcd90e2..25ed660 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/Constants.java +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/Constants.java @@ -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; } \ No newline at end of file diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/ui/ViewUtils.java b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/ui/ViewUtils.java index 75338d3..1af8a0b 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/ui/ViewUtils.java +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/java/de/beyondsoft/ownchat/utils/ui/ViewUtils.java @@ -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; + } } diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/layout/dialog_file_chooser.xml b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/layout/dialog_file_chooser.xml index 70da05b..f5cb74b 100644 --- a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/layout/dialog_file_chooser.xml +++ b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/layout/dialog_file_chooser.xml @@ -2,7 +2,7 @@ + + WdP)>YIW1%s|QcVmWz{0}XLJACpcG%!out5?C9(Q7n5E2T%01YKHevC^l zLV}G!3!({-i0|$0k;~m?XJ_Ybomu|BLMU^X5H?000000000000000z(QroMf_c(Ut@A7X=(sLiF{!pI1G-B4Mc8?`2avX4+=Zt-hg%zsb zt*n?9P2A*{+~7F15HlDj9PKr_exp)ycpJUs7dvtgGZ;U33%;mCp5d2S8ljl}_{%x! zL$LWNmZP@DB&R<%f|SJDYPkeCQOK7RlpJ34bXjtG+bx)!v`iDXc)>qQ78E7!AWk=4 z=%(RCe)DhpHE+Rh7BAmzQtb`@`N!~F+iN+WNZ&WqIV?v%>ph!OQdf%0xR%n-4U$g0 zE+);1S~;3$BOBS&Stq5%URAbOsvK8Io^CO{?kY!qwy2ZBO43~6zH^n6 zzoTo(khXbNyf9MS*M~e^^mDie=J{;Wf9nsR*6AQ)WG+? zqxhMw-R6b<`VTGFBN*6)7g;iraWC>CZEVvYq6rL6?O% zKk2EY3$PydlcebuHQsjO9=Dp8X^A{b000000000000000;648UrRlO0hgvFv00000 LNkvXXu0mjfi(qbQ literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_slide_left.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_slide_left.png new file mode 100644 index 0000000000000000000000000000000000000000..ec9677445fd66caee07dc8bd76e994db8a2ceab9 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!2R&UJLn>~)y=lvJ$U(#{P`Xt2 z7Tdu?tWVf=T68WewR&$T)W4OzSU*8^rpQ5&i^UI`r#$3aGUH4dP%jY7f3+(vCDJTh zNpQJF*D{^c$-mclxX-!qd9T}&k~wAlHs{M9EqN?+M9^KP5JLQ1Z}E1W;EO+RLqoUz zYPDFbtCXuItPxisY0YV(b4j;MGV%4v+IFFd?+R~Kf0t0|RGH)fA$Yq)Zm*i$_vCn@ jze?dRrA}tB{Uue5u1}6~h$u=N1@S#y{an^LB{Ts5s)=7@ literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_trash_bin.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-hdpi/ic_trash_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..e5453ac5b17c00f198d44bd2f178cc6151bbd178 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2V3hN8aSW-r_4byb7qcTn>%;bK zvuAob=qIFVMrex7Qwrr%5c1ICmX_8|OfT=Aqo7dHWMUcN6k{BH!!_Jc`OTC64@wgg z>Na_IflLO03!GEm%nUF4cX!r#nG_j)bIp|38~UeRjeBOdlR^KKU-8%cva_e{+Pe4u zS2*|FERjEcZn&oP%a{d0XhDf)V6ocZu=7o-;^hCwwRUpX2`^a{@?Oh^>Ac~! zId^|LwB9kfxBIv+r;7rUV21;Xl0YK|R_3?GQzVabJxP5p#PKBWG3%??a=Qz&OJwvm z_XuQsRFTzW-FZeK=7nj_-gbl4AJ)#Pwp@PYOv>-v`kmSFO^FbnFsLMP>&?2l?Sf?S PZ;*(mtDnm{r-UW|S73rd literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_abort.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_abort.png new file mode 100644 index 0000000000000000000000000000000000000000..a15570ce118a727ca2ae7c5a96755b14809aafa2 GIT binary patch literal 515 zcmV+e0{s1nP)nf+!q01O6$!C){LjK**W;eG<)SpvZTuZI*dh(4~Tj}Y#)mUs+77m3a> zmKZ;ppnEfnPHTwYLa>d5CI-@~_{JDNfrz}4r; zPa7bg#n>r%beLmxU58h=E_6gOWAC_LYxYFPrGS@p65(ZGQ!iBHvr^HBm^t!!aj3D% z^adiK5>X^itIWij#X9K|DB#>s%Wq{7L>8M^Xd%A}YIY6;1hHj9=9wVE8F^Ywwn9L$Y_d$4+{vi`TL~4()2iFp>Su$2iwyKkFl16b?qw}jG{TCLi%q>=S?DGA&%T9cv8V5*(#cfjR*m86z-3z*| zhq>nlhq;M|v%uC4zWA#yc^b)SUwAnaJb*Z;BZA0#KPSsf{H2_x-oCtkW3SxFc&MjQ zoX!)i{W~H1L{D~X8aqaGO;aq5;{4-@!C){L3`;002ovPDHLk FV1lt3;_Ltb literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_slide_left.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_slide_left.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d40c21f34c17831ade68732da2c4475223664b GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUt!=5gVAr-gYPV?nDWFX*H%((h` z!9(3$C-_?$tPcijRL!2}wsiR>zXeVlP1k&7EBWniJ)P}i9Gnc)%E0hX=y{BAa?FaU z+ponvtvvZY>S?>o`@eC$HMh5UPuyqwR8>9n)6tXnRnwnL{QuyP*!?|rKZ|a8>=HOs zm6di=RR78TzMh+JV;*k`k9JU7x@A?@3zsxw)1L;<;$mtGJNsY#t6t?7a716U@Iu^? z1)Dmmj+|O@bLHD3JKjhwp14ui>M0}04fj4V{C<5~)N=C17!cRf)z4*}Q$iB}=xuN^ literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_trash_bin.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-mdpi/ic_trash_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e22b2e80fec375c8aa177b46d5da79d09ca5bc GIT binary patch literal 289 zcmV++0p9+JP)QFjIkCCnIgoy(IoR3K}X zU)T6`kFCab;If+f*(y6^CQtUGJe@fU1tV}kbjpcrYmsfoLu_69IZoLHwmb4ap{$1R z1E9A~?67XOTXzRgXdZL#uKcdxzBIqCnZ(EY8L;3hy#|eVnYDNI9Gi zI4umbD3y~FzhP3aAE!LuXJ7bqG$&Qe^trWlEgw(ABZZYq+DDC*Bqtw)d zH`IB7Kk#N7iQg#9#&<_f-nZu4PkhIuMKyY#z)^NTM4vCeH^o+tA!?CrIz+9h%4W?- z@kfa|IM1$V3bD`58j)z6AnO)?{Ud_-<#Domow0`XJcQ$yj9djQ#smGxw?{lSYTF^i zFR|!-f6tccPS9EjMy>)D;FG3!Z@nT=tppt>lqB+f>d&;M0~QR6{@g|WV7r-Ve&WEitl5TyY4--tFHvF!d&!o&}M-jitY^M}rb`-@4vjz?0vQNXNod{FSI8#)w6)B$fQ<@G~B-047A(Mmg;h5uve+si4bLyT88?ga% zGe>lqMfjq7D1YdLs8h|uDXJ6sb@BH#|908ft0`&~gt#JNPsW_>Y{?mOxT`RkK{Az5 zq7IJ6kL`LfOP)_K{s9iv5q)bz@i*il5lRDGAn)-9{?$g}S7fh1X+jmocDSBib9Y^- zKy@cCTkM3IJS39Z2ltM&h^FnnbC{j+iaeiyl%qMe5J#v1-d+shcjZ>LT#Xm!LfHsKT2hmoCpd>X^^>(q zlYU;VLC(pAV7ZkI6%$6znAJglzpN59U+S0d$u&qQ1ONa400000000000000000000 d003w;zX1ShwYF!=P5l4>002ovPDHLkV1j1i50?M{ literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_slide_left.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_slide_left.png new file mode 100644 index 0000000000000000000000000000000000000000..0b86f4d7ca860ece4292fc3aff7e7117086e62d4 GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>VD$5JaSW-r_4c-}9!sDA`-ehy zZgIs#q0Mvtd8~gkr-65Q5l7#XWTTwS#Zgg8mp0D{KlFb3m9Egxz2E=I8qQ_}8UzI) zp`|jVD}*^;?V9Jlc9C40;|q_6XXR(_m&{J(cxqn%d9mE=WtJBfZkqi+^!>#@uYXLn zjlDH-Tdx12i?2JM?LV5Zt|a68+4@%G;f{uTFH;spYiDhr0Xl*)FlP+HZYwWw>w{nz_m@2ZtO)w$xIqw>c@xqq9?u1{Pt gIpH%R3>y69-~4}9duZoGUr?ZUy85}Sb4q9e0Df1qc>n+a literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_trash_bin.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xhdpi/ic_trash_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..d14f210b7c9fb5eb627814d97282062d83b5a1d7 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>V9fAzaSW-r_4dv|EtW!=10Ums zT+^<_J$b+>W7ERi$-TbWtW#z8X1{q}l}t-3n2I7E?vE@=*dBY^Z|3>sb=T*<{l50* z%~>-!fCfUqs^uLyi)DYFoUl2sIQc@?tvtb>#k006K400p1q5`bxsJzQ)=fXf>ao1z@se>+AhR&$L!9$e~P+~vp$_~O>I53BpQsHS=KRy2{>NX0e(Fc7 zg;#uhLQET&nQPqST9LzT1(eJKl2XmfjH}u1FS?79Upac6{w`uGO%p#CX6Iezes}Th znxmfW&5p3kGp-C@cev(CZw!Yf-Y6)cDrJ7XHwr^}+Kc=iz$S^jhSf1w!HZEIA;-1FaEtsO>%U*@H*%xU;$uWzQ#^Q#V|t|TVf z3!dtA#o_E9%^~O;;}MeV&-MDX$(SM4x_{!g+oKMH1HSKm&#wBYOMar>V(E@rA!{^! zZaFQPNVn7v=yo3s(hX>-VP()#rHdeOk|fsoScqcc@~Ihc7pFXjyBs-AR{`Qn38SG|qLmqek;C+AYw? zI$})vU}ijee@}`(j#Au4qC}S$>1_^#+6)>g#1rOF-6T)K1OOXYK9Q6g}ZE zKD1sro@F{8N}-sL=@0JMnS5;#?&pjFMvHiFauS|fn{2$0%&LH>sWR9qC^3?o0~JkP zP50bOvv>DIB;^_R1Q+&89C8kRPkI##0uQHjSy@#pMEO+q?WD9b1i3oi9ykN+7uK!8 zO8gc8L0rr6;-or=H(UY!*u1g;6m!_A8lv^=wZ83I8*AkOI6GS)iVrJs_GNAjG~DU$Lepf?*FA%LMh&HEh6!8xd2|&L4)aGkW&-Y-&HL-w)5MXxle9?f zns7;ZyT(c=q(H~%B7^<)M;gN4LP!lY_aN!P{i&w2qrtzPoHwJvw$fe$E_l3*Y@S#n zYs8%;>8BylPAg);U2Mh`r`nhC4ABV@utTvG8@OU{xzn}}cSfKPWqoR_~4am1VB=X4X_^b-a zQ)_+cTmeyhVV$j<1X0{&s~LFU5zD`Au~;l~6(FW8G>4~dBEU|vTpgY~7HHZ^Dva@b z$Awc6$vH48>V~HpmS`Q!`ZjLv^H@1Bm+nCQdvA7_>3D(wwEGag6rV+a=PYp`Z+Ku* zj-~Sf4B|NA_WF1)!I>zWWnIs}L{2Lba?r)>2{b+??}xM7NziTSJa?)naIi@v+X8r{ zEI?|k^J<^6!Kku7;g(qPvMT3m;Y-MP{h&)KtZcJV2vDlTR3_nW7lCRVROLYl+aWzt4WgD^!#ZLqWTr@*Uj79StK4YlqOh<36ck8ZsykwblI57O?ptp!4=K z3A;dq-~ec3;_+JTBX-0{aZkm*uk6_kAX1fBwh)Am-VVvHt_fj?N&JeGytdS{1Odfa z5N|e%%t*1R}y1VuCyd74d_W4 zzoG}sn)_g?n156dBuHzk%-B~bWPxlzs#R>T3{UWFB%#dF2s2GO#)S+b^ zjQvEw^tukeXcasN7U^#QQ0+X5 zuPjm}d@EUlCRjA5m>awgpP%Nh{dSN%_3nx^!2j^x?{0Mzh8{S+cO~+UQ%wO zrfn@#rGEu2( zQsm91p*R&NSbc>lE`S6~wi-4$v_j8WWKLzjy=TNI<$OW^udnzSx=i@N-)YZCG62qex;5++LKleOi@=_+C zS=hjVNpEH_O?tfYY8L<3s=cXN9=+)nlDg%}L60Q;j~V=)+u_ma?lPq>-AYMA#@~#s z@XpegN~-e~R?HATpAl$dsOKXdZ#DPax(bgz^+h|*f4(8af8S*G*}Zc$bQsbYo&i#gDTURgWBPI@(ROH=MuRT{u@Z|C)xBf4Gg$>E8!eSo0S@mh5bwdUWz$ zgYNbv$ERHtTlw)uqMGHr!XuxB>~9zTxvSQ1aelVNdFJV5&5wR2Kh{0A@U*rZW2d{r z|8ptRe_9?dign0Ibzu^k*zhmeW&K8%x~}ibkNe6M&f7li<7~-5bG-{QdtFYse9==9 zbN!;I6jrC+^?hNnprP@iH>r^>DyR4P=qtG#sR~_v_3z1hT~{TQoLq7oUCP!(dbuo5 z>oF4i>T={xN0Hvg--do?BPHeI~Sds|Ce0`_mCw(eft4Mote0kS+lMWW5StVJ8O;h$Kr(g8;-}P7biy_~jvH3NWGR|CKIs_V7N| zD{i&-i;l8{+G98NZkzK~I?1}o-0phVEAuM2@ng*#m)hK_ z-f3EQ7E4^q4cY#A|KFz;tG@r7wD-5YpWA1>^^aZS4zE4F(Pje=0~T;#(N9)~YE#z< R=7DA)X-`)_mvv4FO#n#A@J;{# literal 0 HcmV?d00001 diff --git a/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxxhdpi/ic_abort.png b/BeWoPlanerChat/bewoplaner-chat-android/app/src/main/res/mipmap-xxxhdpi/ic_abort.png new file mode 100644 index 0000000000000000000000000000000000000000..d44700a6dc36e703cdd26a180fa45462058f9713 GIT binary patch literal 2658 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 literal 0 HcmV?d00001