fetch bookmarks from server

iNPUTmice created

Change summary

res/layout/join_conference_dialog.xml                          |  3 
res/menu/conference_context.xml                                | 11 
res/values/strings.xml                                         |  1 
src/eu/siacs/conversations/entities/Account.java               | 12 
src/eu/siacs/conversations/entities/Bookmark.java              | 94 ++++
src/eu/siacs/conversations/entities/Conversation.java          |  6 
src/eu/siacs/conversations/services/XmppConnectionService.java | 53 ++
src/eu/siacs/conversations/ui/StartConversation.java           | 91 +++
8 files changed, 254 insertions(+), 17 deletions(-)

Detailed changes

res/layout/join_conference_dialog.xml 🔗

@@ -41,6 +41,7 @@
         android:layout_marginTop="8dp"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/save_as_bookmark" />
+        android:text="@string/save_as_bookmark"
+        android:checked="true" />
 
 </LinearLayout>

res/menu/conference_context.xml 🔗

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/context_join_conference"
+        android:title="@string/join_conference"/>
+    <item
+        android:id="@+id/context_delete_conference"
+        android:title="@string/delete_bookmark"/>
+
+</menu>

res/values/strings.xml 🔗

@@ -267,4 +267,5 @@
     <string name="conference_address">Conference address</string>
     <string name="conference_address_example">room@conference.example.com</string>
     <string name="save_as_bookmark">Save as bookmark</string>
+    <string name="delete_bookmark">Delete bookmark</string>
 </resources>

src/eu/siacs/conversations/entities/Account.java 🔗

@@ -1,6 +1,8 @@
 package eu.siacs.conversations.entities;
 
 import java.security.interfaces.DSAPublicKey;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
 import net.java.otr4j.crypto.OtrCryptoEngineImpl;
@@ -67,6 +69,8 @@ public class Account  extends AbstractEntity{
 	private String otrFingerprint;
 	
 	private Roster roster = null;
+
+	private List<Bookmark> bookmarks = new ArrayList<Bookmark>();
 	
 	public Account() {
 		this.uuid = "0";
@@ -297,4 +301,12 @@ public class Account  extends AbstractEntity{
 		}
 		return this.roster;
 	}
+
+	public void setBookmarks(List<Bookmark> bookmarks) {
+		this.bookmarks = bookmarks;
+	}
+	
+	public List<Bookmark> getBookmarks() {
+		return this.bookmarks;
+	}
 }

src/eu/siacs/conversations/entities/Bookmark.java 🔗

@@ -0,0 +1,94 @@
+package eu.siacs.conversations.entities;
+
+import java.util.Locale;
+
+import eu.siacs.conversations.xml.Element;
+
+public class Bookmark implements ListItem {
+	
+	private Account account;
+	private String jid;
+	private String nick;
+	private String displayName;
+	private boolean autojoin;
+	
+	public Bookmark(Account account) {
+		this.account = account;
+	}
+
+	public static Bookmark parse(Element element, Account account) {
+		Bookmark bookmark = new Bookmark(account);
+		bookmark.setJid(element.getAttribute("jid"));
+		bookmark.setDisplayName(element.getAttribute("name"));
+		String autojoin = element.getAttribute("autojoin");
+		if (autojoin!=null && (autojoin.equals("true")||autojoin.equals("1"))) {
+			bookmark.setAutojoin(true);
+		} else {
+			bookmark.setAutojoin(false);
+		}
+		Element nick = element.findChild("nick");
+		if (nick!=null) {
+			bookmark.setNick(nick.getContent());
+		}
+		return bookmark;
+	}
+
+	public void setAutojoin(boolean autojoin) {
+		this.autojoin = autojoin;
+	}
+	
+	public void setDisplayName(String name) {
+		this.displayName = name;
+	}
+	
+	public void setJid(String jid) {
+		this.jid = jid;
+	}
+	
+	public void setNick(String nick) {
+		this.nick = nick;
+	}
+
+	@Override
+	public int compareTo(ListItem another) {
+		return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+	}
+
+	@Override
+	public String getDisplayName() {
+		if (displayName!=null) {
+			return displayName;
+		} else {
+			return this.jid.split("@")[0];
+		}
+	}
+
+	@Override
+	public String getJid() {
+		return this.jid.toLowerCase(Locale.US);
+	}
+	
+	public String getNick() {
+		return this.nick;
+	}
+	
+	public boolean autojoin() {
+		return autojoin;
+	}
+
+	@Override
+	public String getProfilePhoto() {
+		return null;
+	}
+
+	public boolean match(String needle) {
+		return needle == null
+				|| getJid().contains(needle.toLowerCase(Locale.US))
+				|| getDisplayName().toLowerCase(Locale.US)
+						.contains(needle.toLowerCase(Locale.US));
+	}
+
+	public Account getAccount() {
+		return this.account;
+	}
+}

src/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -64,6 +64,8 @@ public class Conversation extends AbstractEntity {
 
 	private boolean otrSessionNeedsStarting = false;
 
+	private Bookmark bookmark;
+
 	public Conversation(String name, Account account, String contactJid,
 			int mode) {
 		this(java.util.UUID.randomUUID().toString(), name, null, account
@@ -375,4 +377,8 @@ public class Conversation extends AbstractEntity {
 	public byte[] getSymmetricKey() {
 		return this.symmetricKey;
 	}
+
+	public void setBookmark(Bookmark bookmark) {
+		this.bookmark = bookmark;
+	}
 }

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -20,6 +20,7 @@ import net.java.otr4j.session.Session;
 import net.java.otr4j.session.SessionStatus;
 import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
@@ -245,9 +246,13 @@ public class XmppConnectionService extends Service {
 		return message;
 	}
 
-	public Conversation findMuc(String name, Account account) {
+	public Conversation findMuc(Bookmark bookmark) {
+		return findMuc(bookmark.getJid(), bookmark.getAccount());
+	}
+	
+	public Conversation findMuc(String jid, Account account) {
 		for (Conversation conversation : this.conversations) {
-			if (conversation.getContactJid().split("/")[0].equals(name)
+			if (conversation.getContactJid().split("/")[0].equals(jid)
 					&& (conversation.getAccount() == account)) {
 				return conversation;
 			}
@@ -466,6 +471,7 @@ public class XmppConnectionService extends Service {
 				account.getRoster().clearPresences();
 				account.clearPresences(); // self presences
 				fetchRosterFromServer(account);
+				fetchBookmarks(account);
 				sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
 				connectMultiModeConversations(account);
 				updateConversationUi();
@@ -660,6 +666,45 @@ public class XmppConnectionService extends Service {
 					}
 				});
 	}
+	
+	public void fetchBookmarks(Account account) {
+		IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+		Element query = iqPacket.query("jabber:iq:private");
+		query.addChild("storage", "storage:bookmarks");
+		OnIqPacketReceived callback = new OnIqPacketReceived() {
+			
+			@Override
+			public void onIqPacketReceived(Account account, IqPacket packet) {
+				Element query = packet.query();
+				List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+				Element storage = query.findChild("storage", "storage:bookmarks");
+				if (storage!=null) {
+					for(Element item : storage.getChildren()) {
+						if (item.getName().equals("conference")) {
+							Log.d(LOGTAG,item.toString());
+							Bookmark bookmark = Bookmark.parse(item,account);
+							bookmarks.add(bookmark);
+							if (bookmark.autojoin()) {
+								Log.d(LOGTAG,"has autojoin");
+								Conversation conversation = findMuc(bookmark);
+								if (conversation!=null) {
+									Log.d(LOGTAG,"conversation existed. adding bookmark");
+									conversation.setBookmark(bookmark);
+								} else {
+									Log.d(LOGTAG,"creating new conversation");
+									conversation = findOrCreateConversation(account, bookmark.getJid(), true);
+									conversation.setBookmark(bookmark);
+								}
+							}
+						}
+					}
+				}
+				account.setBookmarks(bookmarks);
+			}
+		};
+		sendIqPacket(account, iqPacket, callback);
+		
+	}
 
 	private void mergePhoneContactsWithRoster() {
 		PhoneHelper.loadPhoneContacts(getApplicationContext(),
@@ -1297,6 +1342,10 @@ public class XmppConnectionService extends Service {
 		account.getXmppConnection().sendPresencePacket(packet);
 	}
 	
+	public void sendIqPacket(Account account, IqPacket packet, OnIqPacketReceived callback) {
+		account.getXmppConnection().sendIqPacket(packet, callback);
+	}
+	
 	public MessageGenerator getMessageGenerator() {
 		return this.mMessageGenerator;
 	}

src/eu/siacs/conversations/ui/StartConversation.java 🔗

@@ -37,6 +37,7 @@ import android.widget.Spinner;
 import android.widget.TextView;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.ListItem;
@@ -63,6 +64,9 @@ public class StartConversation extends XmppActivity {
 	private List<String> mKnownConferenceHosts;
 
 	private EditText mSearchEditText;
+	
+	public int conference_context_id;
+	public int contact_context_id;
 
 	private TabListener mTabListener = new TabListener() {
 
@@ -115,7 +119,7 @@ public class StartConversation extends XmppActivity {
 			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
 					InputMethodManager.HIDE_IMPLICIT_ONLY);
 			mSearchEditText.setText("");
-			filterContacts(null);
+			filter(null);
 			return true;
 		}
 	};
@@ -123,7 +127,7 @@ public class StartConversation extends XmppActivity {
 
 		@Override
 		public void afterTextChanged(Editable editable) {
-			filterContacts(editable.toString());
+			filter(editable.toString());
 		}
 
 		@Override
@@ -172,9 +176,19 @@ public class StartConversation extends XmppActivity {
 
 		mConferenceAdapter = new ListItemAdapter(conferences);
 		mConferenceListFragment.setListAdapter(mConferenceAdapter);
+		mConferenceListFragment.setContextMenu(R.menu.conference_context);
+		mConferenceListFragment.setOnListItemClickListener(new OnItemClickListener() {
+
+			@Override
+			public void onItemClick(AdapterView<?> arg0, View arg1,
+					int position, long arg3) {
+				openConversationForBookmark(position);
+			}
+		});
 
 		mContactsAdapter = new ListItemAdapter(contacts);
 		mContactsListFragment.setListAdapter(mContactsAdapter);
+		mContactsListFragment.setContextMenu(R.menu.contact_context);
 		mContactsListFragment
 				.setOnListItemClickListener(new OnItemClickListener() {
 
@@ -192,18 +206,35 @@ public class StartConversation extends XmppActivity {
 		Conversation conversation = xmppConnectionService
 				.findOrCreateConversation(contact.getAccount(),
 						contact.getJid(), false);
-		switchToConversation(conversation, null, false);
+		switchToConversation(conversation);
+	}
+	
+	protected void openConversationForContact() {
+		int position = contact_context_id;
+		openConversationForContact(position);
+	}
+	
+	protected void openConversationForBookmark() {
+		openConversationForBookmark(conference_context_id);
+	}
+	
+	protected void openConversationForBookmark(int position) {
+		Bookmark bookmark = (Bookmark) conferences.get(position);
+		Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), bookmark.getJid(), true);
+		switchToConversation(conversation);
 	}
 
-	protected void openDetailsForContact(int position) {
+	protected void openDetailsForContact() {
+		int position = contact_context_id;
 		Contact contact = (Contact) contacts.get(position);
 		switchToContactDetails(contact);
 	}
 
-	protected void deleteContact(int position) {
+	protected void deleteContact() {
+		int position = contact_context_id;
 		Contact contact = (Contact) contacts.get(position);
 		xmppConnectionService.deleteContactOnServer(contact);
-		filterContacts(mSearchEditText.getText().toString());
+		filter(mSearchEditText.getText().toString());
 	}
 
 	protected void showCreateContactDialog() {
@@ -339,9 +370,9 @@ public class StartConversation extends XmppActivity {
 	@Override
 	void onBackendConnected() {
 		if (mSearchEditText != null) {
-			filterContacts(mSearchEditText.getText().toString());
+			filter(mSearchEditText.getText().toString());
 		} else {
-			filterContacts(null);
+			filter(null);
 		}
 		this.mActivatedAccounts.clear();
 		for (Account account : xmppConnectionService.getAccounts()) {
@@ -353,6 +384,11 @@ public class StartConversation extends XmppActivity {
 		this.mKnownConferenceHosts = xmppConnectionService
 				.getKnownConferenceHosts();
 	}
+	
+	protected void filter(String needle) {
+		this.filterContacts(needle);
+		this.filterConferences(needle);
+	}
 
 	protected void filterContacts(String needle) {
 		this.contacts.clear();
@@ -368,6 +404,21 @@ public class StartConversation extends XmppActivity {
 		Collections.sort(this.contacts);
 		mContactsAdapter.notifyDataSetChanged();
 	}
+	
+	protected void filterConferences(String needle) {
+		this.conferences.clear();
+		for (Account account : xmppConnectionService.getAccounts()) {
+			if (account.getStatus() != Account.STATUS_DISABLED) {
+				for(Bookmark bookmark : account.getBookmarks()) {
+					if (bookmark.match(needle)) {
+						this.conferences.add(bookmark);
+					}
+				}
+			}
+		}
+		Collections.sort(this.conferences);
+		mConferenceAdapter.notifyDataSetChanged();
+	}
 
 	private void onTabChanged() {
 		invalidateOptionsMenu();
@@ -403,7 +454,11 @@ public class StartConversation extends XmppActivity {
 
 	public static class MyListFragment extends ListFragment {
 		private AdapterView.OnItemClickListener mOnItemClickListener;
-		private int mContextPosition = -1;
+		private int mResContextMenu;
+		
+		public void setContextMenu(int res) {
+			this.mResContextMenu = res;
+		}
 
 		@Override
 		public void onListItemClick(ListView l, View v, int position, long id) {
@@ -426,10 +481,15 @@ public class StartConversation extends XmppActivity {
 		public void onCreateContextMenu(ContextMenu menu, View v,
 				ContextMenuInfo menuInfo) {
 			super.onCreateContextMenu(menu, v, menuInfo);
-			getActivity().getMenuInflater().inflate(R.menu.contact_context,
+			StartConversation activity = (StartConversation) getActivity();
+			activity.getMenuInflater().inflate(mResContextMenu,
 					menu);
 			AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
-			this.mContextPosition = acmi.position;
+			if (mResContextMenu == R.menu.conference_context) {
+				activity.conference_context_id = acmi.position;
+			} else {
+				activity.contact_context_id = acmi.position;
+			}
 		}
 
 		@Override
@@ -437,13 +497,16 @@ public class StartConversation extends XmppActivity {
 			StartConversation activity = (StartConversation) getActivity();
 			switch (item.getItemId()) {
 			case R.id.context_start_conversation:
-				activity.openConversationForContact(mContextPosition);
+				activity.openConversationForContact();
 				break;
 			case R.id.context_contact_details:
-				activity.openDetailsForContact(mContextPosition);
+				activity.openDetailsForContact();
 				break;
 			case R.id.context_delete_contact:
-				activity.deleteContact(mContextPosition);
+				activity.deleteContact();
+				break;
+			case R.id.context_join_conference:
+				activity.openConversationForBookmark();
 				break;
 			}
 			return true;