Merge branch 'adb/use-spotless' of https://github.com/deltachat/deltachat-android into adb/use-spotless

This commit is contained in:
adbenitez
2026-03-11 19:26:52 +01:00
18 changed files with 2530 additions and 2184 deletions
+90 -69
View File
@@ -4,85 +4,106 @@ import org.thoughtcrime.securesms.util.Util;
public class DcChat {
public static final int DC_CHAT_TYPE_UNDEFINED = 0;
public static final int DC_CHAT_TYPE_SINGLE = 100;
public static final int DC_CHAT_TYPE_GROUP = 120;
public static final int DC_CHAT_TYPE_MAILINGLIST = 140;
public static final int DC_CHAT_TYPE_OUT_BROADCAST = 160;
public static final int DC_CHAT_TYPE_IN_BROADCAST = 165;
public static final int DC_CHAT_TYPE_UNDEFINED = 0;
public static final int DC_CHAT_TYPE_SINGLE = 100;
public static final int DC_CHAT_TYPE_GROUP = 120;
public static final int DC_CHAT_TYPE_MAILINGLIST = 140;
public static final int DC_CHAT_TYPE_OUT_BROADCAST = 160;
public static final int DC_CHAT_TYPE_IN_BROADCAST = 165;
public static final int DC_CHAT_NO_CHAT = 0;
public final static int DC_CHAT_ID_ARCHIVED_LINK = 6;
public final static int DC_CHAT_ID_ALLDONE_HINT = 7;
public final static int DC_CHAT_ID_LAST_SPECIAL = 9;
public static final int DC_CHAT_NO_CHAT = 0;
public static final int DC_CHAT_ID_ARCHIVED_LINK = 6;
public static final int DC_CHAT_ID_ALLDONE_HINT = 7;
public static final int DC_CHAT_ID_LAST_SPECIAL = 9;
public final static int DC_CHAT_VISIBILITY_NORMAL = 0;
public final static int DC_CHAT_VISIBILITY_ARCHIVED = 1;
public final static int DC_CHAT_VISIBILITY_PINNED = 2;
public static final int DC_CHAT_VISIBILITY_NORMAL = 0;
public static final int DC_CHAT_VISIBILITY_ARCHIVED = 1;
public static final int DC_CHAT_VISIBILITY_PINNED = 2;
private int accountId;
private int accountId;
public DcChat(int accountId, long chatCPtr) {
this.accountId = accountId;
this.chatCPtr = chatCPtr;
public DcChat(int accountId, long chatCPtr) {
this.accountId = accountId;
this.chatCPtr = chatCPtr;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
unrefChatCPtr();
chatCPtr = 0;
}
public int getAccountId() {
return accountId;
}
public native int getId();
public native int getType();
public native int getVisibility();
public native String getName();
public native String getMailinglistAddr();
public native String getProfileImage();
public native int getColor();
public native boolean isEncrypted();
public native boolean isUnpromoted();
public native boolean isSelfTalk();
public native boolean isDeviceTalk();
public native boolean canSend();
public native boolean isSendingLocations();
public native boolean isMuted();
public native boolean isContactRequest();
// aliases and higher-level tools
public boolean isMultiUser() {
int type = getType();
return type != DC_CHAT_TYPE_SINGLE;
}
public boolean shallLeaveBeforeDelete(DcContext dcContext) {
if (isInBroadcast()) {
final int[] members = dcContext.getChatContacts(getId());
return Util.contains(members, DcContact.DC_CONTACT_ID_SELF);
} else if (isMultiUser() && isEncrypted() && canSend() && !isOutBroadcast()) {
return true;
}
return false;
}
@Override protected void finalize() throws Throwable {
super.finalize();
unrefChatCPtr();
chatCPtr = 0;
}
public boolean isMailingList() {
return getType() == DC_CHAT_TYPE_MAILINGLIST;
}
public int getAccountId () { return accountId; }
public native int getId ();
public native int getType ();
public native int getVisibility ();
public native String getName ();
public native String getMailinglistAddr();
public native String getProfileImage ();
public native int getColor ();
public native boolean isEncrypted ();
public native boolean isUnpromoted ();
public native boolean isSelfTalk ();
public native boolean isDeviceTalk ();
public native boolean canSend ();
public native boolean isSendingLocations();
public native boolean isMuted ();
public native boolean isContactRequest ();
public boolean isInBroadcast() {
return getType() == DC_CHAT_TYPE_IN_BROADCAST;
}
public boolean isOutBroadcast() {
return getType() == DC_CHAT_TYPE_OUT_BROADCAST;
}
// aliases and higher-level tools
// working with raw c-data
public boolean isMultiUser() {
int type = getType();
return type != DC_CHAT_TYPE_SINGLE;
}
private long chatCPtr; // CAVE: the name is referenced in the JNI
public boolean shallLeaveBeforeDelete(DcContext dcContext) {
if (isInBroadcast()) {
final int[] members = dcContext.getChatContacts(getId());
return Util.contains(members, DcContact.DC_CONTACT_ID_SELF);
} else if (isMultiUser() && isEncrypted() && canSend() && !isOutBroadcast()) {
return true;
}
return false;
}
public boolean isMailingList() {
return getType() == DC_CHAT_TYPE_MAILINGLIST;
}
public boolean isInBroadcast() {
return getType() == DC_CHAT_TYPE_IN_BROADCAST;
}
public boolean isOutBroadcast() {
return getType() == DC_CHAT_TYPE_OUT_BROADCAST;
}
// working with raw c-data
private long chatCPtr; // CAVE: the name is referenced in the JNI
private native void unrefChatCPtr();
public long getChatCPtr () { return chatCPtr; }
private native void unrefChatCPtr();
public long getChatCPtr() {
return chatCPtr;
}
}
+68 -53
View File
@@ -2,67 +2,82 @@ package com.b44t.messenger;
public class DcContact {
public final static int DC_CONTACT_ID_SELF = 1;
public final static int DC_CONTACT_ID_INFO = 2;
public final static int DC_CONTACT_ID_DEVICE = 5;
public final static int DC_CONTACT_ID_LAST_SPECIAL = 9;
public final static int DC_CONTACT_ID_NEW_CLASSIC_CONTACT= -1; // used by the UI, not valid to the core
public final static int DC_CONTACT_ID_NEW_GROUP = -2; // - " -
public final static int DC_CONTACT_ID_ADD_MEMBER = -3; // - " -
public final static int DC_CONTACT_ID_QR_INVITE = -4; // - " -
public final static int DC_CONTACT_ID_NEW_BROADCAST = -5; // - " -
public final static int DC_CONTACT_ID_ADD_ACCOUNT = -6; // - " -
public final static int DC_CONTACT_ID_NEW_UNENCRYPTED_GROUP = -7; // - " -
public static final int DC_CONTACT_ID_SELF = 1;
public static final int DC_CONTACT_ID_INFO = 2;
public static final int DC_CONTACT_ID_DEVICE = 5;
public static final int DC_CONTACT_ID_LAST_SPECIAL = 9;
public static final int DC_CONTACT_ID_NEW_CLASSIC_CONTACT =
-1; // used by the UI, not valid to the core
public static final int DC_CONTACT_ID_NEW_GROUP = -2; // - " -
public static final int DC_CONTACT_ID_ADD_MEMBER = -3; // - " -
public static final int DC_CONTACT_ID_QR_INVITE = -4; // - " -
public static final int DC_CONTACT_ID_NEW_BROADCAST = -5; // - " -
public static final int DC_CONTACT_ID_ADD_ACCOUNT = -6; // - " -
public static final int DC_CONTACT_ID_NEW_UNENCRYPTED_GROUP = -7; // - " -
public DcContact(long contactCPtr) {
this.contactCPtr = contactCPtr;
public DcContact(long contactCPtr) {
this.contactCPtr = contactCPtr;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
unrefContactCPtr();
contactCPtr = 0;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof DcContact)) {
return false;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
unrefContactCPtr();
contactCPtr = 0;
}
DcContact that = (DcContact) other;
return this.getId() == that.getId();
}
@Override
public int hashCode() {
return this.getId();
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof DcContact)) {
return false;
}
@Override
public String toString() {
return getAddr();
}
DcContact that = (DcContact) other;
return this.getId()==that.getId();
}
public native int getId();
@Override
public int hashCode() {
return this.getId();
}
public native String getName();
@Override
public String toString() {
return getAddr();
}
public native String getAuthName();
public native int getId ();
public native String getName ();
public native String getAuthName ();
public native String getDisplayName ();
public native String getAddr ();
public native String getProfileImage();
public native int getColor ();
public native String getStatus ();
public native long getLastSeen ();
public native boolean wasSeenRecently();
public native boolean isBlocked ();
public native boolean isVerified ();
public native boolean isKeyContact ();
public native int getVerifierId ();
public native boolean isBot ();
public native String getDisplayName();
// working with raw c-data
private long contactCPtr; // CAVE: the name is referenced in the JNI
private native void unrefContactCPtr();
public native String getAddr();
public native String getProfileImage();
public native int getColor();
public native String getStatus();
public native long getLastSeen();
public native boolean wasSeenRecently();
public native boolean isBlocked();
public native boolean isVerified();
public native boolean isKeyContact();
public native int getVerifierId();
public native boolean isBot();
// working with raw c-data
private long contactCPtr; // CAVE: the name is referenced in the JNI
private native void unrefContactCPtr();
}
+360 -237
View File
@@ -2,273 +2,396 @@ package com.b44t.messenger;
public class DcContext {
public final static int DC_EVENT_INFO = 100;
public final static int DC_EVENT_WARNING = 300;
public final static int DC_EVENT_ERROR = 400;
public final static int DC_EVENT_ERROR_SELF_NOT_IN_GROUP = 410;
public final static int DC_EVENT_MSGS_CHANGED = 2000;
public final static int DC_EVENT_REACTIONS_CHANGED = 2001;
public final static int DC_EVENT_INCOMING_REACTION = 2002;
public final static int DC_EVENT_INCOMING_WEBXDC_NOTIFY = 2003;
public final static int DC_EVENT_INCOMING_MSG = 2005;
public final static int DC_EVENT_MSGS_NOTICED = 2008;
public final static int DC_EVENT_MSG_DELIVERED = 2010;
public final static int DC_EVENT_MSG_FAILED = 2012;
public final static int DC_EVENT_MSG_READ = 2015;
public final static int DC_EVENT_MSG_DELETED = 2016;
public final static int DC_EVENT_CHAT_MODIFIED = 2020;
public final static int DC_EVENT_CHAT_EPHEMERAL_TIMER_MODIFIED = 2021;
public final static int DC_EVENT_CHAT_DELETED = 2023;
public final static int DC_EVENT_CONTACTS_CHANGED = 2030;
public final static int DC_EVENT_LOCATION_CHANGED = 2035;
public final static int DC_EVENT_CONFIGURE_PROGRESS = 2041;
public final static int DC_EVENT_IMEX_PROGRESS = 2051;
public final static int DC_EVENT_IMEX_FILE_WRITTEN = 2052;
public final static int DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060;
public final static int DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061;
public final static int DC_EVENT_CONNECTIVITY_CHANGED = 2100;
public final static int DC_EVENT_SELFAVATAR_CHANGED = 2110;
public final static int DC_EVENT_WEBXDC_STATUS_UPDATE = 2120;
public final static int DC_EVENT_WEBXDC_INSTANCE_DELETED = 2121;
public final static int DC_EVENT_WEBXDC_REALTIME_DATA = 2150;
public final static int DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE = 2200;
public final static int DC_EVENT_INCOMING_CALL = 2550;
public final static int DC_EVENT_INCOMING_CALL_ACCEPTED = 2560;
public final static int DC_EVENT_OUTGOING_CALL_ACCEPTED = 2570;
public final static int DC_EVENT_CALL_ENDED = 2580;
public final static int DC_EVENT_TRANSPORTS_MODIFIED = 2600;
public static final int DC_EVENT_INFO = 100;
public static final int DC_EVENT_WARNING = 300;
public static final int DC_EVENT_ERROR = 400;
public static final int DC_EVENT_ERROR_SELF_NOT_IN_GROUP = 410;
public static final int DC_EVENT_MSGS_CHANGED = 2000;
public static final int DC_EVENT_REACTIONS_CHANGED = 2001;
public static final int DC_EVENT_INCOMING_REACTION = 2002;
public static final int DC_EVENT_INCOMING_WEBXDC_NOTIFY = 2003;
public static final int DC_EVENT_INCOMING_MSG = 2005;
public static final int DC_EVENT_MSGS_NOTICED = 2008;
public static final int DC_EVENT_MSG_DELIVERED = 2010;
public static final int DC_EVENT_MSG_FAILED = 2012;
public static final int DC_EVENT_MSG_READ = 2015;
public static final int DC_EVENT_MSG_DELETED = 2016;
public static final int DC_EVENT_CHAT_MODIFIED = 2020;
public static final int DC_EVENT_CHAT_EPHEMERAL_TIMER_MODIFIED = 2021;
public static final int DC_EVENT_CHAT_DELETED = 2023;
public static final int DC_EVENT_CONTACTS_CHANGED = 2030;
public static final int DC_EVENT_LOCATION_CHANGED = 2035;
public static final int DC_EVENT_CONFIGURE_PROGRESS = 2041;
public static final int DC_EVENT_IMEX_PROGRESS = 2051;
public static final int DC_EVENT_IMEX_FILE_WRITTEN = 2052;
public static final int DC_EVENT_SECUREJOIN_INVITER_PROGRESS = 2060;
public static final int DC_EVENT_SECUREJOIN_JOINER_PROGRESS = 2061;
public static final int DC_EVENT_CONNECTIVITY_CHANGED = 2100;
public static final int DC_EVENT_SELFAVATAR_CHANGED = 2110;
public static final int DC_EVENT_WEBXDC_STATUS_UPDATE = 2120;
public static final int DC_EVENT_WEBXDC_INSTANCE_DELETED = 2121;
public static final int DC_EVENT_WEBXDC_REALTIME_DATA = 2150;
public static final int DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE = 2200;
public static final int DC_EVENT_INCOMING_CALL = 2550;
public static final int DC_EVENT_INCOMING_CALL_ACCEPTED = 2560;
public static final int DC_EVENT_OUTGOING_CALL_ACCEPTED = 2570;
public static final int DC_EVENT_CALL_ENDED = 2580;
public static final int DC_EVENT_TRANSPORTS_MODIFIED = 2600;
public final static int DC_IMEX_EXPORT_SELF_KEYS = 1;
public final static int DC_IMEX_IMPORT_SELF_KEYS = 2;
public final static int DC_IMEX_EXPORT_BACKUP = 11;
public final static int DC_IMEX_IMPORT_BACKUP = 12;
public static final int DC_IMEX_EXPORT_SELF_KEYS = 1;
public static final int DC_IMEX_IMPORT_SELF_KEYS = 2;
public static final int DC_IMEX_EXPORT_BACKUP = 11;
public static final int DC_IMEX_IMPORT_BACKUP = 12;
public final static int DC_GCL_VERIFIED_ONLY = 1;
public final static int DC_GCL_ADD_SELF = 2;
public final static int DC_GCL_ADDRESS = 0x04;
public final static int DC_GCL_ARCHIVED_ONLY = 0x01;
public final static int DC_GCL_NO_SPECIALS = 0x02;
public final static int DC_GCL_ADD_ALLDONE_HINT = 0x04;
public final static int DC_GCL_FOR_FORWARDING = 0x08;
public static final int DC_GCL_VERIFIED_ONLY = 1;
public static final int DC_GCL_ADD_SELF = 2;
public static final int DC_GCL_ADDRESS = 0x04;
public static final int DC_GCL_ARCHIVED_ONLY = 0x01;
public static final int DC_GCL_NO_SPECIALS = 0x02;
public static final int DC_GCL_ADD_ALLDONE_HINT = 0x04;
public static final int DC_GCL_FOR_FORWARDING = 0x08;
public final static int DC_GCM_ADDDAYMARKER = 0x01;
public static final int DC_GCM_ADDDAYMARKER = 0x01;
public final static int DC_QR_ASK_VERIFYCONTACT = 200;
public final static int DC_QR_ASK_VERIFYGROUP = 202;
public final static int DC_QR_ASK_JOIN_BROADCAST= 204;
public final static int DC_QR_FPR_OK = 210;
public final static int DC_QR_FPR_MISMATCH = 220;
public final static int DC_QR_FPR_WITHOUT_ADDR = 230;
public final static int DC_QR_ACCOUNT = 250;
public final static int DC_QR_BACKUP2 = 252;
public final static int DC_QR_BACKUP_TOO_NEW = 255;
public final static int DC_QR_WEBRTC = 260;
public final static int DC_QR_PROXY = 271;
public final static int DC_QR_ADDR = 320;
public final static int DC_QR_TEXT = 330;
public final static int DC_QR_URL = 332;
public final static int DC_QR_ERROR = 400;
public final static int DC_QR_WITHDRAW_VERIFYCONTACT = 500;
public final static int DC_QR_WITHDRAW_VERIFYGROUP = 502;
public final static int DC_QR_WITHDRAW_JOINBROADCAST = 504;
public final static int DC_QR_REVIVE_VERIFYCONTACT = 510;
public final static int DC_QR_REVIVE_VERIFYGROUP = 512;
public final static int DC_QR_REVIVE_JOINBROADCAST = 514;
public final static int DC_QR_LOGIN = 520;
public static final int DC_QR_ASK_VERIFYCONTACT = 200;
public static final int DC_QR_ASK_VERIFYGROUP = 202;
public static final int DC_QR_ASK_JOIN_BROADCAST = 204;
public static final int DC_QR_FPR_OK = 210;
public static final int DC_QR_FPR_MISMATCH = 220;
public static final int DC_QR_FPR_WITHOUT_ADDR = 230;
public static final int DC_QR_ACCOUNT = 250;
public static final int DC_QR_BACKUP2 = 252;
public static final int DC_QR_BACKUP_TOO_NEW = 255;
public static final int DC_QR_WEBRTC = 260;
public static final int DC_QR_PROXY = 271;
public static final int DC_QR_ADDR = 320;
public static final int DC_QR_TEXT = 330;
public static final int DC_QR_URL = 332;
public static final int DC_QR_ERROR = 400;
public static final int DC_QR_WITHDRAW_VERIFYCONTACT = 500;
public static final int DC_QR_WITHDRAW_VERIFYGROUP = 502;
public static final int DC_QR_WITHDRAW_JOINBROADCAST = 504;
public static final int DC_QR_REVIVE_VERIFYCONTACT = 510;
public static final int DC_QR_REVIVE_VERIFYGROUP = 512;
public static final int DC_QR_REVIVE_JOINBROADCAST = 514;
public static final int DC_QR_LOGIN = 520;
public final static int DC_SOCKET_AUTO = 0;
public final static int DC_SOCKET_SSL = 1;
public final static int DC_SOCKET_STARTTLS = 2;
public final static int DC_SOCKET_PLAIN = 3;
public static final int DC_SOCKET_AUTO = 0;
public static final int DC_SOCKET_SSL = 1;
public static final int DC_SOCKET_STARTTLS = 2;
public static final int DC_SOCKET_PLAIN = 3;
public final static int DC_SHOW_EMAILS_OFF = 0;
public final static int DC_SHOW_EMAILS_ACCEPTED_CONTACTS = 1;
public final static int DC_SHOW_EMAILS_ALL = 2;
public static final int DC_SHOW_EMAILS_OFF = 0;
public static final int DC_SHOW_EMAILS_ACCEPTED_CONTACTS = 1;
public static final int DC_SHOW_EMAILS_ALL = 2;
public final static int DC_MEDIA_QUALITY_BALANCED = 0;
public final static int DC_MEDIA_QUALITY_WORSE = 1;
public static final int DC_MEDIA_QUALITY_BALANCED = 0;
public static final int DC_MEDIA_QUALITY_WORSE = 1;
public final static int DC_CONNECTIVITY_NOT_CONNECTED = 1000;
public final static int DC_CONNECTIVITY_CONNECTING = 2000;
public final static int DC_CONNECTIVITY_WORKING = 3000;
public final static int DC_CONNECTIVITY_CONNECTED = 4000;
public static final int DC_CONNECTIVITY_NOT_CONNECTED = 1000;
public static final int DC_CONNECTIVITY_CONNECTING = 2000;
public static final int DC_CONNECTIVITY_WORKING = 3000;
public static final int DC_CONNECTIVITY_CONNECTED = 4000;
private static final String CONFIG_MUTE_MENTIONS_IF_MUTED = "ui.mute_mentions_if_muted";
private static final String CONFIG_MUTE_MENTIONS_IF_MUTED = "ui.mute_mentions_if_muted";
// when using DcAccounts, use Rpc.addAccount() instead
public DcContext(String osName, String dbfile) {
contextCPtr = createContextCPtr(osName, dbfile);
// when using DcAccounts, use Rpc.addAccount() instead
public DcContext(String osName, String dbfile) {
contextCPtr = createContextCPtr(osName, dbfile);
}
public DcContext(long contextCPtr) {
this.contextCPtr = contextCPtr;
}
public boolean isOk() {
return contextCPtr != 0;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (contextCPtr != 0) {
unrefContextCPtr();
contextCPtr = 0;
}
}
public DcContext(long contextCPtr) {
this.contextCPtr = contextCPtr;
public native int getAccountId();
// when using DcAccounts, use DcAccounts.getEventEmitter() instead
public DcEventEmitter getEventEmitter() {
return new DcEventEmitter(getEventEmitterCPtr());
}
public native void setStockTranslation(int stockId, String translation);
public native String getBlobdir();
public native String getLastError();
public native void stopOngoingProcess();
public native int isConfigured();
public native boolean open(String passphrase);
public native boolean isOpen();
// when using DcAccounts, use DcAccounts.startIo() instead
public native void startIo();
// when using DcAccounts, use DcAccounts.stopIo() instead
public native void stopIo();
// when using DcAccounts, use DcAccounts.maybeNetwork() instead
public native void maybeNetwork();
public native void setConfig(String key, String value);
public void setConfigInt(String key, int value) {
setConfig(key, Integer.toString(value));
}
public native boolean setConfigFromQr(String qr);
public native String getConfig(String key);
public int getConfigInt(String key) {
try {
return Integer.parseInt(getConfig(key));
} catch (Exception e) {
}
return 0;
}
public boolean isOk() {
return contextCPtr != 0;
public native String getInfo();
public native int getConnectivity();
public native String getConnectivityHtml();
public native String initiateKeyTransfer();
public native void imex(int what, String dir);
public native String imexHasBackup(String dir);
public DcBackupProvider newBackupProvider() {
return new DcBackupProvider(newBackupProviderCPtr());
}
public native boolean receiveBackup(String qr);
public native boolean mayBeValidAddr(String addr);
public native int lookupContactIdByAddr(String addr);
public native int[] getContacts(int flags, String query);
public native int[] getBlockedContacts();
public DcContact getContact(int contact_id) {
return new DcContact(getContactCPtr(contact_id));
}
public native int createContact(String name, String addr);
public native void blockContact(int id, int block);
public native String getContactEncrInfo(int contact_id);
public native boolean deleteContact(int id);
public native int addAddressBook(String adrbook);
public DcChatlist getChatlist(int listflags, String query, int queryId) {
return new DcChatlist(getAccountId(), getChatlistCPtr(listflags, query, queryId));
}
public DcChat getChat(int chat_id) {
return new DcChat(getAccountId(), getChatCPtr(chat_id));
}
public native String getChatEncrInfo(int chat_id);
public native void markseenMsgs(int msg_ids[]);
public native void marknoticedChat(int chat_id);
public native void setChatVisibility(int chat_id, int visibility);
public native int getChatIdByContactId(int contact_id);
public native int createChatByContactId(int contact_id);
public native int createGroupChat(String name);
public native int createBroadcastList();
public native boolean isContactInChat(int chat_id, int contact_id);
public native int addContactToChat(int chat_id, int contact_id);
public native int removeContactFromChat(int chat_id, int contact_id);
public native void setDraft(int chat_id, DcMsg msg /*null=delete*/);
public DcMsg getDraft(int chat_id) {
return new DcMsg(getDraftCPtr(chat_id));
}
public native int setChatName(int chat_id, String name);
public native int setChatProfileImage(int chat_id, String name);
public native int[] getChatMsgs(int chat_id, int flags, int marker1before);
public native int[] searchMsgs(int chat_id, String query);
public native int[] getFreshMsgs();
public native int[] getChatMedia(int chat_id, int type1, int type2, int type3);
public native int[] getChatContacts(int chat_id);
public native int getChatEphemeralTimer(int chat_id);
public native boolean setChatEphemeralTimer(int chat_id, int timer);
public native boolean setChatMuteDuration(int chat_id, long duration);
public native void deleteChat(int chat_id);
public native void blockChat(int chat_id);
public native void acceptChat(int chat_id);
public DcMsg getMsg(int msg_id) {
return new DcMsg(getMsgCPtr(msg_id));
}
public native void sendEditRequest(int msg_id, String text);
public native String getMsgInfo(int id);
public native String getMsgHtml(int msg_id);
public native void downloadFullMsg(int msg_id);
public native int getFreshMsgCount(int chat_id);
public native int estimateDeletionCount(boolean from_server, long seconds);
public native void deleteMsgs(int msg_ids[]);
public native void sendDeleteRequest(int msg_ids[]);
public native void forwardMsgs(int msg_ids[], int chat_id);
public native void saveMsgs(int msg_ids[]);
public native boolean resendMsgs(int msg_ids[]);
public native int sendMsg(int chat_id, DcMsg msg);
public native int sendTextMsg(int chat_id, String text);
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload);
public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial);
public native void setWebxdcIntegration(String file);
public native int initWebxdcIntegration(int chat_id);
public native int addDeviceMsg(String label, DcMsg msg);
public native boolean wasDeviceMsgEverAdded(String label);
public DcLot checkQr(String qr) {
return new DcLot(checkQrCPtr(qr));
}
public native String getSecurejoinQr(int chat_id);
public native String getSecurejoinQrSvg(int chat_id);
public native String createQrSvg(String payload);
public native int joinSecurejoin(String qr);
public native void sendLocationsToChat(int chat_id, int seconds);
public native boolean isSendingLocationsToChat(int chat_id);
public DcProvider getProviderFromEmailWithDns(String email) {
long cptr = getProviderFromEmailWithDnsCPtr(email);
return cptr != 0 ? new DcProvider(cptr) : null;
}
public boolean isMentionsEnabled() {
return getConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED) != 1;
}
public void setMentionsEnabled(boolean enabled) {
setConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED, enabled ? 0 : 1);
}
public String getName() {
String displayname = getConfig("displayname");
if (displayname.isEmpty()) {
displayname = getConfig("addr");
}
return displayname;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (contextCPtr != 0) {
unrefContextCPtr();
contextCPtr = 0;
}
}
public boolean isChatmail() {
return getConfigInt("is_chatmail") == 1;
}
public native int getAccountId ();
public boolean isMuted() {
return getConfigInt("is_muted") == 1;
}
// when using DcAccounts, use DcAccounts.getEventEmitter() instead
public DcEventEmitter getEventEmitter () { return new DcEventEmitter(getEventEmitterCPtr()); }
public void setMuted(boolean muted) {
setConfigInt("is_muted", muted ? 1 : 0);
}
public native void setStockTranslation (int stockId, String translation);
public native String getBlobdir ();
public native String getLastError ();
public native void stopOngoingProcess ();
public native int isConfigured ();
public native boolean open (String passphrase);
public native boolean isOpen ();
public void restartIo() {
stopIo();
startIo();
}
// when using DcAccounts, use DcAccounts.startIo() instead
public native void startIo ();
/**
* @return true if at least one chat has location streaming enabled
*/
public native boolean setLocation(float latitude, float longitude, float accuracy);
// when using DcAccounts, use DcAccounts.stopIo() instead
public native void stopIo ();
// working with raw c-data
private long contextCPtr; // CAVE: the name is referenced in the JNI
// when using DcAccounts, use DcAccounts.maybeNetwork() instead
public native void maybeNetwork ();
private native long createContextCPtr(String osName, String dbfile);
public native void setConfig (String key, String value);
public void setConfigInt (String key, int value) { setConfig(key, Integer.toString(value)); }
public native boolean setConfigFromQr (String qr);
public native String getConfig (String key);
public int getConfigInt (String key) { try{return Integer.parseInt(getConfig(key));} catch(Exception e) {} return 0; }
public native String getInfo ();
public native int getConnectivity ();
public native String getConnectivityHtml ();
public native String initiateKeyTransfer ();
public native void imex (int what, String dir);
public native String imexHasBackup (String dir);
public DcBackupProvider newBackupProvider () { return new DcBackupProvider(newBackupProviderCPtr()); }
public native boolean receiveBackup (String qr);
public native boolean mayBeValidAddr (String addr);
public native int lookupContactIdByAddr(String addr);
public native int[] getContacts (int flags, String query);
public native int[] getBlockedContacts ();
public DcContact getContact (int contact_id) { return new DcContact(getContactCPtr(contact_id)); }
public native int createContact (String name, String addr);
public native void blockContact (int id, int block);
public native String getContactEncrInfo (int contact_id);
public native boolean deleteContact (int id);
public native int addAddressBook (String adrbook);
public DcChatlist getChatlist (int listflags, String query, int queryId) { return new DcChatlist(getAccountId(), getChatlistCPtr(listflags, query, queryId)); }
public DcChat getChat (int chat_id) { return new DcChat(getAccountId(), getChatCPtr(chat_id)); }
public native String getChatEncrInfo (int chat_id);
public native void markseenMsgs (int msg_ids[]);
public native void marknoticedChat (int chat_id);
public native void setChatVisibility (int chat_id, int visibility);
public native int getChatIdByContactId (int contact_id);
public native int createChatByContactId(int contact_id);
public native int createGroupChat (String name);
public native int createBroadcastList ();
public native boolean isContactInChat (int chat_id, int contact_id);
public native int addContactToChat (int chat_id, int contact_id);
public native int removeContactFromChat(int chat_id, int contact_id);
public native void setDraft (int chat_id, DcMsg msg/*null=delete*/);
public DcMsg getDraft (int chat_id) { return new DcMsg(getDraftCPtr(chat_id)); }
public native int setChatName (int chat_id, String name);
public native int setChatProfileImage (int chat_id, String name);
public native int[] getChatMsgs (int chat_id, int flags, int marker1before);
public native int[] searchMsgs (int chat_id, String query);
public native int[] getFreshMsgs ();
public native int[] getChatMedia (int chat_id, int type1, int type2, int type3);
public native int[] getChatContacts (int chat_id);
public native int getChatEphemeralTimer (int chat_id);
public native boolean setChatEphemeralTimer (int chat_id, int timer);
public native boolean setChatMuteDuration (int chat_id, long duration);
public native void deleteChat (int chat_id);
public native void blockChat (int chat_id);
public native void acceptChat (int chat_id);
public DcMsg getMsg (int msg_id) { return new DcMsg(getMsgCPtr(msg_id)); }
public native void sendEditRequest (int msg_id, String text);
public native String getMsgInfo (int id);
public native String getMsgHtml (int msg_id);
public native void downloadFullMsg (int msg_id);
public native int getFreshMsgCount (int chat_id);
public native int estimateDeletionCount(boolean from_server, long seconds);
public native void deleteMsgs (int msg_ids[]);
public native void sendDeleteRequest (int msg_ids[]);
public native void forwardMsgs (int msg_ids[], int chat_id);
public native void saveMsgs (int msg_ids[]);
public native boolean resendMsgs (int msg_ids[]);
public native int sendMsg (int chat_id, DcMsg msg);
public native int sendTextMsg (int chat_id, String text);
public native boolean sendWebxdcStatusUpdate(int msg_id, String payload);
public native String getWebxdcStatusUpdates(int msg_id, int last_known_serial);
public native void setWebxdcIntegration (String file);
public native int initWebxdcIntegration(int chat_id);
public native int addDeviceMsg (String label, DcMsg msg);
public native boolean wasDeviceMsgEverAdded(String label);
public DcLot checkQr (String qr) { return new DcLot(checkQrCPtr(qr)); }
public native String getSecurejoinQr (int chat_id);
public native String getSecurejoinQrSvg (int chat_id);
public native String createQrSvg (String payload);
public native int joinSecurejoin (String qr);
public native void sendLocationsToChat (int chat_id, int seconds);
public native boolean isSendingLocationsToChat(int chat_id);
public DcProvider getProviderFromEmailWithDns (String email) { long cptr = getProviderFromEmailWithDnsCPtr(email); return cptr!=0 ? new DcProvider(cptr) : null; }
private native void unrefContextCPtr();
public boolean isMentionsEnabled() {
return getConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED) != 1;
}
private native long getEventEmitterCPtr();
public void setMentionsEnabled(boolean enabled) {
setConfigInt(CONFIG_MUTE_MENTIONS_IF_MUTED, enabled? 0 : 1);
}
public native long createMsgCPtr(int viewtype);
public String getName() {
String displayname = getConfig("displayname");
if (displayname.isEmpty()) {
displayname = getConfig("addr");
}
return displayname;
}
private native long getChatlistCPtr(int listflags, String query, int queryId);
public boolean isChatmail() {
return getConfigInt("is_chatmail") == 1;
}
private native long getChatCPtr(int chat_id);
public boolean isMuted() {
return getConfigInt("is_muted") == 1;
}
private native long getMsgCPtr(int id);
public void setMuted(boolean muted) {
setConfigInt("is_muted", muted? 1 : 0);
}
private native long getDraftCPtr(int id);
public void restartIo() {
stopIo();
startIo();
}
private native long getContactCPtr(int id);
/**
* @return true if at least one chat has location streaming enabled
*/
public native boolean setLocation (float latitude, float longitude, float accuracy);
private native long checkQrCPtr(String qr);
// working with raw c-data
private long contextCPtr; // CAVE: the name is referenced in the JNI
private native long createContextCPtr(String osName, String dbfile);
private native void unrefContextCPtr ();
private native long getEventEmitterCPtr();
public native long createMsgCPtr (int viewtype);
private native long getChatlistCPtr (int listflags, String query, int queryId);
private native long getChatCPtr (int chat_id);
private native long getMsgCPtr (int id);
private native long getDraftCPtr (int id);
private native long getContactCPtr (int id);
private native long checkQrCPtr (String qr);
private native long getProviderFromEmailWithDnsCPtr (String addr);
private native long newBackupProviderCPtr();
private native long getProviderFromEmailWithDnsCPtr(String addr);
private native long newBackupProviderCPtr();
}
+286 -228
View File
@@ -1,262 +1,320 @@
package com.b44t.messenger;
import android.text.TextUtils;
import org.json.JSONObject;
import java.io.File;
import java.util.Set;
import org.json.JSONObject;
public class DcMsg {
public final static int DC_MSG_UNDEFINED = 0;
public final static int DC_MSG_TEXT = 10;
public final static int DC_MSG_IMAGE = 20;
public final static int DC_MSG_GIF = 21;
public final static int DC_MSG_STICKER = 23;
public final static int DC_MSG_AUDIO = 40;
public final static int DC_MSG_VOICE = 41;
public final static int DC_MSG_VIDEO = 50;
public final static int DC_MSG_FILE = 60;
public final static int DC_MSG_CALL = 71;
public final static int DC_MSG_WEBXDC = 80;
public final static int DC_MSG_VCARD = 90;
public static final int DC_MSG_UNDEFINED = 0;
public static final int DC_MSG_TEXT = 10;
public static final int DC_MSG_IMAGE = 20;
public static final int DC_MSG_GIF = 21;
public static final int DC_MSG_STICKER = 23;
public static final int DC_MSG_AUDIO = 40;
public static final int DC_MSG_VOICE = 41;
public static final int DC_MSG_VIDEO = 50;
public static final int DC_MSG_FILE = 60;
public static final int DC_MSG_CALL = 71;
public static final int DC_MSG_WEBXDC = 80;
public static final int DC_MSG_VCARD = 90;
public final static int DC_INFO_UNKNOWN = 0;
public final static int DC_INFO_GROUP_NAME_CHANGED = 2;
public final static int DC_INFO_GROUP_IMAGE_CHANGED = 3;
public final static int DC_INFO_MEMBER_ADDED_TO_GROUP = 4;
public final static int DC_INFO_MEMBER_REMOVED_FROM_GROUP = 5;
public final static int DC_INFO_AUTOCRYPT_SETUP_MESSAGE = 6;
public final static int DC_INFO_SECURE_JOIN_MESSAGE = 7;
public final static int DC_INFO_LOCATIONSTREAMING_ENABLED = 8;
public final static int DC_INFO_LOCATION_ONLY = 9;
public final static int DC_INFO_EPHEMERAL_TIMER_CHANGED = 10;
public final static int DC_INFO_PROTECTION_ENABLED = 11;
public final static int DC_INFO_INVALID_UNENCRYPTED_MAIL = 13;
public final static int DC_INFO_WEBXDC_INFO_MESSAGE = 32;
public final static int DC_INFO_CHAT_E2EE = 50;
public final static int DC_INFO_CHAT_DESCRIPTION_CHANGED = 70;
public static final int DC_INFO_UNKNOWN = 0;
public static final int DC_INFO_GROUP_NAME_CHANGED = 2;
public static final int DC_INFO_GROUP_IMAGE_CHANGED = 3;
public static final int DC_INFO_MEMBER_ADDED_TO_GROUP = 4;
public static final int DC_INFO_MEMBER_REMOVED_FROM_GROUP = 5;
public static final int DC_INFO_AUTOCRYPT_SETUP_MESSAGE = 6;
public static final int DC_INFO_SECURE_JOIN_MESSAGE = 7;
public static final int DC_INFO_LOCATIONSTREAMING_ENABLED = 8;
public static final int DC_INFO_LOCATION_ONLY = 9;
public static final int DC_INFO_EPHEMERAL_TIMER_CHANGED = 10;
public static final int DC_INFO_PROTECTION_ENABLED = 11;
public static final int DC_INFO_INVALID_UNENCRYPTED_MAIL = 13;
public static final int DC_INFO_WEBXDC_INFO_MESSAGE = 32;
public static final int DC_INFO_CHAT_E2EE = 50;
public static final int DC_INFO_CHAT_DESCRIPTION_CHANGED = 70;
public final static int DC_STATE_UNDEFINED = 0;
public final static int DC_STATE_IN_FRESH = 10;
public final static int DC_STATE_IN_NOTICED = 13;
public final static int DC_STATE_IN_SEEN = 16;
public final static int DC_STATE_OUT_PREPARING = 18;
public final static int DC_STATE_OUT_DRAFT = 19;
public final static int DC_STATE_OUT_PENDING = 20;
public final static int DC_STATE_OUT_FAILED = 24;
public final static int DC_STATE_OUT_DELIVERED = 26;
public final static int DC_STATE_OUT_MDN_RCVD = 28;
public static final int DC_STATE_UNDEFINED = 0;
public static final int DC_STATE_IN_FRESH = 10;
public static final int DC_STATE_IN_NOTICED = 13;
public static final int DC_STATE_IN_SEEN = 16;
public static final int DC_STATE_OUT_PREPARING = 18;
public static final int DC_STATE_OUT_DRAFT = 19;
public static final int DC_STATE_OUT_PENDING = 20;
public static final int DC_STATE_OUT_FAILED = 24;
public static final int DC_STATE_OUT_DELIVERED = 26;
public static final int DC_STATE_OUT_MDN_RCVD = 28;
public final static int DC_DOWNLOAD_DONE = 0;
public final static int DC_DOWNLOAD_AVAILABLE = 10;
public final static int DC_DOWNLOAD_FAILURE = 20;
public final static int DC_DOWNLOAD_UNDECIPHERABLE = 30;
public final static int DC_DOWNLOAD_IN_PROGRESS = 1000;
public static final int DC_DOWNLOAD_DONE = 0;
public static final int DC_DOWNLOAD_AVAILABLE = 10;
public static final int DC_DOWNLOAD_FAILURE = 20;
public static final int DC_DOWNLOAD_UNDECIPHERABLE = 30;
public static final int DC_DOWNLOAD_IN_PROGRESS = 1000;
public static final int DC_MSG_NO_ID = 0;
public final static int DC_MSG_ID_MARKER1 = 1;
public final static int DC_MSG_ID_DAYMARKER = 9;
public static final int DC_MSG_NO_ID = 0;
public static final int DC_MSG_ID_MARKER1 = 1;
public static final int DC_MSG_ID_DAYMARKER = 9;
public final static int DC_VIDEOCHATTYPE_UNKNOWN = 0;
public final static int DC_VIDEOCHATTYPE_BASICWEBRTC = 1;
public static final int DC_VIDEOCHATTYPE_UNKNOWN = 0;
public static final int DC_VIDEOCHATTYPE_BASICWEBRTC = 1;
private static final String TAG = DcMsg.class.getSimpleName();
private static final String TAG = DcMsg.class.getSimpleName();
public DcMsg(DcContext context, int viewtype) {
msgCPtr = context.createMsgCPtr(viewtype);
public DcMsg(DcContext context, int viewtype) {
msgCPtr = context.createMsgCPtr(viewtype);
}
public DcMsg(long msgCPtr) {
this.msgCPtr = msgCPtr;
}
public boolean isOk() {
return msgCPtr != 0;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
unrefMsgCPtr();
msgCPtr = 0;
}
@Override
public int hashCode() {
return this.getId();
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof DcMsg)) {
return false;
}
public DcMsg(long msgCPtr) {
this.msgCPtr = msgCPtr;
}
DcMsg that = (DcMsg) other;
return this.getId() == that.getId() && this.getId() != 0;
}
public boolean isOk() {
return msgCPtr != 0;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
unrefMsgCPtr();
msgCPtr = 0;
}
@Override
public int hashCode() {
return this.getId();
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof DcMsg)) {
return false;
}
DcMsg that = (DcMsg) other;
return this.getId()==that.getId() && this.getId()!=0;
}
/**
* If given a message, calculates the position of the message in the chat
*/
public static int getMessagePosition(DcMsg msg, DcContext dcContext) {
int msgs[] = dcContext.getChatMsgs(msg.getChatId(), 0, 0);
int startingPosition = -1;
int msgId = msg.getId();
for (int i = 0; i < msgs.length; i++) {
if (msgs[i] == msgId) {
startingPosition = msgs.length - 1 - i;
break;
}
}
return startingPosition;
}
public native int getId ();
public native String getText ();
public native String getSubject ();
public native long getTimestamp ();
public native long getSortTimestamp ();
public native boolean hasDeviatingTimestamp();
public native boolean hasLocation ();
public native int getType ();
public native int getInfoType ();
public native int getInfoContactId ();
public native int getState ();
public native int getDownloadState ();
public native int getChatId ();
public native int getFromId ();
public native int getWidth (int def);
public native int getHeight (int def);
public native int getDuration ();
public native void lateFilingMediaSize(int width, int height, int duration);
public DcLot getSummary (DcChat chat) { return new DcLot(getSummaryCPtr(chat.getChatCPtr())); }
public native String getSummarytext (int approx_characters);
public native int showPadlock ();
public boolean hasFile () { String file = getFile(); return file!=null && !file.isEmpty(); }
public native String getFile ();
public native String getFilemime ();
public native String getFilename ();
public native long getFilebytes ();
public native byte[] getWebxdcBlob (String filename);
public JSONObject getWebxdcInfo () {
try {
String json = getWebxdcInfoJson();
if (json != null && !json.isEmpty()) return new JSONObject(json);
} catch(Exception e) {
e.printStackTrace();
/** If given a message, calculates the position of the message in the chat */
public static int getMessagePosition(DcMsg msg, DcContext dcContext) {
int msgs[] = dcContext.getChatMsgs(msg.getChatId(), 0, 0);
int startingPosition = -1;
int msgId = msg.getId();
for (int i = 0; i < msgs.length; i++) {
if (msgs[i] == msgId) {
startingPosition = msgs.length - 1 - i;
break;
}
return new JSONObject();
}
public native String getWebxdcHref ();
public native boolean isForwarded ();
public native boolean isInfo ();
public native boolean hasHtml ();
public native String getSetupCodeBegin ();
public native void setText (String text);
public native void setFileAndDeduplicate(String file, String name, String filemime);
public native void setDimension (int width, int height);
public native void setDuration (int duration);
public native void setLocation (float latitude, float longitude);
public void setQuote (DcMsg quote) { setQuoteCPtr(quote.msgCPtr); }
public native String getQuotedText ();
public native String getError ();
public native String getOverrideSenderName();
public native boolean isEdited ();
return startingPosition;
}
public String getSenderName(DcContact dcContact) {
String overrideName = getOverrideSenderName();
if (overrideName != null) {
return "~" + overrideName;
} else {
return dcContact.getDisplayName();
}
}
public native int getId();
public DcMsg getQuotedMsg () {
long cPtr = getQuotedMsgCPtr();
return cPtr != 0 ? new DcMsg(cPtr) : null;
}
public native String getText();
public DcMsg getParent() {
long cPtr = getParentCPtr();
return cPtr != 0 ? new DcMsg(cPtr) : null;
}
public native String getSubject();
public native int getOriginalMsgId ();
public native int getSavedMsgId ();
public native long getTimestamp();
public boolean canSave() {
// saving info-messages out of context results in confusion, see https://github.com/deltachat/deltachat-ios/issues/2567
return !isInfo();
}
public native long getSortTimestamp();
public File getFileAsFile() {
if(getFile()==null)
throw new AssertionError("expected a file to be present.");
return new File(getFile());
}
public native boolean hasDeviatingTimestamp();
// aliases and higher-level tools
public static int[] msgSetToIds(final Set<DcMsg> dcMsgs) {
if (dcMsgs == null) {
return new int[0];
}
int[] ids = new int[dcMsgs.size()];
int i = 0;
for (DcMsg dcMsg : dcMsgs) {
ids[i++] = dcMsg.getId();
}
return ids;
}
public native boolean hasLocation();
public boolean isOutgoing() {
return getFromId() == DcContact.DC_CONTACT_ID_SELF;
}
public native int getType();
public String getDisplayBody() {
return getText();
}
public native int getInfoType();
public String getBody() {
return getText();
}
public native int getInfoContactId();
public long getDateReceived() {
return getTimestamp();
}
public native int getState();
public boolean isFailed() {
return (getState() == DC_STATE_OUT_FAILED) || (!TextUtils.isEmpty(getError()));
}
public boolean isPreparing() {
return getState() == DC_STATE_OUT_PREPARING;
}
public boolean isSecure() {
return showPadlock()!=0;
}
public boolean isPending() {
return getState() == DC_STATE_OUT_PENDING;
}
public boolean isDelivered() {
return getState() == DC_STATE_OUT_DELIVERED;
}
public boolean isRemoteRead() {
return getState() == DC_STATE_OUT_MDN_RCVD;
}
public boolean isSeen() {
return getState() == DC_STATE_IN_SEEN;
}
public native int getDownloadState();
public native int getChatId();
// working with raw c-data
private long msgCPtr; // CAVE: the name is referenced in the JNI
private native void unrefMsgCPtr ();
private native long getSummaryCPtr (long chatCPtr);
private native void setQuoteCPtr (long quoteCPtr);
private native long getQuotedMsgCPtr ();
private native long getParentCPtr ();
private native String getWebxdcInfoJson ();
};
public native int getFromId();
public native int getWidth(int def);
public native int getHeight(int def);
public native int getDuration();
public native void lateFilingMediaSize(int width, int height, int duration);
public DcLot getSummary(DcChat chat) {
return new DcLot(getSummaryCPtr(chat.getChatCPtr()));
}
public native String getSummarytext(int approx_characters);
public native int showPadlock();
public boolean hasFile() {
String file = getFile();
return file != null && !file.isEmpty();
}
public native String getFile();
public native String getFilemime();
public native String getFilename();
public native long getFilebytes();
public native byte[] getWebxdcBlob(String filename);
public JSONObject getWebxdcInfo() {
try {
String json = getWebxdcInfoJson();
if (json != null && !json.isEmpty()) return new JSONObject(json);
} catch (Exception e) {
e.printStackTrace();
}
return new JSONObject();
}
public native String getWebxdcHref();
public native boolean isForwarded();
public native boolean isInfo();
public native boolean hasHtml();
public native String getSetupCodeBegin();
public native void setText(String text);
public native void setFileAndDeduplicate(String file, String name, String filemime);
public native void setDimension(int width, int height);
public native void setDuration(int duration);
public native void setLocation(float latitude, float longitude);
public void setQuote(DcMsg quote) {
setQuoteCPtr(quote.msgCPtr);
}
public native String getQuotedText();
public native String getError();
public native String getOverrideSenderName();
public native boolean isEdited();
public String getSenderName(DcContact dcContact) {
String overrideName = getOverrideSenderName();
if (overrideName != null) {
return "~" + overrideName;
} else {
return dcContact.getDisplayName();
}
}
public DcMsg getQuotedMsg() {
long cPtr = getQuotedMsgCPtr();
return cPtr != 0 ? new DcMsg(cPtr) : null;
}
public DcMsg getParent() {
long cPtr = getParentCPtr();
return cPtr != 0 ? new DcMsg(cPtr) : null;
}
public native int getOriginalMsgId();
public native int getSavedMsgId();
public boolean canSave() {
// saving info-messages out of context results in confusion, see
// https://github.com/deltachat/deltachat-ios/issues/2567
return !isInfo();
}
public File getFileAsFile() {
if (getFile() == null) throw new AssertionError("expected a file to be present.");
return new File(getFile());
}
// aliases and higher-level tools
public static int[] msgSetToIds(final Set<DcMsg> dcMsgs) {
if (dcMsgs == null) {
return new int[0];
}
int[] ids = new int[dcMsgs.size()];
int i = 0;
for (DcMsg dcMsg : dcMsgs) {
ids[i++] = dcMsg.getId();
}
return ids;
}
public boolean isOutgoing() {
return getFromId() == DcContact.DC_CONTACT_ID_SELF;
}
public String getDisplayBody() {
return getText();
}
public String getBody() {
return getText();
}
public long getDateReceived() {
return getTimestamp();
}
public boolean isFailed() {
return (getState() == DC_STATE_OUT_FAILED) || (!TextUtils.isEmpty(getError()));
}
public boolean isPreparing() {
return getState() == DC_STATE_OUT_PREPARING;
}
public boolean isSecure() {
return showPadlock() != 0;
}
public boolean isPending() {
return getState() == DC_STATE_OUT_PENDING;
}
public boolean isDelivered() {
return getState() == DC_STATE_OUT_DELIVERED;
}
public boolean isRemoteRead() {
return getState() == DC_STATE_OUT_MDN_RCVD;
}
public boolean isSeen() {
return getState() == DC_STATE_IN_SEEN;
}
// working with raw c-data
private long msgCPtr; // CAVE: the name is referenced in the JNI
private native void unrefMsgCPtr();
private native long getSummaryCPtr(long chatCPtr);
private native void setQuoteCPtr(long quoteCPtr);
private native long getQuotedMsgCPtr();
private native long getParentCPtr();
private native String getWebxdcInfoJson();
}
;
@@ -23,16 +23,20 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg;
import java.lang.ref.SoftReference;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
import org.thoughtcrime.securesms.components.audioplay.AudioPlaybackViewModel;
import org.thoughtcrime.securesms.components.audioplay.AudioView;
@@ -45,61 +49,50 @@ import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.lang.ref.SoftReference;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A DC adapter for a conversation thread. Ultimately
* used by ConversationActivity to display a conversation
* thread in a ListActivity.
* A DC adapter for a conversation thread. Ultimately used by ConversationActivity to display a
* conversation thread in a ListActivity.
*
* @author Moxie Marlinspike
*
*/
// FIXME: this breaks type checks, that is why there are so many casts.
public class ConversationAdapter <V extends View & BindableConversationItem>
public class ConversationAdapter<V extends View & BindableConversationItem>
extends RecyclerView.Adapter
implements StickyHeaderDecoration.StickyHeaderAdapter<HeaderViewHolder>
{
implements StickyHeaderDecoration.StickyHeaderAdapter<HeaderViewHolder> {
private static final int MAX_CACHE_SIZE = 40;
private final Map<Integer,SoftReference<DcMsg>> recordCache =
Collections.synchronizedMap(new LRUCache<Integer,SoftReference<DcMsg>>(MAX_CACHE_SIZE));
private final Map<Integer, SoftReference<DcMsg>> recordCache =
Collections.synchronizedMap(new LRUCache<Integer, SoftReference<DcMsg>>(MAX_CACHE_SIZE));
private static final int MESSAGE_TYPE_OUTGOING = 0;
private static final int MESSAGE_TYPE_INCOMING = 1;
private static final int MESSAGE_TYPE_INFO = 2;
private static final int MESSAGE_TYPE_AUDIO_OUTGOING = 3;
private static final int MESSAGE_TYPE_AUDIO_INCOMING = 4;
private static final int MESSAGE_TYPE_OUTGOING = 0;
private static final int MESSAGE_TYPE_INCOMING = 1;
private static final int MESSAGE_TYPE_INFO = 2;
private static final int MESSAGE_TYPE_AUDIO_OUTGOING = 3;
private static final int MESSAGE_TYPE_AUDIO_INCOMING = 4;
private static final int MESSAGE_TYPE_THUMBNAIL_OUTGOING = 5;
private static final int MESSAGE_TYPE_THUMBNAIL_INCOMING = 6;
private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7;
private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8;
private static final int MESSAGE_TYPE_STICKER_INCOMING = 9;
private static final int MESSAGE_TYPE_STICKER_OUTGOING = 10;
private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7;
private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8;
private static final int MESSAGE_TYPE_STICKER_INCOMING = 9;
private static final int MESSAGE_TYPE_STICKER_OUTGOING = 10;
private final Set<DcMsg> batchSelected = Collections.synchronizedSet(new HashSet<DcMsg>());
private final @Nullable ItemClickListener clickListener;
private final @NonNull GlideRequests glideRequests;
private final @NonNull Recipient recipient;
private final @NonNull LayoutInflater inflater;
private final @NonNull Context context;
private final @NonNull Calendar calendar;
private final @NonNull GlideRequests glideRequests;
private final @NonNull Recipient recipient;
private final @NonNull LayoutInflater inflater;
private final @NonNull Context context;
private final @NonNull Calendar calendar;
private final DcContext dcContext;
private @NonNull DcChat dcChat;
private @NonNull int[] dcMsgList = new int[0];
private int positionToPulseHighlight = -1;
private int positionCurrentlyPulseHighlighting = -1;
private long pulseHighlightingSince = -1;
private int lastSeenPosition = -1;
private long lastSeen = -1;
private final DcContext dcContext;
private @NonNull DcChat dcChat;
private @NonNull int[] dcMsgList = new int[0];
private int positionToPulseHighlight = -1;
private int positionCurrentlyPulseHighlighting = -1;
private long pulseHighlightingSince = -1;
private int lastSeenPosition = -1;
private long lastSeen = -1;
private AudioPlaybackViewModel playbackViewModel;
private AudioView.OnActionListener audioPlayPauseListener;
@@ -110,7 +103,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@SuppressWarnings("unchecked")
public <V extends View & BindableConversationItem> V getView() {
return (V)itemView;
return (V) itemView;
}
public BindableConversationItem getItem() {
@@ -118,16 +111,14 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
}
public boolean isActive() {
return dcMsgList.length > 0;
}
public @NonNull DcChat getChat(){
public @NonNull DcChat getChat() {
return dcChat;
}
public void setLastSeen(long timestamp) {
lastSeen = timestamp;
}
@@ -151,14 +142,14 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public long getItemId(int position) {
if (position<0 || position>=dcMsgList.length) {
if (position < 0 || position >= dcMsgList.length) {
return 0;
}
return dcMsgList[dcMsgList.length-1-position];
return dcMsgList[dcMsgList.length - 1 - position];
}
public @NonNull DcMsg getMsg(int position) {
if(position<0 || position>=dcMsgList.length) {
if (position < 0 || position >= dcMsgList.length) {
return new DcMsg(0);
}
@@ -170,7 +161,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
}
final DcMsg fromDb = dcContext.getMsg((int)getItemId(position));
final DcMsg fromDb = dcContext.getMsg((int) getItemId(position));
recordCache.put(position, new SoftReference<>(fromDb));
return fromDb;
}
@@ -183,12 +174,10 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
this.audioPlayPauseListener = audioPlayPauseListener;
}
/**
* Returns the position of the message with msgId in the chat list, counted from the top
*/
/** Returns the position of the message with msgId in the chat list, counted from the top */
public int msgIdToPosition(int msgId) {
for(int i=0; i<dcMsgList.length; i++ ) {
if(dcMsgList[i]==msgId) {
for (int i = 0; i < dcMsgList.length; i++) {
if (dcMsgList[i] == msgId) {
return dcMsgList.length - 1 - i;
}
}
@@ -213,17 +202,18 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
}
interface ItemClickListener extends BindableConversationItem.EventListener {
void onItemClick(DcMsg item);
void onItemLongClick(DcMsg item, View view);
}
public ConversationAdapter(@NonNull Context context,
@NonNull DcChat dcChat,
@NonNull GlideRequests glideRequests,
@Nullable ItemClickListener clickListener,
@NonNull Recipient recipient) {
public ConversationAdapter(
@NonNull Context context,
@NonNull DcChat dcChat,
@NonNull GlideRequests glideRequests,
@Nullable ItemClickListener clickListener,
@NonNull Recipient recipient) {
this.dcChat = dcChat;
this.glideRequests = glideRequests;
this.clickListener = clickListener;
@@ -231,14 +221,14 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
this.context = context;
this.inflater = LayoutInflater.from(context);
this.calendar = Calendar.getInstance();
this.dcContext = DcHelper.getContext(context);
this.dcContext = DcHelper.getContext(context);
setHasStableIds(true);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
ConversationAdapter.ViewHolder holder = (ConversationAdapter.ViewHolder)viewHolder;
ConversationAdapter.ViewHolder holder = (ConversationAdapter.ViewHolder) viewHolder;
long now = System.currentTimeMillis();
if (position == positionToPulseHighlight) {
@@ -248,14 +238,25 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
long elapsed = now - pulseHighlightingSince;
boolean pulseHighlight = (positionCurrentlyPulseHighlighting == position && elapsed < PULSE_HIGHLIGHT_MILLIS);
boolean pulseHighlight =
(positionCurrentlyPulseHighlighting == position && elapsed < PULSE_HIGHLIGHT_MILLIS);
holder.getItem().bind(getMsg(position), dcChat, glideRequests, batchSelected, recipient, pulseHighlight, playbackViewModel, audioPlayPauseListener);
holder
.getItem()
.bind(
getMsg(position),
dcChat,
glideRequests,
batchSelected,
recipient,
pulseHighlight,
playbackViewModel,
audioPlayPauseListener);
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder.itemView instanceof ConversationItem) {
if (viewHolder.itemView instanceof ConversationItem) {
ConversationSwipeAnimationHelper.update((ConversationItem) viewHolder.itemView, 0, 1);
}
}
@@ -263,17 +264,19 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType));
itemView.setOnClickListener(view -> {
if (clickListener != null) {
clickListener.onItemClick(itemView.getMessageRecord());
}
});
itemView.setOnLongClickListener(view -> {
if (clickListener != null) {
clickListener.onItemLongClick(itemView.getMessageRecord(), view);
}
return true;
});
itemView.setOnClickListener(
view -> {
if (clickListener != null) {
clickListener.onItemClick(itemView.getMessageRecord());
}
});
itemView.setOnLongClickListener(
view -> {
if (clickListener != null) {
clickListener.onItemLongClick(itemView.getMessageRecord(), view);
}
return true;
});
itemView.setEventListener(clickListener);
return new ViewHolder(itemView);
}
@@ -284,14 +287,19 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
case MESSAGE_TYPE_THUMBNAIL_OUTGOING:
case MESSAGE_TYPE_DOCUMENT_OUTGOING:
case MESSAGE_TYPE_STICKER_OUTGOING:
case MESSAGE_TYPE_OUTGOING: return R.layout.conversation_item_sent;
case MESSAGE_TYPE_OUTGOING:
return R.layout.conversation_item_sent;
case MESSAGE_TYPE_AUDIO_INCOMING:
case MESSAGE_TYPE_THUMBNAIL_INCOMING:
case MESSAGE_TYPE_DOCUMENT_INCOMING:
case MESSAGE_TYPE_STICKER_INCOMING:
case MESSAGE_TYPE_INCOMING: return R.layout.conversation_item_received;
case MESSAGE_TYPE_INFO: return R.layout.conversation_item_update;
default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter");
case MESSAGE_TYPE_INCOMING:
return R.layout.conversation_item_received;
case MESSAGE_TYPE_INFO:
return R.layout.conversation_item_update;
default:
throw new IllegalArgumentException(
"unsupported item view type given to ConversationAdapter");
}
}
@@ -301,21 +309,18 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
int type = dcMsg.getType();
if (dcMsg.isInfo()) {
return MESSAGE_TYPE_INFO;
}
else if (type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_AUDIO_OUTGOING : MESSAGE_TYPE_AUDIO_INCOMING;
}
else if (type==DcMsg.DC_MSG_FILE) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_DOCUMENT_OUTGOING : MESSAGE_TYPE_DOCUMENT_INCOMING;
}
else if (type==DcMsg.DC_MSG_IMAGE || type==DcMsg.DC_MSG_GIF || type==DcMsg.DC_MSG_VIDEO) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_THUMBNAIL_OUTGOING : MESSAGE_TYPE_THUMBNAIL_INCOMING;
}
else if (type == DcMsg.DC_MSG_STICKER) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_STICKER_OUTGOING : MESSAGE_TYPE_STICKER_INCOMING;
}
else {
return dcMsg.isOutgoing()? MESSAGE_TYPE_OUTGOING : MESSAGE_TYPE_INCOMING;
} else if (type == DcMsg.DC_MSG_AUDIO || type == DcMsg.DC_MSG_VOICE) {
return dcMsg.isOutgoing() ? MESSAGE_TYPE_AUDIO_OUTGOING : MESSAGE_TYPE_AUDIO_INCOMING;
} else if (type == DcMsg.DC_MSG_FILE) {
return dcMsg.isOutgoing() ? MESSAGE_TYPE_DOCUMENT_OUTGOING : MESSAGE_TYPE_DOCUMENT_INCOMING;
} else if (type == DcMsg.DC_MSG_IMAGE
|| type == DcMsg.DC_MSG_GIF
|| type == DcMsg.DC_MSG_VIDEO) {
return dcMsg.isOutgoing() ? MESSAGE_TYPE_THUMBNAIL_OUTGOING : MESSAGE_TYPE_THUMBNAIL_INCOMING;
} else if (type == DcMsg.DC_MSG_STICKER) {
return dcMsg.isOutgoing() ? MESSAGE_TYPE_STICKER_OUTGOING : MESSAGE_TYPE_STICKER_INCOMING;
} else {
return dcMsg.isOutgoing() ? MESSAGE_TYPE_OUTGOING : MESSAGE_TYPE_INCOMING;
}
}
@@ -338,16 +343,16 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
public void pulseHighlightItem(int position) {
if (position>=0 && position < getItemCount()) {
if (position >= 0 && position < getItemCount()) {
positionToPulseHighlight = position;
notifyItemChanged(position);
}
}
public long getSortTimestamp(int position) {
if (!isActive()) return 0;
if (!isActive()) return 0;
if (position >= getItemCount()) return 0;
if (position < 0) return 0;
if (position < 0) return 0;
DcMsg msg = getMsg(position);
return msg.getSortTimestamp();
@@ -361,7 +366,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public long getHeaderId(int position) {
if (position >= getItemCount()) return -1;
if (position < 0) return -1;
if (position < 0) return -1;
calendar.setTime(new Date(getSortTimestamp(position)));
return Util.hashCode(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR));
@@ -369,18 +374,17 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_header, parent, false));
return new HeaderViewHolder(
LayoutInflater.from(getContext())
.inflate(R.layout.conversation_item_header, parent, false));
}
/**
* date header view
*/
/** date header view */
@Override
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
viewHolder.setText(DateUtils.getRelativeDate(getContext(), getSortTimestamp(position)));
}
public void changeData(@Nullable int[] dcMsgList) {
// should be called when there are new messages
this.dcMsgList = dcMsgList == null ? new int[0] : dcMsgList;
@@ -400,12 +404,11 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
private int findLastSeenPosition(long lastSeen) {
if (lastSeen <= 0) return -1;
if (!isActive()) return -1;
if (lastSeen <= 0) return -1;
if (!isActive()) return -1;
int count = getItemCount();
for (int i = 0; i < count; i++) {
DcMsg msg = getMsg(i);
if (msg.isOutgoing() || msg.getTimestamp() <= lastSeen) {
@@ -417,11 +420,16 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
}
public HeaderViewHolder onCreateLastSeenViewHolder(ViewGroup parent) {
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_last_seen, parent, false));
return new HeaderViewHolder(
LayoutInflater.from(getContext())
.inflate(R.layout.conversation_item_last_seen, parent, false));
}
public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) {
viewHolder.setText(getContext().getResources().getQuantityString(R.plurals.chat_n_new_messages, (position + 1), (position + 1)));
viewHolder.setText(
getContext()
.getResources()
.getQuantityString(R.plurals.chat_n_new_messages, (position + 1), (position + 1)));
}
static class LastSeenHeader extends StickyHeaderDecoration {
@@ -429,32 +437,45 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
LastSeenHeader(ConversationAdapter adapter) {
super(adapter, false, false);
this.adapter = adapter;
this.adapter = adapter;
}
@Override
protected boolean hasHeader(RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
return adapter.isActive() && position == adapter.getLastSeenPosition();
protected boolean hasHeader(
RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
return adapter.isActive() && position == adapter.getLastSeenPosition();
}
@Override
protected int getHeaderTop(RecyclerView parent, View child, View header, int adapterPos, int layoutPos) {
protected int getHeaderTop(
RecyclerView parent, View child, View header, int adapterPos, int layoutPos) {
return parent.getLayoutManager().getDecoratedTop(child);
}
@Override
protected HeaderViewHolder getHeader(RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
protected HeaderViewHolder getHeader(
RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
HeaderViewHolder viewHolder = adapter.onCreateLastSeenViewHolder(parent);
adapter.onBindLastSeenViewHolder(viewHolder, position);
int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
int heightSpec =
View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
int childWidth = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), viewHolder.itemView.getLayoutParams().width);
int childHeight = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), viewHolder.itemView.getLayoutParams().height);
int childWidth =
ViewGroup.getChildMeasureSpec(
widthSpec,
parent.getPaddingLeft() + parent.getPaddingRight(),
viewHolder.itemView.getLayoutParams().width);
int childHeight =
ViewGroup.getChildMeasureSpec(
heightSpec,
parent.getPaddingTop() + parent.getPaddingBottom(),
viewHolder.itemView.getLayoutParams().height);
viewHolder.itemView.measure(childWidth, childHeight);
viewHolder.itemView.layout(0, 0, viewHolder.itemView.getMeasuredWidth(), viewHolder.itemView.getMeasuredHeight());
viewHolder.itemView.layout(
0, 0, viewHolder.itemView.getMeasuredWidth(), viewHolder.itemView.getMeasuredHeight());
return viewHolder;
}
File diff suppressed because it is too large Load Diff
@@ -8,14 +8,11 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.DateUtils;
import chat.delta.rpc.types.CallInfo;
import chat.delta.rpc.types.CallState;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.DateUtils;
public class CallItemView extends FrameLayout {
private static final String TAG = CallItemView.class.getSimpleName();
@@ -43,11 +40,12 @@ public class CallItemView extends FrameLayout {
this.title = findViewById(R.id.title);
this.duration = findViewById(R.id.duration);
setOnClickListener(v -> {
if (viewListener != null && callInfo != null) {
viewListener.onClick(v, callInfo);
}
});
setOnClickListener(
v -> {
if (viewListener != null && callInfo != null) {
viewListener.onClick(v, callInfo);
}
});
}
public void setCallClickListener(CallClickListener listener) {
@@ -58,7 +56,9 @@ public class CallItemView extends FrameLayout {
this.callInfo = callInfo;
if (callInfo.state instanceof CallState.Completed) {
duration.setText(DateUtils.getFormattedCallDuration(getContext(), ((CallState.Completed) callInfo.state).duration));
duration.setText(
DateUtils.getFormattedCallDuration(
getContext(), ((CallState.Completed) callInfo.state).duration));
duration.setVisibility(VISIBLE);
} else {
duration.setVisibility(GONE);
@@ -76,17 +76,20 @@ public class CallItemView extends FrameLayout {
title.setText(R.string.audio_call);
}
icon.setImageResource(callInfo.hasVideo? R.drawable.ic_videocam_white_24dp : R.drawable.baseline_call_24);
icon.setImageResource(
callInfo.hasVideo ? R.drawable.ic_videocam_white_24dp : R.drawable.baseline_call_24);
int[] attrs;
if (isOutgoing) {
attrs = new int[]{
R.attr.conversation_item_outgoing_text_primary_color,
};
attrs =
new int[] {
R.attr.conversation_item_outgoing_text_primary_color,
};
} else {
attrs = new int[]{
R.attr.conversation_item_incoming_text_primary_color,
};
attrs =
new int[] {
R.attr.conversation_item_incoming_text_primary_color,
};
}
try (TypedArray ta = getContext().obtainStyledAttributes(attrs)) {
icon.setColorFilter(ta.getColor(0, Color.BLACK));
@@ -94,7 +97,8 @@ public class CallItemView extends FrameLayout {
}
public String getDescription() {
return title.getText() + (duration.getVisibility()==VISIBLE ? ("\n" + duration.getText()) : "");
return title.getText()
+ (duration.getVisibility() == VISIBLE ? ("\n" + duration.getText()) : "");
}
public interface CallClickListener {
@@ -4,55 +4,55 @@ import android.content.Context;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.util.Log;
import org.thoughtcrime.securesms.R;
public class InChatSounds {
private static final String TAG = InChatSounds.class.getSimpleName();
private static volatile InChatSounds instance;
private static final String TAG = InChatSounds.class.getSimpleName();
private static volatile InChatSounds instance;
private SoundPool soundPool = null;
private int soundIn = 0;
private int soundOut = 0;
private SoundPool soundPool = null;
private int soundIn = 0;
private int soundOut = 0;
static public InChatSounds getInstance(Context context) {
public static InChatSounds getInstance(Context context) {
if (instance == null) {
synchronized (InChatSounds.class) {
if (instance == null) {
synchronized (InChatSounds.class) {
if (instance == null) {
instance = new InChatSounds(context);
}
}
instance = new InChatSounds(context);
}
return instance;
}
}
return instance;
}
private InChatSounds(Context context) {
try {
AudioAttributes audioAttrs = new AudioAttributes.Builder()
private InChatSounds(Context context) {
try {
AudioAttributes audioAttrs =
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
soundPool = new SoundPool.Builder().setMaxStreams(3).setAudioAttributes(audioAttrs).build();
soundIn = soundPool.load(context, R.raw.sound_in, 1);
soundOut = soundPool.load(context, R.raw.sound_out, 1);
} catch(Exception e) {
Log.e(TAG, "cannot initialize sounds", e);
}
soundPool = new SoundPool.Builder().setMaxStreams(3).setAudioAttributes(audioAttrs).build();
soundIn = soundPool.load(context, R.raw.sound_in, 1);
soundOut = soundPool.load(context, R.raw.sound_out, 1);
} catch (Exception e) {
Log.e(TAG, "cannot initialize sounds", e);
}
}
public void playSendSound() {
try {
soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f);
} catch(Exception e) {
Log.e(TAG, "cannot play send sound", e);
}
public void playSendSound() {
try {
soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f);
} catch (Exception e) {
Log.e(TAG, "cannot play send sound", e);
}
}
public void playIncomingSound() {
try {
soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f);
} catch(Exception e) {
Log.e(TAG, "cannot play incoming sound", e);
}
public void playIncomingSound() {
try {
soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f);
} catch (Exception e) {
Log.e(TAG, "cannot play incoming sound", e);
}
}
}
@@ -24,23 +24,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.core.app.RemoteInput;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.Util;
/**
* Get the response text from the Wearable Device and sends an message as a reply
*/
/** Get the response text from the Wearable Device and sends an message as a reply */
public class RemoteReplyReceiver extends BroadcastReceiver {
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
public static final String ACCOUNT_ID_EXTRA = "account_id";
public static final String CHAT_ID_EXTRA = "chat_id";
public static final String MSG_ID_EXTRA = "msg_id";
@@ -60,20 +54,21 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
final CharSequence responseText = remoteInput.getCharSequence(EXTRA_REMOTE_REPLY);
if (responseText != null) {
Util.runOnAnyBackgroundThread(() -> {
DcContext dcContext = DcHelper.getAccounts(context).getAccount(accountId);
dcContext.marknoticedChat(chatId);
dcContext.markseenMsgs(new int[]{msgId});
if (dcContext.getChat(chatId).isContactRequest()) {
dcContext.acceptChat(chatId);
}
Util.runOnAnyBackgroundThread(
() -> {
DcContext dcContext = DcHelper.getAccounts(context).getAccount(accountId);
dcContext.marknoticedChat(chatId);
dcContext.markseenMsgs(new int[] {msgId});
if (dcContext.getChat(chatId).isContactRequest()) {
dcContext.acceptChat(chatId);
}
DcMsg msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
msg.setText(responseText.toString());
dcContext.sendMsg(chatId, msg);
DcMsg msg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
msg.setText(responseText.toString());
dcContext.sendMsg(chatId, msg);
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
});
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
});
}
}
}
@@ -6,11 +6,9 @@ import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.ForegroundDetector;
@@ -65,27 +63,31 @@ public final class FetchForegroundService extends Service {
Log.i(TAG, "Creating fetch service");
super.onCreate();
Notification notification = new NotificationCompat.Builder(this, NotificationCenter.CH_GENERIC)
.setContentTitle(getString(R.string.connectivity_updating))
.setSmallIcon(R.drawable.notification_permanent)
.build();
Notification notification =
new NotificationCompat.Builder(this, NotificationCenter.CH_GENERIC)
.setContentTitle(getString(R.string.connectivity_updating))
.setSmallIcon(R.drawable.notification_permanent)
.build();
try {
startForeground(NotificationCenter.ID_FETCH, notification);
Util.runOnAnyBackgroundThread(() -> {
Log.i(TAG, "Starting fetch");
if (!ApplicationContext.getDcAccounts().backgroundFetch(300)) { // as startForeground() was called, there is time
FetchForegroundService.stop(this);
} // else we stop FetchForegroundService on DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE
});
Util.runOnAnyBackgroundThread(
() -> {
Log.i(TAG, "Starting fetch");
if (!ApplicationContext.getDcAccounts()
.backgroundFetch(300)) { // as startForeground() was called, there is time
FetchForegroundService.stop(this);
} // else we stop FetchForegroundService on DC_EVENT_ACCOUNTS_BACKGROUND_FETCH_DONE
});
} catch (Exception e) {
Log.e(TAG, "Error calling startForeground()", e);
}
}
public static void fetchSynchronously() {
// According to the documentation https://firebase.google.com/docs/cloud-messaging/android/receive,
// According to the documentation
// https://firebase.google.com/docs/cloud-messaging/android/receive,
// we need to handle the message within 20s, and the time window may be even shorter than 20s,
// so, use 10s to be safe.
fetchingSynchronously = true;
@@ -97,9 +99,11 @@ public final class FetchForegroundService extends Service {
while (fetchingSynchronously) {
try {
// The `wait()` needs to be enclosed in a while loop because there may be
// "spurious wake-ups", i.e. `wait()` may return even though `notifyAll()` wasn't called.
// "spurious wake-ups", i.e. `wait()` may return even though `notifyAll()` wasn't
// called.
STOP_NOTIFIER.wait();
} catch (InterruptedException ex) {}
} catch (InterruptedException ex) {
}
}
}
}
@@ -121,5 +125,4 @@ public final class FetchForegroundService extends Service {
ApplicationContext.getDcAccounts().stopBackgroundFetch();
stopSelf();
}
}
@@ -11,23 +11,20 @@ import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat.Builder;
import androidx.core.content.ContextCompat;
import org.thoughtcrime.securesms.DummyActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.notifications.NotificationCenter;
import org.thoughtcrime.securesms.util.IntentUtils;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.thoughtcrime.securesms.DummyActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.notifications.NotificationCenter;
import org.thoughtcrime.securesms.util.IntentUtils;
public final class GenericForegroundService extends Service {
@@ -35,17 +32,17 @@ public final class GenericForegroundService extends Service {
private final IBinder binder = new LocalBinder();
private static final String EXTRA_TITLE = "extra_title";
private static final String EXTRA_CONTENT_TEXT = "extra_content_text";
private static final String EXTRA_CHANNEL_ID = "extra_channel_id";
private static final String EXTRA_ICON_RES = "extra_icon_res";
private static final String EXTRA_ID = "extra_id";
private static final String EXTRA_PROGRESS = "extra_progress";
private static final String EXTRA_PROGRESS_MAX = "extra_progress_max";
private static final String EXTRA_TITLE = "extra_title";
private static final String EXTRA_CONTENT_TEXT = "extra_content_text";
private static final String EXTRA_CHANNEL_ID = "extra_channel_id";
private static final String EXTRA_ICON_RES = "extra_icon_res";
private static final String EXTRA_ID = "extra_id";
private static final String EXTRA_PROGRESS = "extra_progress";
private static final String EXTRA_PROGRESS_MAX = "extra_progress_max";
private static final String EXTRA_PROGRESS_INDETERMINATE = "extra_progress_indeterminate";
private static final String ACTION_START = "start";
private static final String ACTION_STOP = "stop";
private static final String ACTION_STOP = "stop";
private static final AtomicInteger NEXT_ID = new AtomicInteger();
private static final AtomicBoolean CHANNEL_CREATED = new AtomicBoolean(false);
@@ -54,7 +51,9 @@ public final class GenericForegroundService extends Service {
private final LinkedHashMap<Integer, Entry> allActiveMessages = new LinkedHashMap<>();
private static final Entry DEFAULTS = new Entry("", "", NotificationCenter.CH_GENERIC, R.drawable.icon_notification, -1, 0, 0, false);
private static final Entry DEFAULTS =
new Entry(
"", "", NotificationCenter.CH_GENERIC, R.drawable.icon_notification, -1, 0, 0, false);
private @Nullable Entry lastPosted;
@@ -66,9 +65,11 @@ public final class GenericForegroundService extends Service {
synchronized (GenericForegroundService.class) {
String action = intent.getAction();
if (ACTION_START.equals(action)) handleStart(intent);
else if (ACTION_STOP .equals(action)) handleStop(intent);
else throw new IllegalStateException(String.format("Action needs to be %s or %s.", ACTION_START, ACTION_STOP));
if (ACTION_START.equals(action)) handleStart(intent);
else if (ACTION_STOP.equals(action)) handleStop(intent);
else
throw new IllegalStateException(
String.format("Action needs to be %s or %s.", ACTION_START, ACTION_STOP));
updateNotification();
@@ -89,7 +90,6 @@ public final class GenericForegroundService extends Service {
}
}
private synchronized void handleStart(@NonNull Intent intent) {
Entry entry = Entry.fromIntent(intent);
@@ -112,14 +112,18 @@ public final class GenericForegroundService extends Service {
private void postObligatoryForegroundNotification(@NonNull Entry active) {
lastPosted = active;
startForeground(NotificationCenter.ID_GENERIC, new Builder(this, active.channelId)
.setSmallIcon(active.iconRes)
.setContentTitle(active.title)
.setTicker(active.contentText)
.setContentText(active.contentText)
.setProgress(active.progressMax, active.progress, active.indeterminate)
.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, DummyActivity.class), IntentUtils.FLAG_MUTABLE()))
.build());
startForeground(
NotificationCenter.ID_GENERIC,
new Builder(this, active.channelId)
.setSmallIcon(active.iconRes)
.setContentTitle(active.title)
.setTicker(active.contentText)
.setContentText(active.contentText)
.setProgress(active.progressMax, active.progress, active.indeterminate)
.setContentIntent(
PendingIntent.getActivity(
this, 0, new Intent(this, DummyActivity.class), IntentUtils.FLAG_MUTABLE()))
.build());
}
@Override
@@ -127,8 +131,8 @@ public final class GenericForegroundService extends Service {
return binder;
}
public static NotificationController startForegroundTask(@NonNull Context context, @NonNull String task) {
public static NotificationController startForegroundTask(
@NonNull Context context, @NonNull String task) {
startedCounter++;
final int id = NEXT_ID.getAndIncrement();
@@ -151,14 +155,15 @@ public final class GenericForegroundService extends Service {
intent.putExtra(EXTRA_ID, id);
ContextCompat.startForegroundService(context, intent);
startedCounter = Math.max(startedCounter-1, 0);
startedCounter = Math.max(startedCounter - 1, 0);
}
public static boolean isForegroundTaskStarted() {
return startedCounter > 0;
}
synchronized void replaceProgress(int id, int progressMax, int progress, boolean indeterminate, String message) {
synchronized void replaceProgress(
int id, int progressMax, int progress, boolean indeterminate, String message) {
Entry oldEntry = allActiveMessages.get(id);
if (oldEntry == null) {
@@ -170,7 +175,16 @@ public final class GenericForegroundService extends Service {
message = oldEntry.contentText;
}
Entry newEntry = new Entry(oldEntry.title, message, oldEntry.channelId, oldEntry.iconRes, oldEntry.id, progressMax, progress, indeterminate);
Entry newEntry =
new Entry(
oldEntry.title,
message,
oldEntry.channelId,
oldEntry.iconRes,
oldEntry.id,
progressMax,
progress,
indeterminate);
if (oldEntry.equals(newEntry)) {
Log.d(TAG, String.format("handleReplace() skip, no change %s", newEntry));
@@ -185,36 +199,47 @@ public final class GenericForegroundService extends Service {
}
@TargetApi(Build.VERSION_CODES.O)
static public void createFgNotificationChannel(Context context) {
if(!CHANNEL_CREATED.get() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
public static void createFgNotificationChannel(Context context) {
if (!CHANNEL_CREATED.get() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CHANNEL_CREATED.set(true);
NotificationChannel channel = new NotificationChannel(NotificationCenter.CH_GENERIC,
"Generic Background Service", NotificationManager.IMPORTANCE_MIN);
channel.setDescription("Ensure app will not be killed while long ongoing background tasks are running.");
NotificationChannel channel =
new NotificationChannel(
NotificationCenter.CH_GENERIC,
"Generic Background Service",
NotificationManager.IMPORTANCE_MIN);
channel.setDescription(
"Ensure app will not be killed while long ongoing background tasks are running.");
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
private static class Entry {
final @NonNull String title;
final @NonNull String contentText;
final @NonNull String channelId;
final int id;
final @DrawableRes int iconRes;
final int progress;
final int progressMax;
final boolean indeterminate;
final @NonNull String title;
final @NonNull String contentText;
final @NonNull String channelId;
final int id;
final @DrawableRes int iconRes;
final int progress;
final int progressMax;
final boolean indeterminate;
private Entry(@NonNull String title, @NonNull String contentText, @NonNull String channelId, @DrawableRes int iconRes, int id, int progressMax, int progress, boolean indeterminate) {
this.title = title;
this.contentText = contentText;
this.channelId = channelId;
this.iconRes = iconRes;
this.id = id;
this.progress = progress;
this.progressMax = progressMax;
private Entry(
@NonNull String title,
@NonNull String contentText,
@NonNull String channelId,
@DrawableRes int iconRes,
int id,
int progressMax,
int progress,
boolean indeterminate) {
this.title = title;
this.contentText = contentText;
this.channelId = channelId;
this.iconRes = iconRes;
this.id = id;
this.progress = progress;
this.progressMax = progressMax;
this.indeterminate = indeterminate;
}
@@ -230,17 +255,26 @@ public final class GenericForegroundService extends Service {
String channelId = intent.getStringExtra(EXTRA_CHANNEL_ID);
if (channelId == null) channelId = DEFAULTS.channelId;
int iconRes = intent.getIntExtra(EXTRA_ICON_RES, DEFAULTS.iconRes);
int progress = intent.getIntExtra(EXTRA_PROGRESS, DEFAULTS.progress);
int progressMax = intent.getIntExtra(EXTRA_PROGRESS_MAX, DEFAULTS.progressMax);
boolean indeterminate = intent.getBooleanExtra(EXTRA_PROGRESS_INDETERMINATE, DEFAULTS.indeterminate);
int iconRes = intent.getIntExtra(EXTRA_ICON_RES, DEFAULTS.iconRes);
int progress = intent.getIntExtra(EXTRA_PROGRESS, DEFAULTS.progress);
int progressMax = intent.getIntExtra(EXTRA_PROGRESS_MAX, DEFAULTS.progressMax);
boolean indeterminate =
intent.getBooleanExtra(EXTRA_PROGRESS_INDETERMINATE, DEFAULTS.indeterminate);
return new Entry(title, contentText, channelId, iconRes, id, progressMax, progress, indeterminate);
return new Entry(
title, contentText, channelId, iconRes, id, progressMax, progress, indeterminate);
}
@Override
public @NonNull String toString() {
return String.format(Locale.ENGLISH, "ChannelId: %s Id: %d Progress: %d/%d %s", channelId, id, progress, progressMax, indeterminate ? "indeterminate" : "determinate");
return String.format(
Locale.ENGLISH,
"ChannelId: %s Id: %d Progress: %d/%d %s",
channelId,
id,
progress,
progressMax,
indeterminate ? "indeterminate" : "determinate");
}
@Override
@@ -249,14 +283,14 @@ public final class GenericForegroundService extends Service {
if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o;
return id == entry.id &&
iconRes == entry.iconRes &&
progress == entry.progress &&
progressMax == entry.progressMax &&
indeterminate == entry.indeterminate &&
title.equals(entry.title) &&
contentText.equals(entry.contentText) &&
channelId.equals(entry.channelId);
return id == entry.id
&& iconRes == entry.iconRes
&& progress == entry.progress
&& progressMax == entry.progressMax
&& indeterminate == entry.indeterminate
&& title.equals(entry.title)
&& contentText.equals(entry.contentText)
&& channelId.equals(entry.channelId);
}
@Override
@@ -5,25 +5,20 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import androidx.annotation.NonNull;
import java.util.concurrent.atomic.AtomicReference;
/**
* Class to control notifications triggered by GenericForeGroundService.
*
*/
/** Class to control notifications triggered by GenericForeGroundService. */
public final class NotificationController {
private final @NonNull Context context;
private final int id;
private int progress;
private int progressMax;
private int progress;
private int progressMax;
private boolean indeterminate;
private String message = "";
private long percent = -1;
private String message = "";
private long percent = -1;
private final ServiceConnection serviceConnection;
@@ -31,26 +26,31 @@ public final class NotificationController {
NotificationController(@NonNull Context context, int id) {
this.context = context;
this.id = id;
this.id = id;
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
GenericForegroundService.LocalBinder binder = (GenericForegroundService.LocalBinder) service;
GenericForegroundService genericForegroundService = binder.getService();
serviceConnection =
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
GenericForegroundService.LocalBinder binder =
(GenericForegroundService.LocalBinder) service;
GenericForegroundService genericForegroundService = binder.getService();
NotificationController.this.service.set(genericForegroundService);
NotificationController.this.service.set(genericForegroundService);
updateProgressOnService();
}
updateProgressOnService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
service.set(null);
}
};
@Override
public void onServiceDisconnected(ComponentName name) {
service.set(null);
}
};
context.bindService(new Intent(context, GenericForegroundService.class), serviceConnection, Context.BIND_AUTO_CREATE);
context.bindService(
new Intent(context, GenericForegroundService.class),
serviceConnection,
Context.BIND_AUTO_CREATE);
}
public int getId() {
@@ -61,7 +61,7 @@ public final class NotificationController {
try {
GenericForegroundService.stopForegroundTask(context, id);
context.unbindService(serviceConnection);
} catch(Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -74,16 +74,18 @@ public final class NotificationController {
setProgress((int) newProgressMax, (int) newProgress, false, newMessage);
}
private synchronized void setProgress(int newProgressMax, int newProgress, boolean indeterminant, @NonNull String newMessage) {
private synchronized void setProgress(
int newProgressMax, int newProgress, boolean indeterminant, @NonNull String newMessage) {
int newPercent = newProgressMax != 0 ? 100 * newProgress / newProgressMax : -1;
boolean same = newPercent == percent && indeterminate == indeterminant && newMessage.equals(message);
boolean same =
newPercent == percent && indeterminate == indeterminant && newMessage.equals(message);
percent = newPercent;
progress = newProgress;
progressMax = newProgressMax;
percent = newPercent;
progress = newProgress;
progressMax = newProgressMax;
indeterminate = indeterminant;
message = newMessage;
message = newMessage;
if (same) return;
@@ -95,6 +97,6 @@ public final class NotificationController {
if (genericForegroundService == null) return;
genericForegroundService.replaceProgress(id, progressMax, progress, indeterminate, message);
genericForegroundService.replaceProgress(id, progressMax, progress, indeterminate, message);
}
}
+33 -32
View File
@@ -9,42 +9,43 @@
android:gravity="center_vertical"
android:focusable="true">
<ImageView
android:id="@+id/call_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@null" />
<ImageView
android:id="@+id/call_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@null" />
<LinearLayout android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:fontFamily="sans-serif"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?conversation_item_outgoing_text_primary_color"
tools:text="Incoming call" />
android:layout_weight="1"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:fontFamily="sans-serif"
android:textColor="?conversation_item_incoming_text_secondary_color"
tools:text="Incoming call" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:fontFamily="sans-serif"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?conversation_item_outgoing_text_primary_color"
tools:text="Incoming call" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:fontFamily="sans-serif"
android:textColor="?conversation_item_incoming_text_secondary_color"
tools:text="Incoming call" />
</LinearLayout>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.CallItemView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/call_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible"/>
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/call_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
+240 -242
View File
@@ -13,265 +13,263 @@
android:clipToPadding="false"
android:clipChildren="false">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/conversation_individual_right_gutter"
android:layout_marginEnd="@dimen/conversation_individual_right_gutter"
android:layout_marginBottom="@dimen/below_bubble"
android:paddingLeft="6dp"
android:paddingStart="6dp"
android:clipToPadding="false"
android:clipChildren="false"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/jumpto_icon"
>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/reply_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignStart="@id/body_bubble"
android:layout_alignTop="@id/body_bubble"
android:layout_alignBottom="@id/body_bubble"
android:alpha="0"
app:srcCompat="?menu_reply_icon"
android:tint="?icon_tint"
android:layout_alignLeft="@id/body_bubble" />
<FrameLayout
android:id="@+id/contact_photo_container"
android:layout_width="36dp"
<RelativeLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignBottom="@id/body_bubble">
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/contact_photo"
android:foreground="@drawable/contact_photo_background"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginBottom="1dp"
android:cropToPadding="true"
android:contentDescription="@string/pref_profile_photo" />
</FrameLayout>
<LinearLayout
android:id="@+id/body_bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/message_bubble_edge_margin"
android:layout_marginEnd="@dimen/message_bubble_edge_margin"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_toRightOf="@id/contact_photo_container"
android:layout_toEndOf="@id/contact_photo_container"
android:orientation="vertical"
android:layout_marginRight="@dimen/conversation_individual_right_gutter"
android:layout_marginEnd="@dimen/conversation_individual_right_gutter"
android:layout_marginBottom="@dimen/below_bubble"
android:paddingLeft="6dp"
android:paddingStart="6dp"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/core_light_10">
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/jumpto_icon">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/reply_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignStart="@id/body_bubble"
android:layout_alignTop="@id/body_bubble"
android:layout_alignBottom="@id/body_bubble"
android:alpha="0"
app:srcCompat="?menu_reply_icon"
android:tint="?icon_tint"
android:layout_alignLeft="@id/body_bubble" />
<FrameLayout
android:id="@+id/contact_photo_container"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignBottom="@id/body_bubble">
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/contact_photo"
android:foreground="@drawable/contact_photo_background"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginBottom="1dp"
android:cropToPadding="true"
android:contentDescription="@string/pref_profile_photo" />
</FrameLayout>
<LinearLayout
android:id="@+id/group_sender_holder"
android:id="@+id/body_bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="2dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
android:layout_marginRight="@dimen/message_bubble_edge_margin"
android:layout_marginEnd="@dimen/message_bubble_edge_margin"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_toRightOf="@id/contact_photo_container"
android:layout_toEndOf="@id/contact_photo_container"
android:orientation="vertical"
android:clipToPadding="false"
android:clipChildren="false"
android:background="@color/white"
tools:backgroundTint="@color/core_light_10">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/group_message_sender"
<LinearLayout
android:id="@+id/group_sender_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="4sp"
android:layout_marginEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-medium"
android:maxLines="1"
android:ellipsize="end"
tools:visibility="visible"
tools:text="Alice"/>
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="2dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/group_message_sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="4sp"
android:layout_marginEnd="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-medium"
android:maxLines="1"
android:ellipsize="end"
tools:visibility="visible"
tools:text="Alice" />
</LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:visibility="gone"
app:message_type="incoming"
app:quote_colorPrimary="?attr/conversation_item_quote_text_color"
app:quote_colorSecondary="?attr/conversation_item_quote_text_color"
tools:visibility="visible" />
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_thumbnail" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sticker" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_received_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_received_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/webxdc_view_stub"
android:layout="@layout/conversation_item_webxdc"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/vcard_view_stub"
android:layout="@layout/conversation_item_vcard"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/call_view_stub"
android:layout="@layout/conversation_item_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.AutoScaledEmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:paddingTop="@dimen/message_bubble_top_padding"
android:textColor="?conversation_item_incoming_text_primary_color"
android:textColorLink="?attr/colorAccent"
android:importantForAccessibility="no"
tools:text="Mango pickle lorem ipsum" />
<Button
android:id="@+id/msg_action_button"
android:visibility="gone"
style="@style/ButtonPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:padding="@dimen/message_bubble_showmore_padding"
android:minHeight="1dp"
android:minWidth="0dp"
android:text="@string/show_full_message"
android:textAllCaps="false" />
<Button
android:id="@+id/show_full_button"
android:visibility="gone"
style="@style/Signal.Text.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:paddingTop="@dimen/message_bubble_showmore_padding"
android:paddingBottom="@dimen/message_bubble_showmore_padding"
android:minHeight="1dp"
android:minWidth="0dp"
android:background="@drawable/touch_highlight_background_strong"
android:textColor="@color/delta_accent_darker"
android:text="@string/show_full_message"
android:textAllCaps="false" />
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:layout_gravity="end"
android:gravity="end"
android:clipChildren="false"
android:clipToPadding="false"
android:alpha="0.7"
app:footer_text_color="?conversation_item_incoming_text_secondary_color" />
</LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView
android:id="@+id/quote_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:visibility="gone"
app:message_type="incoming"
app:quote_colorPrimary="?attr/conversation_item_quote_text_color"
app:quote_colorSecondary="?attr/conversation_item_quote_text_color"
tools:visibility="visible"/>
<ViewStub
android:id="@+id/image_view_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_thumbnail" />
<ViewStub
android:id="@+id/sticker_view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sticker" />
<ViewStub
android:id="@+id/audio_view_stub"
android:layout="@layout/conversation_item_received_audio"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/document_view_stub"
android:layout="@layout/conversation_item_received_document"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/webxdc_view_stub"
android:layout="@layout/conversation_item_webxdc"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/vcard_view_stub"
android:layout="@layout/conversation_item_vcard"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<ViewStub
android:id="@+id/call_view_stub"
android:layout="@layout/conversation_item_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding" />
<org.thoughtcrime.securesms.components.emoji.AutoScaledEmojiTextView
android:id="@+id/conversation_item_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
style="@style/Signal.Text.Body"
android:paddingTop="@dimen/message_bubble_top_padding"
android:textColor="?conversation_item_incoming_text_primary_color"
android:textColorLink="?attr/colorAccent"
android:importantForAccessibility="no"
tools:text="Mango pickle lorem ipsum"/>
<Button
android:id="@+id/msg_action_button"
android:visibility="gone"
style="@style/ButtonPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:padding="@dimen/message_bubble_showmore_padding"
android:minHeight="1dp"
android:minWidth="0dp"
android:text="@string/show_full_message"
android:textAllCaps="false"/>
<Button
android:id="@+id/show_full_button"
android:visibility="gone"
style="@style/Signal.Text.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:paddingTop="@dimen/message_bubble_showmore_padding"
android:paddingBottom="@dimen/message_bubble_showmore_padding"
android:minHeight="1dp"
android:minWidth="0dp"
android:background="@drawable/touch_highlight_background_strong"
android:textColor="@color/delta_accent_darker"
android:text="@string/show_full_message"
android:textAllCaps="false"/>
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
<org.thoughtcrime.securesms.reactions.ReactionsConversationView
android:id="@+id/reactions_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/body_bubble"
android:layout_alignStart="@id/body_bubble"
android:layout_marginTop="-4dp"
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:layout_gravity="end"
android:gravity="end"
android:clipChildren="false"
android:clipToPadding="false"
android:alpha="0.7"
app:footer_text_color="?conversation_item_incoming_text_secondary_color"/>
android:orientation="horizontal"
app:message_type="incoming" />
</LinearLayout>
</RelativeLayout>
<org.thoughtcrime.securesms.reactions.ReactionsConversationView
android:id="@+id/reactions_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/body_bubble"
android:layout_alignStart="@id/body_bubble"
android:layout_marginTop="-4dp"
android:orientation="horizontal"
app:message_type="incoming" />
</RelativeLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/jumpto_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginEnd="@dimen/conversation_individual_right_gutter"
android:padding="5dp"
android:src="@drawable/rounded_arrow_forward_24"
android:background="@drawable/jumpto_btn_bg"
android:contentDescription="@string/show_in_chat"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/jumpto_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginEnd="@dimen/conversation_individual_right_gutter"
android:padding="5dp"
android:src="@drawable/rounded_arrow_forward_24"
android:background="@drawable/jumpto_btn_bg"
android:contentDescription="@string/show_in_chat"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</org.thoughtcrime.securesms.ConversationItem>
+18 -19
View File
@@ -13,18 +13,17 @@
android:clipToPadding="false"
android:clipChildren="false">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/jumpto_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/conversation_individual_left_gutter"
android:padding="5dp"
android:src="@drawable/rounded_arrow_forward_24"
android:background="@drawable/jumpto_btn_bg"
android:contentDescription="@string/show_in_chat"
android:visibility="gone"
/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/jumpto_icon"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/conversation_individual_left_gutter"
android:padding="5dp"
android:src="@drawable/rounded_arrow_forward_24"
android:background="@drawable/jumpto_btn_bg"
android:contentDescription="@string/show_in_chat"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/container"
@@ -86,7 +85,7 @@
android:maxLines="1"
android:ellipsize="end"
tools:visibility="visible"
tools:text="Bob"/>
tools:text="Bob" />
</LinearLayout>
@@ -101,7 +100,7 @@
app:message_type="incoming"
app:quote_colorPrimary="?attr/conversation_item_quote_text_color"
app:quote_colorSecondary="?attr/conversation_item_quote_text_color"
tools:visibility="visible"/>
tools:visibility="visible" />
<ViewStub
android:id="@+id/image_view_stub"
@@ -176,7 +175,7 @@
android:textColor="?conversation_item_outgoing_text_primary_color"
android:textColorLink="?attr/colorAccent"
android:importantForAccessibility="no"
tools:text="Mango pickle lorem ipsum"/>
tools:text="Mango pickle lorem ipsum" />
<Button
android:id="@+id/msg_action_button"
@@ -192,7 +191,7 @@
android:minHeight="1dp"
android:minWidth="0dp"
android:text="@string/show_full_message"
android:textAllCaps="false"/>
android:textAllCaps="false" />
<Button
android:id="@+id/show_full_button"
@@ -210,7 +209,7 @@
android:background="@drawable/touch_highlight_background_strong"
android:textColor="@color/delta_accent_darker"
android:text="@string/show_full_message"
android:textAllCaps="false"/>
android:textAllCaps="false" />
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_item_footer"
@@ -224,7 +223,7 @@
android:gravity="end"
android:clipChildren="false"
android:clipToPadding="false"
app:footer_text_color="?attr/conversation_item_outgoing_text_secondary_color"/>
app:footer_text_color="?attr/conversation_item_outgoing_text_secondary_color" />
</LinearLayout>
@@ -239,7 +238,7 @@
app:message_type="outgoing" />
<!-- the following view is only left because it is used as a reference for positioning above.
removing would require some re-layouting, it's just not done yet.-->
removing would require some re-layouting, it's just not done yet. -->
<View
android:visibility="gone"
android:id="@+id/indicators_parent"
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.ConversationUpdateItem xmlns:android="http://schemas.android.com/apk/res/android"
<org.thoughtcrime.securesms.ConversationUpdateItem
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -40,7 +41,7 @@
android:scaleType="centerCrop"
android:visibility="gone" />
<!--Links should be clickable, see https://github.com/deltachat/deltachat-android/issues/1546-->
<!--Links should be clickable, see https://github.com/deltachat/deltachat-android/issues/1546 -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/conversation_update_body"
style="@style/Delta.Text.UpdateHeader"
@@ -54,7 +55,8 @@
</LinearLayout>
<ImageView android:id="@+id/delivery_indicator"
<ImageView
android:id="@+id/delivery_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
+15 -10
View File
@@ -1,16 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string-array name="pref_theme_entries" tools:ignore="InconsistentArrays">
<item>@string/pref_system_default</item>
<item>@string/pref_light_theme</item>
<item>@string/pref_dark_theme</item>
</string-array>
<string-array
name="pref_theme_entries"
tools:ignore="InconsistentArrays">
<item>@string/pref_system_default</item>
<item>@string/pref_light_theme</item>
<item>@string/pref_dark_theme</item>
</string-array>
<string-array name="pref_theme_values" translatable="false" tools:ignore="InconsistentArrays">
<item>system</item>
<item>light</item>
<item>dark</item>
</string-array>
<string-array
name="pref_theme_values"
translatable="false"
tools:ignore="InconsistentArrays">
<item>system</item>
<item>light</item>
<item>dark</item>
</string-array>
</resources>