Partially fix build

This commit is contained in:
Niels Andriesse 2019-10-15 13:39:17 +11:00
parent 2f18c5bad2
commit a8c4fa22a3
16 changed files with 94 additions and 98 deletions

View File

@ -87,8 +87,8 @@ import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol; import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.api.LokiLongPoller; import org.whispersystems.signalservice.loki.api.LokiLongPoller;
import org.whispersystems.signalservice.loki.api.LokiP2PAPI; import org.whispersystems.signalservice.loki.api.LokiP2PAPI;
import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate; import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate;
@ -138,7 +138,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private LokiRSSFeedPoller lokiNewsFeedPoller = null; private LokiRSSFeedPoller lokiNewsFeedPoller = null;
private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null; private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null;
private LokiPublicChatManager lokiPublicChatManager = null; private LokiPublicChatManager lokiPublicChatManager = null;
private LokiGroupChatAPI lokiGroupChatAPI = null; private LokiPublicChatAPI lokiPublicChatAPI = null;
public SignalCommunicationModule communicationModule; public SignalCommunicationModule communicationModule;
public MixpanelAPI mixpanel; public MixpanelAPI mixpanel;
@ -253,16 +253,16 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
return lokiPublicChatManager; return lokiPublicChatManager;
} }
public @Nullable LokiGroupChatAPI getLokiGroupChatAPI() { public @Nullable LokiPublicChatAPI getLokiPublicChatAPI() {
if (lokiGroupChatAPI == null && IdentityKeyUtil.hasIdentityKey(this)) { if (lokiPublicChatAPI == null && IdentityKeyUtil.hasIdentityKey(this)) {
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this); String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this);
byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize();
LokiAPIDatabase apiDatabase = DatabaseFactory.getLokiAPIDatabase(this); LokiAPIDatabase apiDatabase = DatabaseFactory.getLokiAPIDatabase(this);
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this); LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this);
lokiGroupChatAPI = new LokiGroupChatAPI(userHexEncodedPublicKey, userPrivateKey, apiDatabase, userDatabase); lokiPublicChatAPI = new LokiPublicChatAPI(userHexEncodedPublicKey, userPrivateKey, apiDatabase, userDatabase);
} }
return lokiGroupChatAPI; return lokiPublicChatAPI;
} }
private void initializeSecurityProvider() { private void initializeSecurityProvider() {
@ -502,8 +502,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
} }
public void createGroupChatsIfNeeded() { public void createGroupChatsIfNeeded() {
List<LokiGroupChat> defaultChats = LokiGroupChat.Companion.defaultChats(BuildConfig.DEBUG); List<LokiPublicChat> defaultChats = LokiPublicChat.Companion.defaultChats(BuildConfig.DEBUG);
for (LokiGroupChat chat : defaultChats) { for (LokiPublicChat chat : defaultChats) {
long threadID = GroupManager.getThreadId(chat.getId(), this); long threadID = GroupManager.getThreadId(chat.getId(), this);
String migrationKey = chat.getId() + "_migrated"; String migrationKey = chat.getId() + "_migrated";
boolean isChatMigrated = TextSecurePreferences.getBooleanPreference(this, migrationKey, false); boolean isChatMigrated = TextSecurePreferences.getBooleanPreference(this, migrationKey, false);

View File

@ -61,8 +61,8 @@ import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.crypto.ProfileCipher; import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import org.whispersystems.signalservice.loki.utilities.Analytics; import org.whispersystems.signalservice.loki.utilities.Analytics;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -383,7 +383,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
Analytics.Companion.getShared().track("Display Name Updated"); Analytics.Companion.getShared().track("Display Name Updated");
TextSecurePreferences.setProfileName(context, name); TextSecurePreferences.setProfileName(context, name);
LokiGroupChatAPI chatAPI = ApplicationContext.getInstance(context).getLokiGroupChatAPI(); LokiPublicChatAPI chatAPI = ApplicationContext.getInstance(context).getLokiPublicChatAPI();
if (chatAPI != null) { if (chatAPI != null) {
Set<String> groupChatServers = DatabaseFactory.getLokiThreadDatabase(context).getAllGroupChatServers(); Set<String> groupChatServers = DatabaseFactory.getLokiThreadDatabase(context).getAllGroupChatServers();
for (String server : groupChatServers) { for (String server : groupChatServers) {

View File

@ -32,8 +32,8 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import java.util.List; import java.util.List;
@ -200,7 +200,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
// If we're in a group then try and use the display name in the group // If we're in a group then try and use the display name in the group
if (conversationRecipient.isGroupRecipient()) { if (conversationRecipient.isGroupRecipient()) {
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(conversationRecipient); long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(conversationRecipient);
LokiGroupChat chat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId); LokiPublicChat chat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId);
if (chat != null) { if (chat != null) {
String senderDisplayName = DatabaseFactory.getLokiUserDatabase(getContext()).getServerDisplayName(chat.getId(), author.getAddress().serialize()); String senderDisplayName = DatabaseFactory.getLokiUserDatabase(getContext()).getServerDisplayName(chat.getId(), author.getAddress().serialize());
if (senderDisplayName != null) { quoteeDisplayName = senderDisplayName; } if (senderDisplayName != null) { quoteeDisplayName = senderDisplayName; }

View File

@ -106,8 +106,8 @@ import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.internal.util.concurrent.SettableFuture; import org.whispersystems.signalservice.internal.util.concurrent.SettableFuture;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -410,14 +410,14 @@ public class ConversationFragment extends Fragment
boolean isGroupChat = recipient.isGroupRecipient(); boolean isGroupChat = recipient.isGroupRecipient();
if (isGroupChat) { if (isGroupChat) {
LokiGroupChat groupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId); LokiPublicChat groupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId);
boolean isPublicChat = groupChat != null; boolean isPublicChat = groupChat != null;
int selectedMessageCount = messageRecords.size(); int selectedMessageCount = messageRecords.size();
boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing(); boolean isSentByUser = ((MessageRecord)messageRecords.toArray()[0]).isOutgoing();
menu.findItem(R.id.menu_context_copy_public_key).setVisible(isPublicChat && selectedMessageCount == 1 && !isSentByUser); menu.findItem(R.id.menu_context_copy_public_key).setVisible(isPublicChat && selectedMessageCount == 1 && !isSentByUser);
menu.findItem(R.id.menu_context_reply).setVisible(isPublicChat && selectedMessageCount == 1); menu.findItem(R.id.menu_context_reply).setVisible(isPublicChat && selectedMessageCount == 1);
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext()); String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext());
boolean userCanModerate = groupChat != null && LokiGroupChatAPI.Companion.isUserModerator(userHexEncodedPublicKey, groupChat.getChannel(), groupChat.getServer()); boolean userCanModerate = groupChat != null && LokiPublicChatAPI.Companion.isUserModerator(userHexEncodedPublicKey, groupChat.getChannel(), groupChat.getServer());
boolean isDeleteOptionVisible = isPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate); boolean isDeleteOptionVisible = isPublicChat && selectedMessageCount == 1 && (isSentByUser || userCanModerate);
menu.findItem(R.id.menu_context_delete_message).setVisible(isDeleteOptionVisible); menu.findItem(R.id.menu_context_delete_message).setVisible(isDeleteOptionVisible);
} else { } else {
@ -513,7 +513,7 @@ public class ConversationFragment extends Fragment
builder.setCancelable(true); builder.setCancelable(true);
// Loki - The delete option is only visible to the user in a group chat // Loki - The delete option is only visible to the user in a group chat
LokiGroupChat groupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId); LokiPublicChat groupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getGroupChat(threadId);
builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
@Override @Override
@ -530,7 +530,7 @@ public class ConversationFragment extends Fragment
if (groupChat != null) { if (groupChat != null) {
final SettableFuture<?>[] future = { new SettableFuture<Unit>() }; final SettableFuture<?>[] future = { new SettableFuture<Unit>() };
LokiGroupChatAPI chatAPI = ApplicationContext.getInstance(getContext()).getLokiGroupChatAPI(); LokiPublicChatAPI chatAPI = ApplicationContext.getInstance(getContext()).getLokiPublicChatAPI();
boolean isSentByUser = messageRecord.isOutgoing(); boolean isSentByUser = messageRecord.isOutgoing();
Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id); Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id);

View File

@ -114,8 +114,8 @@ import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.Stub; import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@ -941,9 +941,9 @@ public class ConversationItem extends LinearLayout
int visibility = View.GONE; int visibility = View.GONE;
// If we have a chat then use that to determine mod status // If we have a chat then use that to determine mod status
LokiGroupChat groupChat = DatabaseFactory.getLokiThreadDatabase(context).getGroupChat(messageRecord.getThreadId()); LokiPublicChat groupChat = DatabaseFactory.getLokiThreadDatabase(context).getGroupChat(messageRecord.getThreadId());
if (groupChat != null) { if (groupChat != null) {
boolean isModerator = LokiGroupChatAPI.Companion.isUserModerator(current.getRecipient().getAddress().toString(), groupChat.getChannel(), groupChat.getServer()); boolean isModerator = LokiPublicChatAPI.Companion.isUserModerator(current.getRecipient().getAddress().toString(), groupChat.getChannel(), groupChat.getServer());
visibility = isModerator ? View.VISIBLE : View.GONE; visibility = isModerator ? View.VISIBLE : View.GONE;
} }

View File

@ -45,8 +45,8 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import org.whispersystems.signalservice.loki.api.LokiGroupChat; import org.whispersystems.signalservice.loki.api.LokiPublicChat;
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI; import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -290,7 +290,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
// Loki - All group messages should be directed to their servers // Loki - All group messages should be directed to their servers
long threadID = GroupManager.getThreadIdFromGroupId(groupId, context); long threadID = GroupManager.getThreadIdFromGroupId(groupId, context);
LokiGroupChat chat = DatabaseFactory.getLokiThreadDatabase(context).getGroupChat(threadID); LokiPublicChat chat = DatabaseFactory.getLokiThreadDatabase(context).getGroupChat(threadID);
if (chat != null) { if (chat != null) {
// We need to somehow maintain information that will allow the sender to map // We need to somehow maintain information that will allow the sender to map
// a Recipient to the correct public chat thread, and so this might be a bit hacky // a Recipient to the correct public chat thread, and so this might be a bit hacky

View File

@ -1,13 +1,10 @@
package org.thoughtcrime.securesms.loki package org.thoughtcrime.securesms.loki
import android.Manifest
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Patterns import android.util.Patterns
import android.view.MenuItem import android.view.MenuItem
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Toast import android.widget.Toast
import kotlinx.android.synthetic.main.activity_account_details.*
import kotlinx.android.synthetic.main.fragment_add_public_chat.* import kotlinx.android.synthetic.main.fragment_add_public_chat.*
import network.loki.messenger.R import network.loki.messenger.R
import nl.komponents.kovenant.ui.failUi import nl.komponents.kovenant.ui.failUi
@ -15,16 +12,7 @@ import nl.komponents.kovenant.ui.successUi
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.conversation.ConversationActivity
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.DynamicTheme import org.thoughtcrime.securesms.util.DynamicTheme
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import org.whispersystems.signalservice.loki.utilities.Analytics
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class AddPublicChatActivity : PassphraseRequiredActionBarActivity() { class AddPublicChatActivity : PassphraseRequiredActionBarActivity() {
private val dynamicTheme = DynamicTheme() private val dynamicTheme = DynamicTheme()

View File

@ -8,11 +8,9 @@ import network.loki.messenger.R
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.ConversationListActivity import org.thoughtcrime.securesms.ConversationListActivity
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.crypto.ProfileCipher import org.whispersystems.signalservice.api.crypto.ProfileCipher
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import org.whispersystems.signalservice.loki.utilities.Analytics import org.whispersystems.signalservice.loki.utilities.Analytics
class DisplayNameActivity : BaseActionBarActivity() { class DisplayNameActivity : BaseActionBarActivity() {
@ -46,9 +44,9 @@ class DisplayNameActivity : BaseActionBarActivity() {
startActivity(Intent(this, ConversationListActivity::class.java)) startActivity(Intent(this, ConversationListActivity::class.java))
finish() finish()
val chatAPI = ApplicationContext.getInstance(this).lokiGroupChatAPI val chatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI
if (chatAPI != null && name != null) { if (chatAPI != null && name != null) {
val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllGroupChatServers() val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers()
servers.forEach { chatAPI.setDisplayName(name, it) } servers.forEach { chatAPI.setDisplayName(name, it) }
} }
} }

View File

@ -7,7 +7,6 @@ import android.support.annotation.ColorRes
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -25,7 +24,7 @@ fun toPx(dp: Int, resources: Resources): Int {
} }
fun isGroupRecipient(context: Context, recipient: String): Boolean { fun isGroupRecipient(context: Context, recipient: String): Boolean {
return DatabaseFactory.getLokiThreadDatabase(context).getAllGroupChats().values.map { it.server }.contains(recipient) return DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().values.map { it.server }.contains(recipient)
} }
fun getFriendPublicKeys(context: Context, devicePublicKeys: Set<String>): Set<String> { fun getFriendPublicKeys(context: Context, devicePublicKeys: Set<String>): Set<String> {

View File

@ -9,7 +9,7 @@ import org.whispersystems.signalservice.loki.api.LokiAPI
object LokiAPIUtilities { object LokiAPIUtilities {
fun populateUserIDCacheIfNeeded(threadID: Long, context: Context) { fun populateUserIDCacheIfNeeded(threadID: Long, context: Context) {
if (LokiAPI.userIDCache[threadID] != null) { return } if (LokiAPI.userHexEncodedPublicKeyCache[threadID] != null) { return }
val result = mutableSetOf<String>() val result = mutableSetOf<String>()
val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context) val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context)
val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID)) val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID))
@ -24,6 +24,6 @@ object LokiAPIUtilities {
} }
reader.close() reader.close()
result.add(TextSecurePreferences.getLocalNumber(context)) result.add(TextSecurePreferences.getLocalNumber(context))
LokiAPI.userIDCache[threadID] = result LokiAPI.userHexEncodedPublicKeyCache[threadID] = result
} }
} }

View File

@ -7,20 +7,17 @@ import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.functional.map import nl.komponents.kovenant.functional.map
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.DatabaseContentProviders import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.groups.GroupManager
import org.thoughtcrime.securesms.util.GroupUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.Util import org.thoughtcrime.securesms.util.Util
import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import java.util.*
import java.util.HashSet
class LokiPublicChatManager(private val context: Context) { class LokiPublicChatManager(private val context: Context) {
private var chats = mutableMapOf<Long, LokiGroupChat>() private var chats = mutableMapOf<Long, LokiPublicChat>()
private val pollers = mutableMapOf<Long, LokiGroupChatPoller>() private val pollers = mutableMapOf<Long, LokiPublicChatPoller>()
private val observers = mutableMapOf<Long, ContentObserver>() private val observers = mutableMapOf<Long, ContentObserver>()
private var isPolling = false private var isPolling = false
@ -28,7 +25,7 @@ class LokiPublicChatManager(private val context: Context) {
refreshChatsAndPollers() refreshChatsAndPollers()
for ((threadId, chat) in chats) { for ((threadId, chat) in chats) {
val poller = pollers[threadId] ?: LokiGroupChatPoller(context, chat) val poller = pollers[threadId] ?: LokiPublicChatPoller(context, chat)
poller.startIfNeeded() poller.startIfNeeded()
listenToThreadDeletion(threadId) listenToThreadDeletion(threadId)
if (!pollers.containsKey(threadId)) { pollers[threadId] = poller } if (!pollers.containsKey(threadId)) { pollers[threadId] = poller }
@ -41,8 +38,8 @@ class LokiPublicChatManager(private val context: Context) {
isPolling = false isPolling = false
} }
public fun addChat(server: String, channel: Long): Promise<LokiGroupChat, Exception> { public fun addChat(server: String, channel: Long): Promise<LokiPublicChat, Exception> {
val groupChatAPI = ApplicationContext.getInstance(context).lokiGroupChatAPI ?: return Promise.ofFail(IllegalStateException("LokiGroupChatAPI is not set!")) val groupChatAPI = ApplicationContext.getInstance(context).lokiPublicChatAPI ?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!"))
return groupChatAPI.getAuthToken(server).bind { return groupChatAPI.getAuthToken(server).bind {
groupChatAPI.getChannelInfo(channel, server) groupChatAPI.getChannelInfo(channel, server)
}.map { }.map {
@ -50,19 +47,19 @@ class LokiPublicChatManager(private val context: Context) {
} }
} }
public fun addChat(server: String, channel: Long, name: String): LokiGroupChat { public fun addChat(server: String, channel: Long, name: String): LokiPublicChat {
val chat = LokiGroupChat(channel, server, name, true) val chat = LokiPublicChat(channel, server, name, true)
var threadID = GroupManager.getThreadId(chat.id, context) var threadID = GroupManager.getThreadId(chat.id, context)
// Create the group if we don't have one // Create the group if we don't have one
if (threadID < 0) { if (threadID < 0) {
val result = GroupManager.createGroup(chat.id, context, HashSet(), null, chat.displayName, false) val result = GroupManager.createGroup(chat.id, context, HashSet(), null, chat.displayName, false)
threadID = result.threadId threadID = result.threadId
} }
DatabaseFactory.getLokiThreadDatabase(context).setGroupChat(chat, threadID) DatabaseFactory.getLokiThreadDatabase(context).setPublicChat(chat, threadID)
// Set our name on the server // Set our name on the server
val displayName = TextSecurePreferences.getProfileName(context) val displayName = TextSecurePreferences.getProfileName(context)
if (!TextUtils.isEmpty(displayName)) { if (!TextUtils.isEmpty(displayName)) {
ApplicationContext.getInstance(context).lokiGroupChatAPI?.setDisplayName(server, displayName) ApplicationContext.getInstance(context).lokiPublicChatAPI?.setDisplayName(server, displayName)
} }
// Start polling // Start polling
Util.runOnMain{ startPollersIfNeeded() } Util.runOnMain{ startPollersIfNeeded() }
@ -71,7 +68,7 @@ class LokiPublicChatManager(private val context: Context) {
} }
private fun refreshChatsAndPollers() { private fun refreshChatsAndPollers() {
val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllGroupChats() val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats()
val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) } val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }
removedChatThreadIds.forEach { pollers.remove(it)?.stop() } removedChatThreadIds.forEach { pollers.remove(it)?.stop() }
@ -91,7 +88,7 @@ class LokiPublicChatManager(private val context: Context) {
apiDatabase.removeLastMessageServerID(chat.channel, chat.server) apiDatabase.removeLastMessageServerID(chat.channel, chat.server)
} }
DatabaseFactory.getLokiThreadDatabase(context).removeGroupChat(threadID) DatabaseFactory.getLokiThreadDatabase(context).removePublicChat(threadID)
pollers.remove(threadID)?.stop() pollers.remove(threadID)?.stop()
observers.remove(threadID) observers.remove(threadID)
startPollersIfNeeded() startPollersIfNeeded()

View File

@ -21,23 +21,23 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.messages.SignalServiceGroup
import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignalServiceAddress
import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI
import org.whispersystems.signalservice.loki.api.LokiGroupMessage import org.whispersystems.signalservice.loki.api.LokiPublicChatMessage
class LokiGroupChatPoller(private val context: Context, private val group: LokiGroupChat) { class LokiPublicChatPoller(private val context: Context, private val group: LokiPublicChat) {
private val handler = Handler() private val handler = Handler()
private var hasStarted = false private var hasStarted = false
// region Convenience // region Convenience
private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
private val api: LokiGroupChatAPI private val api: LokiPublicChatAPI
get() = { get() = {
val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize()
val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context)
val lokiUserDatabase = DatabaseFactory.getLokiUserDatabase(context) val lokiUserDatabase = DatabaseFactory.getLokiUserDatabase(context)
LokiGroupChatAPI(userHexEncodedPublicKey, userPrivateKey, lokiAPIDatabase, lokiUserDatabase) LokiPublicChatAPI(userHexEncodedPublicKey, userPrivateKey, lokiAPIDatabase, lokiUserDatabase)
}() }()
// endregion // endregion
@ -94,7 +94,7 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
// region Polling // region Polling
private fun pollForNewMessages() { private fun pollForNewMessages() {
fun processIncomingMessage(message: LokiGroupMessage) { fun processIncomingMessage(message: LokiPublicChatMessage) {
val id = group.id.toByteArray() val id = group.id.toByteArray()
val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null) val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, null, null, null)
val quote: SignalServiceDataMessage.Quote? val quote: SignalServiceDataMessage.Quote?
@ -113,7 +113,7 @@ class LokiGroupChatPoller(private val context: Context, private val group: LokiG
PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID)) PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.of(message.serverID))
} }
} }
fun processOutgoingMessage(message: LokiGroupMessage) { fun processOutgoingMessage(message: LokiPublicChatMessage) {
val messageServerID = message.serverID ?: return val messageServerID = message.serverID ?: return
val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null val isDuplicate = lokiMessageDatabase.getMessageID(messageServerID) != null

View File

@ -9,11 +9,10 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.whispersystems.signalservice.internal.util.JsonUtil import org.whispersystems.signalservice.internal.util.JsonUtil
import org.whispersystems.signalservice.loki.api.LokiGroupChat import org.whispersystems.signalservice.loki.api.LokiPublicChat
import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol import org.whispersystems.signalservice.loki.messaging.LokiThreadDatabaseProtocol
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus
import java.lang.Exception
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol { class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
var delegate: LokiThreadDatabaseDelegate? = null var delegate: LokiThreadDatabaseDelegate? = null
@ -92,17 +91,17 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
notifyConversationListeners(threadID) notifyConversationListeners(threadID)
} }
fun getAllGroupChats(): Map<Long, LokiGroupChat> { fun getAllPublicChats(): Map<Long, LokiPublicChat> {
val database = databaseHelper.readableDatabase val database = databaseHelper.readableDatabase
var cursor: Cursor? = null var cursor: Cursor? = null
try { try {
val map = mutableMapOf<Long, LokiGroupChat>() val map = mutableMapOf<Long, LokiPublicChat>()
cursor = database.rawQuery("select * from $groupChatMappingTableName", null) cursor = database.rawQuery("select * from $groupChatMappingTableName", null)
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
val threadID = cursor.getLong(Companion.threadID) val threadID = cursor.getLong(Companion.threadID)
val string = cursor.getString(groupChatJSON) val string = cursor.getString(groupChatJSON)
val chat = LokiGroupChat.fromJSON(string) val chat = LokiPublicChat.fromJSON(string)
if (chat != null) { map[threadID] = chat } if (chat != null) { map[threadID] = chat }
} }
return map return map
@ -115,20 +114,20 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
return mapOf() return mapOf()
} }
fun getAllGroupChatServers(): Set<String> { fun getAllPublicChatServers(): Set<String> {
return getAllGroupChats().values.fold(setOf<String>()) { set, chat -> set.plus(chat.server) } return getAllPublicChats().values.fold(setOf<String>()) { set, chat -> set.plus(chat.server) }
} }
override fun getGroupChat(threadID: Long): LokiGroupChat? { override fun getPublicChat(threadID: Long): LokiPublicChat? {
if (threadID < 0) { return null } if (threadID < 0) { return null }
val database = databaseHelper.readableDatabase val database = databaseHelper.readableDatabase
return database.get(groupChatMappingTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> return database.get(groupChatMappingTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
val string = cursor.getString(groupChatJSON) val string = cursor.getString(groupChatJSON)
LokiGroupChat.fromJSON(string) LokiPublicChat.fromJSON(string)
} }
} }
override fun setGroupChat(groupChat: LokiGroupChat, threadID: Long) { override fun setPublicChat(groupChat: LokiPublicChat, threadID: Long) {
if (threadID < 0) { return } if (threadID < 0) { return }
val database = databaseHelper.writableDatabase val database = databaseHelper.writableDatabase
@ -138,7 +137,7 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
database.insertOrUpdate(groupChatMappingTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) database.insertOrUpdate(groupChatMappingTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
} }
override fun removeGroupChat(threadID: Long) { override fun removePublicChat(threadID: Long) {
databaseHelper.writableDatabase.delete(groupChatMappingTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) databaseHelper.writableDatabase.delete(groupChatMappingTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
} }
} }

View File

@ -8,31 +8,32 @@ import android.util.Range
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
import java.util.regex.Pattern import java.util.regex.Pattern
object MentionUtilities { object MentionUtilities {
@JvmStatic @JvmStatic
fun highlightMentions(text: CharSequence, isGroupThread: Boolean, context: Context): String { fun highlightMentions(text: CharSequence, threadID: Long, context: Context): String {
return MentionUtilities.highlightMentions(text, false, isGroupThread, context).toString() // isOutgoingMessage is irrelevant return MentionUtilities.highlightMentions(text, false, threadID, context).toString() // isOutgoingMessage is irrelevant
} }
@JvmStatic @JvmStatic
fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, isGroupThread: Boolean, context: Context): SpannableString { fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, threadID: Long, context: Context): SpannableString {
var text = text var text = text
val pattern = Pattern.compile("@[0-9a-fA-F]*") val pattern = Pattern.compile("@[0-9a-fA-F]*")
var matcher = pattern.matcher(text) var matcher = pattern.matcher(text)
val mentions = mutableListOf<Range<Int>>() val mentions = mutableListOf<Range<Int>>()
var startIndex = 0 var startIndex = 0
if (matcher.find(startIndex) && isGroupThread) { val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
if (matcher.find(startIndex)) {
while (true) { while (true) {
val userID = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @ val userID = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @
val userDisplayName: String? = if (userID.toLowerCase() == TextSecurePreferences.getLocalNumber(context).toLowerCase()) { val userDisplayName: String? = if (userID.toLowerCase() == TextSecurePreferences.getLocalNumber(context).toLowerCase()) {
TextSecurePreferences.getProfileName(context) TextSecurePreferences.getProfileName(context)
} else if (publicChat != null) {
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, userID)
} else { } else {
val publicChatID = LokiGroupChatAPI.publicChatServer + "." + LokiGroupChatAPI.publicChatServerID "" // TODO: Implement
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChatID, userID)
} }
if (userDisplayName != null) { if (userDisplayName != null) {
text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length) text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length)

View File

@ -13,7 +13,10 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) { class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) {
private var users = listOf<Tuple2<String, String>>() private var users = listOf<Tuple2<String, String>>()
set(newValue) { field = newValue; userSelectionViewAdapter.users = newValue } set(newValue) { field = newValue; userSelectionViewAdapter.users = newValue }
private var hasGroupContext = false var publicChatServer: String? = null
set(newValue) { field = newValue; userSelectionViewAdapter.publicChatServer = publicChatServer }
var publicChatChannel: Long? = null
set(newValue) { field = newValue; userSelectionViewAdapter.publicChatChannel = publicChatChannel }
var onUserSelected: ((Tuple2<String, String>) -> Unit)? = null var onUserSelected: ((Tuple2<String, String>) -> Unit)? = null
private val userSelectionViewAdapter by lazy { Adapter(context) } private val userSelectionViewAdapter by lazy { Adapter(context) }
@ -21,7 +24,8 @@ class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: In
private class Adapter(private val context: Context) : BaseAdapter() { private class Adapter(private val context: Context) : BaseAdapter() {
var users = listOf<Tuple2<String, String>>() var users = listOf<Tuple2<String, String>>()
set(newValue) { field = newValue; notifyDataSetChanged() } set(newValue) { field = newValue; notifyDataSetChanged() }
var hasGroupContext = false var publicChatServer: String? = null
var publicChatChannel: Long? = null
override fun getCount(): Int { override fun getCount(): Int {
return users.count() return users.count()
@ -39,7 +43,8 @@ class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: In
val cell = cellToBeReused as UserSelectionViewCell? ?: UserSelectionViewCell.inflate(LayoutInflater.from(context), parent) val cell = cellToBeReused as UserSelectionViewCell? ?: UserSelectionViewCell.inflate(LayoutInflater.from(context), parent)
val user = getItem(position) val user = getItem(position)
cell.user = user cell.user = user
cell.hasGroupContext = hasGroupContext cell.publicChatServer = publicChatServer
cell.publicChatChannel = publicChatChannel
return cell return cell
} }
} }
@ -56,7 +61,11 @@ class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: In
} }
fun show(users: List<Tuple2<String, String>>, threadID: Long) { fun show(users: List<Tuple2<String, String>>, threadID: Long) {
hasGroupContext = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID)!!.isGroupRecipient val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
if (publicChat != null) {
publicChatServer = publicChat.server
publicChatChannel = publicChat.channel
}
this.users = users this.users = users
val layoutParams = this.layoutParams as ViewGroup.LayoutParams val layoutParams = this.layoutParams as ViewGroup.LayoutParams
layoutParams.height = toPx(6 + Math.min(users.count(), 4) * 52, resources) layoutParams.height = toPx(6 + Math.min(users.count(), 4) * 52, resources)

View File

@ -11,12 +11,13 @@ import android.widget.LinearLayout
import kotlinx.android.synthetic.main.cell_user_selection_view.view.* import kotlinx.android.synthetic.main.cell_user_selection_view.view.*
import network.loki.messenger.R import network.loki.messenger.R
import nl.komponents.kovenant.combine.Tuple2 import nl.komponents.kovenant.combine.Tuple2
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI
class UserSelectionViewCell(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { class UserSelectionViewCell(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
var user = Tuple2("", "") var user = Tuple2("", "")
set(newValue) { field = newValue; update() } set(newValue) { field = newValue; update() }
var hasGroupContext = false var publicChatServer: String? = null
var publicChatChannel: Long? = null
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null) constructor(context: Context) : this(context, null)
@ -42,7 +43,11 @@ class UserSelectionViewCell(context: Context, attrs: AttributeSet?, defStyleAttr
private fun update() { private fun update() {
displayNameTextView.text = user.second displayNameTextView.text = user.second
profilePictureImageView.update(user.first) profilePictureImageView.update(user.first)
val isUserModerator = LokiGroupChatAPI.isUserModerator(user.first, LokiGroupChatAPI.publicChatServerID, LokiGroupChatAPI.publicChatServer) if (publicChatServer != null && publicChatChannel != null) {
moderatorIconImageView.visibility = if (isUserModerator && hasGroupContext) View.VISIBLE else View.GONE val isUserModerator = LokiPublicChatAPI.isUserModerator(user.first, publicChatChannel!!, publicChatServer!!)
moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE
} else {
moderatorIconImageView.visibility = View.GONE
}
} }
} }