join mucs upon bookmark retrival
This commit is contained in:
parent
21831e4340
commit
db6eb55b7d
11 changed files with 228 additions and 15 deletions
|
@ -5,19 +5,25 @@ import androidx.room.Dao;
|
|||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Transaction;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import im.conversations.android.database.entity.ChatEntity;
|
||||
import im.conversations.android.database.model.Account;
|
||||
import im.conversations.android.database.model.ChatIdentifier;
|
||||
import im.conversations.android.database.model.ChatType;
|
||||
import im.conversations.android.database.model.GroupIdentifier;
|
||||
import im.conversations.android.database.model.MucWithNick;
|
||||
import im.conversations.android.xmpp.model.stanza.Message;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Dao
|
||||
public abstract class ChatDao {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ChatDao.class);
|
||||
|
||||
@Transaction
|
||||
public ChatIdentifier getOrCreateChat(
|
||||
final Account account,
|
||||
|
@ -56,6 +62,76 @@ public abstract class ChatDao {
|
|||
@Insert
|
||||
protected abstract long insert(ChatEntity chatEntity);
|
||||
|
||||
@Query("UPDATE chat SET archived=:archived WHERE chat.id=:chatId")
|
||||
public abstract void setArchived(final long chatId, final boolean archived);
|
||||
|
||||
@Query(
|
||||
"UPDATE chat SET archived=:archived WHERE chat.accountId=:account AND"
|
||||
+ " chat.address=:address")
|
||||
protected abstract void setArchived(
|
||||
final long account, final String address, final boolean archived);
|
||||
|
||||
@Query("SELECT id,name FROM `group` ORDER BY name")
|
||||
public abstract LiveData<List<GroupIdentifier>> getGroups();
|
||||
|
||||
@Transaction
|
||||
public void syncWithBookmarks(final Account account) {
|
||||
final var chatsNotInBookmarks = getChatsNotInBookmarks(account.id, ChatType.MUC);
|
||||
final var bookmarksNotInChat = getBookmarksNotInChats(account.id, ChatType.MUC);
|
||||
LOGGER.info("chatsNotInBookmark {}", chatsNotInBookmarks);
|
||||
LOGGER.info("bookmarkNotInChat {}", bookmarksNotInChat);
|
||||
archive(account.id, chatsNotInBookmarks);
|
||||
createOrUnarchiveMuc(account.id, bookmarksNotInChat);
|
||||
}
|
||||
|
||||
private void archive(final long account, final List<String> addresses) {
|
||||
for (final String address : addresses) {
|
||||
setArchived(account, address, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void createOrUnarchiveMuc(final long account, final List<Jid> addresses) {
|
||||
for (final Jid address : addresses) {
|
||||
createOrUnarchiveMuc(account, address);
|
||||
}
|
||||
}
|
||||
|
||||
private void createOrUnarchiveMuc(final long account, final Jid address) {
|
||||
final var bareJid = address.asBareJid();
|
||||
final var existing = get(account, bareJid);
|
||||
if (existing != null) {
|
||||
if (existing.archived) {
|
||||
setArchived(existing.id, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
final var entity = new ChatEntity();
|
||||
entity.accountId = account;
|
||||
entity.address = bareJid.toString();
|
||||
entity.type = ChatType.MUC;
|
||||
entity.archived = false;
|
||||
insert(entity);
|
||||
}
|
||||
|
||||
@Query(
|
||||
"SELECT chat.address FROM chat WHERE chat.accountId=:account AND chat.type=:chatType"
|
||||
+ " AND archived=0 EXCEPT SELECT bookmark.address FROM bookmark WHERE"
|
||||
+ " bookmark.accountId=:account AND bookmark.autoJoin=1")
|
||||
protected abstract List<String> getChatsNotInBookmarks(long account, ChatType chatType);
|
||||
|
||||
@Query(
|
||||
"SELECT bookmark.address FROM bookmark WHERE bookmark.accountId=accountId AND"
|
||||
+ " bookmark.autoJoin=1 EXCEPT SELECT chat.address FROM chat WHERE"
|
||||
+ " chat.accountId=:account AND chat.type=:chatType AND archived=0")
|
||||
protected abstract List<Jid> getBookmarksNotInChats(long account, ChatType chatType);
|
||||
|
||||
// TODO get pending only
|
||||
@Query(
|
||||
"SELECT chat.address,bookmark.nick as nickBookmark,nick.nick as nickAccount FROM chat"
|
||||
+ " LEFT JOIN bookmark ON chat.accountId=bookmark.accountId AND"
|
||||
+ " chat.address=bookmark.address JOIN account ON account.id=chat.accountId LEFT"
|
||||
+ " JOIN nick ON nick.accountId=chat.accountId AND nick.address=account.address"
|
||||
+ " WHERE chat.accountId=:account AND chat.type=:chatType AND chat.archived=0")
|
||||
public abstract ListenableFuture<List<MucWithNick>> getMultiUserChats(
|
||||
final long account, final ChatType chatType);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import androidx.room.Entity;
|
|||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import com.google.common.base.Strings;
|
||||
import im.conversations.android.xmpp.model.bookmark.Conference;
|
||||
import im.conversations.android.xmpp.model.bookmark.Nick;
|
||||
import java.util.Map;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
@ -47,11 +49,13 @@ public class BookmarkEntity {
|
|||
if (address == null) {
|
||||
return null;
|
||||
}
|
||||
final Nick nick = conference.getNick();
|
||||
final var entity = new BookmarkEntity();
|
||||
entity.accountId = accountId;
|
||||
entity.address = address;
|
||||
entity.autoJoin = conference.isAutoJoin();
|
||||
entity.name = conference.getConferenceName();
|
||||
entity.nick = Strings.emptyToNull(nick == null ? null : nick.getContent());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.annotation.NonNull;
|
|||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.primitives.Ints;
|
||||
import im.conversations.android.IDs;
|
||||
|
@ -11,6 +12,7 @@ import java.io.IOException;
|
|||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
|
||||
public class Account extends AccountIdentifier {
|
||||
|
||||
|
@ -59,4 +61,23 @@ public class Account extends AccountIdentifier {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Resourcepart fallbackNick() {
|
||||
final var localPart = address.getLocalpartOrNull();
|
||||
if (localPart != null) {
|
||||
final var resourceFromLocalPart = Resourcepart.fromOrNull(localPart.toString());
|
||||
if (resourceFromLocalPart != null) {
|
||||
return resourceFromLocalPart;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return Resourcepart.fromOrThrowUnchecked(
|
||||
BaseEncoding.base32Hex()
|
||||
.lowerCase()
|
||||
.omitPadding()
|
||||
.encode(ByteSource.wrap(randomSeed).slice(0, 6).read()));
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package im.conversations.android.database.model;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
|
||||
public class MucWithNick {
|
||||
|
||||
public final BareJid address;
|
||||
private final String nickBookmark;
|
||||
private final String nickAccount;
|
||||
|
||||
public MucWithNick(BareJid address, String nickBookmark, String nickAccount) {
|
||||
this.address = address;
|
||||
this.nickBookmark = nickBookmark;
|
||||
this.nickAccount = nickAccount;
|
||||
}
|
||||
|
||||
public Resourcepart nick() {
|
||||
final var bookmark = nickBookmark == null ? null : Resourcepart.fromOrNull(nickBookmark);
|
||||
final var account = nickAccount == null ? null : Resourcepart.fromOrNull(nickAccount);
|
||||
return bookmark != null ? bookmark : account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("address", address)
|
||||
.add("nickBookmark", nickBookmark)
|
||||
.add("nickAccount", nickAccount)
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import im.conversations.android.xml.Namespace;
|
|||
import im.conversations.android.xmpp.NodeConfiguration;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.bookmark.Conference;
|
||||
import im.conversations.android.xmpp.model.bookmark.Nick;
|
||||
import im.conversations.android.xmpp.model.pubsub.Items;
|
||||
import im.conversations.android.xmpp.model.pubsub.event.Retract;
|
||||
import java.util.Collection;
|
||||
|
@ -36,7 +37,7 @@ public class BookmarkManager extends AbstractManager {
|
|||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(final Map<String, Conference> bookmarks) {
|
||||
getDatabase().bookmarkDao().setItems(getAccount(), bookmarks);
|
||||
setBookmarks(bookmarks);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,6 +48,17 @@ public class BookmarkManager extends AbstractManager {
|
|||
MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private void setBookmarks(final Map<String, Conference> bookmarks) {
|
||||
final var database = getDatabase();
|
||||
final var account = getAccount();
|
||||
database.runInTransaction(
|
||||
() -> {
|
||||
database.bookmarkDao().setItems(account, bookmarks);
|
||||
database.chatDao().syncWithBookmarks(account);
|
||||
});
|
||||
getManager(MultiUserChatManager.class).joinMultiUserChats();
|
||||
}
|
||||
|
||||
private void updateItems(final Map<String, Conference> items) {
|
||||
getDatabase().bookmarkDao().updateItems(getAccount(), items);
|
||||
}
|
||||
|
@ -74,9 +86,18 @@ public class BookmarkManager extends AbstractManager {
|
|||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<Void> publishBookmark(final Jid address) {
|
||||
public ListenableFuture<Void> publishBookmark(final Jid address, final boolean autoJoin) {
|
||||
return publishBookmark(address, autoJoin, null);
|
||||
}
|
||||
|
||||
public ListenableFuture<Void> publishBookmark(
|
||||
final Jid address, final boolean autoJoin, final String nick) {
|
||||
final var itemId = address.toString();
|
||||
final var conference = new Conference();
|
||||
conference.setAutoJoin(autoJoin);
|
||||
if (nick != null) {
|
||||
conference.addExtension(new Nick()).setContent(nick);
|
||||
}
|
||||
return Futures.transform(
|
||||
getManager(PepManager.class)
|
||||
.publish(conference, itemId, NodeConfiguration.WHITELIST_MAX_ITEMS),
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.google.common.base.Preconditions;
|
|||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import im.conversations.android.database.model.ChatType;
|
||||
import im.conversations.android.database.model.MucWithNick;
|
||||
import im.conversations.android.xmpp.Entity;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||
|
@ -13,9 +15,9 @@ import im.conversations.android.xmpp.model.muc.History;
|
|||
import im.conversations.android.xmpp.model.muc.MultiUserChat;
|
||||
import im.conversations.android.xmpp.model.muc.user.MucUser;
|
||||
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import java.util.List;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.jid.parts.Resourcepart;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -27,15 +29,36 @@ public class MultiUserChatManager extends AbstractManager {
|
|||
super(context, connection);
|
||||
}
|
||||
|
||||
public void enter(final BareJid room) {
|
||||
final var discoInfoFuture = getManager(DiscoManager.class).info(Entity.discoItem(room));
|
||||
public void joinMultiUserChats() {
|
||||
final var future = getDatabase().chatDao().getMultiUserChats(getAccount().id, ChatType.MUC);
|
||||
Futures.addCallback(
|
||||
future,
|
||||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(List<MucWithNick> result) {
|
||||
for (final MucWithNick mucWithNick : result) {
|
||||
enter(mucWithNick);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
LOGGER.info("Could not query db", t);
|
||||
}
|
||||
},
|
||||
MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
public void enter(final MucWithNick mucWithNick) {
|
||||
final var discoInfoFuture =
|
||||
getManager(DiscoManager.class).info(Entity.discoItem(mucWithNick.address));
|
||||
// TODO catching
|
||||
Futures.addCallback(
|
||||
discoInfoFuture,
|
||||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(final InfoQuery result) {
|
||||
enter(room, result);
|
||||
enter(mucWithNick, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,10 +69,16 @@ public class MultiUserChatManager extends AbstractManager {
|
|||
MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
public void enter(final BareJid room, final InfoQuery infoQuery) {
|
||||
// TODO look up bookmark, then nick then user local part
|
||||
public void enter(final MucWithNick mucWithNick, final InfoQuery infoQuery) {
|
||||
final var nick = mucWithNick.nick();
|
||||
final Jid to;
|
||||
if (nick != null) {
|
||||
to = JidCreate.fullFrom(mucWithNick.address, nick);
|
||||
} else {
|
||||
to = JidCreate.fullFrom(mucWithNick.address, getAccount().fallbackNick());
|
||||
}
|
||||
final var presence = new Presence();
|
||||
presence.setTo(JidCreate.fullFrom(room, Resourcepart.fromOrThrowUnchecked("c3-test-user")));
|
||||
presence.setTo(to);
|
||||
final var muc = presence.addExtension(new MultiUserChat());
|
||||
final var history = muc.addExtension(new History());
|
||||
history.setMaxChars(0);
|
||||
|
|
|
@ -2,6 +2,8 @@ package im.conversations.android.xmpp.manager;
|
|||
|
||||
import android.content.Context;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import im.conversations.android.xmpp.NodeConfiguration;
|
||||
import im.conversations.android.xmpp.XmppConnection;
|
||||
import im.conversations.android.xmpp.model.nick.Nick;
|
||||
import im.conversations.android.xmpp.model.pubsub.Items;
|
||||
|
@ -25,4 +27,10 @@ public class NickManager extends AbstractManager {
|
|||
}
|
||||
getDatabase().nickDao().set(getAccount(), from.asBareJid(), nick);
|
||||
}
|
||||
|
||||
public ListenableFuture<Void> publishNick(final String name) {
|
||||
final Nick nick = new Nick();
|
||||
nick.setContent(name);
|
||||
return getManager(PepManager.class).publishSingleton(nick, NodeConfiguration.PRESENCE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,11 @@ public class PepManager extends AbstractManager {
|
|||
return pubSubManager().publishSingleton(pepService(), item, node, nodeConfiguration);
|
||||
}
|
||||
|
||||
public ListenableFuture<Void> publishSingleton(
|
||||
final Extension item, final NodeConfiguration nodeConfiguration) {
|
||||
return pubSubManager().publishSingleton(pepService(), item, nodeConfiguration);
|
||||
}
|
||||
|
||||
public ListenableFuture<Iq> retract(final String itemId, final String node) {
|
||||
return pubSubManager().retract(pepService(), itemId, node);
|
||||
}
|
||||
|
|
|
@ -17,4 +17,12 @@ public class Conference extends Extension {
|
|||
public String getConferenceName() {
|
||||
return this.getAttribute("name");
|
||||
}
|
||||
|
||||
public void setAutoJoin(boolean autoJoin) {
|
||||
setAttribute("autojoin", autoJoin);
|
||||
}
|
||||
|
||||
public Nick getNick() {
|
||||
return this.getExtension(Nick.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package im.conversations.android.xmpp.model.bookmark;
|
||||
|
||||
import im.conversations.android.annotation.XmlElement;
|
||||
import im.conversations.android.xmpp.model.Extension;
|
||||
|
||||
@XmlElement
|
||||
public class Nick extends Extension {
|
||||
|
||||
public Nick() {
|
||||
super(Nick.class);
|
||||
}
|
||||
}
|
|
@ -8,12 +8,10 @@ import im.conversations.android.xmpp.manager.AxolotlManager;
|
|||
import im.conversations.android.xmpp.manager.BlockingManager;
|
||||
import im.conversations.android.xmpp.manager.BookmarkManager;
|
||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||
import im.conversations.android.xmpp.manager.MultiUserChatManager;
|
||||
import im.conversations.android.xmpp.manager.PresenceManager;
|
||||
import im.conversations.android.xmpp.manager.RosterManager;
|
||||
import java.util.function.Consumer;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -30,6 +28,7 @@ public class BindProcessor extends XmppConnection.Delegate implements Consumer<J
|
|||
final var account = getAccount();
|
||||
final var database = getDatabase();
|
||||
|
||||
// TODO reset errorCondition; mucState in chats
|
||||
database.presenceDao().deletePresences(account.id);
|
||||
|
||||
getManager(RosterManager.class).fetch();
|
||||
|
@ -50,8 +49,5 @@ public class BindProcessor extends XmppConnection.Delegate implements Consumer<J
|
|||
getManager(AxolotlManager.class).publishIfNecessary();
|
||||
|
||||
getManager(PresenceManager.class).sendPresence();
|
||||
|
||||
getManager(MultiUserChatManager.class)
|
||||
.enter(JidCreate.bareFromOrThrowUnchecked("xsf@muc.xmpp.org"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue