forked from mirror/monocles_chat_clean
update fork #128
12 changed files with 395 additions and 5 deletions
Add initial call log screen
commit
f6ed6f0e14
|
|
@ -468,6 +468,8 @@
|
|||
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.ceb" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.CallsActivity"
|
||||
android:label="@string/calls" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
|||
47
src/main/java/eu/siacs/conversations/entities/Call.java
Normal file
47
src/main/java/eu/siacs/conversations/entities/Call.java
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
package eu.siacs.conversations.entities;
|
||||
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
|
||||
public class Call {
|
||||
|
||||
private final String contact;
|
||||
private final Jid jid;
|
||||
private final long startTime;
|
||||
private final int status;
|
||||
private final boolean isVideoCall;
|
||||
private final boolean successful;
|
||||
|
||||
public Call(String contact, Jid jid, long startTime, int status, boolean isVideoCall, boolean successful) {
|
||||
this.contact = contact;
|
||||
this.jid = jid;
|
||||
this.startTime = startTime;
|
||||
this.status = status;
|
||||
this.isVideoCall = isVideoCall;
|
||||
this.successful = successful;
|
||||
}
|
||||
|
||||
public String getContact() {
|
||||
return contact;
|
||||
}
|
||||
|
||||
public Jid getJid() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean isVideoCall() {
|
||||
return isVideoCall;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
36
src/main/java/eu/siacs/conversations/ui/CallsActivity.java
Normal file
36
src/main/java/eu/siacs/conversations/ui/CallsActivity.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.databinding.ActivityCallsBinding;
|
||||
|
||||
public class CallsActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ActivityCallsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_calls);
|
||||
setSupportActionBar(binding.toolbar);
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, new CallsFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
114
src/main/java/eu/siacs/conversations/ui/CallsFragment.java
Normal file
114
src/main/java/eu/siacs/conversations/ui/CallsFragment.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Call;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.ui.adapter.CallsAdapter;
|
||||
import eu.siacs.conversations.entities.RtpSessionStatus;
|
||||
|
||||
|
||||
public class CallsFragment extends Fragment implements CallsAdapter.OnCallAgainClickListener {
|
||||
|
||||
private XmppConnectionService xmppConnectionService;
|
||||
private RecyclerView recyclerView;
|
||||
private CallsAdapter adapter;
|
||||
private List<Call> calls = new ArrayList<>();
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
XmppConnectionService.XmppConnectionBinder binder = (XmppConnectionService.XmppConnectionBinder) service;
|
||||
xmppConnectionService = binder.getService();
|
||||
loadCalls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
xmppConnectionService = null;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Intent intent = new Intent(getActivity(), XmppConnectionService.class);
|
||||
getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
getActivity().unbindService(mConnection);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_calls, container, false);
|
||||
|
||||
recyclerView = view.findViewById(R.id.list);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
adapter = new CallsAdapter(calls, this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void loadCalls() {
|
||||
if (xmppConnectionService != null) {
|
||||
calls.clear();
|
||||
calls.addAll(getCalls());
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Call> getCalls() {
|
||||
List<Call> calls = new ArrayList<>();
|
||||
for (Conversation conversation : xmppConnectionService.getConversations()) {
|
||||
for (Message message : xmppConnectionService.databaseBackend.getMessages(conversation, 100)) { // Limiting to last 100 messages per conversation for performance
|
||||
if (message.getType() == Message.TYPE_RTP_SESSION) {
|
||||
RtpSessionStatus rtpSessionStatus = RtpSessionStatus.of(message.getBody());
|
||||
boolean isVideo = message.getBody().contains("video");
|
||||
Call call = new Call(conversation.getName().toString(), conversation.getJid(), message.getTimeSent(), message.getStatus(), isVideo, rtpSessionStatus.successful);
|
||||
calls.add(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
return calls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallAgainClick(Call call) {
|
||||
Intent intent = new Intent(getActivity(), RtpSessionActivity.class);
|
||||
if (call.isVideoCall()) {
|
||||
intent.setAction(RtpSessionActivity.ACTION_MAKE_VIDEO_CALL);
|
||||
} else {
|
||||
intent.setAction(RtpSessionActivity.ACTION_MAKE_VOICE_CALL);
|
||||
}
|
||||
intent.putExtra("jid", call.getJid().toString());
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
|
@ -365,9 +365,11 @@ public class ConversationsOverviewFragment extends XmppFragment {
|
|||
final MenuItem manageAccounts = menu.findItem(R.id.action_accounts);
|
||||
final MenuItem settings = menu.findItem(R.id.action_settings);
|
||||
final MenuItem stories = menu.findItem(R.id.action_stories);
|
||||
final MenuItem calls = menu.findItem(R.id.action_calls);
|
||||
if (manageAccounts != null) manageAccounts.setVisible(false);
|
||||
if (settings != null) settings.setVisible(false);
|
||||
if (stories != null) stories.setVisible(false);
|
||||
if (calls != null) calls.setVisible(false);
|
||||
}
|
||||
if (activity == null || activity.xmppConnectionService == null || activity.xmppConnectionService.getAccounts().size() != 1) {
|
||||
noteToSelf.setVisible(false);
|
||||
|
|
@ -484,10 +486,12 @@ public class ConversationsOverviewFragment extends XmppFragment {
|
|||
MenuItem manageAccount = menu.findItem(R.id.action_account);
|
||||
MenuItem manageAccounts = menu.findItem(R.id.action_accounts);
|
||||
MenuItem stories = menu.findItem(R.id.action_stories);
|
||||
MenuItem calls = menu.findItem(R.id.action_calls);
|
||||
if (navBarVisible) {
|
||||
manageAccount.setVisible(false);
|
||||
manageAccounts.setVisible(false);
|
||||
stories.setVisible(false);
|
||||
calls.setVisible(false);
|
||||
} else {
|
||||
AccountUtils.showHideMenuItems(menu);
|
||||
}
|
||||
|
|
@ -541,6 +545,9 @@ public class ConversationsOverviewFragment extends XmppFragment {
|
|||
case R.id.action_stories:
|
||||
startActivity(new Intent(getActivity(), StoriesActivity.class));
|
||||
return true;
|
||||
case R.id.action_calls:
|
||||
startActivity(new Intent(getActivity(), CallsActivity.class));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
package eu.siacs.conversations.ui.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Call;
|
||||
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
|
||||
import eu.siacs.conversations.ui.widget.AvatarView;
|
||||
import eu.siacs.conversations.utils.UIHelper;
|
||||
|
||||
public class CallsAdapter extends RecyclerView.Adapter<CallsAdapter.CallViewHolder> {
|
||||
|
||||
private final List<Call> calls;
|
||||
private final OnCallAgainClickListener listener;
|
||||
|
||||
public interface OnCallAgainClickListener {
|
||||
void onCallAgainClick(Call call);
|
||||
}
|
||||
|
||||
public CallsAdapter(List<Call> calls, OnCallAgainClickListener listener) {
|
||||
this.calls = calls;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public CallViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_call, parent, false);
|
||||
return new CallViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull CallViewHolder holder, int position) {
|
||||
Call call = calls.get(position);
|
||||
holder.bind(call, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return calls.size();
|
||||
}
|
||||
|
||||
static class CallViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final AvatarView avatar;
|
||||
private final TextView contactName;
|
||||
private final TextView callInfo;
|
||||
private final ImageButton callAgainButton;
|
||||
|
||||
public CallViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
avatar = itemView.findViewById(R.id.avatar);
|
||||
contactName = itemView.findViewById(R.id.contact_name);
|
||||
callInfo = itemView.findViewById(R.id.call_info);
|
||||
callAgainButton = itemView.findViewById(R.id.call_again);
|
||||
}
|
||||
|
||||
public void bind(final Call call, final OnCallAgainClickListener listener) {
|
||||
Glide.with(itemView.getContext()).load(call).into(avatar);
|
||||
//AvatarWorkerTask.loadAvatar(call, avatar, R.dimen.avatar_story_size); //TODO add correct avatar loading
|
||||
contactName.setText(call.getContact());
|
||||
callInfo.setText(UIHelper.getCallInfo(itemView.getContext(), call));
|
||||
callAgainButton.setOnClickListener(v -> listener.onCallAgainClick(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
package eu.siacs.conversations.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
|
@ -38,6 +39,7 @@ import eu.siacs.conversations.Config;
|
|||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Call;
|
||||
import eu.siacs.conversations.entities.Contact;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.entities.Conversational;
|
||||
|
|
@ -60,7 +62,7 @@ import java.util.Locale;
|
|||
|
||||
public class UIHelper {
|
||||
|
||||
private static final List<String> LOCATION_QUESTIONS =
|
||||
private static final List<String> LOCATION_QUESTIONS =
|
||||
Arrays.asList(
|
||||
"where are you", // en
|
||||
"where are you now", // en
|
||||
|
|
@ -81,12 +83,12 @@ public class UIHelper {
|
|||
"donde estas" // es
|
||||
);
|
||||
|
||||
private static final List<Character> PUNCTIONATION =
|
||||
private static final List<Character> PUNCTIONATION =
|
||||
Arrays.asList('.', ',', '?', '!', ';', ':');
|
||||
|
||||
private static final int SHORT_DATE_FLAGS =
|
||||
private static final int SHORT_DATE_FLAGS =
|
||||
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL;
|
||||
private static final int FULL_DATE_FLAGS =
|
||||
private static final int FULL_DATE_FLAGS =
|
||||
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE;
|
||||
|
||||
public static String readableTimeDifference(Context context, long time, boolean allowRelative) {
|
||||
|
|
@ -635,6 +637,15 @@ public class UIHelper {
|
|||
ContextCompat.getColor(textView.getContext(), color))));
|
||||
}
|
||||
|
||||
public static String getCallInfo(Context context, Call call) {
|
||||
final boolean received = call.getStatus() == Message.STATUS_RECEIVED;
|
||||
if (!call.isSuccessful() && received) {
|
||||
return context.getString(R.string.missed_call);
|
||||
} else {
|
||||
return context.getString(received ? R.string.incoming_call : R.string.outgoing_call);
|
||||
}
|
||||
}
|
||||
|
||||
public static String filesizeToString(long size) {
|
||||
if (size > (1.5 * 1024 * 1024)) {
|
||||
return Math.round(size * 1f / (1024 * 1024)) + " MiB";
|
||||
|
|
|
|||
29
src/main/res/layout/activity_calls.xml
Normal file
29
src/main/res/layout/activity_calls.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/calls" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
11
src/main/res/layout/fragment_calls.xml
Normal file
11
src/main/res/layout/fragment_calls.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
49
src/main/res/layout/item_call.xml
Normal file
49
src/main/res/layout/item_call.xml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<eu.siacs.conversations.ui.widget.AvatarView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_toStartOf="@+id/call_again"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contact_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/call_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/call_again"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_call_24dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -34,6 +34,11 @@
|
|||
android:orderInCategory="92"
|
||||
android:title="@string/stories"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_calls"
|
||||
android:orderInCategory="93"
|
||||
android:title="@string/calls"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_privacy_policy"
|
||||
android:orderInCategory="98"
|
||||
|
|
|
|||
|
|
@ -1593,4 +1593,5 @@
|
|||
<string name="no_active_account_to_show_stories">No active account to show or publish stories</string>
|
||||
<string name="of">of</string>
|
||||
<string name="error_creating_story">Could not create story</string>
|
||||
<string name="calls">Calls</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue