diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/enums/MemberCallStatus.java b/app/src/main/java/org/communiquons/android/comunic/client/data/enums/MemberCallStatus.java new file mode 100644 index 0000000..ddb43e3 --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/enums/MemberCallStatus.java @@ -0,0 +1,15 @@ +package org.communiquons.android.comunic.client.data.enums; + +/** + * Single member call status + * + * @author Pierre HUBERT + */ +public enum MemberCallStatus { + + ACCEPTED, + REJECTED, + UNKNOWN, + HANG_UP + +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/CallsHelper.java b/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/CallsHelper.java index 442fa44..61f92d2 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/CallsHelper.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/helpers/CallsHelper.java @@ -3,9 +3,13 @@ package org.communiquons.android.comunic.client.data.helpers; import android.content.Context; import android.support.annotation.Nullable; +import org.communiquons.android.comunic.client.data.enums.MemberCallStatus; import org.communiquons.android.comunic.client.data.models.APIRequest; import org.communiquons.android.comunic.client.data.models.APIResponse; +import org.communiquons.android.comunic.client.data.models.CallInformation; +import org.communiquons.android.comunic.client.data.models.CallMember; import org.communiquons.android.comunic.client.data.models.CallsConfiguration; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -48,7 +52,7 @@ public class CallsHelper extends BaseHelper { APIResponse response = request.exec(); //Parse response - mCallsConfiguration = JSONObjectToCallConfiguration(response.getJSONObject()); + mCallsConfiguration = JSONObjectToCallsConfiguration(response.getJSONObject()); } catch (Exception e) { @@ -60,10 +64,13 @@ public class CallsHelper extends BaseHelper { /** * Get Calls configuration, if available * + * Note if IsCallSystemAvailable returned TRUE, it is guaranteed that this method WILL NOT + * return null + * * @return Calls configuration */ @Nullable - public static CallsConfiguration getCallConfiguration(){ + public static CallsConfiguration GetCallsConfiguration(){ return mCallsConfiguration; } @@ -76,10 +83,38 @@ public class CallsHelper extends BaseHelper { * * @return TRUE if call system is available / FALSE else */ - public static boolean isCallSystemAvailable(){ + public static boolean IsCallSystemAvailable(){ return mCallsConfiguration != null && mCallsConfiguration.isEnabled(); } + /** + * Create a call for a conversation, returns information about this call then + * + * Note : if a similar call already exists, it will be returned instead of + * creating a new call + * + * @param convID The ID of the target conversation + * @return Information about the created call / null in case of failure + */ + @Nullable + public CallInformation createForConversation(int convID){ + + APIRequest request = new APIRequest(getContext(), "calls/createForConversation"); + request.addInt("conversationID", convID); + try { + + //Execute request + APIResponse response = request.exec(); + + return JSONObjectToCallInformation(response.getJSONObject()); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + /** * Turn a {@link JSONObject} object into a {@link CallsConfiguration} object. @@ -88,7 +123,7 @@ public class CallsHelper extends BaseHelper { * @return The result of the operation * @throws JSONException Exception thrown in case of failure */ - private static CallsConfiguration JSONObjectToCallConfiguration(JSONObject object) + private static CallsConfiguration JSONObjectToCallsConfiguration(JSONObject object) throws JSONException { CallsConfiguration config = new CallsConfiguration(); @@ -109,4 +144,60 @@ public class CallsHelper extends BaseHelper { return config; } + + /** + * Turn a {@link JSONObject} into {@link CallInformation} object + * + * @param object object to convert + * @return Generated CallInformation object + * @throws JSONException in case of failure + */ + private static CallInformation JSONObjectToCallInformation(JSONObject object) + throws JSONException { + + CallInformation call = new CallInformation(); + call.setId(object.getInt("id")); + call.setConversationID(object.getInt("conversation_id")); + call.setLastActive(object.getInt("last_active")); + + JSONArray members = object.getJSONArray("members"); + for (int i = 0; i < members.length(); i++) { + + JSONObject member_obj = members.getJSONObject(i); + + call.addMember(new CallMember( + member_obj.getInt("userID"), + member_obj.getInt("call_id"), + member_obj.getString("user_call_id"), + StringToMemberCallStatus(member_obj.getString("status")) + )); + } + + return call; + + } + + /** + * Turn a string into a {@link MemberCallStatus} + * + * @param s String to convert + * @return Generated MemberCallStatus + */ + private static MemberCallStatus StringToMemberCallStatus(String s){ + switch (s){ + + case "accepted": + return MemberCallStatus.ACCEPTED; + + case "rejected": + return MemberCallStatus.REJECTED; + + case "hang_up": + return MemberCallStatus.HANG_UP; + + case "unknown": + default: + return MemberCallStatus.UNKNOWN; + } + } } diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallInformation.java b/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallInformation.java new file mode 100644 index 0000000..95d99e5 --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallInformation.java @@ -0,0 +1,60 @@ +package org.communiquons.android.comunic.client.data.models; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; + +/** + * Single call information + * + * @author Pierre HUBERT + */ +public class CallInformation { + + //Private fields + private int id; + private int conversationID; + private int lastActive; + private ArrayList members = null; + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getConversationID() { + return conversationID; + } + + public void setConversationID(int conversationID) { + this.conversationID = conversationID; + } + + public int getLastActive() { + return lastActive; + } + + public void setLastActive(int lastActive) { + this.lastActive = lastActive; + } + + public ArrayList getMembers() { + return members; + } + + public void addMember(@NonNull CallMember member){ + + if(members == null) + members = new ArrayList<>(); + + members.add(member); + } + + public void setMembers(ArrayList members) { + this.members = members; + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallMember.java b/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallMember.java new file mode 100644 index 0000000..abaa1f2 --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/data/models/CallMember.java @@ -0,0 +1,59 @@ +package org.communiquons.android.comunic.client.data.models; + +import org.communiquons.android.comunic.client.data.enums.MemberCallStatus; + +/** + * Single call member information + * + * @author Pierre HUBERT + */ +public class CallMember { + + //Private fields + private int userID; + private int callID; + private String userCallID; + private MemberCallStatus status; + + public CallMember() { + } + + public CallMember(int userID, int callID, String userCallID, MemberCallStatus status) { + this.userID = userID; + this.callID = callID; + this.userCallID = userCallID; + this.status = status; + } + + public int getUserID() { + return userID; + } + + public void setUserID(int userID) { + this.userID = userID; + } + + public int getCallID() { + return callID; + } + + public void setCallID(int callID) { + this.callID = callID; + } + + public String getUserCallID() { + return userCallID; + } + + public void setUserCallID(String userCallID) { + this.userCallID = userCallID; + } + + public MemberCallStatus getStatus() { + return status; + } + + public void setStatus(MemberCallStatus status) { + this.status = status; + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/MainActivity.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/MainActivity.java index 1ad15f4..e16cf20 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/MainActivity.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/activities/MainActivity.java @@ -2,6 +2,7 @@ package org.communiquons.android.comunic.client.ui.activities; import android.app.Activity; import android.app.AlertDialog; +import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -31,11 +32,13 @@ import org.communiquons.android.comunic.client.data.helpers.AccountHelper; import org.communiquons.android.comunic.client.data.helpers.ConversationsListHelper; import org.communiquons.android.comunic.client.data.helpers.DatabaseHelper; import org.communiquons.android.comunic.client.data.helpers.DebugHelper; +import org.communiquons.android.comunic.client.data.models.CallInformation; import org.communiquons.android.comunic.client.data.models.NotificationsCount; import org.communiquons.android.comunic.client.data.models.VirtualDirectory; import org.communiquons.android.comunic.client.data.runnables.FriendRefreshLoopRunnable; import org.communiquons.android.comunic.client.data.services.NotificationsService; import org.communiquons.android.comunic.client.data.utils.PreferencesUtils; +import org.communiquons.android.comunic.client.ui.asynctasks.CreateCallForConversationTask; import org.communiquons.android.comunic.client.ui.asynctasks.FindVirtualDirectoryTask; import org.communiquons.android.comunic.client.ui.asynctasks.GetCallConfigurationTask; import org.communiquons.android.comunic.client.ui.asynctasks.SafeAsyncTask; @@ -51,6 +54,7 @@ import org.communiquons.android.comunic.client.ui.fragments.groups.GroupPageMain import org.communiquons.android.comunic.client.ui.fragments.groups.UserGroupsFragment; import org.communiquons.android.comunic.client.ui.fragments.userpage.UserAccessDeniedFragment; import org.communiquons.android.comunic.client.ui.fragments.userpage.UserPageFragment; +import org.communiquons.android.comunic.client.ui.listeners.OnOpenCallListener; import org.communiquons.android.comunic.client.ui.listeners.OnOpenPageListener; import org.communiquons.android.comunic.client.ui.listeners.onPostOpenListener; import org.communiquons.android.comunic.client.ui.listeners.openConversationListener; @@ -71,7 +75,7 @@ import static org.communiquons.android.comunic.client.ui.Constants.IntentRequest */ public class MainActivity extends BaseActivity implements openConversationListener, updateConversationListener, OnOpenPageListener, - onPostOpenListener, NavigationBar.OnNavigationItemSelectedListener { + onPostOpenListener, NavigationBar.OnNavigationItemSelectedListener, OnOpenCallListener { /** * Debug tag @@ -840,4 +844,37 @@ public class MainActivity extends BaseActivity implements transaction.replace(R.id.main_fragment, fragment); transaction.commit(); } + + @Override + public void createCallForConversation(int convID) { + final Dialog dialog = UiUtils.create_loading_dialog(this); + + //Create the call for the conversation + CreateCallForConversationTask task = new CreateCallForConversationTask(this); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, convID); + getTasksManager().addTask(task, true); + task.setOnPostExecuteListener(new SafeAsyncTask.OnPostExecuteListener() { + @Override + public void OnPostExecute(@Nullable CallInformation callInformation) { + + dialog.dismiss(); + + //Check for errors + if(callInformation == null) + Toast.makeText( + MainActivity.this, + R.string.err_create_call_for_conversation, + Toast.LENGTH_SHORT).show(); + + else + //Open call + openCall(callInformation.getId()); + } + }); + } + + @Override + public void openCall(int callID) { + Log.e(TAG, "Open call " + callID); + } } diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/asynctasks/CreateCallForConversationTask.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/asynctasks/CreateCallForConversationTask.java new file mode 100644 index 0000000..8f8e524 --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/asynctasks/CreateCallForConversationTask.java @@ -0,0 +1,23 @@ +package org.communiquons.android.comunic.client.ui.asynctasks; + +import android.content.Context; + +import org.communiquons.android.comunic.client.data.helpers.CallsHelper; +import org.communiquons.android.comunic.client.data.models.CallInformation; + +/** + * Task used to create new calls from conversations + * + * @author Pierre HUBERT + */ +public class CreateCallForConversationTask extends SafeAsyncTask { + + public CreateCallForConversationTask(Context context) { + super(context); + } + + @Override + protected CallInformation doInBackground(Integer... integers) { + return new CallsHelper(getContext()).createForConversation(integers[0]); + } +} diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/fragments/ConversationFragment.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/fragments/ConversationFragment.java index 8a74b3a..5a16887 100644 --- a/app/src/main/java/org/communiquons/android/comunic/client/ui/fragments/ConversationFragment.java +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/fragments/ConversationFragment.java @@ -26,6 +26,7 @@ import android.widget.Toast; import org.communiquons.android.comunic.client.R; import org.communiquons.android.comunic.client.data.arrays.ConversationMessagesList; +import org.communiquons.android.comunic.client.data.helpers.CallsHelper; import org.communiquons.android.comunic.client.data.helpers.ConversationMessagesHelper; import org.communiquons.android.comunic.client.data.helpers.ConversationsListHelper; import org.communiquons.android.comunic.client.data.helpers.DatabaseHelper; @@ -43,6 +44,7 @@ import org.communiquons.android.comunic.client.ui.asynctasks.SafeAsyncTask; import org.communiquons.android.comunic.client.ui.asynctasks.SendConversationMessageTask; import org.communiquons.android.comunic.client.ui.asynctasks.UpdateConversationMessageContentTask; import org.communiquons.android.comunic.client.ui.listeners.OnConversationMessageActionsListener; +import org.communiquons.android.comunic.client.ui.listeners.OnOpenCallListener; import org.communiquons.android.comunic.client.ui.listeners.OnScrollChangeDetectListener; import org.communiquons.android.comunic.client.ui.utils.BitmapUtils; import org.communiquons.android.comunic.client.ui.utils.UiUtils; @@ -51,6 +53,7 @@ import org.communiquons.android.comunic.client.ui.views.ScrollRecyclerView; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.Objects; import static android.app.Activity.RESULT_OK; import static org.communiquons.android.comunic.client.ui.Constants.IntentRequestCode.CONVERSATION_MESSAGE_PICK_PHOTO; @@ -174,6 +177,11 @@ public class ConversationFragment extends Fragment */ private Bitmap new_message_bitmap = null; + /** + * Contains whether a call button is visible on the conversation or not + */ + private boolean mHasCallButton = false; + /** * Get user helper */ @@ -392,6 +400,7 @@ public class ConversationFragment extends Fragment } + @Override public void onDestroy() { super.onDestroy(); @@ -516,6 +525,23 @@ public class ConversationFragment extends Fragment //Update the name of the conversation setTitle(info.getDisplayName()); + + //Add call button (if possible) + if(CallsHelper.IsCallSystemAvailable() && info.getMembers().size() > 1 && info.getMembers().size() <= + Objects.requireNonNull(CallsHelper.GetCallsConfiguration()).getMaximumNumberMembers() && + !mHasCallButton) { + + mHasCallButton = true; + + mAppBar.addButton(R.drawable.ic_call, new View.OnClickListener() { + @Override + public void onClick(View v) { + ((OnOpenCallListener)Objects.requireNonNull(getActivity())) + .createCallForConversation(conversation_id); + } + }); + } + } /** diff --git a/app/src/main/java/org/communiquons/android/comunic/client/ui/listeners/OnOpenCallListener.java b/app/src/main/java/org/communiquons/android/comunic/client/ui/listeners/OnOpenCallListener.java new file mode 100644 index 0000000..33783e7 --- /dev/null +++ b/app/src/main/java/org/communiquons/android/comunic/client/ui/listeners/OnOpenCallListener.java @@ -0,0 +1,23 @@ +package org.communiquons.android.comunic.client.ui.listeners; + +/** + * Open call listener + * + * @author Pierre HUBERT + */ +public interface OnOpenCallListener { + + /** + * Create and open a call for a conversation + * + * @param convID The ID of the target conversation + */ + void createCallForConversation(int convID); + + /** + * Open a specifed call + * + * @param callID The ID of the target call + */ + void openCall(int callID); +} diff --git a/app/src/main/res/drawable/ic_call.xml b/app/src/main/res/drawable/ic_call.xml new file mode 100644 index 0000000..f848904 --- /dev/null +++ b/app/src/main/res/drawable/ic_call.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8afbd98..b57b1b5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -319,4 +319,5 @@ Accès au groupe refusé. Impossible de récupérer les informations sur le groupe ! Accès sur invitation + Une erreur a survenu lors de la création d\'un appel pour la conversation ! \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cab995c..4ed99f9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -318,4 +318,5 @@ Search Search a user, a group… Could not get results of your search! + Could not create a call for the conversation!