mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-26 01:37:43 +00:00
Open group avatars.
This commit is contained in:
parent
2c173a963d
commit
70815e61d0
@ -213,6 +213,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
|
|||||||
import org.thoughtcrime.securesms.util.Dialogs;
|
import org.thoughtcrime.securesms.util.Dialogs;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
@ -227,6 +228,7 @@ import org.thoughtcrime.securesms.util.views.Stub;
|
|||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat;
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat;
|
||||||
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI;
|
||||||
import org.whispersystems.signalservice.loki.protocol.mentions.Mention;
|
import org.whispersystems.signalservice.loki.protocol.mentions.Mention;
|
||||||
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager;
|
||||||
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol;
|
||||||
@ -457,7 +459,18 @@ 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) {
|
||||||
ApplicationContext.getInstance(this).getPublicChatAPI().getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(displayName -> {
|
PublicChatAPI publicChatAPI = ApplicationContext.getInstance(this).getPublicChatAPI();
|
||||||
|
publicChatAPI.getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(info -> {
|
||||||
|
String groupId = GroupUtil.getEncodedOpenGroupId(publicChat.getId().getBytes());
|
||||||
|
|
||||||
|
publicChatAPI.updateOpenGroupProfileIfNeeded(
|
||||||
|
publicChat.getChannel(),
|
||||||
|
publicChat.getServer(),
|
||||||
|
groupId,
|
||||||
|
info,
|
||||||
|
DatabaseFactory.getGroupDatabase(this),
|
||||||
|
false);
|
||||||
|
|
||||||
runOnUiThread(ConversationActivity.this::updateSubtitleTextView);
|
runOnUiThread(ConversationActivity.this::updateSubtitleTextView);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.util.GroupUtil;
|
|||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||||
|
import org.whispersystems.signalservice.loki.database.LokiGroupDatabaseProtocol;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -29,7 +30,7 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GroupDatabase extends Database {
|
public class GroupDatabase extends Database implements LokiGroupDatabaseProtocol {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static final String TAG = GroupDatabase.class.getSimpleName();
|
private static final String TAG = GroupDatabase.class.getSimpleName();
|
||||||
@ -240,6 +241,7 @@ public class GroupDatabase extends Database {
|
|||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateTitle(String groupId, String title) {
|
public void updateTitle(String groupId, String title) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(TITLE, title);
|
contentValues.put(TITLE, title);
|
||||||
@ -254,6 +256,7 @@ public class GroupDatabase extends Database {
|
|||||||
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
|
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateAvatar(String groupId, byte[] avatar) {
|
public void updateAvatar(String groupId, byte[] avatar) {
|
||||||
long avatarId;
|
long avatarId;
|
||||||
|
|
||||||
@ -271,6 +274,15 @@ public class GroupDatabase extends Database {
|
|||||||
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> recipient.setGroupAvatarId(avatarId == 0 ? null : avatarId));
|
Recipient.applyCached(Address.fromSerialized(groupId), recipient -> recipient.setGroupAvatarId(avatarId == 0 ? null : avatarId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasAvatar(String groupId) {
|
||||||
|
try (Cursor cursor = databaseHelper.getReadableDatabase().rawQuery(
|
||||||
|
"SELECT COUNT("+ID+") FROM "+TABLE_NAME+" WHERE "+GROUP_ID+" == ? AND "+AVATAR+" NOT NULL",
|
||||||
|
new String[]{groupId})) {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor.getInt(0) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateMembers(String groupId, List<Address> members) {
|
public void updateMembers(String groupId, List<Address> members) {
|
||||||
Collections.sort(members);
|
Collections.sort(members);
|
||||||
|
|
||||||
|
@ -91,8 +91,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int lokiV12 = 33;
|
private static final int lokiV12 = 33;
|
||||||
private static final int lokiV13 = 34;
|
private static final int lokiV13 = 34;
|
||||||
private static final int lokiV14_BACKUP_FILES = 35;
|
private static final int lokiV14_BACKUP_FILES = 35;
|
||||||
|
private static final int lokiV15_OPEN_GROUP_AVATARS = 36;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = lokiV14_BACKUP_FILES; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
private static final int DATABASE_VERSION = lokiV15_OPEN_GROUP_AVATARS; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -154,6 +155,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampTableCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampTableCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateOpenGroupPublicKeyTableCommand());
|
db.execSQL(LokiAPIDatabase.getCreateOpenGroupPublicKeyTableCommand());
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateOpenGroupAvatarCacheCommand());
|
||||||
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
|
||||||
@ -626,6 +628,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < lokiV15_OPEN_GROUP_AVATARS) {
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateOpenGroupAvatarCacheCommand());
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.api
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.ContentObserver
|
import android.database.ContentObserver
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
@ -10,8 +11,10 @@ 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
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager
|
import org.thoughtcrime.securesms.groups.GroupManager
|
||||||
|
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatInfo
|
||||||
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
import org.whispersystems.signalservice.loki.api.opengroups.PublicChat
|
||||||
|
|
||||||
class PublicChatManager(private val context: Context) {
|
class PublicChatManager(private val context: Context) {
|
||||||
@ -56,7 +59,8 @@ class PublicChatManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun addChat(server: String, channel: Long): Promise<PublicChat, Exception> {
|
public fun addChat(server: String, channel: Long): Promise<PublicChat, Exception> {
|
||||||
val groupChatAPI = ApplicationContext.getInstance(context).publicChatAPI ?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!"))
|
val groupChatAPI = ApplicationContext.getInstance(context).publicChatAPI
|
||||||
|
?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!"))
|
||||||
return groupChatAPI.getAuthToken(server).bind {
|
return groupChatAPI.getAuthToken(server).bind {
|
||||||
groupChatAPI.getChannelInfo(channel, server)
|
groupChatAPI.getChannelInfo(channel, server)
|
||||||
}.map {
|
}.map {
|
||||||
@ -64,12 +68,20 @@ class PublicChatManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun addChat(server: String, channel: Long, name: String): PublicChat {
|
public fun addChat(server: String, channel: Long, info: LokiPublicChatInfo): PublicChat {
|
||||||
val chat = PublicChat(channel, server, name, true)
|
val chat = PublicChat(channel, server, info.displayName, true)
|
||||||
var threadID = GroupManager.getOpenGroupThreadID(chat.id, context)
|
var threadID = GroupManager.getOpenGroupThreadID(chat.id, context)
|
||||||
|
var avatar: 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) {
|
||||||
val result = GroupManager.createOpenGroup(chat.id, context, null, chat.displayName)
|
if (!info.profilePictureURL.isEmpty()) {
|
||||||
|
val avatarBytes = ApplicationContext.getInstance(context).publicChatAPI
|
||||||
|
?.downloadOpenGroupAvatar(server, info.profilePictureURL)
|
||||||
|
avatar = BitmapUtil.fromByteArray(avatarBytes)
|
||||||
|
}
|
||||||
|
// FIXME: If updating the avatar here, there can be a memory issue if a public chat message contains some attachment.
|
||||||
|
// The error message is "Failed to execute task in background: Canvas: trying to use a recycled bitmap android.graphics.Bitmap"
|
||||||
|
val result = GroupManager.createOpenGroup(chat.id, context, avatar, chat.displayName)
|
||||||
threadID = result.threadId
|
threadID = result.threadId
|
||||||
}
|
}
|
||||||
DatabaseFactory.getLokiThreadDatabase(context).setPublicChat(chat, threadID)
|
DatabaseFactory.getLokiThreadDatabase(context).setPublicChat(chat, threadID)
|
||||||
|
@ -71,6 +71,10 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
// Open group public keys
|
// Open group public keys
|
||||||
private val openGroupPublicKeyTable = "open_group_public_keys"
|
private val openGroupPublicKeyTable = "open_group_public_keys"
|
||||||
@JvmStatic val createOpenGroupPublicKeyTableCommand = "CREATE TABLE $openGroupPublicKeyTable ($server STRING PRIMARY KEY, $publicKey INTEGER DEFAULT 0);"
|
@JvmStatic val createOpenGroupPublicKeyTableCommand = "CREATE TABLE $openGroupPublicKeyTable ($server STRING PRIMARY KEY, $publicKey INTEGER DEFAULT 0);"
|
||||||
|
// Open group avatar cache
|
||||||
|
private val openGroupAvatarCacheTable = "open_group_avatar_cache"
|
||||||
|
private val openGroupAvatar = "open_group_avatar"
|
||||||
|
@JvmStatic val createOpenGroupAvatarCacheCommand = "CREATE TABLE $openGroupAvatarCacheTable ($publicChatID STRING PRIMARY KEY, $openGroupAvatar TEXT NULLABLE DEFAULT NULL);"
|
||||||
|
|
||||||
// region Deprecated
|
// region Deprecated
|
||||||
private val deviceLinkCache = "loki_pairing_authorisation_cache"
|
private val deviceLinkCache = "loki_pairing_authorisation_cache"
|
||||||
@ -343,6 +347,21 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
database.insertOrUpdate(openGroupPublicKeyTable, row, "${LokiAPIDatabase.server} = ?", wrap(server))
|
database.insertOrUpdate(openGroupPublicKeyTable, row, "${LokiAPIDatabase.server} = ?", wrap(server))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getOpenGroupAvatarURL(group: Long, server: String): String? {
|
||||||
|
val database = databaseHelper.readableDatabase
|
||||||
|
val index = "$server.$group"
|
||||||
|
return database.get(openGroupAvatarCacheTable, "$publicChatID = ?", wrap(index)) { cursor ->
|
||||||
|
cursor.getString(openGroupAvatar)
|
||||||
|
}?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setOpenGroupAvatarURL(url: String, group: Long, server: String) {
|
||||||
|
val database = databaseHelper.writableDatabase
|
||||||
|
val index = "$server.$group"
|
||||||
|
val row = wrap(mapOf(publicChatID to index, openGroupAvatar to url))
|
||||||
|
database.insertOrUpdate(openGroupAvatarCacheTable, row, "$publicChatID = ?", wrap(index))
|
||||||
|
}
|
||||||
|
|
||||||
// region Deprecated
|
// region Deprecated
|
||||||
override fun getDeviceLinks(publicKey: String): Set<DeviceLink> {
|
override fun getDeviceLinks(publicKey: String): Set<DeviceLink> {
|
||||||
return setOf()
|
return setOf()
|
||||||
|
@ -68,12 +68,21 @@ class ProfilePictureView : RelativeLayout {
|
|||||||
return result ?: publicKey
|
return result ?: publicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun isOpenGroupWithAvatar(recipient: Recipient): Boolean {
|
||||||
|
return recipient.isOpenGroupRecipient &&
|
||||||
|
DatabaseFactory.getGroupDatabase(context).hasAvatar(recipient.address.toString())
|
||||||
|
}
|
||||||
if (recipient.isGroupRecipient) {
|
if (recipient.isGroupRecipient) {
|
||||||
if ("Session Public Chat" == recipient.name) {
|
if ("Session Public Chat" == recipient.name) {
|
||||||
publicKey = ""
|
publicKey = ""
|
||||||
displayName = ""
|
displayName = ""
|
||||||
additionalPublicKey = null
|
additionalPublicKey = null
|
||||||
isRSSFeed = true
|
isRSSFeed = true
|
||||||
|
} else if (isOpenGroupWithAvatar(recipient)) {
|
||||||
|
publicKey = recipient.address.toString()
|
||||||
|
displayName = getUserDisplayName(publicKey)
|
||||||
|
additionalPublicKey = null
|
||||||
|
isRSSFeed = false
|
||||||
} else {
|
} else {
|
||||||
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toMutableList() ?: mutableListOf()
|
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toMutableList() ?: mutableListOf()
|
||||||
users.remove(TextSecurePreferences.getLocalNumber(context))
|
users.remove(TextSecurePreferences.getLocalNumber(context))
|
||||||
|
@ -419,6 +419,10 @@ public class Recipient implements RecipientModifiedListener {
|
|||||||
return address.isGroup();
|
return address.isGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOpenGroupRecipient() {
|
||||||
|
return address.isOpenGroup();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMmsGroupRecipient() {
|
public boolean isMmsGroupRecipient() {
|
||||||
return address.isMmsGroup();
|
return address.isMmsGroup();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user