diff options
-rw-r--r-- | res/layout/fragment_conversation.xml | 188 | ||||
-rw-r--r-- | res/values/strings.xml | 4 | ||||
-rw-r--r-- | res/xml/preferences.xml | 5 | ||||
-rw-r--r-- | src/eu/siacs/conversations/entities/Contact.java | 8 | ||||
-rw-r--r-- | src/eu/siacs/conversations/entities/Message.java | 9 | ||||
-rw-r--r-- | src/eu/siacs/conversations/parser/MessageParser.java | 23 | ||||
-rw-r--r-- | src/eu/siacs/conversations/ui/ConversationActivity.java | 624 | ||||
-rw-r--r-- | src/eu/siacs/conversations/ui/ConversationFragment.java | 62 | ||||
-rw-r--r-- | src/eu/siacs/conversations/utils/UIHelper.java | 13 |
9 files changed, 556 insertions, 380 deletions
diff --git a/res/layout/fragment_conversation.xml b/res/layout/fragment_conversation.xml index ca09d770..ab9bb528 100644 --- a/res/layout/fragment_conversation.xml +++ b/res/layout/fragment_conversation.xml @@ -3,32 +3,33 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#e5e5e5"> + android:background="#e5e5e5" > <RelativeLayout - android:background="#eee" android:id="@+id/textsend" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" - android:layout_alignParentLeft="true"> + android:layout_alignParentLeft="true" + android:background="#eee" > <EditText android:id="@+id/textinput" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="48dp" android:layout_alignParentLeft="true" - android:paddingBottom="12dp" - android:paddingLeft="8dp" - android:paddingRight="8dp" - android:paddingTop="12dp" android:layout_toLeftOf="@+id/textSendButton" android:background="#eee" android:ems="10" android:inputType="textShortMessage|textMultiLine|textCapSentences" - android:minLines="1" > - <requestFocus /> + android:minHeight="48dp" + android:minLines="1" + android:paddingBottom="12dp" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingTop="12dp" > + + <requestFocus /> </EditText> <ImageButton @@ -52,101 +53,118 @@ android:divider="@null" android:dividerHeight="0dp" android:listSelector="@android:color/transparent" + android:stackFromBottom="true" android:transcriptMode="alwaysScroll" - tools:listitem="@layout/message_sent" - android:stackFromBottom="true"> - + tools:listitem="@layout/message_sent" > </ListView> + <LinearLayout android:id="@+id/info_box" - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:orientation="vertical" - > - - <LinearLayout - android:id="@+id/muc_error" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@drawable/redbackground" - android:orientation="vertical" - android:visibility="gone" - > + android:orientation="vertical" > - <TextView - android:id="@+id/muc_error_msg" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="#eee" - android:textStyle="bold" - android:padding="8dp" - android:textSize="20sp"/> - <TextView - android:layout_width="wrap_content" + <LinearLayout + android:id="@+id/muc_error" + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:text="Click to edit conference details" - android:textColor="#eee" - android:paddingLeft="8dp" - android:paddingBottom="8dp" - android:textSize="14sp"/> - - </LinearLayout> - - - <LinearLayout - android:id="@+id/new_fingerprint" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="@drawable/redbackground" - android:orientation="vertical" - android:visibility="gone" - > + android:background="@drawable/redbackground" + android:orientation="vertical" + android:visibility="gone" > - <TextView - android:layout_width="wrap_content" + <TextView + android:id="@+id/muc_error_msg" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:textColor="#eee" + android:textSize="20sp" + android:textStyle="bold" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingBottom="8dp" + android:paddingLeft="8dp" + android:text="Click to edit conference details" + android:textColor="#eee" + android:textSize="14sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/new_fingerprint" + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:text="Unknown OTR Fingerprint" - android:textColor="#eee" - android:textStyle="bold" - android:padding="8dp" - android:textSize="20sp"/> - <TextView - android:layout_width="wrap_content" + android:background="@drawable/redbackground" + android:orientation="vertical" + android:visibility="gone" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:text="Unknown OTR Fingerprint" + android:textColor="#eee" + android:textSize="20sp" + android:textStyle="bold" /> + + <TextView + android:id="@+id/otr_fingerprint" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingBottom="8dp" + android:paddingLeft="8dp" + android:textColor="#eee" + android:textSize="14sp" + android:typeface="monospace" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/pgp_keyentry" + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:id="@+id/otr_fingerprint" - android:textColor="#eee" - android:paddingLeft="8dp" - android:paddingBottom="8dp" - android:textSize="14sp" - android:typeface="monospace"/> - + android:background="@drawable/bluebackground" + android:orientation="vertical" + android:visibility="gone" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:text="OpenPGP encrypted messages found" + android:textColor="#eee" + android:textSize="20sp" + android:textStyle="bold" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingBottom="8dp" + android:paddingLeft="8dp" + android:text="Click here to enter passphrase and decrypt messages" + android:textColor="#eee" + android:textSize="14sp" /> + </LinearLayout> </LinearLayout> + <LinearLayout - android:id="@+id/pgp_keyentry" + android:id="@+id/last_seen" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@drawable/bluebackground" + android:background="#7f333333" android:orientation="vertical" android:visibility="gone" - > + android:layout_below="@+id/info_box"> <TextView + android:id="@+id/last_seen_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="OpenPGP encrypted messages found" - android:textColor="#eee" - android:textStyle="bold" - android:padding="8dp" - android:textSize="20sp"/> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="#eee" - android:text="Click here to enter passphrase and decrypt messages" - android:paddingLeft="8dp" - android:paddingBottom="8dp" - android:textSize="14sp"/> - - </LinearLayout> + android:layout_gravity="center" + android:padding="4dp" + android:text="@string/last_seen" + android:textColor="#e5e5e5" + android:textSize="14sp" /> </LinearLayout> + </RelativeLayout>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 6767568e..48849eb4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -147,6 +147,8 @@ <string name="pref_never_send_crash_summary">By sending in stack traces you are helping the ongoing development of Conversations</string> <string name="pref_confirm_messages">Confirm Messages</string> <string name="pref_confirm_messages_summary">Let your contact know when you have received and read a message</string> + <string name="pref_show_last_seen">Display last seen</string> + <string name="pref_show_last_seen_summary">Display the latest time a contact has been seen online</string> <string name="openpgp_error">OpenKeychain reporeted an error</string> <string name="error_decrypting_file">I/O Error decrypting file</string> <string name="error_copying_image_file">Error copying image file.</string> @@ -234,4 +236,6 @@ <string name="hours">hours</string> <string name="mins">mins</string> <string name="missing_public_keys">Missing public key announcements</string> + <string name="last_seen">last seen %1$s ago on %2$s</string> + <string name="never_seen">never seen</string> </resources>
\ No newline at end of file diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 40039cd5..be9a2be7 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -72,6 +72,11 @@ android:title="@string/pref_conference_name" android:summary="@string/pref_conference_name_summary" android:defaultValue="true"/> + <CheckBoxPreference + android:key="show_last_seen" + android:title="@string/pref_show_last_seen" + android:summary="@string/pref_show_last_seen_summary" + android:defaultValue="false"/> </PreferenceCategory> <PreferenceCategory android:title="@string/pref_advanced_options"> diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java index cff0dd73..8f4b6193 100644 --- a/src/eu/siacs/conversations/entities/Contact.java +++ b/src/eu/siacs/conversations/entities/Contact.java @@ -11,7 +11,6 @@ import org.json.JSONObject; import eu.siacs.conversations.xml.Element; import android.content.ContentValues; import android.database.Cursor; -import android.util.Log; public class Contact { public static final String TABLENAME = "contacts"; @@ -38,6 +37,8 @@ public class Contact { protected Account account; protected boolean inRoster = true; + + public Lastseen lastseen = new Lastseen(); public Contact(String account, String systemName, String serverName, String jid, int subscription, String photoUri, @@ -305,4 +306,9 @@ public class Contact { public static final int DIRTY_PUSH = 6; public static final int DIRTY_DELETE = 7; } + + public class Lastseen { + public long time = 0; + public String presence = null; + } } diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java index cc6bc7c2..c298a652 100644 --- a/src/eu/siacs/conversations/entities/Message.java +++ b/src/eu/siacs/conversations/entities/Message.java @@ -203,6 +203,15 @@ public class Message extends AbstractEntity { this.counterpart = this.counterpart.split("/")[0] + "/" + presence; } + public String getPresence() { + String[] counterparts = this.counterpart.split("/"); + if (counterparts.length == 2) { + return counterparts[1]; + } else { + return null; + } + } + public void setJingleConnection(JingleConnection connection) { this.jingleConnection = connection; } diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index 8e099728..ab75d676 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/src/eu/siacs/conversations/parser/MessageParser.java @@ -6,6 +6,7 @@ import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionStatus; import android.util.Log; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; @@ -26,6 +27,7 @@ public class MessageParser { Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); + updateLastseen(packet, account); String pgpBody = getPgpBody(packet); if (pgpBody != null) { return new Message(conversation, packet.getFrom(), pgpBody, @@ -43,6 +45,7 @@ public class MessageParser { String[] fromParts = packet.getFrom().split("/"); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); + updateLastseen(packet, account); String body = packet.getBody(); if (!conversation.hasValidOtrSession()) { if (properlyAddressed) { @@ -171,6 +174,7 @@ public class MessageParser { return null; // either malformed or boring if (status == Message.STATUS_RECIEVED) { fullJid = message.getAttribute("from"); + updateLastseen(message, account); } else { fullJid = message.getAttribute("to"); } @@ -211,4 +215,23 @@ public class MessageParser { return null; } } + + private void updateLastseen(Element message, Account account) { + String[] fromParts = message.getAttribute("from").split("/"); + String from = fromParts[0]; + String presence = null; + if (fromParts.length >= 2) { + presence = fromParts[1]; + } + Contact contact = account.getRoster().getContact(from); + if (presence!=null) { + contact.lastseen.presence = presence; + contact.lastseen.time = System.currentTimeMillis(); + } else if ((contact.getPresences().size() == 1)&&(contact.getPresences().containsKey(contact.lastseen.presence))) { + contact.lastseen.time = System.currentTimeMillis(); + } else { + contact.lastseen.presence = null; + contact.lastseen.time = System.currentTimeMillis(); + } + } } diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index 45a0d632..55c538d6 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -69,7 +69,7 @@ public class ConversationActivity extends XmppActivity { private static final int REQUEST_RECORD_AUDIO = 0x46189; private static final int REQUEST_SEND_PGP_IMAGE = 0x53883; public static final int REQUEST_ENCRYPT_MESSAGE = 0x378018; - + private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x92734; private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x84123; private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x75291; @@ -79,11 +79,12 @@ public class ConversationActivity extends XmppActivity { private List<Conversation> conversationList = new ArrayList<Conversation>(); private Conversation selectedConversation = null; private ListView listView; - + private boolean paneShouldBeOpen = true; private boolean useSubject = true; + private boolean showLastseen = false; private ArrayAdapter<Conversation> listAdapter; - + public Message pendingMessage = null; private OnConversationListChangedListener onConvChanged = new OnConversationListChangedListener() { @@ -113,7 +114,7 @@ public class ConversationActivity extends XmppActivity { }); } }; - + protected ConversationActivity activity = this; private DisplayMetrics metrics; private Toast prepareImageToast; @@ -125,7 +126,7 @@ public class ConversationActivity extends XmppActivity { public Conversation getSelectedConversation() { return this.selectedConversation; } - + public void setSelectedConversation(Conversation conversation) { this.selectedConversation = conversation; } @@ -146,7 +147,7 @@ public class ConversationActivity extends XmppActivity { protected void onCreate(Bundle savedInstanceState) { metrics = getResources().getDisplayMetrics(); - + super.onCreate(savedInstanceState); setContentView(R.layout.fragment_conversations_overview); @@ -182,15 +183,18 @@ public class ConversationActivity extends XmppActivity { convName.setText(conv.getName(useSubject)); TextView convLastMsg = (TextView) view .findViewById(R.id.conversation_lastmsg); - ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage); - + ImageView imagePreview = (ImageView) view + .findViewById(R.id.conversation_lastimage); + Message latestMessage = conv.getLatestMessage(); - + if (latestMessage.getType() == Message.TYPE_TEXT) { - if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP)&&(latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { + if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP) + && (latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { convLastMsg.setText(conv.getLatestMessage().getBody()); } else { - convLastMsg.setText(getText(R.string.encrypted_message_received)); + convLastMsg + .setText(getText(R.string.encrypted_message_received)); } convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); @@ -203,16 +207,16 @@ public class ConversationActivity extends XmppActivity { convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); if (latestMessage.getStatus() == Message.STATUS_RECEIVED_OFFER) { - convLastMsg.setText(getText(R.string.image_offered_for_download)); + convLastMsg + .setText(getText(R.string.image_offered_for_download)); } else if (latestMessage.getStatus() == Message.STATUS_RECIEVING) { - convLastMsg.setText(getText(R.string.receiving_image)); + convLastMsg + .setText(getText(R.string.receiving_image)); } else { convLastMsg.setText(""); } } } - - if (!conv.isRead()) { convName.setTypeface(null, Typeface.BOLD); @@ -223,14 +227,14 @@ public class ConversationActivity extends XmppActivity { } ((TextView) view.findViewById(R.id.conversation_lastupdate)) - .setText(UIHelper.readableTimeDifference(getContext(), conv - .getLatestMessage().getTimeSent())); + .setText(UIHelper.readableTimeDifference(getContext(), + conv.getLatestMessage().getTimeSent())); ImageView profilePicture = (ImageView) view .findViewById(R.id.conversation_image); - profilePicture.setImageBitmap(UIHelper.getContactPicture( - conv, 56, activity.getApplicationContext(), false)); - + profilePicture.setImageBitmap(UIHelper.getContactPicture(conv, + 56, activity.getApplicationContext(), false)); + return view; } @@ -266,6 +270,11 @@ public class ConversationActivity extends XmppActivity { getActionBar().setTitle(R.string.app_name); invalidateOptionsMenu(); hideKeyboard(); + ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if (selectedFragment != null) { + selectedFragment.lastSeen.setVisibility(View.GONE); + } } @Override @@ -279,11 +288,17 @@ public class ConversationActivity extends XmppActivity { getSelectedConversation().getName(useSubject)); invalidateOptionsMenu(); if (!getSelectedConversation().isRead()) { - xmppConnectionService.markRead(getSelectedConversation()); + xmppConnectionService + .markRead(getSelectedConversation()); UIHelper.updateNotification(getApplicationContext(), getConversationList(), null, false); listView.invalidateViews(); } + ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if ((selectedFragment != null) && (showLastseen())) { + selectedFragment.lastSeen.setVisibility(View.VISIBLE); + } } } @@ -307,7 +322,8 @@ public class ConversationActivity extends XmppActivity { MenuItem menuInviteContacts = (MenuItem) menu .findItem(R.id.action_invite); MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file); - MenuItem menuClearHistory = (MenuItem) menu.findItem(R.id.action_clear_history); + MenuItem menuClearHistory = (MenuItem) menu + .findItem(R.id.action_clear_history); if ((spl.isOpen() && (spl.isSlideable()))) { menuArchive.setVisible(false); @@ -336,27 +352,34 @@ public class ConversationActivity extends XmppActivity { } return true; } - + private void selectPresenceToAttachFile(final int attachmentChoice) { selectPresence(getSelectedConversation(), new OnPresenceSelected() { - + @Override public void onPresenceSelected(boolean success, String presence) { if (success) { - if (attachmentChoice==ATTACHMENT_CHOICE_TAKE_PHOTO) { - Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, ImageProvider.getIncomingContentUri()); - if (takePictureIntent.resolveActivity(getPackageManager()) != null) { - startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); + if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { + Intent takePictureIntent = new Intent( + MediaStore.ACTION_IMAGE_CAPTURE); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, + ImageProvider.getIncomingContentUri()); + if (takePictureIntent + .resolveActivity(getPackageManager()) != null) { + startActivityForResult(takePictureIntent, + REQUEST_IMAGE_CAPTURE); } - } else if (attachmentChoice==ATTACHMENT_CHOICE_CHOOSE_IMAGE) { + } else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { Intent attachFileIntent = new Intent(); attachFileIntent.setType("image/*"); attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); - Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file)); - startActivityForResult(chooser, REQUEST_ATTACH_FILE_DIALOG); - } else if (attachmentChoice==ATTACHMENT_CHOICE_RECORD_VOICE) { - Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + Intent chooser = Intent.createChooser(attachFileIntent, + getString(R.string.attach_file)); + startActivityForResult(chooser, + REQUEST_ATTACH_FILE_DIALOG); + } else if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) { + Intent intent = new Intent( + MediaStore.Audio.Media.RECORD_SOUND_ACTION); startActivityForResult(intent, REQUEST_RECORD_AUDIO); } } @@ -365,45 +388,50 @@ public class ConversationActivity extends XmppActivity { @Override public void onSendPlainTextInstead() { // TODO Auto-generated method stub - + } - },"file"); + }, "file"); } private void attachFile(final int attachmentChoice) { final Conversation conversation = getSelectedConversation(); if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) { if (hasPgp()) { - if (conversation.getContact().getPgpKeyId()!=0) { - xmppConnectionService.getPgpEngine().hasKey(conversation.getContact(), new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi) { - ConversationActivity.this.runIntent(pi, attachmentChoice); - } - - @Override - public void success() { - selectPresenceToAttachFile(attachmentChoice); - } - - @Override - public void error(int error) { - displayErrorDialog(error); - } - }); + if (conversation.getContact().getPgpKeyId() != 0) { + xmppConnectionService.getPgpEngine().hasKey( + conversation.getContact(), new UiCallback() { + + @Override + public void userInputRequried(PendingIntent pi) { + ConversationActivity.this.runIntent(pi, + attachmentChoice); + } + + @Override + public void success() { + selectPresenceToAttachFile(attachmentChoice); + } + + @Override + public void error(int error) { + displayErrorDialog(error); + } + }); } else { final ConversationFragment fragment = (ConversationFragment) getFragmentManager() .findFragmentByTag("conversation"); if (fragment != null) { - fragment.showNoPGPKeyDialog(false,new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - selectPresenceToAttachFile(attachmentChoice); - } - }); + fragment.showNoPGPKeyDialog(false, + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + selectPresenceToAttachFile(attachmentChoice); + } + }); } } } @@ -414,29 +442,36 @@ public class ConversationActivity extends XmppActivity { builder.setTitle(getString(R.string.otr_file_transfer)); builder.setMessage(getString(R.string.otr_file_transfer_msg)); builder.setNegativeButton(getString(R.string.cancel), null); - if (conversation.getContact().getPgpKeyId()==0) { - builder.setPositiveButton(getString(R.string.send_unencrypted), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - attachFile(attachmentChoice); - } - }); + if (conversation.getContact().getPgpKeyId() == 0) { + builder.setPositiveButton(getString(R.string.send_unencrypted), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + attachFile(attachmentChoice); + } + }); } else { - builder.setPositiveButton(getString(R.string.use_pgp_encryption), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); - attachFile(attachmentChoice); - } - }); + builder.setPositiveButton( + getString(R.string.use_pgp_encryption), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_PGP); + attachFile(attachmentChoice); + } + }); } builder.create().show(); } } - + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -447,24 +482,25 @@ public class ConversationActivity extends XmppActivity { View menuAttachFile = findViewById(R.id.action_attach_file); PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); attachFilePopup.inflate(R.menu.attachment_choices); - attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.attach_choose_picture: - attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); - break; - case R.id.attach_take_picture: - attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); - break; - case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); - break; - } - return false; - } - }); + attachFilePopup + .setOnMenuItemClickListener(new OnMenuItemClickListener() { + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.attach_choose_picture: + attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); + break; + case R.id.attach_take_picture: + attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case R.id.attach_record_voice: + attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); + break; + } + return false; + } + }); attachFilePopup.show(); break; case R.id.action_add: @@ -478,8 +514,9 @@ public class ConversationActivity extends XmppActivity { if (contact.showInRoster()) { Intent intent = new Intent(this, ContactDetailsActivity.class); intent.setAction(ContactDetailsActivity.ACTION_VIEW_CONTACT); - intent.putExtra("account", this.getSelectedConversation().getAccount().getJid()); - intent.putExtra("contact",contact.getJid()); + intent.putExtra("account", this.getSelectedConversation() + .getAccount().getJid()); + intent.putExtra("contact", contact.getJid()); startActivity(intent); } else { showAddToRosterDialog(getSelectedConversation()); @@ -511,25 +548,31 @@ public class ConversationActivity extends XmppActivity { public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.encryption_choice_none: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); item.setChecked(true); break; case R.id.encryption_choice_otr: - conversation.setNextEncryption(Message.ENCRYPTION_OTR); + conversation + .setNextEncryption(Message.ENCRYPTION_OTR); item.setChecked(true); break; case R.id.encryption_choice_pgp: if (hasPgp()) { - if (conversation.getAccount().getKeys().has("pgp_signature")) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); + if (conversation.getAccount().getKeys() + .has("pgp_signature")) { + conversation + .setNextEncryption(Message.ENCRYPTION_PGP); item.setChecked(true); } else { - announcePgp(conversation.getAccount(),conversation); + announcePgp(conversation.getAccount(), + conversation); } } break; default: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); break; } fragment.updateChatMsgHint(); @@ -537,7 +580,8 @@ public class ConversationActivity extends XmppActivity { } }); popup.inflate(R.menu.encryption_choices); - MenuItem otr = popup.getMenu().findItem(R.id.encryption_choice_otr); + MenuItem otr = popup.getMenu().findItem( + R.id.encryption_choice_otr); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setEnabled(false); } @@ -570,7 +614,7 @@ public class ConversationActivity extends XmppActivity { } return super.onOptionsItemSelected(item); } - + private void endConversation(Conversation conversation) { conversation.setStatus(Conversation.STATUS_ARCHIVED); paneShouldBeOpen = true; @@ -586,20 +630,24 @@ public class ConversationActivity extends XmppActivity { protected void clearHistoryDialog(final Conversation conversation) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.clear_conversation_history)); - View dialogView = getLayoutInflater().inflate(R.layout.dialog_clear_history, null); - final CheckBox endConversationCheckBox = (CheckBox) dialogView.findViewById(R.id.end_conversation_checkbox); + View dialogView = getLayoutInflater().inflate( + R.layout.dialog_clear_history, null); + final CheckBox endConversationCheckBox = (CheckBox) dialogView + .findViewById(R.id.end_conversation_checkbox); builder.setView(dialogView); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.delete_messages), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - activity.xmppConnectionService.clearConversationHistory(conversation); - if (endConversationCheckBox.isChecked()) { - endConversation(conversation); - } - } - }); + builder.setPositiveButton(getString(R.string.delete_messages), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + activity.xmppConnectionService + .clearConversationHistory(conversation); + if (endConversationCheckBox.isChecked()) { + endConversation(conversation); + } + } + }); builder.create().show(); } @@ -626,10 +674,10 @@ public class ConversationActivity extends XmppActivity { } @Override - protected void onNewIntent (Intent intent) { - if ((Intent.ACTION_VIEW.equals(intent.getAction())&&(VIEW_CONVERSATION.equals(intent.getType())))) { - String convToView = (String) intent.getExtras().get( - CONVERSATION); + protected void onNewIntent(Intent intent) { + if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION + .equals(intent.getType())))) { + String convToView = (String) intent.getExtras().get(CONVERSATION); updateConversationList(); for (int i = 0; i < conversationList.size(); ++i) { if (conversationList.get(i).getUuid().equals(convToView)) { @@ -642,13 +690,14 @@ public class ConversationActivity extends XmppActivity { swapConversationFragment().setText(text); } } - + @Override public void onStart() { super.onStart(); SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(this); this.useSubject = preferences.getBoolean("use_subject_in_muc", true); + this.showLastseen = preferences.getBoolean("show_last_seen", false); if (this.xmppConnectionServiceBound) { this.onBackendConnected(); } @@ -722,7 +771,8 @@ public class ConversationActivity extends XmppActivity { } @Override - protected void onActivityResult(int requestCode, int resultCode, final Intent data) { + protected void onActivityResult(int requestCode, int resultCode, + final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_DECRYPT_PGP) { @@ -732,62 +782,68 @@ public class ConversationActivity extends XmppActivity { selectedFragment.hidePgpPassphraseBox(); } } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { - attachImageToConversation(getSelectedConversation(),data.getData()); + attachImageToConversation(getSelectedConversation(), + data.getData()); } else if (requestCode == REQUEST_SEND_PGP_IMAGE) { - + } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) { attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); } else if (requestCode == REQUEST_ANNOUNCE_PGP) { - announcePgp(getSelectedConversation().getAccount(),getSelectedConversation()); + announcePgp(getSelectedConversation().getAccount(), + getSelectedConversation()); } else if (requestCode == REQUEST_ENCRYPT_MESSAGE) { encryptTextMessage(); } else if (requestCode == REQUEST_IMAGE_CAPTURE) { attachImageToConversation(getSelectedConversation(), null); } else if (requestCode == REQUEST_RECORD_AUDIO) { - Log.d("xmppService",data.getData().toString()); - attachAudioToConversation(getSelectedConversation(),data.getData()); + Log.d("xmppService", data.getData().toString()); + attachAudioToConversation(getSelectedConversation(), + data.getData()); } else { - Log.d(LOGTAG,"unknown result code:"+requestCode); + Log.d(LOGTAG, "unknown result code:" + requestCode); } } } - + private void attachAudioToConversation(Conversation conversation, Uri uri) { - + } private void attachImageToConversation(Conversation conversation, Uri uri) { - prepareImageToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG); + prepareImageToast = Toast.makeText(getApplicationContext(), + getText(R.string.preparing_image), Toast.LENGTH_LONG); prepareImageToast.show(); - pendingMessage = xmppConnectionService.attachImageToConversation(conversation, uri, new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi) { - hidePrepareImageToast(); - ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_PGP_IMAGE); - } - - @Override - public void success() { - sendPendingImageMessage(); - hidePrepareImageToast(); - } - - @Override - public void error(int error) { - hidePrepareImageToast(); - pendingMessage = null; - displayErrorDialog(error); - } - }); + pendingMessage = xmppConnectionService.attachImageToConversation( + conversation, uri, new UiCallback() { + + @Override + public void userInputRequried(PendingIntent pi) { + hidePrepareImageToast(); + ConversationActivity.this.runIntent(pi, + ConversationActivity.REQUEST_SEND_PGP_IMAGE); + } + + @Override + public void success() { + sendPendingImageMessage(); + hidePrepareImageToast(); + } + + @Override + public void error(int error) { + hidePrepareImageToast(); + pendingMessage = null; + displayErrorDialog(error); + } + }); } - + private void hidePrepareImageToast() { - if (prepareImageToast!=null) { + if (prepareImageToast != null) { runOnUiThread(new Runnable() { - + @Override public void run() { prepareImageToast.cancel(); @@ -803,41 +859,46 @@ public class ConversationActivity extends XmppActivity { xmppConnectionService.updateUi(pendingMessage.getConversation(), false); pendingMessage = null; } - + public void updateConversationList() { conversationList.clear(); conversationList.addAll(xmppConnectionService.getConversations()); listView.invalidateViews(); } - - public void selectPresence(final Conversation conversation, final OnPresenceSelected listener, String reason) { + + public void selectPresence(final Conversation conversation, + final OnPresenceSelected listener, String reason) { Account account = conversation.getAccount(); if (account.getStatus() != Account.STATUS_ONLINE) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.not_connected)); builder.setIconAttribute(android.R.attr.alertDialogIcon); if ("otr".equals(reason)) { - builder.setMessage(getString(R.string.you_are_offline,getString(R.string.otr_messages))); + builder.setMessage(getString(R.string.you_are_offline, + getString(R.string.otr_messages))); } else if ("file".equals(reason)) { - builder.setMessage(getString(R.string.you_are_offline,getString(R.string.files))); + builder.setMessage(getString(R.string.you_are_offline, + getString(R.string.files))); } else { builder.setMessage(getString(R.string.you_are_offline_blank)); } builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.manage_account), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - startActivity(new Intent(activity, ManageAccountActivity.class)); - } - }); + builder.setPositiveButton(getString(R.string.manage_account), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + startActivity(new Intent(activity, + ManageAccountActivity.class)); + } + }); builder.create().show(); listener.onPresenceSelected(false, null); } else { Contact contact = conversation.getContact(); - if (contact==null) { + if (contact == null) { showAddToRosterDialog(conversation); - listener.onPresenceSelected(false,null); + listener.onPresenceSelected(false, null); } else { Hashtable<String, Integer> presences = contact.getPresences(); if (presences.size() == 0) { @@ -845,13 +906,16 @@ public class ConversationActivity extends XmppActivity { builder.setTitle(getString(R.string.contact_offline)); if ("otr".equals(reason)) { builder.setMessage(getString(R.string.contact_offline_otr)); - builder.setPositiveButton(getString(R.string.send_unencrypted), new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - listener.onSendPlainTextInstead(); - } - }); + builder.setPositiveButton( + getString(R.string.send_unencrypted), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + listener.onSendPlainTextInstead(); + } + }); } else if ("file".equals(reason)) { builder.setMessage(getString(R.string.contact_offline_file)); } @@ -870,13 +934,13 @@ public class ConversationActivity extends XmppActivity { presences.keySet().toArray(presencesArray); builder.setItems(presencesArray, new DialogInterface.OnClickListener() { - + @Override public void onClick(DialogInterface dialog, int which) { String presence = presencesArray[which]; conversation.setNextPresence(presence); - listener.onPresenceSelected(true,presence); + listener.onPresenceSelected(true, presence); } }); builder.create().show(); @@ -884,137 +948,149 @@ public class ConversationActivity extends XmppActivity { } } } - + + public boolean showLastseen() { + if (getSelectedConversation() == null) { + return false; + } else { + return this.showLastseen + && getSelectedConversation().getMode() == Conversation.MODE_SINGLE; + } + } + private void showAddToRosterDialog(final Conversation conversation) { String jid = conversation.getContactJid(); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(jid); builder.setMessage(getString(R.string.not_in_roster)); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.add_contact), new DialogInterface.OnClickListener() { + builder.setPositiveButton(getString(R.string.add_contact), + new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String jid = conversation.getContactJid(); - Account account = getSelectedConversation().getAccount(); - Contact contact = account.getRoster().getContact(jid); - xmppConnectionService.createContact(contact); - } - }); + @Override + public void onClick(DialogInterface dialog, int which) { + String jid = conversation.getContactJid(); + Account account = getSelectedConversation() + .getAccount(); + Contact contact = account.getRoster().getContact(jid); + xmppConnectionService.createContact(contact); + } + }); builder.create().show(); } - + public void runIntent(PendingIntent pi, int requestCode) { try { - this.startIntentSenderForResult(pi.getIntentSender(),requestCode, null, 0, - 0, 0); + this.startIntentSenderForResult(pi.getIntentSender(), requestCode, + null, 0, 0, 0); } catch (SendIntentException e1) { - Log.d("xmppService","failed to start intent to send message"); + Log.d("xmppService", "failed to start intent to send message"); } } - - + class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Message message = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<ImageView>(imageView); - } - - @Override - protected Bitmap doInBackground(Message... params) { - message = params[0]; - try { - return xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288),false); + private final WeakReference<ImageView> imageViewReference; + private Message message = null; + + public BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<ImageView>(imageView); + } + + @Override + protected Bitmap doInBackground(Message... params) { + message = params[0]; + try { + return xmppConnectionService.getFileBackend().getThumbnail( + message, (int) (metrics.density * 288), false); } catch (FileNotFoundException e) { - Log.d("xmppService","file not found!"); + Log.d("xmppService", "file not found!"); return null; } - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (imageViewReference != null && bitmap != null) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (imageViewReference != null && bitmap != null) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } } - + public void loadBitmap(Message message, ImageView imageView) { Bitmap bm; try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288), true); + bm = xmppConnectionService.getFileBackend().getThumbnail(message, + (int) (metrics.density * 288), true); } catch (FileNotFoundException e) { bm = null; } - if (bm!=null) { + if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); } else { - if (cancelPotentialWork(message, imageView)) { - imageView.setBackgroundColor(0xff333333); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = - new AsyncDrawable(getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - task.execute(message); - } + if (cancelPotentialWork(message, imageView)) { + imageView.setBackgroundColor(0xff333333); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable( + getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + task.execute(message); + } } } - - public static boolean cancelPotentialWork(Message message, ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final Message oldMessage = bitmapWorkerTask.message; - if (oldMessage == null || message != oldMessage) { - bitmapWorkerTask.cancel(true); - } else { - return false; - } - } - return true; + + public static boolean cancelPotentialWork(Message message, + ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Message oldMessage = bitmapWorkerTask.message; + if (oldMessage == null || message != oldMessage) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; } - + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { - if (imageView != null) { - final Drawable drawable = imageView.getDrawable(); - if (drawable instanceof AsyncDrawable) { - final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; - return asyncDrawable.getBitmapWorkerTask(); - } - } - return null; + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; } - + static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; - - public AsyncDrawable(Resources res, Bitmap bitmap, - BitmapWorkerTask bitmapWorkerTask) { - super(res, bitmap); - bitmapWorkerTaskReference = - new WeakReference<BitmapWorkerTask>(bitmapWorkerTask); - } - - public BitmapWorkerTask getBitmapWorkerTask() { - return bitmapWorkerTaskReference.get(); - } + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( + bitmapWorkerTask); + } + + public BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } } public void encryptTextMessage() { - xmppConnectionService.getPgpEngine().encrypt(this.pendingMessage, new UiCallback() { + xmppConnectionService.getPgpEngine().encrypt(this.pendingMessage, + new UiCallback() { @Override - public void userInputRequried( - PendingIntent pi) { - activity.runIntent( - pi, + public void userInputRequried(PendingIntent pi) { + activity.runIntent(pi, ConversationActivity.REQUEST_SEND_MESSAGE); } diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index 4a246492..6ca88008 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -107,7 +107,9 @@ public class ConversationFragment extends Fragment { private LinearLayout pgpInfo; private LinearLayout mucError; + public LinearLayout lastSeen; private TextView mucErrorText; + private TextView lastSeenText; private OnClickListener clickToMuc = new OnClickListener() { @Override @@ -161,6 +163,8 @@ public class ConversationFragment extends Fragment { mucError = (LinearLayout) view.findViewById(R.id.muc_error); mucError.setOnClickListener(clickToMuc); mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg); + lastSeen = (LinearLayout) view.findViewById(R.id.last_seen); + lastSeenText = (TextView) view.findViewById(R.id.last_seen_text); messagesView = (ListView) view.findViewById(R.id.messages_view); @@ -181,7 +185,7 @@ public class ConversationFragment extends Fragment { public int getItemViewType(int position) { if (getItem(position).getType() == Message.TYPE_STATUS) { return STATUS; - } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) { + } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) { return RECIEVED; } else { return SENT; @@ -335,18 +339,21 @@ public class ConversationFragment extends Fragment { startActivity(intent); } }); - viewHolder.image.setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - Intent shareIntent = new Intent(); - shareIntent.setAction(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_STREAM, ImageProvider.getContentUri(message)); - shareIntent.setType("image/webp"); - startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with))); - return true; - } - }); + viewHolder.image + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_STREAM, + ImageProvider.getContentUri(message)); + shareIntent.setType("image/webp"); + startActivity(Intent.createChooser(shareIntent, + getText(R.string.share_with))); + return true; + } + }); } @Override @@ -405,8 +412,8 @@ public class ConversationFragment extends Fragment { view.setTag(viewHolder); break; case STATUS: - view = (View) inflater.inflate( - R.layout.message_status, null); + view = (View) inflater.inflate(R.layout.message_status, + null); viewHolder.contact_picture = (ImageView) view .findViewById(R.id.message_photo); if (item.getConversation().getMode() == Conversation.MODE_SINGLE) { @@ -430,7 +437,7 @@ public class ConversationFragment extends Fragment { } else { viewHolder = (ViewHolder) view.getTag(); } - + if (type == STATUS) { return view; } @@ -577,7 +584,11 @@ public class ConversationFragment extends Fragment { activity.getActionBar().setTitle( conversation.getName(useSubject)); activity.invalidateOptionsMenu(); - + if (activity.showLastseen()) { + lastSeen.setVisibility(View.VISIBLE); + } + } else { + lastSeen.setVisibility(View.GONE); } } if (conversation.getMode() == Conversation.MODE_MULTI) { @@ -653,6 +664,16 @@ public class ConversationFragment extends Fragment { break; } } + if (activity.showLastseen()) { + Contact contact = conversation.getContact(); + if ((contact.lastseen.presence != null)&&(contact.lastseen.time != 0)) { + lastSeenText.setText(getString(R.string.last_seen, + UIHelper.lastseen(getActivity(), contact.lastseen.time), + contact.lastseen.presence)); + } else { + lastSeenText.setText(R.string.never_seen); + } + } this.messageList.clear(); this.messageList.addAll(this.conversation.getMessages()); updateStatusMessages(); @@ -685,15 +706,16 @@ public class ConversationFragment extends Fragment { } } } - + protected void updateStatusMessages() { if (conversation.getMode() == Conversation.MODE_SINGLE) { - for(int i = this.messageList.size() - 1; i >= 0; --i) { + for (int i = this.messageList.size() - 1; i >= 0; --i) { if (this.messageList.get(i).getStatus() == Message.STATUS_RECIEVED) { return; } else { if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { - this.messageList.add(i+1, Message.createStatusMessage(conversation)); + this.messageList.add(i + 1, + Message.createStatusMessage(conversation)); return; } } diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java index 9737040b..15d98d85 100644 --- a/src/eu/siacs/conversations/utils/UIHelper.java +++ b/src/eu/siacs/conversations/utils/UIHelper.java @@ -70,6 +70,19 @@ public class UIHelper { return sdf.format(date); } } + + public static String lastseen(Context context, long time) { + long difference = (System.currentTimeMillis() - time) / 1000; + if (difference < 60) { + return context.getString(R.string.just_now); + } else if (difference < 60 * 60) { + return difference / 60 + " " + context.getString(R.string.mins); + } else if (difference < 60 * 60 * 24) { + return difference / (60 * 60)+ " " + context.getString(R.string.hours); + } else { + return "days"; + } + } public static int getRealPx(int dp, Context context) { final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); |