Show related messages (parents, replies)

This commit is contained in:
Christian Basler 2017-04-16 22:35:26 +02:00
parent 8770575c95
commit f77bbe1a43
6 changed files with 190 additions and 17 deletions

View File

@ -18,8 +18,10 @@ package ch.dissem.apps.abit;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -47,12 +49,14 @@ import ch.dissem.apps.abit.util.Drawables;
import ch.dissem.apps.abit.util.Labels; import ch.dissem.apps.abit.util.Labels;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.MessageRepository;
import static android.text.util.Linkify.WEB_URLS; import static android.text.util.Linkify.WEB_URLS;
import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_ADDRESS_PATTERN; import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_ADDRESS_PATTERN;
import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA; import static ch.dissem.apps.abit.util.Constants.BITMESSAGE_URL_SCHEMA;
import static ch.dissem.apps.abit.util.Strings.normalizeWhitespaces;
/** /**
@ -143,16 +147,30 @@ public class MessageDetailFragment extends Fragment {
removed = true; removed = true;
} }
} }
MessageRepository messageRepo = Singleton.getMessageRepository(inflater.getContext());
if (removed) { if (removed) {
if (getActivity() instanceof ActionBarListener) { if (getActivity() instanceof ActionBarListener) {
((ActionBarListener) getActivity()).updateUnread(); ((ActionBarListener) getActivity()).updateUnread();
} }
Singleton.getMessageRepository(inflater.getContext()).save(item); messageRepo.save(item);
} }
List<Plaintext> parents = new ArrayList<>(item.getParents().size());
for (InventoryVector parentIV : item.getParents()) {
parents.add(messageRepo.getMessage(parentIV));
}
showRelatedMessages(rootView, R.id.parents, parents);
showRelatedMessages(rootView, R.id.responses, messageRepo.findResponses(item));
} }
return rootView; return rootView;
} }
private void showRelatedMessages(View rootView, @IdRes int id, List<Plaintext> messages) {
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.parents);
RelatedMessageAdapter adapter = new RelatedMessageAdapter(getActivity(), messages);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.message, menu); inflater.inflate(R.menu.message, menu);
@ -211,6 +229,61 @@ public class MessageDetailFragment extends Fragment {
return false; return false;
} }
private static class RelatedMessageAdapter extends RecyclerView.Adapter<RelatedMessageAdapter.ViewHolder> {
private final List<Plaintext> messages;
private final Context ctx;
private RelatedMessageAdapter(Context ctx, List<Plaintext> messages) {
this.messages = messages;
this.ctx = ctx;
}
@Override
public RelatedMessageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View contactView = inflater.inflate(R.layout.item_message_minimized, parent, false);
// Return a new holder instance
return new RelatedMessageAdapter.ViewHolder(contactView);
}
// Involves populating data into the item through holder
@Override
public void onBindViewHolder(RelatedMessageAdapter.ViewHolder viewHolder, int position) {
// Get the data model based on position
Plaintext message = messages.get(position);
viewHolder.avatar.setImageDrawable(new Identicon(message.getFrom()));
viewHolder.status.setImageResource(Assets.getStatusDrawable(message.getStatus()));
viewHolder.sender.setText(message.getFrom().toString());
viewHolder.extract.setText(normalizeWhitespaces(message.getText()));
}
// Returns the total count of items in the list
@Override
public int getItemCount() {
return messages.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
private final ImageView avatar;
private final ImageView status;
private final TextView sender;
private final TextView extract;
ViewHolder(View itemView) {
super(itemView);
avatar = (ImageView) itemView.findViewById(R.id.avatar);
status = (ImageView) itemView.findViewById(R.id.status);
sender = (TextView) itemView.findViewById(R.id.sender);
extract = (TextView) itemView.findViewById(R.id.text);
}
}
}
private static class LabelAdapter extends private static class LabelAdapter extends
RecyclerView.Adapter<LabelAdapter.ViewHolder> { RecyclerView.Adapter<LabelAdapter.ViewHolder> {

View File

@ -42,6 +42,7 @@ import ch.dissem.bitmessage.networking.nio.NioNetworkHandler;
import ch.dissem.bitmessage.ports.AddressRepository; import ch.dissem.bitmessage.ports.AddressRepository;
import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.ports.ProofOfWorkRepository; import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
import ch.dissem.bitmessage.utils.ConversationService;
import ch.dissem.bitmessage.utils.TTL; import ch.dissem.bitmessage.utils.TTL;
import static ch.dissem.bitmessage.utils.UnixTime.DAY; import static ch.dissem.bitmessage.utils.UnixTime.DAY;
@ -51,6 +52,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
*/ */
public class Singleton { public class Singleton {
private static BitmessageContext bitmessageContext; private static BitmessageContext bitmessageContext;
private static ConversationService conversationService;
private static MessageListener messageListener; private static MessageListener messageListener;
private static BitmessageAddress identity; private static BitmessageAddress identity;
private static AndroidProofOfWorkRepository powRepo; private static AndroidProofOfWorkRepository powRepo;
@ -160,4 +162,16 @@ public class Singleton {
throw new IllegalArgumentException("Identity expected, but no private key available"); throw new IllegalArgumentException("Identity expected, but no private key available");
Singleton.identity = identity; Singleton.identity = identity;
} }
public static ConversationService getConversationService(Context ctx) {
if (conversationService == null) {
final BitmessageContext bmc = getBitmessageContext(ctx);
synchronized (Singleton.class) {
if (conversationService == null) {
conversationService = new ConversationService(bmc.messages());
}
}
}
return conversationService;
}
} }

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:top="1dp" android:bottom="1dp">
<shape
android:shape="rectangle">
<stroke android:width="1dp" android:color="#FFDDDDDD" />
<solid android:color="#00000000" />
</shape>
</item>
</layer-list>

View File

@ -78,12 +78,20 @@
android:paddingRight="8dp" android:paddingRight="8dp"
tools:text="Recipient" /> tools:text="Recipient" />
<android.support.v7.widget.RecyclerView
android:id="@+id/parents"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/avatar"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" />
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/avatar" android:layout_below="@+id/parents"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginTop="32dp" android:layout_marginTop="32dp"
@ -98,5 +106,13 @@
android:layout_below="@+id/text" android:layout_below="@+id/text"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" /> android:layout_marginRight="16dp" />
<android.support.v7.widget.RecyclerView
android:id="@+id/responses"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/text"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" />
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/border_bottom">
<ImageView
android:id="@+id/avatar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:src="@color/colorPrimaryDark"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/sender"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/avatar"
android:layout_marginTop="-5dp"
android:layout_toEndOf="@+id/avatar"
android:ellipsize="end"
android:lines="1"
android:paddingBottom="0dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"
tools:text="Sender" />
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_below="@+id/sender"
android:layout_toEndOf="@+id/avatar"
android:ellipsize="end"
android:gravity="center_vertical"
android:lines="1"
android:paddingBottom="8dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Text" />
<ImageView
android:id="@+id/status"
android:layout_width="24dp"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/avatar"
android:layout_alignEnd="@+id/avatar"
android:layout_marginBottom="-8dp"
android:layout_marginEnd="-8dp"
android:tint="@color/colorAccent"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_notification_proof_of_work" />
</RelativeLayout>

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!--
~ Copyright 2015 Christian Basler ~ Copyright 2015 Christian Basler
~ ~
~ Licensed under the Apache License, Version 2.0 (the "License"); ~ Licensed under the Apache License, Version 2.0 (the "License");
@ -15,8 +14,7 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -31,11 +29,10 @@
android:foreground="?attr/selectableItemBackground" android:foreground="?attr/selectableItemBackground"
tools:ignore="UselessParent"> tools:ignore="UselessParent">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:background="?attr/selectableItemBackground">
android:background="?attr/selectableItemBackground">
<ImageView <ImageView
android:id="@+id/avatar" android:id="@+id/avatar"
@ -45,7 +42,7 @@
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_margin="16dp" android:layout_margin="16dp"
android:src="@color/colorPrimaryDark" android:src="@color/colorPrimaryDark"
tools:ignore="ContentDescription"/> tools:ignore="ContentDescription" />
<TextView <TextView
android:id="@+id/sender" android:id="@+id/sender"
@ -63,8 +60,7 @@
android:paddingTop="0dp" android:paddingTop="0dp"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold" android:textStyle="bold"
tools:text="Sender" tools:text="Sender" />
/>
<TextView <TextView
android:id="@+id/subject" android:id="@+id/subject"
@ -78,7 +74,7 @@
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingRight="8dp" android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Subject"/> tools:text="Subject" />
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
@ -94,7 +90,7 @@
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingRight="8dp" android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Text"/> tools:text="Text" />
<ImageView <ImageView
android:id="@+id/status" android:id="@+id/status"
@ -106,7 +102,7 @@
android:layout_marginEnd="-8dp" android:layout_marginEnd="-8dp"
android:tint="@color/colorAccent" android:tint="@color/colorAccent"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/ic_notification_proof_of_work"/> tools:src="@drawable/ic_notification_proof_of_work" />
</RelativeLayout> </RelativeLayout>