blob: b20f4525cd04d9bcad984ce1c2acc347fb88a300 [file] [log] [blame]
Loïc Siret0202fbf2017-09-28 16:34:28 -04001/*
Sébastien Blinab53ada2019-01-02 17:23:00 -05002 * Copyright (C) 2004-2019 Savoir-faire Linux Inc.
Loïc Siret0202fbf2017-09-28 16:34:28 -04003 *
Adrien Béraud64538722018-03-15 17:34:00 -04004 * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
5 *
Loïc Siret0202fbf2017-09-28 16:34:28 -04006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
Aline Bonnet9c6defe2016-12-21 13:21:02 -050020package cx.ring.fragments;
21
Pierre Duchemin4af6b392018-02-02 11:23:56 -050022import android.Manifest;
Adrien Béraud772e2162019-02-12 16:00:21 -050023import android.animation.ValueAnimator;
Rayan Osseirane4450272019-06-03 14:17:19 -040024import android.content.ActivityNotFoundException;
Adrien Béraudae45ffa2018-07-06 16:21:29 -040025import android.content.ClipData;
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -040026import android.content.Context;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050027import android.content.Intent;
Adrien Béraud3a875a02018-07-18 17:54:17 -040028import android.content.SharedPreferences;
Adrien Béraud4f542f92019-01-03 12:17:53 -050029import android.content.pm.PackageManager;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040030import android.graphics.drawable.BitmapDrawable;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050031import android.os.Bundle;
Adrien Béraud64538722018-03-15 17:34:00 -040032import android.provider.MediaStore;
Adrien Béraud3a875a02018-07-18 17:54:17 -040033import android.text.Editable;
Adrien Béraud58bd92b2018-08-23 10:54:25 -040034import android.text.TextUtils;
Adrien Béraud3a875a02018-07-18 17:54:17 -040035import android.text.TextWatcher;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050036import android.util.Log;
Adrien Béraudb28c4912018-12-02 22:58:52 -050037import android.view.LayoutInflater;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050038import android.view.Menu;
39import android.view.MenuInflater;
40import android.view.MenuItem;
41import android.view.View;
42import android.view.ViewGroup;
43import android.view.inputmethod.EditorInfo;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050044import android.widget.Spinner;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050045import android.widget.Toast;
46
Rayan Osseirane4450272019-06-03 14:17:19 -040047import com.google.android.material.snackbar.Snackbar;
48
amine younes7c56f312019-06-10 11:34:25 -040049import androidx.annotation.NonNull;
50import androidx.annotation.Nullable;
51import androidx.appcompat.app.ActionBar;
52import androidx.appcompat.app.AppCompatActivity;
Adrien Béraud898c2bf2019-09-26 14:49:33 -040053import androidx.appcompat.view.menu.MenuBuilder;
54import androidx.appcompat.view.menu.MenuPopupHelper;
55import androidx.appcompat.widget.PopupMenu;
amine younes7c56f312019-06-10 11:34:25 -040056import androidx.core.content.FileProvider;
Adrien Béraud91f88742019-09-09 00:46:46 -040057import androidx.core.view.ViewCompat;
amine younes7c56f312019-06-10 11:34:25 -040058import androidx.recyclerview.widget.DefaultItemAnimator;
59
Pierre Duchemine0c3a492018-02-01 16:22:45 -050060import java.io.File;
61import java.io.IOException;
Adrien Béraudace37a22018-06-22 14:58:36 -040062import java.util.List;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050063
Aline Bonnet9c6defe2016-12-21 13:21:02 -050064import butterknife.OnEditorAction;
Adrien Béraud5b47cb52018-07-06 16:24:14 -040065import cx.ring.BuildConfig;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050066import cx.ring.R;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050067import cx.ring.adapters.ConversationAdapter;
68import cx.ring.adapters.NumberAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040069import cx.ring.application.JamiApplication;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050070import cx.ring.client.CallActivity;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -050071import cx.ring.client.ContactDetailsActivity;
Aline Bonnet830c4c62016-12-27 14:02:02 -050072import cx.ring.client.ConversationActivity;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050073import cx.ring.client.HomeActivity;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040074import cx.ring.contacts.AvatarFactory;
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -040075import cx.ring.conversation.ConversationPresenter;
76import cx.ring.conversation.ConversationView;
Adrien Béraudb28c4912018-12-02 22:58:52 -050077import cx.ring.databinding.FragConversationBinding;
Adrien Béraude4f901a2019-10-25 17:26:30 -040078import cx.ring.dependencyinjection.JamiInjectionComponent;
Adrien Béraud171ba362018-12-14 21:35:40 -050079import cx.ring.interfaces.Colorable;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050080import cx.ring.model.CallContact;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050081import cx.ring.model.Conversation;
Rayan Osseiran6f415662019-10-25 14:23:25 -040082import cx.ring.model.Interaction;
Adrien Béraud21533292018-03-22 14:11:35 -040083import cx.ring.model.DataTransfer;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050084import cx.ring.model.Phone;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050085import cx.ring.model.RingError;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050086import cx.ring.model.Uri;
Adrien Bérauda373e3b2018-12-12 11:14:50 -050087import cx.ring.mvp.BaseSupportFragment;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -040088import cx.ring.services.NotificationService;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050089import cx.ring.utils.ActionHelper;
Adrien Béraud64538722018-03-15 17:34:00 -040090import cx.ring.utils.AndroidFileUtils;
Adrien Béraud64538722018-03-15 17:34:00 -040091import cx.ring.utils.ContentUriHandler;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -050092import cx.ring.utils.MediaButtonsHelper;
Adrien Béraud44939482019-02-13 21:42:08 -050093import io.reactivex.Completable;
Adrien Béraud898c2bf2019-09-26 14:49:33 -040094import io.reactivex.Single;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040095import io.reactivex.android.schedulers.AndroidSchedulers;
96import io.reactivex.disposables.Disposable;
Rayan Osseiraned9feeb2019-07-05 16:04:30 -040097import io.reactivex.schedulers.Schedulers;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050098
Pierre Duchemine0c3a492018-02-01 16:22:45 -050099import static android.app.Activity.RESULT_OK;
100
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500101public class ConversationFragment extends BaseSupportFragment<ConversationPresenter> implements
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500102 MediaButtonsHelper.MediaButtonsHelperCallback,
Rayan Osseirane634a562019-05-29 13:44:55 -0400103 ConversationView, SharedPreferences.OnSharedPreferenceChangeListener {
Adrien Béraud64538722018-03-15 17:34:00 -0400104 protected static final String TAG = ConversationFragment.class.getSimpleName();
105
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400106 public static final int REQ_ADD_CONTACT = 42;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400107
Adrien Béraud6ac63632018-12-09 00:11:21 -0500108 public static final String KEY_CONTACT_RING_ID = BuildConfig.APPLICATION_ID + ".CONTACT_RING_ID";
109 public static final String KEY_ACCOUNT_ID = BuildConfig.APPLICATION_ID + ".ACCOUNT_ID";
Adrien Béraud3a875a02018-07-18 17:54:17 -0400110 public static final String KEY_PREFERENCE_PENDING_MESSAGE = "pendingMessage";
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500111 public static final String KEY_PREFERENCE_CONVERSATION_COLOR = "color";
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500112
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500113 private static final int REQUEST_CODE_FILE_PICKER = 1000;
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500114 private static final int REQUEST_PERMISSION_CAMERA = 1001;
Adrien Béraud64538722018-03-15 17:34:00 -0400115 private static final int REQUEST_CODE_TAKE_PICTURE = 1002;
amine younes7c56f312019-06-10 11:34:25 -0400116 private static final int REQUEST_CODE_SAVE_FILE = 1003;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400117 private static final int REQUEST_CODE_CAPTURE_AUDIO = 1004;
118 private static final int REQUEST_CODE_CAPTURE_VIDEO = 1005;
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500119
Adrien Béraudb28c4912018-12-02 22:58:52 -0500120 private FragConversationBinding binding;
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400121 private MenuItem mAudioCallBtn = null;
122 private MenuItem mVideoCallBtn = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500123
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400124 private View currentBottomView = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500125 private ConversationAdapter mAdapter = null;
126 private NumberAdapter mNumberAdapter = null;
Adrien Béraud772e2162019-02-12 16:00:21 -0500127 private int marginPx;
Adrien Béraud91f88742019-09-09 00:46:46 -0400128 private int marginPxTotal;
Adrien Béraud772e2162019-02-12 16:00:21 -0500129 private final ValueAnimator animation = new ValueAnimator();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500130
Adrien Béraud3a875a02018-07-18 17:54:17 -0400131 private SharedPreferences mPreferences;
132
Adrien Béraud64538722018-03-15 17:34:00 -0400133 private File mCurrentPhoto = null;
amine younes7c56f312019-06-10 11:34:25 -0400134 private String mCurrentFileAbsolutePath = null;
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400135 private Disposable actionbarTarget = null;
Adrien Béraud742d3202019-11-15 14:28:59 -0500136 private int mSelectedPosition;
Adrien Béraud64538722018-03-15 17:34:00 -0400137
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500138 private static int getIndex(Spinner spinner, Uri myString) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500139 for (int i = 0, n = spinner.getCount(); i < n; i++)
140 if (((Phone) spinner.getItemAtPosition(i)).getNumber().equals(myString)) {
141 return i;
142 }
143 return 0;
144 }
145
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400146 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400147 public void refreshView(final List<Interaction> conversation) {
Adrien Béraud20d42212018-03-02 14:40:38 -0500148 if (conversation == null) {
149 return;
150 }
Adrien Béraudb28c4912018-12-02 22:58:52 -0500151 if (binding != null)
152 binding.pbLoading.setVisibility(View.GONE);
Adrien Béraudace37a22018-06-22 14:58:36 -0400153 if (mAdapter != null) {
154 mAdapter.updateDataset(conversation);
155 }
Rayan Osseiran6f415662019-10-25 14:23:25 -0400156 requireActivity().invalidateOptionsMenu();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500157 }
158
Aline Bonnete8e87f62016-12-26 10:54:37 -0500159 @Override
Adrien Béraud64538722018-03-15 17:34:00 -0400160 public void scrollToEnd() {
Adrien Béraudace37a22018-06-22 14:58:36 -0400161 if (mAdapter.getItemCount() > 0) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500162 binding.histList.scrollToPosition(mAdapter.getItemCount() - 1);
Adrien Béraudace37a22018-06-22 14:58:36 -0400163 }
Adrien Béraud64538722018-03-15 17:34:00 -0400164 }
165
166 @Override
Hadrien De Sousa73d6dd72017-09-07 10:54:51 -0400167 public int getLayout() {
168 return R.layout.frag_conversation;
169 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500170
Hadrien De Sousa73d6dd72017-09-07 10:54:51 -0400171 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400172 public void injectFragment(JamiInjectionComponent component) {
Hadrien De Sousa73d6dd72017-09-07 10:54:51 -0400173 component.inject(this);
174 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500175
Adrien Béraud91f88742019-09-09 00:46:46 -0400176 private static void setBottomPadding(@NonNull View view, int padding) {
177 view.setPadding(
178 view.getPaddingLeft(),
179 view.getPaddingTop(),
180 view.getPaddingRight(),
181 padding);
182 }
183
184 private void updateListPadding() {
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400185 if (currentBottomView != null && currentBottomView.getHeight() != 0)
186 setBottomPadding(binding.histList, currentBottomView.getHeight() + marginPxTotal);
Adrien Béraud91f88742019-09-09 00:46:46 -0400187 }
188
Adrien Béraudb28c4912018-12-02 22:58:52 -0500189 @Nullable
190 @Override
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500191 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400192 injectFragment(((JamiApplication) getActivity().getApplication()).getRingInjectionComponent());
Adrien Béraud91f88742019-09-09 00:46:46 -0400193 marginPx = getResources().getDimensionPixelSize(R.dimen.conversation_message_input_margin);
194 marginPxTotal = marginPx;
Adrien Béraudfd083672019-10-31 13:52:38 -0400195
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500196 binding = FragConversationBinding.inflate(inflater, container, false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500197 binding.setPresenter(this);
Adrien Béraud91f88742019-09-09 00:46:46 -0400198
Adrien Béraudfd083672019-10-31 13:52:38 -0400199 animation.setDuration(150);
200 animation.addUpdateListener(valueAnimator -> setBottomPadding(binding.histList, (Integer)valueAnimator.getAnimatedValue()));
201
Adrien Béraud91f88742019-09-09 00:46:46 -0400202 ViewCompat.setOnApplyWindowInsetsListener(binding.histList, (v, insets) -> {
203 marginPxTotal = marginPx + insets.getSystemWindowInsetBottom();
204 updateListPadding();
205 insets.consumeSystemWindowInsets();
206 return insets;
207 });
208 int paddingTop = binding.conversationLayout.getPaddingTop();
209 ViewCompat.setOnApplyWindowInsetsListener(binding.conversationLayout, (v, insets) -> {
210 v.setPadding(
211 v.getPaddingLeft(),
212 paddingTop + insets.getSystemWindowInsetTop(),
213 v.getPaddingRight(),
214 v.getPaddingBottom());
215 insets.consumeSystemWindowInsets();
216 return insets;
217 });
218
Adrien Béraudfd083672019-10-31 13:52:38 -0400219 binding.ongoingcallPane.setVisibility(View.GONE);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400220 binding.msgInputTxt.setMediaListener(contentInfo -> startFileSend(AndroidFileUtils
Adrien Béraudfd083672019-10-31 13:52:38 -0400221 .getCacheFile(requireContext(), contentInfo.getContentUri())
222 .flatMapCompletable(this::sendFile)
223 .doFinally(contentInfo::releasePermission)));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500224 binding.msgInputTxt.setOnEditorActionListener((v, actionId, event) -> actionSendMsgText(actionId));
225 binding.msgInputTxt.addTextChangedListener(new TextWatcher() {
Adrien Béraud3a875a02018-07-18 17:54:17 -0400226 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500227 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
228 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400229
230 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500231 public void onTextChanged(CharSequence s, int start, int before, int count) {
232 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400233
234 @Override
235 public void afterTextChanged(Editable s) {
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400236 String message = s.toString();
Adrien Béraude09dd012019-11-15 14:57:18 -0500237 boolean hasMessage = !TextUtils.isEmpty(message);
Rayan Osseiran6f415662019-10-25 14:23:25 -0400238 if (hasMessage) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500239 binding.msgSend.setVisibility(View.VISIBLE);
240 binding.emojiSend.setVisibility(View.GONE);
Adrien Béraude09dd012019-11-15 14:57:18 -0500241 } else {
242 binding.msgSend.setVisibility(View.GONE);
243 binding.emojiSend.setVisibility(View.VISIBLE);
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400244 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400245 if (mPreferences != null) {
Rayan Osseiran6f415662019-10-25 14:23:25 -0400246 if (hasMessage)
247 mPreferences.edit().putString(KEY_PREFERENCE_PENDING_MESSAGE, message).apply();
248 else
249 mPreferences.edit().remove(KEY_PREFERENCE_PENDING_MESSAGE).apply();
Adrien Béraud3a875a02018-07-18 17:54:17 -0400250 }
251 }
252 });
Adrien Béraud9d4a81f2018-07-09 01:19:52 -0400253
Adrien Béraudfd083672019-10-31 13:52:38 -0400254 setHasOptionsMenu(true);
255 return binding.getRoot();
256 }
257
258 @Override
259 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
260 super.onViewCreated(view, savedInstanceState);
261
262 if (mPreferences != null) {
263 String pendingMessage = mPreferences.getString(KEY_PREFERENCE_PENDING_MESSAGE, null);
264 if (!TextUtils.isEmpty(pendingMessage)) {
265 binding.msgInputTxt.setText(pendingMessage);
266 binding.msgSend.setVisibility(View.VISIBLE);
267 binding.emojiSend.setVisibility(View.GONE);
268 }
269 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500270
271 binding.msgInputTxt.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400272 if (oldBottom == 0 && oldTop == 0) {
273 updateListPadding();
274 } else {
275 if (animation.isStarted())
276 animation.cancel();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400277 animation.setIntValues(binding.histList.getPaddingBottom(), (currentBottomView == null ? 0 : currentBottomView.getHeight()) + marginPxTotal);
Adrien Béraud91f88742019-09-09 00:46:46 -0400278 animation.start();
279 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500280 });
281
Adrien Béraudb28c4912018-12-02 22:58:52 -0500282 DefaultItemAnimator animator = (DefaultItemAnimator) binding.histList.getItemAnimator();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500283 if (animator != null)
284 animator.setSupportsChangeAnimations(false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500285 binding.histList.setAdapter(mAdapter);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500286 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500287
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500288 @Override
289 public void setConversationColor(int color) {
Adrien Béraud171ba362018-12-14 21:35:40 -0500290 Colorable activity = (Colorable) getActivity();
291 if (activity != null)
292 activity.setColor(color);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500293 mAdapter.setPrimaryColor(color);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500294 }
295
Adrien Béraud7c505112018-03-20 16:03:28 -0400296 @Override
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500297 public void onDestroyView() {
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500298 if (mPreferences != null)
299 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
Adrien Béraud772e2162019-02-12 16:00:21 -0500300 animation.removeAllUpdateListeners();
Adrien Béraudb28c4912018-12-02 22:58:52 -0500301 binding.histList.setAdapter(null);
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500302 super.onDestroyView();
303 }
304
305 @Override
Adrien Béraudfd083672019-10-31 13:52:38 -0400306 public boolean onContextItemSelected(@NonNull MenuItem item) {
Adrien Béraud7c505112018-03-20 16:03:28 -0400307 if (mAdapter.onContextItemSelected(item))
308 return true;
309 return super.onContextItemSelected(item);
310 }
311
Rayan Osseirane634a562019-05-29 13:44:55 -0400312 public void updateAdapterItem() {
Adrien Béraud742d3202019-11-15 14:28:59 -0500313 if (mSelectedPosition != -1) {
314 mAdapter.notifyItemChanged(mSelectedPosition);
315 mSelectedPosition = -1;
Rayan Osseirane634a562019-05-29 13:44:55 -0400316 }
317 }
318
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500319 public void sendMessageText() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500320 String message = binding.msgInputTxt.getText().toString();
Adrien Béraudace37a22018-06-22 14:58:36 -0400321 clearMsgEdit();
322 presenter.sendTextMessage(message);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500323 }
324
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400325 public void sendEmoji() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500326 presenter.sendTextMessage(binding.emojiSend.getText().toString());
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400327 }
328
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500329 public void selectFile() {
330 presenter.selectFile();
331 }
332
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400333 public void expandMenu(View v) {
334 Context context = requireContext();
335 PopupMenu popup = new PopupMenu(context, v);
336 popup.inflate(R.menu.conversation_share_actions);
337 popup.setOnMenuItemClickListener(item -> {
338 switch(item.getItemId()) {
339 case R.id.conv_send_audio: {
340 Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
341 if (intent.resolveActivity(context.getPackageManager()) != null) {
342 try {
343 mCurrentPhoto = AndroidFileUtils.createAudioFile(context);
344 } catch (IOException ex) {
345 Log.e(TAG, "takePicture: error creating temporary file", ex);
346 break;
347 }
348 //intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, mCurrentPhoto));
349 startActivityForResult(intent, REQUEST_CODE_CAPTURE_AUDIO);
350 } else {
351 Toast.makeText(getActivity(), "Can't find audio recorder app", Toast.LENGTH_SHORT).show();
352 }
353 break;
354 }
355 case R.id.conv_send_video: {
356 Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
357 intent.putExtra("android.intent.extras.CAMERA_FACING", android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
358 intent.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
359 intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
360 if (intent.resolveActivity(context.getPackageManager()) != null) {
361 try {
362 mCurrentPhoto = AndroidFileUtils.createVideoFile(context);
363 } catch (IOException ex) {
364 Log.e(TAG, "takePicture: error creating temporary file", ex);
365 break;
366 }
367 intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, mCurrentPhoto));
368 startActivityForResult(intent, REQUEST_CODE_CAPTURE_VIDEO);
369 } else {
370 Toast.makeText(getActivity(), "Can't find video recorder app", Toast.LENGTH_SHORT).show();
371 }
372 break;
373 }
374 case R.id.conv_send_file:
375 selectFile();
376 break;
377 }
378 return false;
379 });
380 MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), v);
381 menuHelper.setForceShowIcon(true);
382 menuHelper.show();
383 }
384
Rayan Osseirane634a562019-05-29 13:44:55 -0400385 /**
386 * Used to update with the past adapter position when a long click was registered
387 * @param position
388 */
389 public void updatePosition(int position) {
Adrien Béraud742d3202019-11-15 14:28:59 -0500390 mSelectedPosition = position;
Rayan Osseirane634a562019-05-29 13:44:55 -0400391 }
392
Adrien Béraud64538722018-03-15 17:34:00 -0400393 public void takePicture() {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500394 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400395 requestPermissions(new String[]{Manifest.permission.CAMERA}, JamiApplication.PERMISSIONS_REQUEST);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500396 } else {
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500397 Context c = getContext();
398 if (c == null)
399 return;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500400 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500401 if (takePictureIntent.resolveActivity(c.getPackageManager()) != null) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500402 // Create the File where the photo should go
Adrien Béraud44939482019-02-13 21:42:08 -0500403 File photoFile;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500404 try {
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500405 photoFile = AndroidFileUtils.createImageFile(c);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500406 } catch (IOException ex) {
407 Log.e(TAG, "takePicture: error creating temporary file", ex);
408 return;
409 }
410 Log.i(TAG, "takePicture: trying to save to " + photoFile);
411 mCurrentPhoto = photoFile;
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500412 android.net.Uri photoURI = FileProvider.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, photoFile);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500413 takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
414 startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE);
Adrien Béraud64538722018-03-15 17:34:00 -0400415 }
Adrien Béraud64538722018-03-15 17:34:00 -0400416 }
417 }
418
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500419 @Override
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500420 public void askWriteExternalStoragePermission() {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400421 requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, JamiApplication.PERMISSIONS_REQUEST);
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500422 }
423
424 @Override
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500425 public void openFilePicker() {
426 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
427 intent.addCategory(Intent.CATEGORY_OPENABLE);
428 intent.setType("*/*");
429
430 startActivityForResult(intent, REQUEST_CODE_FILE_PICKER);
431 }
432
Adrien Béraud44939482019-02-13 21:42:08 -0500433 private Completable sendFile(File file) {
434 return Completable.fromAction(() -> presenter.sendFile(file));
435 }
436
Adrien Béraud44939482019-02-13 21:42:08 -0500437 private void startFileSend(Completable op) {
438 setLoading(true);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400439 op.observeOn(AndroidSchedulers.mainThread())
Adrien Béraud44939482019-02-13 21:42:08 -0500440 .doFinally(() -> setLoading(false))
441 .subscribe(() -> {}, e -> {
442 Log.e(TAG, "startFileSend: not able to create cache file", e);
443 displayErrorToast(RingError.INVALID_FILE);
444 });
445 }
446
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500447 @Override
Pierre Duchemin17542a72018-02-14 16:38:36 -0500448 public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
Adrien Béraud64538722018-03-15 17:34:00 -0400449 Log.w(TAG, "onActivityResult: " + requestCode + " " + resultCode + " " + resultData);
Pierre Duchemin17542a72018-02-14 16:38:36 -0500450 super.onActivityResult(requestCode, resultCode, resultData);
451
452 if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
Adrien Béraud64538722018-03-15 17:34:00 -0400453 if (resultData == null) {
454 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -0500455 }
Adrien Béraud64538722018-03-15 17:34:00 -0400456 android.net.Uri uri = resultData.getData();
457 if (uri == null) {
458 return;
459 }
Adrien Béraud1af6c012019-05-25 23:20:29 -0400460 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri)
461 .observeOn(AndroidSchedulers.mainThread())
462 .flatMapCompletable(this::sendFile));
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400463 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE
464 || requestCode == REQUEST_CODE_CAPTURE_AUDIO
465 || requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
Adrien Béraud64538722018-03-15 17:34:00 -0400466 if (resultCode != RESULT_OK) {
467 mCurrentPhoto = null;
468 return;
469 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500470 Log.w(TAG, "onActivityResult: mCurrentPhoto " + mCurrentPhoto.getAbsolutePath() + " " + mCurrentPhoto.exists() + " " + mCurrentPhoto.length());
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400471 Single<File> file = null;
Adrien Béraud64538722018-03-15 17:34:00 -0400472 if (mCurrentPhoto == null || !mCurrentPhoto.exists() || mCurrentPhoto.length() == 0) {
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400473 android.net.Uri createdUri = resultData.getData();
474 if (createdUri != null) {
475 file = AndroidFileUtils.getCacheFile(requireContext(), createdUri);
476 }
477 } else {
478 file = Single.just(mCurrentPhoto);
Adrien Béraud64538722018-03-15 17:34:00 -0400479 }
Adrien Béraud44939482019-02-13 21:42:08 -0500480 mCurrentPhoto = null;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400481 if (file == null) {
482 Toast.makeText(getActivity(), "Can't find picture", Toast.LENGTH_SHORT).show();
483 return;
484 }
485 startFileSend(file.flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500486 }
amine younes7c56f312019-06-10 11:34:25 -0400487 // File download trough SAF
488 else if(requestCode == ConversationFragment.REQUEST_CODE_SAVE_FILE
489 && resultCode == RESULT_OK){
490 if(resultData != null && resultData.getData() != null ) {
491 //Get the Uri of the file that was created by the app that received our intent
492 android.net.Uri createdUri = resultData.getData();
493
494 //Try to copy the data of the current file into the newly created one
495 File input = new File(mCurrentFileAbsolutePath);
496 if(requireContext().getContentResolver() != null)
497 AndroidFileUtils.copyFileToUri(
498 requireContext().getContentResolver(),input,createdUri).
499 observeOn(AndroidSchedulers.mainThread()).
500 subscribe(()->Toast.makeText(getContext(), R.string.file_saved_successfully,
501 Toast.LENGTH_SHORT).show(),
502 error->Toast.makeText(getContext(), R.string.generic_error,
503 Toast.LENGTH_SHORT).show());
504
505 }
506 }
507
Pierre Duchemin17542a72018-02-14 16:38:36 -0500508 }
509
510 @Override
Adrien Béraud4f542f92019-01-03 12:17:53 -0500511 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
512 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
513 for (int i = 0, n = permissions.length; i < n; i++) {
514 switch (permissions[i]) {
515 case Manifest.permission.CAMERA:
516 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400517 presenter.cameraPermissionChanged(granted);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500518 if (granted) {
519 takePicture();
520 }
521 return;
522 default:
523 break;
524 }
525 }
526 }
527
528 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400529 public void addElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400530 mAdapter.add(element);
531 scrollToEnd();
532 }
Adrien Béraud3cbc7fa2018-07-18 18:36:21 -0400533
Adrien Béraudace37a22018-06-22 14:58:36 -0400534 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400535 public void updateElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400536 mAdapter.update(element);
537 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500538
Adrien Béraudace37a22018-06-22 14:58:36 -0400539 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400540 public void removeElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400541 mAdapter.remove(element);
Adrien Béraud21533292018-03-22 14:11:35 -0400542 }
543
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400544 @Override
545 public void shareFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500546 Context c = getContext();
547 if (c == null)
548 return;
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400549 android.net.Uri fileUri = null;
550 try {
Adrien Béraud50549532019-01-03 12:22:16 -0500551 fileUri = FileProvider.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400552 } catch (IllegalArgumentException e) {
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500553 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400554 }
555 if (fileUri != null) {
556 Intent sendIntent = new Intent();
557 sendIntent.setAction(Intent.ACTION_SEND);
558 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500559 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400560 sendIntent.setDataAndType(fileUri, type);
561 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
562 startActivity(Intent.createChooser(sendIntent, null));
563 }
564 }
565
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500566 @Override
567 public void openFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500568 Context c = getContext();
569 if (c == null)
570 return;
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500571 android.net.Uri fileUri = null;
572 try {
Adrien Béraud50549532019-01-03 12:22:16 -0500573 fileUri = FileProvider.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500574 } catch (IllegalArgumentException e) {
575 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
576 }
577 if (fileUri != null) {
578 Intent sendIntent = new Intent();
579 sendIntent.setAction(Intent.ACTION_VIEW);
580 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500581 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500582 sendIntent.setDataAndType(fileUri, type);
583 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
584 //startActivity(Intent.createChooser(sendIntent, null));
Rayan Osseirane4450272019-06-03 14:17:19 -0400585 try {
586 startActivity(sendIntent);
587 } catch (ActivityNotFoundException e) {
588 Snackbar.make(getView(), R.string.conversation_open_file_error, Snackbar.LENGTH_LONG).show();
589 Log.e("File Loader", "File of unknown type, could not open: " + path.getName());
590 }
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500591 }
592 }
593
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500594 @OnEditorAction(R.id.msg_input_txt)
Adrien Béraud44939482019-02-13 21:42:08 -0500595 boolean actionSendMsgText(int actionId) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500596 switch (actionId) {
597 case EditorInfo.IME_ACTION_SEND:
Adrien Béraudace37a22018-06-22 14:58:36 -0400598 sendMessageText();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500599 return true;
600 }
601 return false;
602 }
603
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500604 public void onClick() {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400605 presenter.clickOnGoingPane();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500606 }
607
608 @Override
609 public void onPause() {
610 super.onPause();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400611 presenter.pause();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500612 }
613
614 @Override
615 public void onResume() {
616 super.onResume();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400617 presenter.resume();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500618 }
619
620 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400621 public void onDetach() {
622 if (actionbarTarget != null) {
623 actionbarTarget.dispose();
624 actionbarTarget = null;
625 }
626 super.onDetach();
627 }
628
629 @Override
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500630 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400631 inflater.inflate(R.menu.conversation_actions, menu);
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400632 mAudioCallBtn = menu.findItem(R.id.conv_action_audiocall);
633 mVideoCallBtn = menu.findItem(R.id.conv_action_videocall);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500634 }
635
636 @Override
637 public boolean onOptionsItemSelected(MenuItem item) {
638 switch (item.getItemId()) {
639 case android.R.id.home:
640 startActivity(new Intent(getActivity(), HomeActivity.class));
641 return true;
642 case R.id.conv_action_audiocall:
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500643 presenter.callWithAudioOnly(true);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500644 return true;
645 case R.id.conv_action_videocall:
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500646 presenter.callWithAudioOnly(false);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500647 return true;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500648 case R.id.conv_contact_details:
649 presenter.openContact();
Aline Bonnet54cf69b2017-03-28 12:03:45 -0400650 return true;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500651 default:
652 return super.onOptionsItemSelected(item);
653 }
654 }
655
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500656 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400657 protected void initPresenter(ConversationPresenter presenter) {
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500658 Bundle args = getArguments();
659 if (args == null)
660 return;
661 Uri contactUri = new Uri(args.getString(KEY_CONTACT_RING_ID));
662 String accountId = args.getString(KEY_ACCOUNT_ID);
663 mAdapter = new ConversationAdapter(this, presenter);
664 presenter.init(contactUri, accountId);
Adrien Béraud56c34132018-11-29 13:32:00 -0500665 try {
Adrien Béraud44939482019-02-13 21:42:08 -0500666 mPreferences = requireActivity().getSharedPreferences(accountId + "_" + contactUri.getRawRingId(), Context.MODE_PRIVATE);
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500667 mPreferences.registerOnSharedPreferenceChangeListener(this);
668 presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
Adrien Béraud56c34132018-11-29 13:32:00 -0500669 } catch (Exception e) {
670 Log.e(TAG, "Can't load conversation preferences");
671 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500672 }
673
674 @Override
675 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
676 switch (key) {
677 case KEY_PREFERENCE_CONVERSATION_COLOR:
678 presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
679 break;
680 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400681 }
682
683 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400684 public void displayContact(final CallContact contact) {
Adrien Béraud44939482019-02-13 21:42:08 -0500685 ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar();
Adrien Béraudace37a22018-06-22 14:58:36 -0400686 if (actionBar == null) {
687 return;
688 }
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400689 Context context = actionBar.getThemedContext();
Adrien Béraudace37a22018-06-22 14:58:36 -0400690 String displayName = contact.getDisplayName();
691 actionBar.setTitle(displayName);
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400692
693 if (actionbarTarget != null) {
694 actionbarTarget.dispose();
695 actionbarTarget = null;
696 }
697 int targetSize = (int) (AvatarFactory.SIZE_AB * context.getResources().getDisplayMetrics().density);
698 actionbarTarget = AvatarFactory.getBitmapAvatar(context, contact, targetSize)
Rayan Osseiraned9feeb2019-07-05 16:04:30 -0400699 .subscribeOn(Schedulers.computation())
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400700 .observeOn(AndroidSchedulers.mainThread())
701 .subscribe(b -> actionBar.setLogo(new BitmapDrawable(context.getResources(), b)));
702
Adrien Béraudace37a22018-06-22 14:58:36 -0400703 String identity = contact.getRingUsername();
704 if (identity != null && !identity.equals(displayName)) {
705 actionBar.setSubtitle(identity);
706 }
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400707
708 mAdapter.setPhoto();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400709 }
710
711 @Override
712 public void displayOnGoingCallPane(final boolean display) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500713 binding.ongoingcallPane.setVisibility(display ? View.VISIBLE : View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400714 }
715
716 @Override
717 public void displayNumberSpinner(final Conversation conversation, final Uri number) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500718 binding.numberSelector.setVisibility(View.VISIBLE);
Adrien Béraudace37a22018-06-22 14:58:36 -0400719 mNumberAdapter = new NumberAdapter(getActivity(),
720 conversation.getContact(),
721 false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500722 binding.numberSelector.setAdapter(mNumberAdapter);
723 binding.numberSelector.setSelection(getIndex(binding.numberSelector, number));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400724 }
725
726 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400727 public void hideNumberSpinner() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500728 binding.numberSelector.setVisibility(View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400729 }
730
731 @Override
732 public void clearMsgEdit() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500733 binding.msgInputTxt.setText("");
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400734 }
735
736 @Override
737 public void goToHome() {
738 if (getActivity() instanceof ConversationActivity) {
739 getActivity().finish();
Aline Bonneteb5f7ff2017-01-17 11:09:17 -0500740 }
741 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400742
743 @Override
744 public void goToAddContact(CallContact callContact) {
745 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact), REQ_ADD_CONTACT);
746 }
747
748 @Override
749 public void goToCallActivity(String conferenceId) {
750 startActivity(new Intent(Intent.ACTION_VIEW)
Adrien Béraud44939482019-02-13 21:42:08 -0500751 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400752 .putExtra(NotificationService.KEY_CALL_ID, conferenceId));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400753 }
754
755 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500756 public void goToContactActivity(String accountId, String contactRingId) {
757 startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contactRingId))
Adrien Béraud44939482019-02-13 21:42:08 -0500758 .setClass(requireActivity().getApplicationContext(), ContactDetailsActivity.class));
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500759 }
760
761 @Override
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500762 public void goToCallActivityWithResult(String accountId, String contactRingId, boolean audioOnly) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400763 Intent intent = new Intent(CallActivity.ACTION_CALL)
Adrien Béraud44939482019-02-13 21:42:08 -0500764 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500765 .putExtra(KEY_ACCOUNT_ID, accountId)
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500766 .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500767 .putExtra(KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400768 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
769 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500770
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500771 public void blockContactRequest() {
772 presenter.onBlockIncomingContactRequest();
773 }
774
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500775 public void refuseContactRequest() {
776 presenter.onRefuseIncomingContactRequest();
777 }
778
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500779 public void acceptContactRequest() {
780 presenter.onAcceptIncomingContactRequest();
781 }
782
Adrien Béraudace37a22018-06-22 14:58:36 -0400783 public void addContact() {
784 presenter.onAddContact();
785 }
786
787 @Override
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400788 public void onPrepareOptionsMenu(Menu menu) {
789 super.onPrepareOptionsMenu(menu);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500790 boolean visible = binding.cvMessageInput.getVisibility() == View.VISIBLE;
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400791 if (mAudioCallBtn != null)
792 mAudioCallBtn.setVisible(visible);
793 if (mVideoCallBtn != null)
794 mVideoCallBtn.setVisible(visible);
795 }
796
797 @Override
Adrien Béraudace37a22018-06-22 14:58:36 -0400798 public void switchToUnknownView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500799 binding.cvMessageInput.setVisibility(View.GONE);
800 binding.unknownContactPrompt.setVisibility(View.VISIBLE);
801 binding.trustRequestPrompt.setVisibility(View.GONE);
802 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted), contactDisplayName));
803 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400804 currentBottomView = binding.unknownContactPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -0500805 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400806 updateListPadding();
Adrien Béraudace37a22018-06-22 14:58:36 -0400807 }
808
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500809 @Override
810 public void switchToIncomingTrustRequestView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500811 binding.cvMessageInput.setVisibility(View.GONE);
812 binding.unknownContactPrompt.setVisibility(View.GONE);
813 binding.trustRequestPrompt.setVisibility(View.VISIBLE);
814 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted_yet), contactDisplayName));
815 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400816 currentBottomView = binding.trustRequestPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -0500817 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400818 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500819 }
820
821 @Override
822 public void switchToConversationView() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500823 binding.cvMessageInput.setVisibility(View.VISIBLE);
824 binding.unknownContactPrompt.setVisibility(View.GONE);
825 binding.trustRequestPrompt.setVisibility(View.GONE);
826 binding.trustRequestMessageLayout.setVisibility(View.GONE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400827 currentBottomView = binding.cvMessageInput;
Adrien Béraud44939482019-02-13 21:42:08 -0500828 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400829 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500830 }
831
832 @Override
833 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500834 presenter.clickOnGoingPane();
835 }
836
837 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500838 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500839 presenter.clickOnGoingPane();
840 }
841
842 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500843 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500844 presenter.clickOnGoingPane();
845 }
Pierre Duchemin17542a72018-02-14 16:38:36 -0500846
847 private void setLoading(boolean isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500848 if (binding == null)
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400849 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -0500850 if (isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500851 binding.btnTakePicture.setVisibility(View.GONE);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500852 binding.pbDataTransfer.setVisibility(View.VISIBLE);
Pierre Duchemin17542a72018-02-14 16:38:36 -0500853 } else {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500854 binding.btnTakePicture.setVisibility(View.VISIBLE);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500855 binding.pbDataTransfer.setVisibility(View.GONE);
Pierre Duchemin17542a72018-02-14 16:38:36 -0500856 }
857 }
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -0400858
Adrien Béraudae45ffa2018-07-06 16:21:29 -0400859 public void handleShareIntent(Intent intent) {
860 String type = intent.getType();
861 if (type == null) {
862 Log.w(TAG, "Can't share with no type");
863 return;
864 }
Rayan Osseirane4450272019-06-03 14:17:19 -0400865 if (type.startsWith("text/plain")) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500866 binding.msgInputTxt.setText(intent.getStringExtra(Intent.EXTRA_TEXT));
Rayan Osseirane4450272019-06-03 14:17:19 -0400867 } else {
Adrien Béraudae45ffa2018-07-06 16:21:29 -0400868 android.net.Uri uri = intent.getData();
869 ClipData clip = intent.getClipData();
870 if (uri == null && clip != null && clip.getItemCount() > 0)
871 uri = clip.getItemAt(0).getUri();
872 if (uri == null)
873 return;
Adrien Béraud1af6c012019-05-25 23:20:29 -0400874 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri).flatMapCompletable(this::sendFile));
Adrien Béraudae45ffa2018-07-06 16:21:29 -0400875 }
876 }
amine younes7c56f312019-06-10 11:34:25 -0400877
878 /**
879 * Creates an intent using Android Storage Access Framework
880 * This intent is then received by applications that can handle it like
881 * Downloads or Google drive
882 * @param file DataTransfer of the file that is going to be stored
883 * @param currentFileAbsolutePath absolute path of the file we want to save
884 */
885 public void startSaveFile(DataTransfer file, String currentFileAbsolutePath){
886 //Get the current file absolute path and store it
887 mCurrentFileAbsolutePath = currentFileAbsolutePath;
888
889 //Use Android Storage File Access to download the file
890 Intent downloadFileIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
891 downloadFileIntent.setType(AndroidFileUtils.getMimeTypeFromExtension(file.getExtension()));
892
893 downloadFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
894 downloadFileIntent.putExtra(Intent.EXTRA_TITLE,file.getDisplayName());
895
896 startActivityForResult(downloadFileIntent, ConversationFragment.REQUEST_CODE_SAVE_FILE);
897 }
898
Adrien Béraude32ab742018-08-25 21:15:08 -0400899}