mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eed844469b | |||
| 59ceae46a0 | |||
| 693188dcff | |||
| 025ff086c8 | |||
| a802bfcb61 | |||
| 1f18bfe2dd | |||
| dc1bc77925 | |||
| ac6383d79a | |||
| 59fec8462c | |||
| d64baa294f | |||
| e7e14af158 | |||
| e094e96669 | |||
| fa56e8ca0d | |||
| 3d5abdcd79 | |||
| 92c4e41b59 | |||
| bbfd0c31da | |||
| d5f627be50 | |||
| f0ca58d53f | |||
| 56f5655693 | |||
| 310a7f99c8 | |||
| d0f7fca8c9 | |||
| 80de08f980 | |||
| 80a0ff0098 | |||
| 9c55de17a3 | |||
| 8c1bc8e70e | |||
| f0760d6695 | |||
| 6d038e9d7f | |||
| 46be278bf5 | |||
| 1577b90047 | |||
| 515a84b161 | |||
| d757ef59c0 | |||
| d0a584d15d | |||
| f8ec6d2da2 | |||
| c3b7e06b86 | |||
| d5edcea5d0 | |||
| 8a3d29fca3 | |||
| 6156ee0534 |
@@ -25,7 +25,7 @@ jobs:
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
ndk-version: "r29"
|
||||
|
||||
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1.6.0
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27
|
||||
ndk-version: "r29"
|
||||
|
||||
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
|
||||
with:
|
||||
@@ -77,12 +77,14 @@ jobs:
|
||||
|
||||
- name: Upload APK
|
||||
id: upload
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: app-preview.apk
|
||||
path: 'build/outputs/apk/foss/debug/*.apk'
|
||||
|
||||
- name: Add artifact links to PR
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
env:
|
||||
ARTIFACT_URL: ${{ steps.upload.outputs.artifact-url }}
|
||||
|
||||
+11
-1
@@ -1,5 +1,15 @@
|
||||
# Delta Chat Android Changelog
|
||||
|
||||
## v2.53.0
|
||||
2026-06
|
||||
|
||||
* Use message style notifications for longer message previews
|
||||
* Remove notification after audio playback ends
|
||||
* Fix: do not allow blocked contacts to use our invite links
|
||||
* Fix sending mini-app that was used/prepared before sending
|
||||
* Some more small fixes and updated translations
|
||||
* Update to core 2.53.0
|
||||
|
||||
## v2.52.0
|
||||
2026-06
|
||||
|
||||
@@ -7,7 +17,7 @@
|
||||
* Fix: Incorrect total time when attaching audio files as draft
|
||||
* Fix: Audio files in draft showing total time from wrong file
|
||||
* Fix: Update the channel title after joining if the QR code had an outdated title
|
||||
* Voice recording will be automatically saved as draft when interrupted
|
||||
* Voice recording will be automatically saved as draft when interrupted
|
||||
* Update to core 2.52.0
|
||||
|
||||
## v2.51.0
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ android {
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
defaultConfig {
|
||||
versionCode 30000745
|
||||
versionName "2.52.0"
|
||||
versionCode 30000746
|
||||
versionName "2.53.0"
|
||||
|
||||
applicationId "chat.delta.lite"
|
||||
multiDexEnabled true
|
||||
|
||||
+1
-1
Submodule jni/deltachat-core-rust updated: 4ecf597ba3...9435042594
@@ -84,7 +84,7 @@ public class DcAccounts {
|
||||
public boolean isAllChatmail() {
|
||||
for (int accountId : getAll()) {
|
||||
DcContext dcContext = getAccount(accountId);
|
||||
if (!dcContext.isChatmail()) {
|
||||
if (dcContext.getConfigInt("is_chatmail") == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,10 +362,6 @@ public class DcContext {
|
||||
return displayname;
|
||||
}
|
||||
|
||||
public boolean isChatmail() {
|
||||
return getConfigInt("is_chatmail") == 1;
|
||||
}
|
||||
|
||||
public boolean isMuted() {
|
||||
return getConfigInt("is_muted") == 1;
|
||||
}
|
||||
|
||||
@@ -302,7 +302,10 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onAvailable() #" + debugOnAvailableCount++);
|
||||
getDcAccounts().maybeNetwork();
|
||||
// onBlockedStatusChanged is only available on API 29+
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
getDcAccounts().maybeNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -310,8 +313,13 @@ public class ApplicationContext extends MultiDexApplication {
|
||||
@NonNull android.net.Network network, boolean blocked) {
|
||||
Log.i(
|
||||
"DeltaChat",
|
||||
"++++++++++++++++++ NetworkCallback.onBlockedStatusChanged() #"
|
||||
"++++++++++++++++++ NetworkCallback.onBlockedStatusChanged("
|
||||
+ blocked
|
||||
+ ") #"
|
||||
+ debugOnBlockedStatusChangedCount++);
|
||||
if (!blocked) {
|
||||
getDcAccounts().maybeNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -260,12 +260,11 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
||||
final String addr = extraEmail[0];
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
|
||||
if (contactId == 0) {
|
||||
contactId = dcContext.createContact(null, addr);
|
||||
if (contactId != 0 || dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 0) {
|
||||
if (contactId == 0) contactId = dcContext.createContact(null, addr);
|
||||
chatId = dcContext.createChatByContactId(contactId);
|
||||
accId = dcContext.getAccountId();
|
||||
}
|
||||
|
||||
chatId = dcContext.createChatByContactId(contactId);
|
||||
accId = dcContext.getAccountId();
|
||||
}
|
||||
Intent composeIntent;
|
||||
if (accId != -1 && chatId > 0) {
|
||||
|
||||
@@ -51,7 +51,6 @@ import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.json.JSONObject;
|
||||
import org.thoughtcrime.securesms.connect.AccountManager;
|
||||
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.util.IntentUtils;
|
||||
|
||||
+4
-1
@@ -264,7 +264,10 @@ public class AudioPlaybackViewModel extends ViewModel {
|
||||
updateCurrentState(false);
|
||||
} else if (player.getPlaybackState() == Player.STATE_ENDED
|
||||
&& !player.hasNextMediaItem()) {
|
||||
mediaController.setPlayWhenReady(false);
|
||||
mediaController.stop();
|
||||
mediaController.clearMediaItems();
|
||||
stopUpdateProgress();
|
||||
playbackState.setValue(AudioPlaybackState.idle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class DcContactsLoader extends AsyncLoader<DcContactsLoader.Ret> {
|
||||
if (query == null && addScanQRLink) {
|
||||
additional_items = Util.appendInt(additional_items, DcContact.DC_CONTACT_ID_QR_INVITE);
|
||||
}
|
||||
if (addCreateContactLink && !dcContext.isChatmail()) {
|
||||
if (addCreateContactLink && dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 0) {
|
||||
additional_items =
|
||||
Util.appendInt(additional_items, DcContact.DC_CONTACT_ID_NEW_CLASSIC_CONTACT);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class DcContactsLoader extends AsyncLoader<DcContactsLoader.Ret> {
|
||||
additional_items = Util.appendInt(additional_items, DcContact.DC_CONTACT_ID_NEW_GROUP);
|
||||
additional_items = Util.appendInt(additional_items, DcContact.DC_CONTACT_ID_NEW_BROADCAST);
|
||||
|
||||
if (!dcContext.isChatmail()) {
|
||||
if (dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 0) {
|
||||
additional_items =
|
||||
Util.appendInt(additional_items, DcContact.DC_CONTACT_ID_NEW_UNENCRYPTED_GROUP);
|
||||
}
|
||||
|
||||
@@ -528,16 +528,20 @@ public class DcHelper {
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void showInvalidUnencryptedDialog(Context context) {
|
||||
new AlertDialog.Builder(context)
|
||||
public static AlertDialog.Builder prepareInvalidUnencryptedDialog(
|
||||
Context context, AlertDialog.Builder builder) {
|
||||
return builder
|
||||
.setMessage(context.getString(R.string.invalid_unencrypted_explanation))
|
||||
.setNeutralButton(R.string.learn_more, (d, w) -> openHelp(context, "#howtoe2ee"))
|
||||
.setNegativeButton(
|
||||
R.string.qrscan_title,
|
||||
(d, w) -> context.startActivity(new Intent(context, QrActivity.class)))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
.setCancelable(true);
|
||||
}
|
||||
|
||||
public static void showInvalidUnencryptedDialog(Context context) {
|
||||
prepareInvalidUnencryptedDialog(context, new AlertDialog.Builder(context)).show();
|
||||
}
|
||||
|
||||
public static void openHelp(Context context, String section) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.RingtoneManager;
|
||||
@@ -23,13 +24,18 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.app.Person;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import androidx.core.app.TaskStackBuilder;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.HashMap;
|
||||
@@ -42,6 +48,7 @@ import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.ShareActivity;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
@@ -61,8 +68,18 @@ public class NotificationCenter {
|
||||
private volatile long lastAudibleNotification = 0;
|
||||
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
|
||||
|
||||
// Map<accountId, Map<chatId, lines>, contains the last lines of each chat for each account
|
||||
private final HashMap<Integer, HashMap<Integer, LinkedHashMap<Integer, String>>> inboxes =
|
||||
private static class NotifData {
|
||||
final Person sender;
|
||||
final String text;
|
||||
|
||||
NotifData(Person sender, String text) {
|
||||
this.sender = sender;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
// notification history of each chat for each account
|
||||
private final HashMap<Integer, HashMap<Integer, LinkedHashMap<Integer, NotifData>>> inboxes =
|
||||
new HashMap<>();
|
||||
|
||||
public NotificationCenter(Context context) {
|
||||
@@ -410,31 +427,36 @@ public class NotificationCenter {
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context);
|
||||
|
||||
String shortLine =
|
||||
DcContact sender = dcContext.getContact(dcMsg.getFromId());
|
||||
String senderName = dcMsg.getSenderName(sender);
|
||||
String text =
|
||||
privacy.isDisplayMessage()
|
||||
? dcMsg.getSummarytext(2000)
|
||||
: context.getString(R.string.notify_new_message);
|
||||
String shortLine = text;
|
||||
if (dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
shortLine =
|
||||
dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + shortLine;
|
||||
shortLine = senderName + ": " + text;
|
||||
}
|
||||
String tickerLine = shortLine;
|
||||
if (!dcChat.isMultiUser() && privacy.isDisplayContact()) {
|
||||
tickerLine =
|
||||
dcMsg.getSenderName(dcContext.getContact(dcMsg.getFromId())) + ": " + tickerLine;
|
||||
|
||||
if (dcMsg.getOverrideSenderName() != null) {
|
||||
// There is an "overridden" display name on the message, so, we need to prepend the
|
||||
// display name to the message,
|
||||
// i.e. set the shortLine to be the same as the tickerLine.
|
||||
shortLine = tickerLine;
|
||||
}
|
||||
NotifData notifData =
|
||||
new NotifData(
|
||||
new Person.Builder()
|
||||
.setName(senderName)
|
||||
.setIcon(getAvatarIcon(sender))
|
||||
.setBot(sender.isBot())
|
||||
.setKey(accountId + "-" + sender.getId())
|
||||
.build(),
|
||||
text);
|
||||
|
||||
String tickerLine = text;
|
||||
if (privacy.isDisplayContact()) {
|
||||
tickerLine = senderName + ": " + text;
|
||||
}
|
||||
|
||||
DcMsg quotedMsg = dcMsg.getQuotedMsg();
|
||||
boolean isMention = dcChat.isMultiUser() && quotedMsg != null && quotedMsg.isOutgoing();
|
||||
|
||||
maybeAddNotification(accountId, dcChat, msgId, shortLine, tickerLine, true, isMention);
|
||||
maybeAddNotification(accountId, dcChat, msgId, notifData, tickerLine, true, isMention);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -451,15 +473,27 @@ public class NotificationCenter {
|
||||
}
|
||||
|
||||
DcContact sender = dcContext.getContact(contactId);
|
||||
String shortLine =
|
||||
String senderName = dcMsg.getSenderName(sender);
|
||||
String text =
|
||||
context.getString(
|
||||
R.string.reaction_by_other,
|
||||
sender.getDisplayName(),
|
||||
reaction,
|
||||
dcMsg.getSummarytext(2000));
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
|
||||
NotifData notifData =
|
||||
new NotifData(
|
||||
new Person.Builder()
|
||||
.setName(senderName)
|
||||
.setIcon(getAvatarIcon(sender))
|
||||
.setBot(sender.isBot())
|
||||
.setKey(accountId + "-" + sender.getId())
|
||||
.build(),
|
||||
text);
|
||||
|
||||
maybeAddNotification(
|
||||
accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
|
||||
accountId, dcChat, msgId, notifData, text, false, dcChat.isMultiUser());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -473,6 +507,7 @@ public class NotificationCenter {
|
||||
|
||||
DcContext dcContext = context.getDcAccounts().getAccount(accountId);
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
DcMsg parentMsg;
|
||||
if (dcMsg.getType() == DcMsg.DC_MSG_WEBXDC) {
|
||||
parentMsg = dcMsg;
|
||||
@@ -486,10 +521,34 @@ public class NotificationCenter {
|
||||
|
||||
JSONObject info = parentMsg.getWebxdcInfo();
|
||||
final String name = JsonUtils.optString(info, "name");
|
||||
String shortLine = name.isEmpty() ? text : (name + ": " + text);
|
||||
DcChat dcChat = dcContext.getChat(dcMsg.getChatId());
|
||||
String tickerLine = name.isEmpty() ? text : (name + ": " + text);
|
||||
|
||||
NotifData notifData;
|
||||
if (dcChat.isMultiUser()) {
|
||||
byte[] blob = parentMsg.getWebxdcBlob(JsonUtils.optString(info, "icon"));
|
||||
notifData =
|
||||
new NotifData(
|
||||
new Person.Builder()
|
||||
.setName(name)
|
||||
.setIcon(getAvatarIcon(blob))
|
||||
.setKey(accountId + "-webxdc-" + msgId)
|
||||
.build(),
|
||||
text);
|
||||
} else {
|
||||
DcContact sender = dcContext.getContact(contactId);
|
||||
notifData =
|
||||
new NotifData(
|
||||
new Person.Builder()
|
||||
.setName(dcMsg.getSenderName(sender))
|
||||
.setIcon(getAvatarIcon(sender))
|
||||
.setBot(sender.isBot())
|
||||
.setKey(dcContext.getAccountId() + "-" + sender.getId())
|
||||
.build(),
|
||||
tickerLine);
|
||||
}
|
||||
|
||||
maybeAddNotification(
|
||||
accountId, dcChat, msgId, shortLine, shortLine, false, dcChat.isMultiUser());
|
||||
accountId, dcChat, msgId, notifData, tickerLine, false, dcChat.isMultiUser());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -498,7 +557,7 @@ public class NotificationCenter {
|
||||
int accountId,
|
||||
DcChat dcChat,
|
||||
int msgId,
|
||||
String shortLine,
|
||||
NotifData notifData,
|
||||
String tickerLine,
|
||||
boolean playInChatSound,
|
||||
boolean isMention) {
|
||||
@@ -538,20 +597,23 @@ public class NotificationCenter {
|
||||
// the user may eg. have chosen a different sound
|
||||
String notificationChannel = getNotificationChannel(notificationManager, chatData, dcChat);
|
||||
|
||||
LinkedHashMap<Integer, String> messagesForInbox = null;
|
||||
if (privacy.isDisplayContact() && privacy.isDisplayMessage()) {
|
||||
LinkedHashMap<Integer, NotifData> messagesForInbox = null;
|
||||
if (privacy.isDisplayContact()) {
|
||||
synchronized (inboxes) {
|
||||
HashMap<Integer, LinkedHashMap<Integer, String>> accountInbox = inboxes.get(accountId);
|
||||
HashMap<Integer, LinkedHashMap<Integer, NotifData>> accountInbox = inboxes.get(accountId);
|
||||
if (accountInbox == null) {
|
||||
accountInbox = new HashMap<>();
|
||||
inboxes.put(accountId, accountInbox);
|
||||
}
|
||||
LinkedHashMap<Integer, String> messages = accountInbox.get(chatId);
|
||||
LinkedHashMap<Integer, NotifData> messages = accountInbox.get(chatId);
|
||||
if (messages == null) {
|
||||
messages = new LinkedHashMap<>();
|
||||
accountInbox.put(chatId, messages);
|
||||
}
|
||||
messages.put(msgId, shortLine);
|
||||
if (!privacy.isDisplayMessage()) {
|
||||
messages.clear();
|
||||
}
|
||||
messages.put(msgId, notifData);
|
||||
messagesForInbox = new LinkedHashMap<>(messages);
|
||||
}
|
||||
}
|
||||
@@ -564,7 +626,7 @@ public class NotificationCenter {
|
||||
dcContext,
|
||||
dcChat,
|
||||
notificationChannel,
|
||||
shortLine,
|
||||
notifData.text,
|
||||
tickerLine,
|
||||
signal,
|
||||
messagesForInbox,
|
||||
@@ -583,7 +645,7 @@ public class NotificationCenter {
|
||||
String contentText,
|
||||
String ticker,
|
||||
boolean signal,
|
||||
LinkedHashMap<Integer, String> messagesForInbox,
|
||||
LinkedHashMap<Integer, NotifData> messagesForInbox,
|
||||
int messageCount,
|
||||
boolean includeSummary) {
|
||||
try {
|
||||
@@ -694,14 +756,42 @@ public class NotificationCenter {
|
||||
}
|
||||
}
|
||||
|
||||
// Create inbox style (gets visible if the notification is expanded)
|
||||
if (privacy.isDisplayContact() && privacy.isDisplayMessage() && messagesForInbox != null) {
|
||||
// Create messaging style
|
||||
if (privacy.isDisplayContact() && messagesForInbox != null) {
|
||||
try {
|
||||
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
|
||||
for (String line : messagesForInbox.values()) {
|
||||
inboxStyle.addLine(line);
|
||||
Intent viewChatIntent = new Intent(context, ShareActivity.class);
|
||||
viewChatIntent.setAction(Intent.ACTION_SEND);
|
||||
viewChatIntent.putExtra(ShareActivity.EXTRA_ACC_ID, dcContext.getAccountId());
|
||||
viewChatIntent.putExtra(ShareActivity.EXTRA_CHAT_ID, dcChat.getId());
|
||||
|
||||
ShortcutInfoCompat shortcut =
|
||||
new ShortcutInfoCompat.Builder(
|
||||
context, "chat-" + dcContext.getAccountId() + "-" + dcChat.getId())
|
||||
.setShortLabel(dcChat.getName())
|
||||
.setLongLived(true)
|
||||
.setIntent(viewChatIntent)
|
||||
.build();
|
||||
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut);
|
||||
builder.setShortcutInfo(shortcut);
|
||||
|
||||
DcContact selfContact = dcContext.getContact(DcContact.DC_CONTACT_ID_SELF);
|
||||
Person self =
|
||||
new Person.Builder()
|
||||
.setName(selfContact.getDisplayName())
|
||||
.setIcon(getAvatarIcon(selfContact))
|
||||
.setKey(accountId + "-" + selfContact.getId())
|
||||
.build();
|
||||
NotificationCompat.MessagingStyle style = new NotificationCompat.MessagingStyle(self);
|
||||
if (dcChat.isMultiUser()) {
|
||||
style.setGroupConversation(true);
|
||||
style.setConversationTitle(dcChat.getName());
|
||||
}
|
||||
builder.setStyle(inboxStyle);
|
||||
for (Map.Entry<Integer, NotifData> msgEntry : messagesForInbox.entrySet()) {
|
||||
long timestamp_ms = dcContext.getMsg(msgEntry.getKey()).getSortTimestamp() * 1000;
|
||||
NotifData notifData = msgEntry.getValue();
|
||||
style.addMessage(notifData.text, timestamp_ms, notifData.sender);
|
||||
}
|
||||
builder.setStyle(style);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
@@ -748,7 +838,7 @@ public class NotificationCenter {
|
||||
|
||||
@WorkerThread
|
||||
private void rebuildNotification(
|
||||
int accountId, int chatId, LinkedHashMap<Integer, String> messages) {
|
||||
int accountId, int chatId, LinkedHashMap<Integer, NotifData> messages) {
|
||||
try {
|
||||
DcContext dcContext = ApplicationContext.getDcAccounts().getAccount(accountId);
|
||||
DcChat dcChat = dcContext.getChat(chatId);
|
||||
@@ -766,9 +856,9 @@ public class NotificationCenter {
|
||||
// Get the latest message ID (last entry in LinkedHashMap)
|
||||
Integer latestMsgId = null;
|
||||
String lastLine = null;
|
||||
for (Map.Entry<Integer, String> entry : messages.entrySet()) {
|
||||
for (Map.Entry<Integer, NotifData> entry : messages.entrySet()) {
|
||||
latestMsgId = entry.getKey();
|
||||
lastLine = entry.getValue();
|
||||
lastLine = entry.getValue().text;
|
||||
}
|
||||
if (latestMsgId == null || lastLine == null) {
|
||||
return;
|
||||
@@ -797,8 +887,35 @@ public class NotificationCenter {
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap getAvatar(DcChat dcChat) {
|
||||
Recipient recipient = new Recipient(context, dcChat);
|
||||
private static @Nullable IconCompat getAvatarIcon(byte[] blob) {
|
||||
if (blob == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(blob);
|
||||
BitmapDrawable drawable = (BitmapDrawable) Drawable.createFromStream(is, "icon");
|
||||
Bitmap bitmap = drawable.getBitmap();
|
||||
return IconCompat.createWithBitmap(bitmap);
|
||||
}
|
||||
|
||||
private @Nullable IconCompat getAvatarIcon(DcChat dcChat) {
|
||||
Bitmap avatar = getAvatar(dcChat);
|
||||
return avatar != null ? IconCompat.createWithBitmap(avatar) : null;
|
||||
}
|
||||
|
||||
private @Nullable IconCompat getAvatarIcon(DcContact dcContact) {
|
||||
Bitmap avatar = getAvatar(dcContact);
|
||||
return avatar != null ? IconCompat.createWithBitmap(avatar) : null;
|
||||
}
|
||||
|
||||
private @Nullable Bitmap getAvatar(DcChat dcChat) {
|
||||
return getAvatar(new Recipient(context, dcChat));
|
||||
}
|
||||
|
||||
private @Nullable Bitmap getAvatar(DcContact dcContact) {
|
||||
return getAvatar(new Recipient(context, dcContact));
|
||||
}
|
||||
|
||||
private @Nullable Bitmap getAvatar(Recipient recipient) {
|
||||
try {
|
||||
Drawable drawable;
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(context);
|
||||
@@ -837,12 +954,12 @@ public class NotificationCenter {
|
||||
public void removeNotification(int accountId, int chatId, int msgId) {
|
||||
boolean shouldCancelNotification = false;
|
||||
boolean removeSummary = false;
|
||||
LinkedHashMap<Integer, String> remainingMessages = null;
|
||||
LinkedHashMap<Integer, NotifData> remainingMessages = null;
|
||||
|
||||
synchronized (inboxes) {
|
||||
HashMap<Integer, LinkedHashMap<Integer, String>> accountInbox = inboxes.get(accountId);
|
||||
HashMap<Integer, LinkedHashMap<Integer, NotifData>> accountInbox = inboxes.get(accountId);
|
||||
if (accountInbox != null) {
|
||||
LinkedHashMap<Integer, String> messages = accountInbox.get(chatId);
|
||||
LinkedHashMap<Integer, NotifData> messages = accountInbox.get(chatId);
|
||||
if (messages != null) {
|
||||
messages.remove(msgId);
|
||||
|
||||
@@ -875,7 +992,7 @@ public class NotificationCenter {
|
||||
public void removeNotifications(int accountId, int chatId) {
|
||||
boolean removeSummary;
|
||||
synchronized (inboxes) {
|
||||
HashMap<Integer, LinkedHashMap<Integer, String>> accountInbox = inboxes.get(accountId);
|
||||
HashMap<Integer, LinkedHashMap<Integer, NotifData>> accountInbox = inboxes.get(accountId);
|
||||
if (accountInbox == null) {
|
||||
accountInbox = new HashMap<>();
|
||||
}
|
||||
@@ -901,7 +1018,7 @@ public class NotificationCenter {
|
||||
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||
String tag = String.valueOf(accountId);
|
||||
synchronized (inboxes) {
|
||||
HashMap<Integer, LinkedHashMap<Integer, String>> accountInbox = inboxes.get(accountId);
|
||||
HashMap<Integer, LinkedHashMap<Integer, NotifData>> accountInbox = inboxes.get(accountId);
|
||||
notificationManager.cancel(tag, ID_MSG_SUMMARY);
|
||||
if (accountInbox != null) {
|
||||
for (Integer chatId : accountInbox.keySet()) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
@@ -120,10 +121,12 @@ public class QrActivity extends BaseActionBarActivity implements View.OnClickLis
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
|
||||
menu.clear();
|
||||
getMenuInflater().inflate(R.menu.qr_show, menu);
|
||||
menu.findItem(R.id.new_classic_contact)
|
||||
.setVisible(!scanRelay && !DcHelper.getContext(this).isChatmail());
|
||||
.setVisible(!scanRelay && dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 0);
|
||||
|
||||
Util.redMenuItem(menu, R.id.withdraw);
|
||||
if (tabLayout.getSelectedTabPosition() == TAB_SCAN) {
|
||||
|
||||
@@ -314,6 +314,12 @@ public class QrCodeHandler {
|
||||
|
||||
private void showFingerprintOrQrSuccess(
|
||||
AlertDialog.Builder builder, DcLot qrParsed, String name) {
|
||||
if (qrParsed.getState() == DcContext.DC_QR_ADDR
|
||||
&& dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 1) {
|
||||
DcHelper.prepareInvalidUnencryptedDialog(activity, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
@StringRes
|
||||
int resId =
|
||||
qrParsed.getState() == DcContext.DC_QR_ADDR
|
||||
|
||||
@@ -57,22 +57,26 @@ public class LongClickCopySpan extends ClickableSpan {
|
||||
DcContext dcContext = DcHelper.getContext(activity);
|
||||
|
||||
int contactId = dcContext.lookupContactIdByAddr(addr);
|
||||
if (contactId == 0 && dcContext.mayBeValidAddr(addr)) {
|
||||
contactId = dcContext.createContact(null, addr);
|
||||
}
|
||||
DcContact contact = dcContext.getContact(contactId);
|
||||
if (contact.getId() != 0
|
||||
DcContact contact = (contactId != 0) ? dcContext.getContact(contactId) : null;
|
||||
if (contact != null
|
||||
&& !contact.isBlocked()
|
||||
&& dcContext.getChatIdByContactId(contact.getId()) != 0) {
|
||||
openChat(activity, contact);
|
||||
} else if (contact == null
|
||||
&& dcContext.getConfigInt(DcHelper.CONFIG_FORCE_ENCRYPTION) == 1) {
|
||||
DcHelper.showInvalidUnencryptedDialog(activity);
|
||||
} else {
|
||||
String name = contact != null ? contact.getDisplayName() : addr;
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage(
|
||||
activity.getString(R.string.ask_start_chat_with, contact.getDisplayName()))
|
||||
.setMessage(activity.getString(R.string.ask_start_chat_with, name))
|
||||
.setPositiveButton(
|
||||
android.R.string.ok,
|
||||
(dialog, which) -> {
|
||||
openChat(activity, contact);
|
||||
openChat(
|
||||
activity,
|
||||
contact == null
|
||||
? dcContext.getContact(dcContext.createContact(null, addr))
|
||||
: contact);
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channels">Canals</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="new_channel">Nou Canal</string>
|
||||
<string name="new_channel">Canal nou</string>
|
||||
<!-- consider keeping the term "channel" as in WhatsApp or Telegram -->
|
||||
<string name="channel_name">Nom del Canal</string>
|
||||
<!-- The number of times a message is shown in channels. Use what other messengers are using here, smth. as "N-times seen" or "1 Aufruf" (german) work as well, where "1 impression" or "1 hit" may sound too formal and may be more marketing slang. -->
|
||||
|
||||
@@ -673,7 +673,7 @@
|
||||
<string name="welcome_chat_over_email">Sicherer dezentraler Chat</string>
|
||||
<string name="scan_invitation_code">Einladungscode scannen</string>
|
||||
<string name="login_title">Login</string>
|
||||
<string name="login_advanced_hint">Für fortgeschrittene Benutzer:\n\nVerwende keine Adresse, die du bereits in einer anderen App nutzt.</string>
|
||||
<string name="login_advanced_hint">Für fortgeschrittene Benutzer.\n\nVerwende keine Adresse, die du bereits in einer anderen App nutzt.</string>
|
||||
<string name="login_inbox">Posteingang</string>
|
||||
<string name="login_imap_login">IMAP-Anmeldename</string>
|
||||
<string name="login_imap_server">IMAP-Server</string>
|
||||
|
||||
+397
-187
File diff suppressed because it is too large
Load Diff
@@ -450,6 +450,7 @@
|
||||
<string name="call_answered_elsewhere">Chiamata risposta su un altro dispositivo</string>
|
||||
<string name="call_requires_camera_permission">Per le videochiamate è necessaria l\'autorizzazione per l\'utilizzo della fotocamera.</string>
|
||||
<string name="call_requires_mic_permission">Per le chiamate è necessaria l\'autorizzazione per l\'utilizzo del microfono.</string>
|
||||
<string name="call_requires_connection">Impossibile avviare la chiamata. Assicurati che il tuo dispositivo disponga di una connessione a Internet e riprova.</string>
|
||||
<!-- Used e.g. in a notifications to describe an ongoing call. "Call" is a noun here, in the meaning of "This is the call with ..." where the placeholder is replaced by the name of the contact. -->
|
||||
<string name="call_with">Chiama con %1$s</string>
|
||||
<!-- Use e.g. in a notifications during ringing. Placeholder is relaced by the name of the contact being called. -->
|
||||
@@ -690,6 +691,7 @@
|
||||
<string name="welcome_chat_over_email">Chat Decentralizzata Sicura</string>
|
||||
<string name="scan_invitation_code">Scansiona Codice Invito</string>
|
||||
<string name="login_title">Accedi</string>
|
||||
<string name="login_advanced_hint">Questo login è riservato agli utenti avanzati.\n\nNon utilizzare un indirizzo che stai già usando in un\'altra app.</string>
|
||||
<string name="login_inbox">In Arrivo</string>
|
||||
<string name="login_imap_login">Nome Accesso IMAP</string>
|
||||
<string name="login_imap_server">Server IMAP</string>
|
||||
@@ -724,6 +726,7 @@
|
||||
<string name="used_for_sending">Utilizzato per l\'invio</string>
|
||||
<string name="hide_from_contacts">Nascondi dai Contatti</string>
|
||||
<string name="hidden_from_contacts">Nascosto dai contatti</string>
|
||||
<string name="enforce_e2ee">Applica Crittografia a Tutti i Ripetitori</string>
|
||||
<!-- Hint for the list of relays -->
|
||||
<string name="transport_list_hint">I messaggi vengono ricevuti su tutti i ripetitori.\n\n⚠️ Se modifichi qualcosa qui, assicurati che tutti i tuoi dispositivi abbiano almeno la versione 2.47.0. Altrimenti i dispositivi più vecchi potrebbero non ricevere i messaggi.</string>
|
||||
<!-- shown if a QR code was scanned that can be used as a relay -->
|
||||
|
||||
Reference in New Issue
Block a user