From cc2651700681d72a38935c6299b600b9242d7001 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 23 Oct 2017 13:50:55 +0200 Subject: [PATCH] Started GroupChatFragment, in standby until Events are wrapped --- res/layout/chat_bubble.xml | 6 +- res/values/strings.xml | 1 + .../linphone/activities/LinphoneActivity.java | 7 +- .../linphone/chat/ChatBubbleViewHolder.java | 109 +++++++ .../org/linphone/chat/ChatEventsAdapter.java | 58 ++++ .../org/linphone/chat/ChatFragment.java | 73 +---- .../org/linphone/chat/GroupChatFragment.java | 283 ++++++++++++++++-- .../linphone/chat/InfoGroupChatFragment.java | 4 +- .../chat/SearchContactsListAdapter.java | 4 +- 9 files changed, 444 insertions(+), 101 deletions(-) create mode 100644 src/android/org/linphone/chat/ChatBubbleViewHolder.java create mode 100644 src/android/org/linphone/chat/ChatEventsAdapter.java diff --git a/res/layout/chat_bubble.xml b/res/layout/chat_bubble.xml index 454fbe5e3..bbe8d147b 100644 --- a/res/layout/chat_bubble.xml +++ b/res/layout/chat_bubble.xml @@ -22,8 +22,7 @@ android:id="@+id/event_date" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textStyle="italic" - android:text="Aujourd'hui"/> + android:textStyle="italic"/> + android:layout_height="wrap_content"/> Do you want to delete selected conversation? Do you want to delete selected message? Remote is writing... + %s is writing... Small Medium Large diff --git a/src/android/org/linphone/activities/LinphoneActivity.java b/src/android/org/linphone/activities/LinphoneActivity.java index b12bf8eb4..1eaa02516 100644 --- a/src/android/org/linphone/activities/LinphoneActivity.java +++ b/src/android/org/linphone/activities/LinphoneActivity.java @@ -711,12 +711,7 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick if(sipUri == null && message == null && fileUri == null) { changeCurrentFragment(FragmentsAvailable.CREATE_CHAT, extras); } else { - ChatRoom room = LinphoneManager.getLc().getChatRoom(lAddress); - if (room.canHandleParticipants()) { - changeCurrentFragment(FragmentsAvailable.GROUP_CHAT, extras); - } else { - changeCurrentFragment(FragmentsAvailable.CHAT, extras); - } + changeCurrentFragment(FragmentsAvailable.GROUP_CHAT, extras); } } diff --git a/src/android/org/linphone/chat/ChatBubbleViewHolder.java b/src/android/org/linphone/chat/ChatBubbleViewHolder.java new file mode 100644 index 000000000..49123e141 --- /dev/null +++ b/src/android/org/linphone/chat/ChatBubbleViewHolder.java @@ -0,0 +1,109 @@ +/* +ChatBubbleViewHolder.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package org.linphone.chat; + +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import org.linphone.R; +import org.linphone.core.Buffer; +import org.linphone.core.ChatMessage; +import org.linphone.core.ChatMessageListener; +import org.linphone.core.Content; + +public class ChatBubbleViewHolder implements ChatMessageListener { + public int id; + + public LinearLayout eventLayout; + public TextView eventTime; + public TextView eventMessage; + + public RelativeLayout bubbleLayout; + public CheckBox delete; + public LinearLayout background; + public ImageView contactPicture; + public TextView contactName; + public TextView messageText; + public ImageView messageImage; + public RelativeLayout fileTransferLayout; + public ProgressBar fileTransferProgressBar; + public Button fileTransferAction; + public ImageView messageStatus; + public ProgressBar messageSendingInProgress; + public ImageView contactPictureMask; + public LinearLayout imdmLayout; + public ImageView imdmIcon; + public TextView imdmLabel; + public TextView fileExtensionLabel; + public TextView fileNameLabel; + + public ChatBubbleViewHolder(View view) { + id = view.getId(); + + eventLayout = view.findViewById(R.id.event); + eventTime = view.findViewById(R.id.event_date); + eventMessage = view.findViewById(R.id.event_text); + + bubbleLayout = (RelativeLayout) view.findViewById(R.id.bubble); + delete = (CheckBox) view.findViewById(R.id.delete_message); + background = (LinearLayout) view.findViewById(R.id.background); + contactPicture = (ImageView) view.findViewById(R.id.contact_picture); + contactName = (TextView) view.findViewById(R.id.contact_header); + messageText = (TextView) view.findViewById(R.id.message); + messageImage = (ImageView) view.findViewById(R.id.image); + fileTransferLayout = (RelativeLayout) view.findViewById(R.id.file_transfer_layout); + fileTransferProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar); + fileTransferAction = (Button) view.findViewById(R.id.file_transfer_action); + messageStatus = (ImageView) view.findViewById(R.id.status); + messageSendingInProgress = (ProgressBar) view.findViewById(R.id.inprogress); + contactPictureMask = (ImageView) view.findViewById(R.id.mask); + imdmLayout = (LinearLayout) view.findViewById(R.id.imdmLayout); + imdmIcon = (ImageView) view.findViewById(R.id.imdmIcon); + imdmLabel = (TextView) view.findViewById(R.id.imdmText); + fileExtensionLabel = (TextView) view.findViewById(R.id.file_extension); + fileNameLabel = (TextView) view.findViewById(R.id.file_name); + } + + @Override + public void onMsgStateChanged(ChatMessage msg, ChatMessage.State state) { + + } + + @Override + public void onFileTransferRecv(ChatMessage msg, Content content, Buffer buffer) { + + } + + @Override + public Buffer onFileTransferSend(ChatMessage message, Content content, int offset, int size) { + return null; + } + + @Override + public void onFileTransferProgressIndication(ChatMessage msg, Content content, int offset, int total) { + if (msg.getStorageId() == id) fileTransferProgressBar.setProgress(offset * 100 / total); + } +} \ No newline at end of file diff --git a/src/android/org/linphone/chat/ChatEventsAdapter.java b/src/android/org/linphone/chat/ChatEventsAdapter.java new file mode 100644 index 000000000..d94803553 --- /dev/null +++ b/src/android/org/linphone/chat/ChatEventsAdapter.java @@ -0,0 +1,58 @@ +/* +GroupChatFragment.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +package org.linphone.chat; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import org.linphone.core.ChatMessage; + +import java.util.ArrayList; + +public class ChatEventsAdapter extends BaseAdapter { + private ArrayList mHistory; + private Context mContext; + + public ChatEventsAdapter() { + + } + + @Override + public int getCount() { + return 0; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return 0; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + return null; + } +} diff --git a/src/android/org/linphone/chat/ChatFragment.java b/src/android/org/linphone/chat/ChatFragment.java index a33604a6e..3abce121d 100644 --- a/src/android/org/linphone/chat/ChatFragment.java +++ b/src/android/org/linphone/chat/ChatFragment.java @@ -1263,72 +1263,7 @@ public class ChatFragment extends Fragment implements OnClickListener, ChatMessa } class ChatMessageAdapter extends BaseAdapter { - private class ViewHolder implements ChatMessageListener { - public int id; - public LinearLayout eventLayout; - public RelativeLayout bubbleLayout; - public CheckBox delete; - public LinearLayout background; - public ImageView contactPicture; - public TextView contactName; - public TextView messageText; - public ImageView messageImage; - public RelativeLayout fileTransferLayout; - public ProgressBar fileTransferProgressBar; - public Button fileTransferAction; - public ImageView messageStatus; - public ProgressBar messageSendingInProgress; - public ImageView contactPictureMask; - public LinearLayout imdmLayout; - public ImageView imdmIcon; - public TextView imdmLabel; - public TextView fileExtensionLabel; - public TextView fileNameLabel; - - public ViewHolder(View view) { - id = view.getId(); - - eventLayout = (LinearLayout) view.findViewById(R.id.event); - bubbleLayout = (RelativeLayout) view.findViewById(R.id.bubble); - delete = (CheckBox) view.findViewById(R.id.delete_message); - background = (LinearLayout) view.findViewById(R.id.background); - contactPicture = (ImageView) view.findViewById(R.id.contact_picture); - contactName = (TextView) view.findViewById(R.id.contact_header); - messageText = (TextView) view.findViewById(R.id.message); - messageImage = (ImageView) view.findViewById(R.id.image); - fileTransferLayout = (RelativeLayout) view.findViewById(R.id.file_transfer_layout); - fileTransferProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar); - fileTransferAction = (Button) view.findViewById(R.id.file_transfer_action); - messageStatus = (ImageView) view.findViewById(R.id.status); - messageSendingInProgress = (ProgressBar) view.findViewById(R.id.inprogress); - contactPictureMask = (ImageView) view.findViewById(R.id.mask); - imdmLayout = (LinearLayout) view.findViewById(R.id.imdmLayout); - imdmIcon = (ImageView) view.findViewById(R.id.imdmIcon); - imdmLabel = (TextView) view.findViewById(R.id.imdmText); - fileExtensionLabel = (TextView) view.findViewById(R.id.file_extension); - fileNameLabel = (TextView) view.findViewById(R.id.file_name); - } - - @Override - public void onMsgStateChanged(ChatMessage msg, State state) { - - } - - @Override - public void onFileTransferRecv(ChatMessage msg, Content content, Buffer buffer) { - - } - - @Override - public Buffer onFileTransferSend(ChatMessage message, Content content, int offset, int size) { - return null; - } - - @Override - public void onFileTransferProgressIndication(ChatMessage msg, Content content, int offset, int total) { - if (msg.getStorageId() == id) fileTransferProgressBar.setProgress(offset * 100 / total); - } - } + private ArrayList history; Context context; @@ -1382,16 +1317,16 @@ public class ChatFragment extends Fragment implements OnClickListener, ChatMessa public View getView(final int position, View convertView, ViewGroup parent) { final ChatMessage message = history.get(position); View view = null; - final ViewHolder holder; + final ChatBubbleViewHolder holder; boolean sameMessage = false; if (convertView != null) { view = convertView; - holder = (ViewHolder) view.getTag(); + holder = (ChatBubbleViewHolder) view.getTag(); //LinphoneManager.removeListener(holder); } else { view = LayoutInflater.from(context).inflate(R.layout.chat_bubble, null); - holder = new ViewHolder(view); + holder = new ChatBubbleViewHolder(view); view.setTag(holder); } diff --git a/src/android/org/linphone/chat/GroupChatFragment.java b/src/android/org/linphone/chat/GroupChatFragment.java index 136f03f16..c3bc5c4c7 100644 --- a/src/android/org/linphone/chat/GroupChatFragment.java +++ b/src/android/org/linphone/chat/GroupChatFragment.java @@ -1,14 +1,3 @@ -package org.linphone.chat; - -import android.app.Fragment; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import org.linphone.R; - /* GroupChatFragment.java Copyright (C) 2017 Belledonne Communications, Grenoble, France @@ -28,27 +17,285 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -public class GroupChatFragment extends Fragment implements View.OnClickListener { - private ImageView call, infos; +package org.linphone.chat; +import android.app.Fragment; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Adapter; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import org.linphone.LinphoneManager; +import org.linphone.LinphoneUtils; +import org.linphone.R; +import org.linphone.activities.LinphoneActivity; +import org.linphone.contacts.ContactsManager; +import org.linphone.contacts.LinphoneContact; +import org.linphone.core.Address; +import org.linphone.core.ChatMessage; +import org.linphone.core.ChatRoom; +import org.linphone.core.ChatRoomListener; +import org.linphone.core.Content; +import org.linphone.core.Core; +import org.linphone.core.Participant; + +import java.util.ArrayList; +import java.util.List; + +public class GroupChatFragment extends Fragment implements ChatRoomListener { + private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton, mEditButton; + private ImageView mCancelEditButton, mSelectAllButton, mDeselectAllButton, mDeleteSelectionButton; + private ImageView mAttachImageButton, mSendMessageButton; + private TextView mRoomLabel, mRemoteComposing; + private EditText mMessageTextToSend; private LayoutInflater mInflater; + private Bitmap defaultContactAvatar; + private ListView mChatEventsList; + + private ChatEventsAdapter mMessagesAdapter; + private String mRemoteSipUri; + private Address mRemoteSipAddress; + private ChatRoom mChatRoom; + private List mParticipants; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Retain the fragment across configuration changes + setRetainInstance(true); + + if (getArguments() != null && getArguments().getString("SipUri") != null) { + mRemoteSipUri = getArguments().getString("SipUri"); + mRemoteSipAddress = LinphoneManager.getLc().createAddress(mRemoteSipUri); + } + + defaultContactAvatar = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.chat_picture_over); + mInflater = inflater; View view = inflater.inflate(R.layout.chat, container, false); - call = view.findViewById(R.id.start_call); - call.setVisibility(View.GONE); + mBackButton = view.findViewById(R.id.back); + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + getFragmentManager().popBackStackImmediate(); + } + }); - infos = view.findViewById(R.id.group_infos); - infos.setVisibility(View.VISIBLE); + mCallButton = view.findViewById(R.id.start_call); + mCallButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + LinphoneActivity.instance().setAddresGoToDialerAndCall(mRemoteSipUri, null, null); + } + }); + + mBackToCallButton = view.findViewById(R.id.back_to_call); + mBackToCallButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + LinphoneActivity.instance().resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); + } + }); + + mGroupInfosButton = view.findViewById(R.id.group_infos); + mGroupInfosButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mEditButton = view.findViewById(R.id.edit); + mEditButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mCancelEditButton = view.findViewById(R.id.cancel); + mCancelEditButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mSelectAllButton = view.findViewById(R.id.select_all); + mSelectAllButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mDeselectAllButton = view.findViewById(R.id.deselect_all); + mDeselectAllButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mDeleteSelectionButton = view.findViewById(R.id.delete); + mDeleteSelectionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mRoomLabel = view.findViewById(R.id.contact_name); + + mAttachImageButton = view.findViewById(R.id.send_picture); + mAttachImageButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mSendMessageButton = view.findViewById(R.id.send_message); + mSendMessageButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }); + + mMessageTextToSend = view.findViewById(R.id.message); + mMessageTextToSend.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + mSendMessageButton.setEnabled(mMessageTextToSend.getText().length() > 0); + if (mChatRoom != null) { + mChatRoom.compose(); + } + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + mRemoteComposing = view.findViewById(R.id.remote_composing); + + mChatEventsList = view.findViewById(R.id.chat_message_list); return view; } @Override - public void onClick(View view) { + public void onResume() { + super.onResume(); + initChatRoom(); + displayChatRoomHeader(); + displayChatRoomHistory(); + } + + private void initChatRoom() { + Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + if (mRemoteSipAddress == null || mRemoteSipUri == null || mRemoteSipUri.length() == 0 || core == null) { + LinphoneActivity.instance().goToDialerFragment(); + return; + } + + mChatRoom = core.getChatRoom(mRemoteSipAddress); + mChatRoom.setListener(this); + mChatRoom.markAsRead(); + LinphoneActivity.instance().updateMissedChatCount(); + + mParticipants = new ArrayList<>(); + if (mChatRoom.canHandleParticipants()) { + for (Participant p : mChatRoom.getParticipants()) { + LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(p.getAddress()); + if (c != null) { + mParticipants.add(c); + } + } + } else { + LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(mRemoteSipAddress); + if (c != null) { + mParticipants.add(c); + } + } + } + + private void displayChatRoomHeader() { + Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + if (core == null) return; + + mRemoteComposing.setVisibility(View.INVISIBLE); + + if (core.getCallByRemoteAddress(mRemoteSipUri) != null) { + mBackToCallButton.setVisibility(View.VISIBLE); + } else { + mBackToCallButton.setVisibility(View.GONE); + if (mChatRoom.canHandleParticipants()) { + mCallButton.setVisibility(View.GONE); + mGroupInfosButton.setVisibility(View.VISIBLE); + mRoomLabel.setText(mChatRoom.getSubject()); + } else { + mCallButton.setVisibility(View.VISIBLE); + mGroupInfosButton.setVisibility(View.GONE); + + if (mParticipants.size() == 0) { + // Contact not found + String displayName = mRemoteSipAddress.getDisplayName(); + if (displayName == null || displayName.isEmpty()) { + mRoomLabel.setText(mRemoteSipAddress.getUsername()); + } else { + mRoomLabel.setText(displayName); + } + } else { + mRoomLabel.setText(mParticipants.get(0).getFullName()); + } + } + } + } + + private void displayChatRoomHistory() { + mMessagesAdapter = new ChatEventsAdapter(); + } + + @Override + public void onUndecryptableMessageReceived(ChatRoom cr, ChatMessage msg) { } + + @Override + public void onMessageReceived(ChatRoom cr, ChatMessage msg) { + cr.markAsRead(); + LinphoneActivity.instance().updateMissedChatCount(); + + String externalBodyUrl = msg.getExternalBodyUrl(); + Content fileTransferContent = msg.getFileTransferInformation(); + if (externalBodyUrl != null || fileTransferContent != null) { + LinphoneActivity.instance().checkAndRequestExternalStoragePermission(); + } + } + + @Override + public void onIsComposingReceived(ChatRoom cr, Address remoteAddr, boolean isComposing) { + if (isComposing) { + mRemoteComposing.setText(getString(R.string.remote_composing_2).replace("%s", remoteAddr.getDisplayName())); + } + mRemoteComposing.setVisibility(isComposing ? View.VISIBLE : View.GONE); + } } diff --git a/src/android/org/linphone/chat/InfoGroupChatFragment.java b/src/android/org/linphone/chat/InfoGroupChatFragment.java index 711bd5398..115f98d41 100644 --- a/src/android/org/linphone/chat/InfoGroupChatFragment.java +++ b/src/android/org/linphone/chat/InfoGroupChatFragment.java @@ -1,5 +1,3 @@ -package org.linphone.chat; - /* InfoGroupChatFragment.java Copyright (C) 2017 Belledonne Communications, Grenoble, France @@ -19,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +package org.linphone.chat; + import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; diff --git a/src/android/org/linphone/chat/SearchContactsListAdapter.java b/src/android/org/linphone/chat/SearchContactsListAdapter.java index 05607044d..c8857460c 100644 --- a/src/android/org/linphone/chat/SearchContactsListAdapter.java +++ b/src/android/org/linphone/chat/SearchContactsListAdapter.java @@ -1,5 +1,3 @@ -package org.linphone.chat; - /* SearchContactsListAdapter.java Copyright (C) 2017 Belledonne Communications, Grenoble, France @@ -19,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +package org.linphone.chat; + import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup;