mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
@@ -24,16 +24,33 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/self_avatar_container"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="45dp">
|
||||
<org.thoughtcrime.securesms.components.AvatarView
|
||||
android:id="@+id/self_avatar"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:clickable="true"
|
||||
app:inverted="true"
|
||||
android:contentDescription="@string/pref_profile_info_headline" />
|
||||
<ImageView android:id="@+id/unread_indicator"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:contentDescription="@null"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView style="@style/TextSecure.TitleTextStyle"
|
||||
android:id="@+id/toolbar_title"
|
||||
|
||||
@@ -28,6 +28,8 @@ import static org.thoughtcrime.securesms.util.RelayUtil.isRelayingMessageContent
|
||||
import static org.thoughtcrime.securesms.util.RelayUtil.resetRelayingMessageContent;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -48,6 +50,8 @@ import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.appcompat.widget.TooltipCompat;
|
||||
import androidx.core.view.MenuCompat;
|
||||
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.b44t.messenger.DcAccounts;
|
||||
import com.b44t.messenger.DcContact;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
@@ -71,6 +75,7 @@ import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.SendRelayedMessageUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -89,10 +94,12 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
private ConversationListFragment conversationListFragment;
|
||||
public TextView title;
|
||||
private AvatarView selfAvatar;
|
||||
private ImageView unreadIndicator;
|
||||
private SearchFragment searchFragment;
|
||||
private SearchToolbar searchToolbar;
|
||||
private ImageView searchAction;
|
||||
private ViewGroup fragmentContainer;
|
||||
private ViewGroup selfAvatarContainer;
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
@@ -131,6 +138,8 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
selfAvatar = findViewById(R.id.self_avatar);
|
||||
selfAvatarContainer = findViewById(R.id.self_avatar_container);
|
||||
unreadIndicator = findViewById(R.id.unread_indicator);
|
||||
title = findViewById(R.id.toolbar_title);
|
||||
searchToolbar = findViewById(R.id.search_toolbar);
|
||||
searchAction = findViewById(R.id.search_action);
|
||||
@@ -231,6 +240,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
}
|
||||
|
||||
refreshAvatar();
|
||||
refreshUnreadIndicator();
|
||||
refreshTitle();
|
||||
handleOpenpgp4fpr();
|
||||
if (isDirectSharing(this)) {
|
||||
@@ -266,9 +276,9 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
|
||||
public void refreshAvatar() {
|
||||
if (isRelayingMessageContent(this)) {
|
||||
selfAvatar.setVisibility(View.GONE);
|
||||
selfAvatarContainer.setVisibility(View.GONE);
|
||||
} else {
|
||||
selfAvatar.setVisibility(View.VISIBLE);
|
||||
selfAvatarContainer.setVisibility(View.VISIBLE);
|
||||
DcContext dcContext = DcHelper.getContext(this);
|
||||
DcContact self = dcContext.getContact(DcContact.DC_CONTACT_ID_SELF);
|
||||
String name = dcContext.getConfig("displayname");
|
||||
@@ -279,6 +289,39 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshUnreadIndicator() {
|
||||
int unreadCount = 0;
|
||||
DcAccounts dcAccounts = DcHelper.getAccounts(this);
|
||||
int skipId = dcAccounts.getSelectedAccount().getAccountId();
|
||||
for (int accountId : dcAccounts.getAll()) {
|
||||
if (accountId != skipId) {
|
||||
unreadCount += dcAccounts.getAccount(accountId).getFreshMsgs().length;
|
||||
}
|
||||
}
|
||||
|
||||
if(unreadCount == 0) {
|
||||
unreadIndicator.setVisibility(View.GONE);
|
||||
} else {
|
||||
boolean isDarkTheme = DynamicTheme.isDarkTheme(this);
|
||||
int badgeColor = Color.WHITE;
|
||||
if (isDarkTheme) {
|
||||
final TypedArray attrs = obtainStyledAttributes(new int[] {
|
||||
R.attr.conversation_list_item_unreadcount_color,
|
||||
});
|
||||
badgeColor = attrs.getColor(0, Color.BLACK);
|
||||
}
|
||||
unreadIndicator.setImageDrawable(TextDrawable.builder()
|
||||
.beginConfig()
|
||||
.width(ViewUtil.dpToPx(this, 20))
|
||||
.height(ViewUtil.dpToPx(this, 20))
|
||||
.textColor(isDarkTheme? Color.WHITE : Color.BLACK)
|
||||
.bold()
|
||||
.endConfig()
|
||||
.buildRound(String.valueOf(unreadCount), badgeColor));
|
||||
unreadIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -409,7 +452,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
private void handleResetRelaying() {
|
||||
resetRelayingMessageContent(this);
|
||||
refreshTitle();
|
||||
selfAvatar.setVisibility(View.VISIBLE);
|
||||
selfAvatarContainer.setVisibility(View.VISIBLE);
|
||||
conversationListFragment.onNewIntent();
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ public class ConversationListFragment extends Fragment
|
||||
archive = getArguments().getBoolean(ARCHIVE, false);
|
||||
|
||||
DcEventCenter eventCenter = DcHelper.getEventCenter(getActivity());
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CHAT_MODIFIED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSGS_CHANGED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSG_DELIVERED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSG_FAILED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_MSG_READ, this);
|
||||
@@ -632,7 +632,13 @@ public class ConversationListFragment extends Fragment
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
if (event.getId() == DcContext.DC_EVENT_CONNECTIVITY_CHANGED) {
|
||||
if (event.getAccountId() != DcHelper.getContext(getActivity()).getAccountId()) {
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof ConversationListActivity) {
|
||||
((ConversationListActivity) activity).refreshUnreadIndicator();
|
||||
}
|
||||
|
||||
} else if (event.getId() == DcContext.DC_EVENT_CONNECTIVITY_CHANGED) {
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof ConversationListActivity) {
|
||||
((ConversationListActivity) activity).refreshTitle();
|
||||
|
||||
@@ -39,8 +39,9 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
recyclerView.setAdapter(adapter);
|
||||
refreshData();
|
||||
DcEventCenter eventCenter = DcHelper.getEventCenter(requireActivity());
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
eventCenter.addObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this);
|
||||
eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -62,11 +63,13 @@ public class AccountSelectionListFragment extends DialogFragment implements DcEv
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
DcHelper.getEventCenter(requireActivity()).removeObservers(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent2(@NonNull DcEvent event) {
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
refreshData();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,13 @@ import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class DcEventCenter {
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> allObservers = new Hashtable<>();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> currentAccountObservers = new Hashtable<>();
|
||||
private @NonNull final Hashtable<Integer, ArrayList<DcEventDelegate>> multiAccountObservers = new Hashtable<>();
|
||||
private final Object LOCK = new Object();
|
||||
private final @NonNull ApplicationContext context;
|
||||
|
||||
public interface DcEventDelegate {
|
||||
void handleEvent(@NonNull DcEvent event);
|
||||
default void handleEvent2(@NonNull DcEvent event) {
|
||||
}
|
||||
default boolean runOnMain() {
|
||||
return true;
|
||||
}
|
||||
@@ -35,10 +34,18 @@ public class DcEventCenter {
|
||||
}
|
||||
|
||||
public void addObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(currentAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
public void addMultiAccountObserver(int eventId, @NonNull DcEventDelegate observer) {
|
||||
addObserver(multiAccountObservers, eventId, observer);
|
||||
}
|
||||
|
||||
private void addObserver(Hashtable<Integer, ArrayList<DcEventDelegate>> observers, int eventId, @NonNull DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(eventId);
|
||||
if (idObservers == null) {
|
||||
allObservers.put(eventId, (idObservers = new ArrayList<>()));
|
||||
observers.put(eventId, (idObservers = new ArrayList<>()));
|
||||
}
|
||||
idObservers.add(observer);
|
||||
}
|
||||
@@ -46,7 +53,11 @@ public class DcEventCenter {
|
||||
|
||||
public void removeObserver(int eventId, DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
@@ -55,8 +66,14 @@ public class DcEventCenter {
|
||||
|
||||
public void removeObservers(DcEventDelegate observer) {
|
||||
synchronized (LOCK) {
|
||||
for(Integer eventId : allObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(eventId);
|
||||
for(Integer eventId : currentAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = currentAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
}
|
||||
for(Integer eventId : multiAccountObservers.keySet()) {
|
||||
ArrayList<DcEventDelegate> idObservers = multiAccountObservers.get(eventId);
|
||||
if (idObservers != null) {
|
||||
idObservers.remove(observer);
|
||||
}
|
||||
@@ -64,41 +81,17 @@ public class DcEventCenter {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendToObservers(@NonNull DcEvent event) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(event.getId());
|
||||
if (idObservers != null) {
|
||||
for (DcEventDelegate observer : idObservers) {
|
||||
// using try/catch blocks as under some circumstances eg. getContext() may return NULL -
|
||||
// and as this function is used virtually everywhere, also in libs,
|
||||
// it's not feasible to check all single occurrences.
|
||||
if(observer.runOnMain()) {
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Util.runOnBackground(() -> {
|
||||
try {
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void sendToMultiAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(multiAccountObservers, event);
|
||||
}
|
||||
|
||||
public void sendToObservers2(@NonNull DcEvent event) {
|
||||
private void sendToCurrentAccountObservers(@NonNull DcEvent event) {
|
||||
sendToObservers(currentAccountObservers, event);
|
||||
}
|
||||
|
||||
private void sendToObservers(Hashtable<Integer, ArrayList<DcEventDelegate>> observers, @NonNull DcEvent event) {
|
||||
synchronized (LOCK) {
|
||||
ArrayList<DcEventDelegate> idObservers = allObservers.get(event.getId());
|
||||
ArrayList<DcEventDelegate> idObservers = observers.get(event.getId());
|
||||
if (idObservers != null) {
|
||||
for (DcEventDelegate observer : idObservers) {
|
||||
// using try/catch blocks as under some circumstances eg. getContext() may return NULL -
|
||||
@@ -107,7 +100,7 @@ public class DcEventCenter {
|
||||
if(observer.runOnMain()) {
|
||||
Util.runOnMain(() -> {
|
||||
try {
|
||||
observer.handleEvent2(event);
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -116,7 +109,7 @@ public class DcEventCenter {
|
||||
} else {
|
||||
Util.runOnBackground(() -> {
|
||||
try {
|
||||
observer.handleEvent2(event);
|
||||
observer.handleEvent(event);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -173,7 +166,7 @@ public class DcEventCenter {
|
||||
int accountId = event.getAccountId();
|
||||
int id = event.getId();
|
||||
|
||||
sendToObservers2(event);
|
||||
sendToMultiAccountObservers(event);
|
||||
|
||||
switch (id) {
|
||||
case DcContext.DC_EVENT_INCOMING_MSG:
|
||||
@@ -185,7 +178,7 @@ public class DcEventCenter {
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_IMEX_PROGRESS:
|
||||
sendToObservers(event);
|
||||
sendToCurrentAccountObservers(event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -210,18 +203,9 @@ public class DcEventCenter {
|
||||
handleError(id, event.getData2Str());
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_INCOMING_MSG:
|
||||
sendToObservers(event);
|
||||
default:
|
||||
sendToCurrentAccountObservers(event);
|
||||
break;
|
||||
|
||||
case DcContext.DC_EVENT_MSGS_NOTICED:
|
||||
sendToObservers(event);
|
||||
break;
|
||||
|
||||
default: {
|
||||
sendToObservers(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (id == DcContext.DC_EVENT_CHAT_MODIFIED) {
|
||||
|
||||
Reference in New Issue
Block a user