mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-12 03:04:20 +00:00
Merge remote-tracking branch 'anton/open-group-info-update-refactoring' into dev
This commit is contained in:
commit
a8e67fafb9
@ -89,7 +89,9 @@ dependencies {
|
|||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
|
||||||
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
implementation "androidx.work:work-runtime-ktx:2.4.0"
|
||||||
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
|
|
||||||
implementation ("com.google.firebase:firebase-messaging:18.0.0") {
|
implementation ("com.google.firebase:firebase-messaging:18.0.0") {
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||||
|
@ -348,7 +348,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true, Collections.singletonList(local));
|
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true, Collections.singletonList(local));
|
||||||
Recipient groupRecipient = Recipient.from(activity, Address.fromSerialized(groupId), true);
|
Recipient groupRecipient = Recipient.from(activity, Address.fromSerialized(groupId), true);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
long threadId = DatabaseFactory.getThreadDatabase(activity).getOrCreateThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||||
|
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
}
|
}
|
||||||
|
@ -767,7 +767,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
.setBlocked(recipient, blocked);
|
.setBlocked(recipient, blocked);
|
||||||
|
|
||||||
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
|
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, recipient);
|
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, recipient);
|
||||||
|
|
||||||
if (threadId != -1 && leaveMessage.isPresent()) {
|
if (threadId != -1 && leaveMessage.isPresent()) {
|
||||||
@ -776,7 +776,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
String groupId = recipient.getAddress().toGroupString();
|
String groupId = recipient.getAddress().toGroupString();
|
||||||
groupDatabase.setActive(groupId, false);
|
groupDatabase.setActive(groupId, false);
|
||||||
groupDatabase.remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
groupDatabase.removeMember(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Failed to leave group. Can't block.");
|
Log.w(TAG, "Failed to leave group. Can't block.");
|
||||||
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
||||||
|
@ -197,7 +197,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
|||||||
|
|
||||||
String quoteeDisplayName = author.toShortString();
|
String quoteeDisplayName = author.toShortString();
|
||||||
|
|
||||||
long threadID = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(conversationRecipient);
|
long threadID = DatabaseFactory.getThreadDatabase(getContext()).getOrCreateThreadIdFor(conversationRecipient);
|
||||||
String senderHexEncodedPublicKey = author.getAddress().serialize();
|
String senderHexEncodedPublicKey = author.getAddress().serialize();
|
||||||
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID);
|
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID);
|
||||||
if (senderHexEncodedPublicKey.equalsIgnoreCase(TextSecurePreferences.getLocalNumber(getContext()))) {
|
if (senderHexEncodedPublicKey.equalsIgnoreCase(TextSecurePreferences.getLocalNumber(getContext()))) {
|
||||||
|
@ -90,7 +90,7 @@ public class TypingStatusSender {
|
|||||||
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
|
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize());
|
||||||
for (String device : linkedDevices) {
|
for (String device : linkedDevices) {
|
||||||
Recipient deviceAsRecipient = Recipient.from(context, Address.fromSerialized(device), false);
|
Recipient deviceAsRecipient = Recipient.from(context, Address.fromSerialized(device), false);
|
||||||
long deviceThreadID = threadDatabase.getThreadIdFor(deviceAsRecipient);
|
long deviceThreadID = threadDatabase.getOrCreateThreadIdFor(deviceAsRecipient);
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
|
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
|||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity;
|
import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity;
|
||||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||||
|
import org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
|
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate;
|
||||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||||
@ -163,6 +164,7 @@ import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol;
|
|||||||
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
|
import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities;
|
||||||
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
|
import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
|
||||||
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
|
import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
|
||||||
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
|
import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView;
|
||||||
@ -462,20 +464,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
|
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
|
||||||
if (publicChat != null) {
|
if (publicChat != null) {
|
||||||
PublicChatAPI publicChatAPI = ApplicationContext.getInstance(this).getPublicChatAPI();
|
// Request open group info update and handle the successful result in #onOpenGroupInfoUpdated().
|
||||||
publicChatAPI.getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(info -> {
|
PublicChatInfoUpdateWorker.scheduleInstant(this, publicChat.getServer(), publicChat.getChannel());
|
||||||
String groupId = GroupUtil.getEncodedOpenGroupId(publicChat.getId().getBytes());
|
|
||||||
|
|
||||||
publicChatAPI.updateProfileIfNeeded(
|
|
||||||
publicChat.getChannel(),
|
|
||||||
publicChat.getServer(),
|
|
||||||
groupId,
|
|
||||||
info,
|
|
||||||
false);
|
|
||||||
|
|
||||||
runOnUiThread(ConversationActivity.this::updateSubtitleTextView);
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
View rootView = findViewById(R.id.rootView);
|
View rootView = findViewById(R.id.rootView);
|
||||||
@ -1940,6 +1930,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
.show(TooltipPopup.POSITION_ABOVE);
|
.show(TooltipPopup.POSITION_ABOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
public void onOpenGroupInfoUpdated(OpenGroupUtilities.GroupInfoUpdatedEvent event) {
|
||||||
|
PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
|
||||||
|
if (publicChat != null &&
|
||||||
|
publicChat.getChannel() == event.getChannel() &&
|
||||||
|
publicChat.getServer().equals(event.getUrl())) {
|
||||||
|
this.updateSubtitleTextView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeReceivers() {
|
private void initializeReceivers() {
|
||||||
securityUpdateReceiver = new BroadcastReceiver() {
|
securityUpdateReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
@ -2095,7 +2095,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
long threadId = params[0];
|
long threadId = params[0];
|
||||||
|
|
||||||
if (drafts.size() > 0) {
|
if (drafts.size() > 0) {
|
||||||
if (threadId == -1) threadId = threadDatabase.getThreadIdFor(getRecipient(), thisDistributionType);
|
if (threadId == -1) threadId = threadDatabase.getOrCreateThreadIdFor(getRecipient(), thisDistributionType);
|
||||||
|
|
||||||
draftDatabase.insertDrafts(threadId, drafts);
|
draftDatabase.insertDrafts(threadId, drafts);
|
||||||
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
||||||
|
@ -218,6 +218,18 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean delete(@NonNull String groupId) {
|
||||||
|
int result = databaseHelper.getWritableDatabase().delete(TABLE_NAME, GROUP_ID + " = ?", new String[]{groupId});
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
Recipient.removeCached(Address.fromSerialized(groupId));
|
||||||
|
notifyConversationListListeners();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void update(String groupId, String title, SignalServiceAttachmentPointer avatar) {
|
public void update(String groupId, String title, SignalServiceAttachmentPointer avatar) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
if (title != null) contentValues.put(TITLE, title);
|
if (title != null) contentValues.put(TITLE, title);
|
||||||
@ -262,7 +274,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
long avatarId;
|
long avatarId;
|
||||||
|
|
||||||
if (newValue != null) avatarId = Math.abs(new SecureRandom().nextLong());
|
if (newValue != null) avatarId = Math.abs(new SecureRandom().nextLong());
|
||||||
else avatarId = 0;
|
else avatarId = 0;
|
||||||
|
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues(2);
|
ContentValues contentValues = new ContentValues(2);
|
||||||
@ -300,7 +312,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId});
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", new String[] {groupId});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(String groupId, Address source) {
|
public void removeMember(String groupId, Address source) {
|
||||||
List<Address> currentMembers = getCurrentMembers(groupId);
|
List<Address> currentMembers = getCurrentMembers(groupId);
|
||||||
currentMembers.remove(source);
|
currentMembers.remove(source);
|
||||||
|
|
||||||
@ -352,13 +364,21 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
|||||||
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId});
|
database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] allocateGroupId() {
|
public byte[] allocateGroupId() {
|
||||||
byte[] groupId = new byte[16];
|
byte[] groupId = new byte[16];
|
||||||
new SecureRandom().nextBytes(groupId);
|
new SecureRandom().nextBytes(groupId);
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasGroup(@NonNull String groupId) {
|
||||||
|
try (Cursor cursor = databaseHelper.getReadableDatabase().rawQuery(
|
||||||
|
"SELECT 1 FROM " + TABLE_NAME + " WHERE " + GROUP_ID + " = ? LIMIT 1",
|
||||||
|
new String[]{groupId}
|
||||||
|
)) {
|
||||||
|
return cursor.getCount() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Reader implements Closeable {
|
public static class Reader implements Closeable {
|
||||||
|
|
||||||
private final Cursor cursor;
|
private final Cursor cursor;
|
||||||
|
@ -321,10 +321,10 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
||||||
if (retrieved.getGroupId() != null) {
|
if (retrieved.getGroupId() != null) {
|
||||||
Recipient groupRecipients = Recipient.from(context, retrieved.getGroupId(), true);
|
Recipient groupRecipients = Recipient.from(context, retrieved.getGroupId(), true);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(groupRecipients);
|
||||||
} else {
|
} else {
|
||||||
Recipient sender = Recipient.from(context, retrieved.getFrom(), true);
|
Recipient sender = Recipient.from(context, retrieved.getFrom(), true);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(sender);
|
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
? Util.toIsoString(notification.getFrom().getTextString())
|
? Util.toIsoString(notification.getFrom().getTextString())
|
||||||
: "";
|
: "";
|
||||||
Recipient recipient = Recipient.from(context, Address.fromExternal(context, fromString), false);
|
Recipient recipient = Recipient.from(context, Address.fromExternal(context, fromString), false);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cursor rawQuery(@NonNull String where, @Nullable String[] arguments) {
|
private Cursor rawQuery(@NonNull String where, @Nullable String[] arguments) {
|
||||||
|
@ -556,7 +556,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
||||||
Recipient recipient = Recipient.from(context, address, true);
|
Recipient recipient = Recipient.from(context, address, true);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
|
|
||||||
ContentValues values = new ContentValues(6);
|
ContentValues values = new ContentValues(6);
|
||||||
values.put(ADDRESS, address.serialize());
|
values.put(ADDRESS, address.serialize());
|
||||||
@ -620,8 +620,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
long threadId;
|
long threadId;
|
||||||
|
|
||||||
if (groupRecipient == null) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
if (groupRecipient == null) threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
else threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(groupRecipient);
|
||||||
|
|
||||||
ContentValues values = new ContentValues(6);
|
ContentValues values = new ContentValues(6);
|
||||||
values.put(ADDRESS, message.getSender().serialize());
|
values.put(ADDRESS, message.getSender().serialize());
|
||||||
|
@ -209,7 +209,7 @@ public class SmsMigrator {
|
|||||||
|
|
||||||
if (ourRecipients != null) {
|
if (ourRecipients != null) {
|
||||||
if (ourRecipients.size() == 1) {
|
if (ourRecipients.size() == 1) {
|
||||||
long ourThreadId = threadDatabase.getThreadIdFor(ourRecipients.iterator().next());
|
long ourThreadId = threadDatabase.getOrCreateThreadIdFor(ourRecipients.iterator().next());
|
||||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||||
} else if (ourRecipients.size() > 1) {
|
} else if (ourRecipients.size() > 1) {
|
||||||
ourRecipients.add(Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
|
ourRecipients.add(Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
|
||||||
@ -222,7 +222,7 @@ public class SmsMigrator {
|
|||||||
|
|
||||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true, null);
|
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true, null);
|
||||||
Recipient ourGroupRecipient = Recipient.from(context, Address.fromSerialized(ourGroupId), true);
|
Recipient ourGroupRecipient = Recipient.from(context, Address.fromSerialized(ourGroupId), true);
|
||||||
long ourThreadId = threadDatabase.getThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long ourThreadId = threadDatabase.getOrCreateThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
|
|
||||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||||
}
|
}
|
||||||
|
@ -512,11 +512,11 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadIdFor(Recipient recipient) {
|
public long getOrCreateThreadIdFor(Recipient recipient) {
|
||||||
return getThreadIdFor(recipient, DistributionTypes.DEFAULT);
|
return getOrCreateThreadIdFor(recipient, DistributionTypes.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadIdFor(Recipient recipient, int distributionType) {
|
public long getOrCreateThreadIdFor(Recipient recipient, int distributionType) {
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
String where = ADDRESS + " = ?";
|
String where = ADDRESS + " = ?";
|
||||||
String[] recipientsArg = new String[]{recipient.getAddress().serialize()};
|
String[] recipientsArg = new String[]{recipient.getAddress().serialize()};
|
||||||
|
@ -62,7 +62,7 @@ public class BucketedThreadMediaLoader extends AsyncTaskLoader<BucketedThreadMed
|
|||||||
@Override
|
@Override
|
||||||
public BucketedThreadMedia loadInBackground() {
|
public BucketedThreadMedia loadInBackground() {
|
||||||
BucketedThreadMedia result = new BucketedThreadMedia(getContext());
|
BucketedThreadMedia result = new BucketedThreadMedia(getContext());
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getOrCreateThreadIdFor(Recipient.from(getContext(), address, true));
|
||||||
|
|
||||||
DatabaseFactory.getMediaDatabase(getContext()).subscribeToMediaChanges(observer);
|
DatabaseFactory.getMediaDatabase(getContext()).subscribeToMediaChanges(observer);
|
||||||
try (Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId)) {
|
try (Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId)) {
|
||||||
|
@ -34,7 +34,7 @@ public class PagingMediaLoader extends AsyncLoader<Pair<Cursor, Integer>> {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Pair<Cursor, Integer> loadInBackground() {
|
public Pair<Cursor, Integer> loadInBackground() {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getOrCreateThreadIdFor(recipient);
|
||||||
Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
||||||
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
@ -23,7 +23,7 @@ public class ThreadMediaLoader extends AbstractCursorLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor getCursor() {
|
public Cursor getCursor() {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(Recipient.from(getContext(), address, true));
|
long threadId = DatabaseFactory.getThreadDatabase(getContext()).getOrCreateThreadIdFor(Recipient.from(getContext(), address, true));
|
||||||
|
|
||||||
if (gallery) return DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
if (gallery) return DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId);
|
||||||
else return DatabaseFactory.getMediaDatabase(getContext()).getDocumentMediaForThread(threadId);
|
else return DatabaseFactory.getMediaDatabase(getContext()).getDocumentMediaForThread(threadId);
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@ -89,7 +90,8 @@ public class GroupManager {
|
|||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
|
||||||
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
|
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
|
||||||
} else {
|
} else {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(
|
||||||
|
groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,10 +129,30 @@ public class GroupManager {
|
|||||||
|
|
||||||
groupDatabase.updateProfilePicture(groupId, avatarBytes);
|
groupDatabase.updateProfilePicture(groupId, avatarBytes);
|
||||||
|
|
||||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(
|
||||||
|
groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
return new GroupActionResult(groupRecipient, threadID);
|
return new GroupActionResult(groupRecipient, threadID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean deleteGroup(@NonNull String groupId,
|
||||||
|
@NonNull Context context)
|
||||||
|
{
|
||||||
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
|
final ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
|
final Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), false);
|
||||||
|
|
||||||
|
if (!groupDatabase.getGroup(groupId).isPresent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long threadId = threadDatabase.getThreadIdIfExistsFor(groupRecipient);
|
||||||
|
if (threadId != -1L) {
|
||||||
|
threadDatabase.deleteConversation(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupDatabase.delete(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
public static GroupActionResult updateGroup(@NonNull Context context,
|
public static GroupActionResult updateGroup(@NonNull Context context,
|
||||||
@NonNull String groupId,
|
@NonNull String groupId,
|
||||||
@NonNull Set<Recipient> members,
|
@NonNull Set<Recipient> members,
|
||||||
@ -154,7 +176,7 @@ public class GroupManager {
|
|||||||
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
|
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
|
||||||
} else {
|
} else {
|
||||||
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), true);
|
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(groupId), true);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(groupRecipient);
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ public class GroupMessageProcessor {
|
|||||||
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
String masterDevice = MultiDeviceProtocol.shared.getMasterDevice(content.getSender());
|
||||||
if (masterDevice == null) { masterDevice = content.getSender(); }
|
if (masterDevice == null) { masterDevice = content.getSender(); }
|
||||||
if (members.contains(Address.fromExternal(context, masterDevice))) {
|
if (members.contains(Address.fromExternal(context, masterDevice))) {
|
||||||
database.remove(id, Address.fromExternal(context, masterDevice));
|
database.removeMember(id, Address.fromExternal(context, masterDevice));
|
||||||
if (outgoing) database.setActive(id, false);
|
if (outgoing) database.setActive(id, false);
|
||||||
|
|
||||||
return storeMessage(context, content, group, builder.build(), outgoing);
|
return storeMessage(context, content, group, builder.build(), outgoing);
|
||||||
@ -260,7 +260,7 @@ public class GroupMessageProcessor {
|
|||||||
Address address = Address.fromExternal(context, GroupUtil.getEncodedId(group));
|
Address address = Address.fromExternal(context, GroupUtil.getEncodedId(group));
|
||||||
Recipient recipient = Recipient.from(context, address, false);
|
Recipient recipient = Recipient.from(context, address, false);
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, null, Collections.emptyList(), Collections.emptyList());
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipient, storage, null, content.getTimestamp(), 0, null, Collections.emptyList(), Collections.emptyList());
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
|
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
|
||||||
|
|
||||||
mmsDatabase.markAsSent(messageId, true);
|
mmsDatabase.markAsSent(messageId, true);
|
||||||
|
@ -498,7 +498,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, "", -1);
|
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, "", -1);
|
||||||
OutgoingEndSessionMessage outgoingEndSessionMessage = new OutgoingEndSessionMessage(outgoingTextMessage);
|
OutgoingEndSessionMessage outgoingEndSessionMessage = new OutgoingEndSessionMessage(outgoingTextMessage);
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
|
|
||||||
if (!recipient.isGroupRecipient()) {
|
if (!recipient.isGroupRecipient()) {
|
||||||
// TODO: Handle session reset on sync messages
|
// TODO: Handle session reset on sync messages
|
||||||
@ -808,7 +808,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
if (result.getMessageId() > -1) {
|
if (result.getMessageId() > -1) {
|
||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
||||||
long originalThreadId = threadDatabase.getThreadIdFor(originalRecipient);
|
long originalThreadId = threadDatabase.getOrCreateThreadIdFor(originalRecipient);
|
||||||
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -822,7 +822,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
message.getTimestamp(),
|
message.getTimestamp(),
|
||||||
message.getMessage().getExpiresInSeconds() * 1000L);
|
message.getMessage().getExpiresInSeconds() * 1000L);
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
long messageId = database.insertMessageOutbox(expirationUpdateMessage, threadId, false, null);
|
long messageId = database.insertMessageOutbox(expirationUpdateMessage, threadId, false, null);
|
||||||
|
|
||||||
database.markAsSent(messageId, true);
|
database.markAsSent(messageId, true);
|
||||||
@ -864,7 +864,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
handleSynchronizeSentExpirationUpdate(message);
|
handleSynchronizeSentExpirationUpdate(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipients);
|
||||||
|
|
||||||
database.beginTransaction();
|
database.beginTransaction();
|
||||||
|
|
||||||
@ -995,7 +995,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
if (result.getMessageId() > -1) {
|
if (result.getMessageId() > -1) {
|
||||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context);
|
||||||
long originalThreadId = threadDatabase.getThreadIdFor(originalRecipient);
|
long originalThreadId = threadDatabase.getOrCreateThreadIdFor(originalRecipient);
|
||||||
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1018,7 +1018,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
handleSynchronizeSentExpirationUpdate(message);
|
handleSynchronizeSentExpirationUpdate(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
boolean isGroup = recipient.getAddress().isGroup();
|
boolean isGroup = recipient.getAddress().isGroup();
|
||||||
|
|
||||||
MessagingDatabase database;
|
MessagingDatabase database;
|
||||||
@ -1102,7 +1102,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
if (canRecoverAutomatically(e)) {
|
if (canRecoverAutomatically(e)) {
|
||||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
|
Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
|
||||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context);
|
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context);
|
||||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
threadDB.addSessionRestoreDevice(threadID, sender);
|
threadDB.addSessionRestoreDevice(threadID, sender);
|
||||||
SessionManagementProtocol.startSessionReset(context, sender);
|
SessionManagementProtocol.startSessionReset(context, sender);
|
||||||
} else {
|
} else {
|
||||||
@ -1249,7 +1249,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
} else {
|
} else {
|
||||||
// See if we need to redirect the message
|
// See if we need to redirect the message
|
||||||
author = getMessageMasterDestination(content.getSender());
|
author = getMessageMasterDestination(content.getSender());
|
||||||
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(author);
|
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(author);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadId <= 0) {
|
if (threadId <= 0) {
|
||||||
@ -1459,7 +1459,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
|||||||
|
|
||||||
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull String sender, int device) {
|
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull String sender, int device) {
|
||||||
Recipient author = Recipient.from(context, Address.fromSerialized(sender), false);
|
Recipient author = Recipient.from(context, Address.fromSerialized(sender), false);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(conversationRecipient);
|
||||||
|
|
||||||
if (threadId > 0) {
|
if (threadId > 0) {
|
||||||
Log.d(TAG, "Typing stopped on thread " + threadId + " due to an incoming message.");
|
Log.d(TAG, "Typing stopped on thread " + threadId + " due to an incoming message.");
|
||||||
|
@ -125,7 +125,7 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM
|
|||||||
ClosedGroupsProtocol.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID ->
|
ClosedGroupsProtocol.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID ->
|
||||||
loader.fadeOut()
|
loader.fadeOut()
|
||||||
isLoading = false
|
isLoading = false
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false))
|
val threadID = DatabaseFactory.getThreadDatabase(this).getOrCreateThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false))
|
||||||
if (!isFinishing) {
|
if (!isFinishing) {
|
||||||
openConversationActivity(this, threadID, Recipient.from(this, Address.fromSerialized(groupID), false))
|
openConversationActivity(this, threadID, Recipient.from(this, Address.fromSerialized(groupID), false))
|
||||||
finish()
|
finish()
|
||||||
|
@ -9,7 +9,6 @@ import android.database.Cursor
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
@ -18,21 +17,24 @@ import android.view.View
|
|||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.loader.app.LoaderManager
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.attachments.AttachmentId
|
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupManager
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob
|
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob
|
||||||
import org.thoughtcrime.securesms.loki.api.PrepareAttachmentAudioExtrasJob
|
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.ConversationOptionsBottomSheet
|
import org.thoughtcrime.securesms.loki.dialogs.ConversationOptionsBottomSheet
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.LightThemeFeatureIntroBottomSheet
|
import org.thoughtcrime.securesms.loki.dialogs.LightThemeFeatureIntroBottomSheet
|
||||||
import org.thoughtcrime.securesms.loki.dialogs.MultiDeviceRemovalBottomSheet
|
import org.thoughtcrime.securesms.loki.dialogs.MultiDeviceRemovalBottomSheet
|
||||||
@ -72,24 +74,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||||
super.onCreate(savedInstanceState, isReady)
|
super.onCreate(savedInstanceState, isReady)
|
||||||
// Process any outstanding deletes
|
|
||||||
val threadDatabase = DatabaseFactory.getThreadDatabase(this)
|
|
||||||
val archivedConversationCount = threadDatabase.archivedConversationListCount
|
|
||||||
if (archivedConversationCount > 0) {
|
|
||||||
val archivedConversations = threadDatabase.archivedConversationList
|
|
||||||
archivedConversations.moveToFirst()
|
|
||||||
fun deleteThreadAtCurrentPosition() {
|
|
||||||
val threadID = archivedConversations.getLong(archivedConversations.getColumnIndex(ThreadDatabase.ID))
|
|
||||||
AsyncTask.execute {
|
|
||||||
threadDatabase.deleteConversation(threadID)
|
|
||||||
(applicationContext as ApplicationContext).messageNotifier.updateNotification(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deleteThreadAtCurrentPosition()
|
|
||||||
while (archivedConversations.moveToNext()) {
|
|
||||||
deleteThreadAtCurrentPosition()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Double check that the long poller is up
|
// Double check that the long poller is up
|
||||||
(applicationContext as ApplicationContext).startPollingIfNeeded()
|
(applicationContext as ApplicationContext).startPollingIfNeeded()
|
||||||
// Set content view
|
// Set content view
|
||||||
@ -342,53 +326,56 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
|||||||
val threadID = thread.threadId
|
val threadID = thread.threadId
|
||||||
val recipient = thread.recipient
|
val recipient = thread.recipient
|
||||||
val threadDB = DatabaseFactory.getThreadDatabase(this)
|
val threadDB = DatabaseFactory.getThreadDatabase(this)
|
||||||
val deleteThread = Runnable {
|
|
||||||
AsyncTask.execute {
|
|
||||||
val publicChat = DatabaseFactory.getLokiThreadDatabase(this@HomeActivity).getPublicChat(threadID)
|
|
||||||
if (publicChat != null) {
|
|
||||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(this@HomeActivity)
|
|
||||||
apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server)
|
|
||||||
apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server)
|
|
||||||
apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server)
|
|
||||||
ApplicationContext.getInstance(this@HomeActivity).publicChatAPI!!.leave(publicChat.channel, publicChat.server)
|
|
||||||
}
|
|
||||||
threadDB.deleteConversation(threadID)
|
|
||||||
ApplicationContext.getInstance(this@HomeActivity).messageNotifier.updateNotification(this@HomeActivity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message
|
val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message
|
||||||
val dialog = AlertDialog.Builder(this)
|
val dialog = AlertDialog.Builder(this)
|
||||||
dialog.setMessage(dialogMessage)
|
dialog.setMessage(dialogMessage)
|
||||||
dialog.setPositiveButton(R.string.yes) { _, _ ->
|
dialog.setPositiveButton(R.string.yes) { _, _ -> lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
val context = this@HomeActivity as Context
|
||||||
|
|
||||||
val isClosedGroup = recipient.address.isClosedGroup
|
val isClosedGroup = recipient.address.isClosedGroup
|
||||||
// Send a leave group message if this is an active closed group
|
// Send a leave group message if this is an active closed group
|
||||||
if (isClosedGroup && DatabaseFactory.getGroupDatabase(this).isActive(recipient.address.toGroupString())) {
|
if (isClosedGroup && DatabaseFactory.getGroupDatabase(context).isActive(recipient.address.toGroupString())) {
|
||||||
var isSSKBasedClosedGroup: Boolean
|
var isSSKBasedClosedGroup: Boolean
|
||||||
var groupPublicKey: String?
|
var groupPublicKey: String?
|
||||||
try {
|
try {
|
||||||
groupPublicKey = ClosedGroupsProtocol.doubleDecodeGroupID(recipient.address.toString()).toHexString()
|
groupPublicKey = ClosedGroupsProtocol.doubleDecodeGroupID(recipient.address.toString()).toHexString()
|
||||||
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(this).isSSKBasedClosedGroup(groupPublicKey)
|
isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(context).isSSKBasedClosedGroup(groupPublicKey)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
groupPublicKey = null
|
groupPublicKey = null
|
||||||
isSSKBasedClosedGroup = false
|
isSSKBasedClosedGroup = false
|
||||||
}
|
}
|
||||||
if (isSSKBasedClosedGroup) {
|
if (isSSKBasedClosedGroup) {
|
||||||
ClosedGroupsProtocol.leave(this, groupPublicKey!!)
|
ClosedGroupsProtocol.leave(context, groupPublicKey!!)
|
||||||
} else if (!ClosedGroupsProtocol.leaveLegacyGroup(this, recipient)) {
|
} else if (!ClosedGroupsProtocol.leaveLegacyGroup(context, recipient)) {
|
||||||
Toast.makeText(this, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show()
|
||||||
return@setPositiveButton
|
return@launch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Archive the conversation and then delete it after 10 seconds (the case where the
|
|
||||||
// app was closed before the conversation could be deleted is handled in onCreate)
|
withContext(Dispatchers.IO) {
|
||||||
threadDB.archiveConversation(threadID)
|
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
val delay = if (isClosedGroup) 10000L else 1000L
|
//TODO Move open group related logic to OpenGroupUtilities / PublicChatManager / GroupManager
|
||||||
val handler = Handler()
|
if (publicChat != null) {
|
||||||
handler.postDelayed(deleteThread, delay)
|
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
|
||||||
|
apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server)
|
||||||
|
apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server)
|
||||||
|
apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server)
|
||||||
|
|
||||||
|
ApplicationContext.getInstance(context).publicChatAPI!!
|
||||||
|
.leave(publicChat.channel, publicChat.server)
|
||||||
|
|
||||||
|
ApplicationContext.getInstance(context).publicChatManager
|
||||||
|
.removeChat(publicChat.server, publicChat.channel)
|
||||||
|
} else {
|
||||||
|
threadDB.deleteConversation(threadID)
|
||||||
|
}
|
||||||
|
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context)
|
||||||
|
}
|
||||||
|
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message
|
||||||
Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show()
|
||||||
}
|
}}
|
||||||
dialog.setNegativeButton(R.string.no) { _, _ ->
|
dialog.setNegativeButton(R.string.no) { _, _ ->
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,12 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import kotlinx.android.synthetic.main.activity_join_public_chat.*
|
import kotlinx.android.synthetic.main.activity_join_public_chat.*
|
||||||
import kotlinx.android.synthetic.main.fragment_enter_chat_url.*
|
import kotlinx.android.synthetic.main.fragment_enter_chat_url.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import nl.komponents.kovenant.ui.failUi
|
import nl.komponents.kovenant.ui.failUi
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
@ -22,6 +26,7 @@ import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
|
|||||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||||
import org.thoughtcrime.securesms.loki.protocol.shelved.SyncMessagesProtocol
|
import org.thoughtcrime.securesms.loki.protocol.shelved.SyncMessagesProtocol
|
||||||
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||||
private val adapter = JoinPublicChatActivityAdapter(this)
|
private val adapter = JoinPublicChatActivityAdapter(this)
|
||||||
@ -67,13 +72,19 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
|
|||||||
}
|
}
|
||||||
showLoader()
|
showLoader()
|
||||||
val channel: Long = 1
|
val channel: Long = 1
|
||||||
OpenGroupUtilities.addGroup(this, url, channel).success {
|
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
OpenGroupUtilities.addGroup(this@JoinPublicChatActivity, url, channel)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
hideLoader()
|
||||||
|
Toast.makeText(this@JoinPublicChatActivity, R.string.activity_join_public_chat_error, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
SyncMessagesProtocol.syncAllOpenGroups(this@JoinPublicChatActivity)
|
SyncMessagesProtocol.syncAllOpenGroups(this@JoinPublicChatActivity)
|
||||||
}.successUi {
|
withContext(Dispatchers.Main) { finish() }
|
||||||
finish()
|
|
||||||
}.failUi {
|
|
||||||
hideLoader()
|
|
||||||
Toast.makeText(this, R.string.activity_join_public_chat_error, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
@ -123,13 +134,13 @@ class EnterChatURLFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun joinPublicChatIfPossible() {
|
private fun joinPublicChatIfPossible() {
|
||||||
val inputMethodManager = context!!.getSystemService(BaseActionBarActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
val inputMethodManager = requireContext().getSystemService(BaseActionBarActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
inputMethodManager.hideSoftInputFromWindow(chatURLEditText.windowToken, 0)
|
inputMethodManager.hideSoftInputFromWindow(chatURLEditText.windowToken, 0)
|
||||||
var chatURL = chatURLEditText.text.trim().toString().toLowerCase().replace("http://", "https://")
|
var chatURL = chatURLEditText.text.trim().toString().toLowerCase().replace("http://", "https://")
|
||||||
if (!chatURL.toLowerCase().startsWith("https")) {
|
if (!chatURL.toLowerCase().startsWith("https")) {
|
||||||
chatURL = "https://$chatURL"
|
chatURL = "https://$chatURL"
|
||||||
}
|
}
|
||||||
(activity!! as JoinPublicChatActivity).joinPublicChatIfPossible(chatURL)
|
(requireActivity() as JoinPublicChatActivity).joinPublicChatIfPossible(chatURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
@ -25,10 +25,9 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun scheduleInstant(context: Context) {
|
fun scheduleInstant(context: Context) {
|
||||||
val workRequest = OneTimeWorkRequestBuilder<BackgroundPollWorker>()
|
val workRequest = OneTimeWorkRequestBuilder<BackgroundPollWorker>()
|
||||||
.setConstraints(
|
.setConstraints(Constraints.Builder()
|
||||||
Constraints.Builder()
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.build()
|
||||||
.build()
|
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -41,10 +40,9 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor
|
|||||||
fun schedulePeriodic(context: Context) {
|
fun schedulePeriodic(context: Context) {
|
||||||
Log.v(TAG, "Scheduling periodic work.")
|
Log.v(TAG, "Scheduling periodic work.")
|
||||||
val workRequest = PeriodicWorkRequestBuilder<BackgroundPollWorker>(15, TimeUnit.MINUTES)
|
val workRequest = PeriodicWorkRequestBuilder<BackgroundPollWorker>(15, TimeUnit.MINUTES)
|
||||||
.setConstraints(
|
.setConstraints(Constraints.Builder()
|
||||||
Constraints.Builder()
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.build()
|
||||||
.build()
|
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package org.thoughtcrime.securesms.loki.api
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.*
|
||||||
|
import org.thoughtcrime.securesms.logging.Log
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
||||||
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates the [OpenGroupUtilities.updateGroupInfo] call to the work manager.
|
||||||
|
*/
|
||||||
|
class PublicChatInfoUpdateWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PublicChatInfoUpdateWorker"
|
||||||
|
|
||||||
|
private const val DATA_KEY_SERVER_URL = "server_uRL"
|
||||||
|
private const val DATA_KEY_CHANNEL = "channel"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun scheduleInstant(context: Context, serverURL: String, channel: Long) {
|
||||||
|
val workRequest = OneTimeWorkRequestBuilder<PublicChatInfoUpdateWorker>()
|
||||||
|
.setConstraints(Constraints.Builder()
|
||||||
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setInputData(workDataOf(
|
||||||
|
DATA_KEY_SERVER_URL to serverURL,
|
||||||
|
DATA_KEY_CHANNEL to channel
|
||||||
|
))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
WorkManager
|
||||||
|
.getInstance(context)
|
||||||
|
.enqueue(workRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
val serverUrl = inputData.getString(DATA_KEY_SERVER_URL)!!
|
||||||
|
val channel = inputData.getLong(DATA_KEY_CHANNEL, -1)
|
||||||
|
|
||||||
|
val publicChatId = PublicChat.getId(channel, serverUrl)
|
||||||
|
|
||||||
|
return try {
|
||||||
|
Log.v(TAG, "Updating open group info for $publicChatId.")
|
||||||
|
OpenGroupUtilities.updateGroupInfo(context, serverUrl, channel)
|
||||||
|
Log.v(TAG, "Open group info was successfully updated for $publicChatId.")
|
||||||
|
Result.success()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to update open group info for $publicChatId", e)
|
||||||
|
Result.failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,7 @@ import android.content.Context
|
|||||||
import android.database.ContentObserver
|
import android.database.ContentObserver
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import nl.komponents.kovenant.Promise
|
import androidx.annotation.WorkerThread
|
||||||
import nl.komponents.kovenant.functional.bind
|
|
||||||
import nl.komponents.kovenant.functional.map
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
@ -16,6 +14,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences
|
|||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatInfo
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatInfo
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
|
import kotlin.jvm.Throws
|
||||||
|
|
||||||
class PublicChatManager(private val context: Context) {
|
class PublicChatManager(private val context: Context) {
|
||||||
private var chats = mutableMapOf<Long, PublicChat>()
|
private var chats = mutableMapOf<Long, PublicChat>()
|
||||||
@ -23,7 +22,7 @@ class PublicChatManager(private val context: Context) {
|
|||||||
private val observers = mutableMapOf<Long, ContentObserver>()
|
private val observers = mutableMapOf<Long, ContentObserver>()
|
||||||
private var isPolling = false
|
private var isPolling = false
|
||||||
|
|
||||||
public fun areAllCaughtUp():Boolean {
|
public fun areAllCaughtUp(): Boolean {
|
||||||
var areAllCaughtUp = true
|
var areAllCaughtUp = true
|
||||||
refreshChatsAndPollers()
|
refreshChatsAndPollers()
|
||||||
for ((threadID, chat) in chats) {
|
for ((threadID, chat) in chats) {
|
||||||
@ -58,19 +57,24 @@ class PublicChatManager(private val context: Context) {
|
|||||||
isPolling = false
|
isPolling = false
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun addChat(server: String, channel: Long): Promise<PublicChat, Exception> {
|
//TODO Declare a specific type of checked exception instead of "Exception".
|
||||||
|
@WorkerThread
|
||||||
|
@Throws(java.lang.Exception::class)
|
||||||
|
public fun addChat(server: String, channel: Long): PublicChat {
|
||||||
val groupChatAPI = ApplicationContext.getInstance(context).publicChatAPI
|
val groupChatAPI = ApplicationContext.getInstance(context).publicChatAPI
|
||||||
?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!"))
|
?: throw IllegalStateException("LokiPublicChatAPI is not set!")
|
||||||
return groupChatAPI.getAuthToken(server).bind {
|
|
||||||
groupChatAPI.getChannelInfo(channel, server)
|
// Ensure the auth token is acquired.
|
||||||
}.map {
|
groupChatAPI.getAuthToken(server).get()
|
||||||
addChat(server, channel, it)
|
|
||||||
}
|
val channelInfo = groupChatAPI.getChannelInfo(channel, server).get()
|
||||||
|
return addChat(server, channel, channelInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
public fun addChat(server: String, channel: Long, info: PublicChatInfo): PublicChat {
|
public fun addChat(server: String, channel: Long, info: PublicChatInfo): PublicChat {
|
||||||
val chat = PublicChat(channel, server, info.displayName, true)
|
val chat = PublicChat(channel, server, info.displayName, true)
|
||||||
var threadID = GroupManager.getOpenGroupThreadID(chat.id, context)
|
var threadID = GroupManager.getOpenGroupThreadID(chat.id, context)
|
||||||
var profilePicture: Bitmap? = null
|
var profilePicture: Bitmap? = null
|
||||||
// Create the group if we don't have one
|
// Create the group if we don't have one
|
||||||
if (threadID < 0) {
|
if (threadID < 0) {
|
||||||
@ -89,11 +93,21 @@ class PublicChatManager(private val context: Context) {
|
|||||||
ApplicationContext.getInstance(context).publicChatAPI?.setDisplayName(displayName, server)
|
ApplicationContext.getInstance(context).publicChatAPI?.setDisplayName(displayName, server)
|
||||||
}
|
}
|
||||||
// Start polling
|
// Start polling
|
||||||
Util.runOnMain{ startPollersIfNeeded() }
|
Util.runOnMain { startPollersIfNeeded() }
|
||||||
|
|
||||||
return chat
|
return chat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun removeChat(server: String, channel: Long) {
|
||||||
|
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
||||||
|
val groupId = PublicChat.getId(channel, server)
|
||||||
|
val threadId = GroupManager.getOpenGroupThreadID(groupId, context)
|
||||||
|
val groupAddress = threadDB.getRecipientForThreadId(threadId)!!.address.serialize()
|
||||||
|
GroupManager.deleteGroup(groupAddress, context)
|
||||||
|
|
||||||
|
Util.runOnMain { startPollersIfNeeded() }
|
||||||
|
}
|
||||||
|
|
||||||
private fun refreshChatsAndPollers() {
|
private fun refreshChatsAndPollers() {
|
||||||
val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats()
|
val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats()
|
||||||
val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }
|
val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }
|
||||||
@ -105,7 +119,7 @@ class PublicChatManager(private val context: Context) {
|
|||||||
|
|
||||||
private fun listenToThreadDeletion(threadID: Long) {
|
private fun listenToThreadDeletion(threadID: Long) {
|
||||||
if (threadID < 0 || observers[threadID] != null) { return }
|
if (threadID < 0 || observers[threadID] != null) { return }
|
||||||
val observer = createDeletionObserver(threadID, Runnable {
|
val observer = createDeletionObserver(threadID) {
|
||||||
val chat = chats[threadID]
|
val chat = chats[threadID]
|
||||||
|
|
||||||
// Reset last message cache
|
// Reset last message cache
|
||||||
@ -119,7 +133,7 @@ class PublicChatManager(private val context: Context) {
|
|||||||
pollers.remove(threadID)?.stop()
|
pollers.remove(threadID)?.stop()
|
||||||
observers.remove(threadID)
|
observers.remove(threadID)
|
||||||
startPollersIfNeeded()
|
startPollersIfNeeded()
|
||||||
})
|
}
|
||||||
observers[threadID] = observer
|
observers[threadID] = observer
|
||||||
|
|
||||||
context.applicationContext.contentResolver.registerContentObserver(DatabaseContentProviders.Conversation.getUriForThread(threadID), true, observer)
|
context.applicationContext.contentResolver.registerContentObserver(DatabaseContentProviders.Conversation.getUriForThread(threadID), true, observer)
|
||||||
|
@ -193,8 +193,8 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
|
|||||||
val messageID = DatabaseFactory.getLokiMessageDatabase(context).getMessageID(messageServerID)
|
val messageID = DatabaseFactory.getLokiMessageDatabase(context).getMessageID(messageServerID)
|
||||||
var isDuplicate = false
|
var isDuplicate = false
|
||||||
if (messageID != null) {
|
if (messageID != null) {
|
||||||
isDuplicate = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageID) > 0
|
isDuplicate = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageID) >= 0
|
||||||
|| DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) > 0
|
|| DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) >= 0
|
||||||
}
|
}
|
||||||
if (isDuplicate) { return }
|
if (isDuplicate) { return }
|
||||||
if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return }
|
if (message.body.isEmpty() && message.attachments.isEmpty() && message.quote == null) { return }
|
||||||
|
@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.loki.database
|
|||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.util.Log
|
|
||||||
import org.thoughtcrime.securesms.database.Address
|
import org.thoughtcrime.securesms.database.Address
|
||||||
import org.thoughtcrime.securesms.database.Database
|
import org.thoughtcrime.securesms.database.Database
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
@ -34,7 +33,7 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa
|
|||||||
override fun getThreadID(hexEncodedPublicKey: String): Long {
|
override fun getThreadID(hexEncodedPublicKey: String): Long {
|
||||||
val address = Address.fromSerialized(hexEncodedPublicKey)
|
val address = Address.fromSerialized(hexEncodedPublicKey)
|
||||||
val recipient = Recipient.from(context, address, false)
|
val recipient = Recipient.from(context, address, false)
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getThreadID(messageID: Long): Long {
|
fun getThreadID(messageID: Long): Long {
|
||||||
|
@ -25,7 +25,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
|||||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.GroupType
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.GroupType
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext
|
||||||
import org.whispersystems.signalservice.loki.api.SnodeAPI
|
|
||||||
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupRatchet
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupRatchet
|
||||||
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupRatchetCollectionType
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupRatchetCollectionType
|
||||||
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupSenderKey
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupSenderKey
|
||||||
@ -82,7 +81,7 @@ object ClosedGroupsProtocol {
|
|||||||
// Add the group to the user's set of public keys to poll for
|
// Add the group to the user's set of public keys to poll for
|
||||||
DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
|
DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
||||||
insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID)
|
insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID)
|
||||||
// Notify the PN server
|
// Notify the PN server
|
||||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey)
|
||||||
@ -166,7 +165,7 @@ object ClosedGroupsProtocol {
|
|||||||
if (isUserLeaving) {
|
if (isUserLeaving) {
|
||||||
sskDatabase.removeClosedGroupPrivateKey(groupPublicKey)
|
sskDatabase.removeClosedGroupPrivateKey(groupPublicKey)
|
||||||
groupDB.setActive(groupID, false)
|
groupDB.setActive(groupID, false)
|
||||||
groupDB.remove(groupID, Address.fromSerialized(userPublicKey))
|
groupDB.removeMember(groupID, Address.fromSerialized(userPublicKey))
|
||||||
// Notify the PN server
|
// Notify the PN server
|
||||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
||||||
} else {
|
} else {
|
||||||
@ -230,7 +229,7 @@ object ClosedGroupsProtocol {
|
|||||||
}
|
}
|
||||||
// Notify the user
|
// Notify the user
|
||||||
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
||||||
insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID)
|
insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID)
|
||||||
deferred.resolve(Unit)
|
deferred.resolve(Unit)
|
||||||
}.start()
|
}.start()
|
||||||
@ -385,7 +384,7 @@ object ClosedGroupsProtocol {
|
|||||||
if (wasCurrentUserRemoved) {
|
if (wasCurrentUserRemoved) {
|
||||||
sskDatabase.removeClosedGroupPrivateKey(groupPublicKey)
|
sskDatabase.removeClosedGroupPrivateKey(groupPublicKey)
|
||||||
groupDB.setActive(groupID, false)
|
groupDB.setActive(groupID, false)
|
||||||
groupDB.remove(groupID, Address.fromSerialized(userPublicKey))
|
groupDB.removeMember(groupID, Address.fromSerialized(userPublicKey))
|
||||||
// Notify the PN server
|
// Notify the PN server
|
||||||
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey)
|
||||||
} else {
|
} else {
|
||||||
@ -510,7 +509,7 @@ object ClosedGroupsProtocol {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun leaveLegacyGroup(context: Context, recipient: Recipient): Boolean {
|
fun leaveLegacyGroup(context: Context, recipient: Recipient): Boolean {
|
||||||
if (!recipient.address.isClosedGroup) { return true }
|
if (!recipient.address.isClosedGroup) { return true }
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
|
||||||
val message = GroupUtil.createGroupLeaveMessage(context, recipient).orNull()
|
val message = GroupUtil.createGroupLeaveMessage(context, recipient).orNull()
|
||||||
if (threadID < 0 || message == null) { return false }
|
if (threadID < 0 || message == null) { return false }
|
||||||
MessageSender.send(context, message, threadID, false, null)
|
MessageSender.send(context, message, threadID, false, null)
|
||||||
@ -522,7 +521,7 @@ object ClosedGroupsProtocol {
|
|||||||
val groupDatabase = DatabaseFactory.getGroupDatabase(context)
|
val groupDatabase = DatabaseFactory.getGroupDatabase(context)
|
||||||
val groupID = recipient.address.toGroupString()
|
val groupID = recipient.address.toGroupString()
|
||||||
groupDatabase.setActive(groupID, false)
|
groupDatabase.setActive(groupID, false)
|
||||||
groupDatabase.remove(groupID, Address.fromSerialized(userPublicKey))
|
groupDatabase.removeMember(groupID, Address.fromSerialized(userPublicKey))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.loki.protocol
|
package org.thoughtcrime.securesms.loki.protocol
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.AsyncTask
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||||
@ -11,7 +10,6 @@ import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob
|
import org.thoughtcrime.securesms.jobs.CleanPreKeysJob
|
||||||
import org.thoughtcrime.securesms.loki.utilities.recipient
|
import org.thoughtcrime.securesms.loki.utilities.recipient
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage
|
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage
|
||||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
|
||||||
@ -28,7 +26,7 @@ object SessionManagementProtocol {
|
|||||||
val recipient = recipient(context, publicKey)
|
val recipient = recipient(context, publicKey)
|
||||||
if (recipient.isGroupRecipient) { return }
|
if (recipient.isGroupRecipient) { return }
|
||||||
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
|
||||||
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
|
val devices = lokiThreadDB.getSessionRestoreDevices(threadID)
|
||||||
for (device in devices) {
|
for (device in devices) {
|
||||||
val endSessionMessage = OutgoingEndSessionMessage(OutgoingTextMessage(recipient, "TERMINATE", 0, -1))
|
val endSessionMessage = OutgoingEndSessionMessage(OutgoingTextMessage(recipient, "TERMINATE", 0, -1))
|
||||||
@ -106,7 +104,7 @@ object SessionManagementProtocol {
|
|||||||
if (TextSecurePreferences.getRestorationTime(context) > errorTimestamp) {
|
if (TextSecurePreferences.getRestorationTime(context) > errorTimestamp) {
|
||||||
return ApplicationContext.getInstance(context).sendSessionRequestIfNeeded(publicKey)
|
return ApplicationContext.getInstance(context).sendSessionRequestIfNeeded(publicKey)
|
||||||
}
|
}
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(masterDeviceAsRecipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(masterDeviceAsRecipient)
|
||||||
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, publicKey)
|
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, publicKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,7 +27,7 @@ class SessionResetImplementation(private val context: Context) : SessionResetPro
|
|||||||
}
|
}
|
||||||
val smsDB = DatabaseFactory.getSmsDatabase(context)
|
val smsDB = DatabaseFactory.getSmsDatabase(context)
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
|
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient)
|
||||||
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
|
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
|
||||||
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
|
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
|
||||||
if (infoMessageID > -1) {
|
if (infoMessageID > -1) {
|
||||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.protocol.shelved
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData
|
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.NumberData
|
import org.thoughtcrime.securesms.contacts.ContactAccessor.NumberData
|
||||||
@ -132,6 +133,7 @@ object SyncMessagesProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@WorkerThread
|
||||||
fun handleOpenGroupSyncMessage(context: Context, content: SignalServiceContent, openGroups: List<PublicChat>) {
|
fun handleOpenGroupSyncMessage(context: Context, content: SignalServiceContent, openGroups: List<PublicChat>) {
|
||||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||||
val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey)
|
||||||
|
@ -6,7 +6,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
|
||||||
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
|
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(threadRecipient)
|
||||||
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
val publicKey = recipient.address.toString()
|
val publicKey = recipient.address.toString()
|
||||||
val displayName = if (publicChat != null) {
|
val displayName = if (publicChat != null) {
|
||||||
|
@ -1,28 +1,42 @@
|
|||||||
package org.thoughtcrime.securesms.loki.utilities
|
package org.thoughtcrime.securesms.loki.utilities
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import nl.komponents.kovenant.Promise
|
import androidx.annotation.WorkerThread
|
||||||
import nl.komponents.kovenant.then
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||||
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.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
import kotlin.jvm.Throws
|
||||||
|
|
||||||
|
//TODO Refactor so methods declare specific type of checked exceptions and not generalized Exception.
|
||||||
object OpenGroupUtilities {
|
object OpenGroupUtilities {
|
||||||
|
|
||||||
@JvmStatic fun addGroup(context: Context, url: String, channel: Long): Promise<PublicChat, Exception> {
|
private const val TAG = "OpenGroupUtilities"
|
||||||
// Check for an existing group
|
|
||||||
val groupID = PublicChat.getId(channel, url)
|
@JvmStatic
|
||||||
val threadID = GroupManager.getOpenGroupThreadID(groupID, context)
|
@WorkerThread
|
||||||
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
@Throws(Exception::class)
|
||||||
if (openGroup != null) { return Promise.of(openGroup) }
|
fun addGroup(context: Context, url: String, channel: Long): PublicChat {
|
||||||
// Add the new group
|
// Check for an existing group.
|
||||||
val application = ApplicationContext.getInstance(context)
|
val groupID = PublicChat.getId(channel, url)
|
||||||
val displayName = TextSecurePreferences.getProfileName(context)
|
val threadID = GroupManager.getOpenGroupThreadID(groupID, context)
|
||||||
val lokiPublicChatAPI = application.publicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.")
|
val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID)
|
||||||
return application.publicChatManager.addChat(url, channel).then { group ->
|
if (openGroup != null) return openGroup
|
||||||
|
|
||||||
|
// Add the new group.
|
||||||
|
val application = ApplicationContext.getInstance(context)
|
||||||
|
val displayName = TextSecurePreferences.getProfileName(context)
|
||||||
|
val lokiPublicChatAPI = application.publicChatAPI
|
||||||
|
?: throw IllegalStateException("LokiPublicChatAPI is not initialized.")
|
||||||
|
|
||||||
|
val group = application.publicChatManager.addChat(url, channel)
|
||||||
|
|
||||||
DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url)
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url)
|
||||||
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url)
|
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url)
|
||||||
lokiPublicChatAPI.getMessages(channel, url)
|
lokiPublicChatAPI.getMessages(channel, url)
|
||||||
@ -31,7 +45,34 @@ object OpenGroupUtilities {
|
|||||||
val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(context)
|
val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(context)
|
||||||
val profileUrl: String? = TextSecurePreferences.getProfilePictureURL(context)
|
val profileUrl: String? = TextSecurePreferences.getProfilePictureURL(context)
|
||||||
lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
||||||
group
|
return group
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Pulls the general public chat data from the server and updates related records.
|
||||||
|
* Fires [GroupInfoUpdatedEvent] on [EventBus] upon success.
|
||||||
|
*
|
||||||
|
* Consider using [org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker] for lazy approach.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@WorkerThread
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun updateGroupInfo(context: Context, url: String, channel: Long) {
|
||||||
|
val publicChatAPI = ApplicationContext.getInstance(context).publicChatAPI
|
||||||
|
?: throw IllegalStateException("Public chat API is not initialized!")
|
||||||
|
|
||||||
|
// Check if open group has a related DB record.
|
||||||
|
val groupId = GroupUtil.getEncodedOpenGroupId(PublicChat.getId(channel, url).toByteArray())
|
||||||
|
if (!DatabaseFactory.getGroupDatabase(context).hasGroup(groupId)) {
|
||||||
|
throw IllegalStateException("Attempt to update open group info for non-existent DB record: $groupId")
|
||||||
|
}
|
||||||
|
|
||||||
|
val info = publicChatAPI.getChannelInfo(channel, url).get()
|
||||||
|
|
||||||
|
publicChatAPI.updateProfileIfNeeded(channel, url, groupId, info, false)
|
||||||
|
|
||||||
|
EventBus.getDefault().post(GroupInfoUpdatedEvent(url, channel))
|
||||||
|
}
|
||||||
|
|
||||||
|
data class GroupInfoUpdatedEvent(val url: String, val channel: Long)
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.loki.views
|
package org.thoughtcrime.securesms.loki.views
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -10,11 +9,9 @@ import kotlinx.android.synthetic.main.view_conversation.view.profilePictureView
|
|||||||
import kotlinx.android.synthetic.main.view_user.view.*
|
import kotlinx.android.synthetic.main.view_user.view.*
|
||||||
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.groups.GroupManager
|
|
||||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities
|
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager
|
|
||||||
|
|
||||||
class UserView : LinearLayout {
|
class UserView : LinearLayout {
|
||||||
var openGroupThreadID: Long = -1 // FIXME: This is a bit ugly
|
var openGroupThreadID: Long = -1 // FIXME: This is a bit ugly
|
||||||
@ -63,7 +60,7 @@ class UserView : LinearLayout {
|
|||||||
return result ?: publicKey
|
return result ?: publicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(user)
|
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(user)
|
||||||
MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded(threadID, context) // FIXME: This is a bad place to do this
|
MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded(threadID, context) // FIXME: This is a bad place to do this
|
||||||
val address = user.address.serialize()
|
val address = user.address.serialize()
|
||||||
profilePictureView.glide = glide
|
profilePictureView.glide = glide
|
||||||
|
@ -121,6 +121,10 @@ public class Recipient implements RecipientModifiedListener {
|
|||||||
if (recipient.isPresent()) consumer.accept(recipient.get());
|
if (recipient.isPresent()) consumer.accept(recipient.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean removeCached(@NonNull Address address) {
|
||||||
|
return provider.removeCached(address);
|
||||||
|
}
|
||||||
|
|
||||||
Recipient(@NonNull Context context,
|
Recipient(@NonNull Context context,
|
||||||
@NonNull Address address,
|
@NonNull Address address,
|
||||||
@Nullable Recipient stale,
|
@Nullable Recipient stale,
|
||||||
|
@ -79,6 +79,10 @@ class RecipientProvider {
|
|||||||
return Optional.fromNullable(recipientCache.get(address));
|
return Optional.fromNullable(recipientCache.get(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean removeCached(@NonNull Address address) {
|
||||||
|
return recipientCache.remove(address);
|
||||||
|
}
|
||||||
|
|
||||||
private @NonNull Optional<RecipientDetails> createPrefetchedRecipientDetails(@NonNull Context context, @NonNull Address address,
|
private @NonNull Optional<RecipientDetails> createPrefetchedRecipientDetails(@NonNull Context context, @NonNull Address address,
|
||||||
@NonNull Optional<RecipientSettings> settings,
|
@NonNull Optional<RecipientSettings> settings,
|
||||||
@NonNull Optional<GroupRecord> groupRecord)
|
@NonNull Optional<GroupRecord> groupRecord)
|
||||||
@ -230,6 +234,10 @@ class RecipientProvider {
|
|||||||
cache.put(address, recipient);
|
cache.put(address, recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized boolean remove(Address address) {
|
||||||
|
return cache.remove(address) != null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -69,7 +69,7 @@ public class MessageSender {
|
|||||||
long allocatedThreadId;
|
long allocatedThreadId;
|
||||||
|
|
||||||
if (threadId == -1) {
|
if (threadId == -1) {
|
||||||
allocatedThreadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
allocatedThreadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
} else {
|
} else {
|
||||||
allocatedThreadId = threadId;
|
allocatedThreadId = threadId;
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ public class MessageSender {
|
|||||||
long allocatedThreadId;
|
long allocatedThreadId;
|
||||||
|
|
||||||
if (threadId == -1) {
|
if (threadId == -1) {
|
||||||
allocatedThreadId = threadDatabase.getThreadIdFor(message.getRecipient(), message.getDistributionType());
|
allocatedThreadId = threadDatabase.getOrCreateThreadIdFor(message.getRecipient(), message.getDistributionType());
|
||||||
} else {
|
} else {
|
||||||
allocatedThreadId = threadId;
|
allocatedThreadId = threadId;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ public class CommunicationActions {
|
|||||||
new AsyncTask<Void, Void, Long>() {
|
new AsyncTask<Void, Void, Long>() {
|
||||||
@Override
|
@Override
|
||||||
protected Long doInBackground(Void... voids) {
|
protected Long doInBackground(Void... voids) {
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
return DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,7 +88,7 @@ public class IdentityUtil {
|
|||||||
smsDatabase.insertMessageInbox(incoming);
|
smsDatabase.insertMessageInbox(incoming);
|
||||||
} else {
|
} else {
|
||||||
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(group.getGroupId(), false)), true);
|
Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(group.getGroupId(), false)), true);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(groupRecipient);
|
||||||
OutgoingTextMessage outgoing ;
|
OutgoingTextMessage outgoing ;
|
||||||
|
|
||||||
if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient);
|
if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient);
|
||||||
@ -112,7 +112,7 @@ public class IdentityUtil {
|
|||||||
if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient);
|
if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient);
|
||||||
else outgoing = new OutgoingIdentityDefaultMessage(recipient);
|
else outgoing = new OutgoingIdentityDefaultMessage(recipient);
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||||
|
|
||||||
Log.i(TAG, "Inserting verified outbox...");
|
Log.i(TAG, "Inserting verified outbox...");
|
||||||
DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null);
|
DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null);
|
||||||
|
Loading…
Reference in New Issue
Block a user