diff --git a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java index 857a195..0552cb6 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/MessageDetailFragment.java @@ -18,8 +18,10 @@ package ch.dissem.apps.abit; import android.content.Context; import android.os.Bundle; +import android.support.annotation.IdRes; import android.support.v4.app.Fragment; import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.util.Linkify; 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.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.ports.MessageRepository; 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_URL_SCHEMA; +import static ch.dissem.apps.abit.util.Strings.normalizeWhitespaces; /** @@ -143,16 +147,30 @@ public class MessageDetailFragment extends Fragment { removed = true; } } + MessageRepository messageRepo = Singleton.getMessageRepository(inflater.getContext()); if (removed) { if (getActivity() instanceof ActionBarListener) { ((ActionBarListener) getActivity()).updateUnread(); } - Singleton.getMessageRepository(inflater.getContext()).save(item); + messageRepo.save(item); } + List 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; } + 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 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.message, menu); @@ -211,6 +229,61 @@ public class MessageDetailFragment extends Fragment { 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 RecyclerView.Adapter<LabelAdapter.ViewHolder> { diff --git a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java index 1bceb0b..e01f099 100644 --- a/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java +++ b/app/src/main/java/ch/dissem/apps/abit/service/Singleton.java @@ -42,6 +42,7 @@ import ch.dissem.bitmessage.networking.nio.NioNetworkHandler; import ch.dissem.bitmessage.ports.AddressRepository; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; +import ch.dissem.bitmessage.utils.ConversationService; import ch.dissem.bitmessage.utils.TTL; import static ch.dissem.bitmessage.utils.UnixTime.DAY; @@ -51,6 +52,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY; */ public class Singleton { private static BitmessageContext bitmessageContext; + private static ConversationService conversationService; private static MessageListener messageListener; private static BitmessageAddress identity; private static AndroidProofOfWorkRepository powRepo; @@ -160,4 +162,16 @@ public class Singleton { throw new IllegalArgumentException("Identity expected, but no private key available"); 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; + } } diff --git a/app/src/main/res/drawable/border_bottom.xml b/app/src/main/res/drawable/border_bottom.xml new file mode 100644 index 0000000..ab52873 --- /dev/null +++ b/app/src/main/res/drawable/border_bottom.xml @@ -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> diff --git a/app/src/main/res/layout/fragment_message_detail.xml b/app/src/main/res/layout/fragment_message_detail.xml index 1c63f9b..e698bf5 100644 --- a/app/src/main/res/layout/fragment_message_detail.xml +++ b/app/src/main/res/layout/fragment_message_detail.xml @@ -78,12 +78,20 @@ android:paddingRight="8dp" 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 android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" - android:layout_below="@+id/avatar" + android:layout_below="@+id/parents" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:layout_marginTop="32dp" @@ -98,5 +106,13 @@ android:layout_below="@+id/text" android:layout_marginLeft="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> </ScrollView> diff --git a/app/src/main/res/layout/item_message_minimized.xml b/app/src/main/res/layout/item_message_minimized.xml new file mode 100644 index 0000000..f556959 --- /dev/null +++ b/app/src/main/res/layout/item_message_minimized.xml @@ -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> diff --git a/app/src/main/res/layout/message_row.xml b/app/src/main/res/layout/message_row.xml index f23d5c1..9c9f88a 100644 --- a/app/src/main/res/layout/message_row.xml +++ b/app/src/main/res/layout/message_row.xml @@ -1,5 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright 2015 Christian Basler ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,8 +14,7 @@ ~ limitations under the License. --> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout 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" @@ -31,11 +29,10 @@ android:foreground="?attr/selectableItemBackground" tools:ignore="UselessParent"> - <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="?attr/selectableItemBackground"> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> <ImageView android:id="@+id/avatar" @@ -45,7 +42,7 @@ android:layout_alignParentTop="true" android:layout_margin="16dp" android:src="@color/colorPrimaryDark" - tools:ignore="ContentDescription"/> + tools:ignore="ContentDescription" /> <TextView android:id="@+id/sender" @@ -63,8 +60,7 @@ android:paddingTop="0dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" - tools:text="Sender" - /> + tools:text="Sender" /> <TextView android:id="@+id/subject" @@ -78,7 +74,7 @@ android:paddingLeft="8dp" android:paddingRight="8dp" android:textAppearance="?android:attr/textAppearanceSmall" - tools:text="Subject"/> + tools:text="Subject" /> <TextView android:id="@+id/text" @@ -94,7 +90,7 @@ android:paddingLeft="8dp" android:paddingRight="8dp" android:textAppearance="?android:attr/textAppearanceSmall" - tools:text="Text"/> + tools:text="Text" /> <ImageView android:id="@+id/status" @@ -106,7 +102,7 @@ android:layout_marginEnd="-8dp" android:tint="@color/colorAccent" tools:ignore="ContentDescription" - tools:src="@drawable/ic_notification_proof_of_work"/> + tools:src="@drawable/ic_notification_proof_of_work" /> </RelativeLayout>