Compare commits

...

9 commits

26 changed files with 323 additions and 57 deletions

View file

@ -83,6 +83,7 @@ dependencies {
implementation 'com.github.singpolyma:TokenAutoComplete:bfa93780e0'
implementation 'com.github.kizitonwose.colorpreference:core:1.1.0'
implementation 'com.github.kizitonwose.colorpreference:support:1.1.0'
implementation 'com.caverock:androidsvg-aar:1.4'
implementation 'com.github.singpolyma:Better-Link-Movement-Method:4df081e1e4'

View file

@ -36,6 +36,7 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
import eu.siacs.conversations.ui.adapter.AccountAdapter;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
@ -44,8 +45,14 @@ import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;
import com.kizitonwose.colorpreference.ColorDialog;
import com.kizitonwose.colorpreference.ColorShape;
public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated, AccountAdapter.OnTglAccountState {
public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate,
KeyChainAliasCallback,
XmppConnectionService.OnAccountCreated,
AccountAdapter.OnTglAccountState,
ColorDialog.OnColorSelectedListener {
private final String STATE_SELECTED_ACCOUNT = "selected_account";
@ -61,6 +68,18 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
protected Pair<Integer, Intent> mPostponedActivityResult = null;
private AccountAdapter.ColorSelectorListener colorSelectorListener = new AccountAdapter.ColorSelectorListener() {
@Override
public void onColorPickerRequested(Jid accountJid, int currentColor) {
new ColorDialog.Builder(ManageAccountActivity.this)
.setColorShape(ColorShape.CIRCLE)
.setColorChoices(R.array.themeColorsOverride)
.setSelectedColor(currentColor)
.setTag(accountJid.asBareJid().toEscapedString())
.show();
}
};
@Override
public void onAccountUpdate() {
refreshUi();
@ -102,7 +121,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
accountListView = findViewById(R.id.account_list);
this.mAccountAdapter = new AccountAdapter(this, accountList);
this.mAccountAdapter = new AccountAdapter(this, accountList, colorSelectorListener);
accountListView.setAdapter(this.mAccountAdapter);
accountListView.setOnItemClickListener((arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
registerForContextMenu(accountListView);
@ -158,6 +177,13 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
super.onSaveInstanceState(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
colorSelectorListener = null;
mAccountAdapter.colorSelectorListener = null;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
@ -349,6 +375,12 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
}
@Override
public void onColorSelected(int newColor, String tag) {
UIHelper.overrideAccountColor(this, tag, newColor);
refreshUiReal();
}
private void addAccountFromKey() {
try {
KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);

View file

@ -352,7 +352,10 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
}
public String replyId() {
return conversation.getMode() == Conversation.MODE_MULTI || getRemoteMsgId() == null ? getServerMsgId() : getRemoteMsgId();
if (conversation.getMode() == Conversation.MODE_MULTI) return getServerMsgId();
final String remote = getRemoteMsgId();
if (remote == null && getStatus() > STATUS_RECEIVED) return getUuid();
return remote;
}
public Message reply() {

View file

@ -508,10 +508,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
if (nextCounterpart != null && mXmppConnectionService.checkIsArchived(account, counterpart.asBareJid(), nextCounterpart)) {
return;
}
if ((body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || oobUrl != null) && !isMucStatusMessage) {
final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, conversationIsProbablyMuc, nextCounterpart != null, false, nextCounterpart);
final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI;

View file

@ -504,7 +504,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
&& contact.getLastseen() > 0
&& contact.getPresences().allOrNonSupport(Namespace.IDLE)) {
binding.detailsLastseen.setVisibility(View.VISIBLE);
binding.detailsLastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.isActive(), contact.getLastseen()));
binding.detailsLastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.isActive(), contact.getLastseen(), false));
} else {
binding.detailsLastseen.setVisibility(View.GONE);
}
@ -523,7 +523,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size);
binding.detailsContactBadge.setOnClickListener(this::onBadgeClick);
binding.presenceIndicator.setStatus(contact.getShownStatus());
binding.presenceIndicator.setStatus(contact);
binding.detailsContactKeys.removeAllViews();
boolean hasKeys = false;

View file

@ -590,7 +590,7 @@ public class ConversationFragment extends XmppFragment
public void onClick(View v) {
stopScrolling();
if (previousClickedReply != null) {
/*if (previousClickedReply != null) {
int lastVisiblePosition = binding.messagesView.getLastVisiblePosition();
Message lastVisibleMessage = messageListAdapter.getItem(lastVisiblePosition);
Message jump = previousClickedReply;
@ -602,7 +602,7 @@ public class ConversationFragment extends XmppFragment
return;
}
}
}
}*/
if (conversation.isInHistoryPart()) {
conversation.jumpToLatest();
@ -3610,7 +3610,7 @@ public class ConversationFragment extends XmppFragment
conversation.refreshSessions();
if (conversation != null && conversation.getMode() == Conversational.MODE_MULTI) {
if (conversation != null && conversation.getMode() == Conversational.MODE_MULTI && conversation.getNextCounterpart() == null) {
String subject = conversation.getMucOptions().getSubject();
Boolean hidden = conversation.getMucOptions().subjectHidden();

View file

@ -42,10 +42,14 @@ import android.app.FragmentTransaction;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
@ -95,7 +99,9 @@ import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import io.michaelrocks.libphonenumber.android.NumberParseException;
@ -135,6 +141,10 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
private boolean mActivityPaused = true;
private final AtomicBoolean mRedirectInProcess = new AtomicBoolean(false);
private final Handler handler = new Handler(Looper.getMainLooper());
private final Runnable refreshTitleRunnable = this::invalidateActionBarTitle;
private boolean showLastSeen = false;
private static boolean isViewOrShareIntent(Intent i) {
Log.d(Config.LOGTAG, "action: " + (i == null ? null : i.getAction()));
return i != null && VIEW_AND_SHARE_ACTIONS.contains(i.getAction()) && i.hasExtra(EXTRA_CONVERSATION);
@ -660,6 +670,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
this.mSkipBackgroundBinding = false;
}
mRedirectInProcess.set(false);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
this.showLastSeen = preferences.getBoolean("last_activity", false);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setSelectedItemId(R.id.chats);
@ -735,6 +747,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
if (actionBar == null) {
return;
}
final FragmentManager fragmentManager = getFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
if (mainFragment instanceof ConversationFragment) {
@ -750,10 +763,38 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
binding.toolbar,
(v) -> openConversationDetails(conversation)
);
if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getNextCounterpart() == null) {
int usersCount = conversation.getMucOptions().getUserCount();
if (usersCount > 0) {
actionBar.setSubtitle(getResources().getQuantityString(R.plurals.x_participants, conversation.getMucOptions().getUserCount(), conversation.getMucOptions().getUserCount()));
} else {
actionBar.setSubtitle("");
}
handler.postDelayed(refreshTitleRunnable, 5000L);
} else if (conversation.getMode() == Conversation.MODE_SINGLE) {
Contact contact = conversation.getContact();
List<String> statuses = contact.getPresences().getStatusMessages();
if (!statuses.isEmpty() && !statuses.get(0).isBlank()) {
actionBar.setSubtitle(statuses.get(0));
handler.postDelayed(refreshTitleRunnable, 5000L);
} else {
actionBar.setSubtitle("");
handler.removeCallbacks(refreshTitleRunnable);
}
} else {
actionBar.setSubtitle("");
handler.removeCallbacks(refreshTitleRunnable);
}
return;
}
}
handler.removeCallbacks(refreshTitleRunnable);
actionBar.setTitle(R.string.app_name);
actionBar.setSubtitle("");
actionBar.setDisplayHomeAsUpEnabled(false);
ActionBarUtil.resetActionBarOnClickListeners(binding.toolbar);
}

View file

@ -9,6 +9,11 @@ import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import com.kizitonwose.colorpreference.ColorDialog;
import com.kizitonwose.colorpreference.ColorPreference;
import com.kizitonwose.colorpreference.ColorShape;
import com.kizitonwose.colorpreference.ColorUtils;
import java.util.List;
import eu.siacs.conversations.Config;
@ -19,22 +24,29 @@ import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
public class AccountAdapter extends ArrayAdapter<Account> {
private final XmppActivity activity;
private final boolean showStateButton;
private final boolean showColorSelector;
public ColorSelectorListener colorSelectorListener = null;
public AccountAdapter(XmppActivity activity, List<Account> objects, boolean showStateButton) {
super(activity, 0, objects);
this.activity = activity;
this.showStateButton = showStateButton;
this.showColorSelector = false;
}
public AccountAdapter(XmppActivity activity, List<Account> objects) {
public AccountAdapter(XmppActivity activity, List<Account> objects, ColorSelectorListener listener) {
super(activity, 0, objects);
this.activity = activity;
this.showStateButton = true;
this.showColorSelector = true;
colorSelectorListener = listener;
}
@Override
@ -77,18 +89,28 @@ public class AccountAdapter extends ArrayAdapter<Account> {
} else {
viewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
}
viewHolder.binding.tglAccountStatus.setOnCheckedChangeListener((compoundButton, b) -> {
if (b == isDisabled && activity instanceof OnTglAccountState) {
((OnTglAccountState) activity).onClickTglAccountState(account, b);
}
});
if (activity.xmppConnectionService.getAccounts().size() > 1) {
viewHolder.binding.accountIndicator.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().getEscapedLocal()));
if (this.showColorSelector && activity.xmppConnectionService.getAccounts().size() > 1 &&
activity.xmppConnectionService.getPreferences().getBoolean("show_account_indicator", activity.getResources().getBoolean(R.bool.show_account_indicator))) {
int color = UIHelper.getAccountColor(activity, account.getJid());
viewHolder.binding.colorView.setVisibility(View.VISIBLE);
ColorUtils.setColorViewValue(viewHolder.binding.colorView, color, false, ColorShape.CIRCLE);
viewHolder.binding.colorView.setOnClickListener(v -> {
if (colorSelectorListener != null) {
colorSelectorListener.onColorPickerRequested(account.getJid(), color);
}
});
} else {
viewHolder.binding.accountIndicator.setBackgroundColor(Color.TRANSPARENT);
viewHolder.binding.colorView.setVisibility(View.GONE);
}
return view;
}
@ -106,4 +128,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
void onClickTglAccountState(Account account, boolean state);
}
public interface ColorSelectorListener {
void onColorPickerRequested(Jid accountJid, int currentColor);
}
}

View file

@ -393,7 +393,7 @@ public class ConversationAdapter
Contact contact = conversation.getContact();
if (contact != null) {
viewHolder.binding.presenceIndicator.setStatus(contact.getShownStatus());
viewHolder.binding.presenceIndicator.setStatus(contact);
} else {
viewHolder.binding.presenceIndicator.setStatus(null);
}
@ -401,7 +401,7 @@ public class ConversationAdapter
Account account = conversation.getAccount();
if (account != null && activity.xmppConnectionService.getAccounts().size() > 1) {
viewHolder.binding.accountIndicator.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().getEscapedLocal()));
viewHolder.binding.accountIndicator.setBackgroundColor(UIHelper.getAccountColor(activity, account.getJid()));
} else {
viewHolder.binding.accountIndicator.setBackgroundColor(Color.TRANSPARENT);
}

View file

@ -94,7 +94,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
AvatarWorkerTask.loadAvatar(item, viewHolder.avatar, R.dimen.avatar);
if (item instanceof Contact) {
viewHolder.presenceIndicator.setStatus(((Contact) item).getShownStatus());
viewHolder.presenceIndicator.setStatus(((Contact) item));
} else {
viewHolder.presenceIndicator.setStatus(null);
}
@ -108,7 +108,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
}
if (account != null && activity.xmppConnectionService.getAccounts().size() > 1) {
viewHolder.accountIndicator.setBackgroundColor(UIHelper.getColorForName(account.getJid().asBareJid().getEscapedLocal()));
viewHolder.accountIndicator.setBackgroundColor(UIHelper.getAccountColor(activity, account.getJid()));
} else {
viewHolder.accountIndicator.setBackgroundColor(Color.TRANSPARENT);
}

View file

@ -91,7 +91,7 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
} else {
viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode));
}
viewHolder.binding.presenceIndicator.setStatus(contact.getShownStatus());
viewHolder.binding.presenceIndicator.setStatus(contact);
} else {
viewHolder.binding.contactDisplayName.setText(name == null ? "" : name);
viewHolder.binding.contactJid.setText(ConferenceDetailsActivity.getStatus(viewHolder.binding.getRoot().getContext(), user, advancedMode));

View file

@ -38,7 +38,7 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
AvatarWorkerTask.loadAvatar(user, viewHolder.binding.avatar, R.dimen.media_size);
Contact contact = user.getContact();
if (contact != null) {
viewHolder.binding.presenceIndicator.setStatus(user.getContact().getShownStatus());
viewHolder.binding.presenceIndicator.setStatus(user.getContact());
} else {
viewHolder.binding.presenceIndicator.setStatus(null);
}

View file

@ -0,0 +1,37 @@
package eu.siacs.conversations.ui.widget
import android.content.Context
import android.util.AttributeSet
import android.view.View
import eu.siacs.conversations.R
import eu.siacs.conversations.ui.XmppActivity
class AccountIndicator : View {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val enabled = (context as? XmppActivity)
?.xmppConnectionService?.preferences
?.getBoolean("show_account_indicator", context.resources.getBoolean(R.bool.show_account_indicator)) ?: false
visibility = if (enabled) {
VISIBLE
} else {
INVISIBLE
}
}
}

View file

@ -8,9 +8,13 @@ import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
import eu.siacs.conversations.R
import eu.siacs.conversations.entities.Contact
import eu.siacs.conversations.entities.Presence
import eu.siacs.conversations.ui.XmppActivity
import eu.siacs.conversations.ui.util.StyledAttributes
import eu.siacs.conversations.utils.UIHelper
import eu.siacs.conversations.xml.Namespace
class PresenceIndicator : View {
private var paint: Paint = Paint().also {
@ -19,13 +23,9 @@ class PresenceIndicator : View {
it.strokeWidth = 1 * Resources.getSystem().displayMetrics.density
}
var status: Presence.Status? = null
set(value) {
if (field != value) {
field = value
invalidate()
}
}
private var status: Presence.Status? = null
private var enabled = false
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
@ -51,7 +51,26 @@ class PresenceIndicator : View {
}
}
fun setStatus(contact: Contact?) {
val status = contact?.shownStatus
if (status != this.status) {
this.status = status
invalidate()
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
enabled = (context as? XmppActivity)
?.xmppConnectionService?.preferences
?.getBoolean("show_contact_status", context.resources.getBoolean(R.bool.show_contact_status)) ?: false
}
override fun onDraw(canvas: Canvas) {
if (!enabled) {
return
}
super.onDraw(canvas)
val color: Int? = UIHelper.getColorForStatus(status);

View file

@ -1,6 +1,7 @@
package eu.siacs.conversations.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
@ -204,26 +205,60 @@ public class UIHelper {
.get(Calendar.DAY_OF_YEAR);
}
public static String lastseen(Context context, boolean active, long time) {
public static String lastseen(Context context, boolean active, long time, boolean shortText) {
long difference = (System.currentTimeMillis() - time) / 1000;
if (active) {
return context.getString(R.string.online_right_now);
if (shortText) {
return context.getString(R.string.online_right_now_short);
} else {
return context.getString(R.string.online_right_now);
}
} else if (difference < 60) {
return context.getString(R.string.last_seen_now);
if (shortText) {
return context.getString(R.string.last_seen_now_short);
} else {
return context.getString(R.string.last_seen_now);
}
} else if (difference < 60 * 2) {
return context.getString(R.string.last_seen_min);
if (shortText) {
return context.getString(R.string.last_seen_min_short);
} else {
return context.getString(R.string.last_seen_min);
}
} else if (difference < 60 * 60) {
return context.getString(R.string.last_seen_mins, Math.round(difference / 60.0));
if (shortText) {
return context.getString(R.string.last_seen_mins_short, Math.round(difference / 60.0));
} else {
return context.getString(R.string.last_seen_mins, Math.round(difference / 60.0));
}
} else if (difference < 60 * 60 * 2) {
return context.getString(R.string.last_seen_hour);
if (shortText) {
return context.getString(R.string.last_seen_hour_short);
} else {
return context.getString(R.string.last_seen_hour);
}
} else if (difference < 60 * 60 * 24) {
return context.getString(R.string.last_seen_hours,
Math.round(difference / (60.0 * 60.0)));
if (shortText) {
return context.getString(R.string.last_seen_hours_short,
Math.round(difference / (60.0 * 60.0)));
} else {
return context.getString(R.string.last_seen_hours,
Math.round(difference / (60.0 * 60.0)));
}
} else if (difference < 60 * 60 * 48) {
return context.getString(R.string.last_seen_day);
if (shortText) {
return context.getString(R.string.last_seen_day_short);
} else {
return context.getString(R.string.last_seen_day);
}
} else {
return context.getString(R.string.last_seen_days,
Math.round(difference / (60.0 * 60.0 * 24.0)));
if (shortText) {
return context.getString(R.string.last_seen_days_short,
Math.round(difference / (60.0 * 60.0 * 24.0)));
} else {
return context.getString(R.string.last_seen_days,
Math.round(difference / (60.0 * 60.0 * 24.0)));
}
}
}
@ -231,6 +266,23 @@ public class UIHelper {
return getColorForName(name, false);
}
public static int getAccountColor(Context context, Jid accountJid) {
SharedPreferences prefs = context.getSharedPreferences("accountColorsPrefs", Context.MODE_PRIVATE);
String name = accountJid.asBareJid().toEscapedString();
int overrideColor = prefs.getInt(name, -1);
if (overrideColor != -1) {
return overrideColor;
} else {
return getColorForName(name);
}
}
public static void overrideAccountColor(Context context, String accountName, int color) {
SharedPreferences prefs = context.getSharedPreferences("accountColorsPrefs", Context.MODE_PRIVATE);
prefs.edit().putInt(accountName, color).apply();
}
public static int getColorForName(String name, boolean safe) {
if (Config.XEP_0392) {
return XEP0392Helper.rgbFromNick(name);

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#000000"
android:pathData="M160,760L160,680L560,680L560,760L160,760ZM160,600L160,520L800,520L800,600L160,600ZM160,440L160,360L800,360L800,440L160,440ZM160,280L160,200L800,200L800,280L160,280Z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#ffffff"
android:pathData="M160,760L160,680L560,680L560,760L160,760ZM160,600L160,520L800,520L800,600L160,600ZM160,440L160,360L800,360L800,440L160,440ZM160,280L160,200L800,200L800,280L160,280Z"/>
</vector>

View file

@ -6,17 +6,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:clipToPadding="false"
android:paddingLeft="8dp"
android:paddingBottom="8dp"
android:paddingTop="8dp">
<View
android:id="@+id/account_indicator"
android:layout_width="@dimen/account_indicator_width"
android:layout_marginStart="-4dp"
android:layout_height="48dp" />
<eu.siacs.conversations.ui.widget.AvatarView
android:id="@+id/account_image"
android:layout_width="48dp"
@ -31,8 +24,8 @@
android:layout_toEndOf="@+id/account_image"
android:orientation="vertical"
android:paddingLeft="@dimen/avatar_item_distance"
android:layout_toLeftOf="@+id/tgl_account_status"
android:layout_toStartOf="@+id/tgl_account_status">
android:layout_toLeftOf="@+id/controls"
android:layout_toStartOf="@+id/controls">
<TextView
android:id="@+id/account_jid"
@ -50,14 +43,31 @@
android:textAppearance="@style/TextAppearance.Conversations.Body2" />
</LinearLayout>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/tgl_account_status"
<LinearLayout
android:id="@+id/controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp"
android:focusable="false" />
android:layout_alignParentRight="true"
android:layout_centerVertical="true">
<ImageView
android:id="@+id/color_view"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:layout_marginEnd="12dp"
android:scaleType="fitXY" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/tgl_account_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false" />
</LinearLayout>
</RelativeLayout>
</layout>

View file

@ -9,7 +9,7 @@
android:clipToPadding="false"
android:padding="@dimen/list_padding">
<View
<eu.siacs.conversations.ui.widget.AccountIndicator
android:id="@+id/account_indicator"
android:layout_width="@dimen/account_indicator_width"
android:layout_marginStart="-4dp"

View file

@ -20,7 +20,7 @@
android:clipToPadding="false"
android:padding="8dp">
<View
<eu.siacs.conversations.ui.widget.AccountIndicator
android:id="@+id/account_indicator"
android:layout_width="@dimen/account_indicator_width"
android:layout_marginStart="-4dp"

View file

@ -54,7 +54,7 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="?attr/ic_pin"
android:src="?attr/ic_subject"
android:layout_marginEnd="8dp"
/>

View file

@ -40,6 +40,7 @@
<attr name="ic_send_voice_offline" format="reference" />
<attr name="ic_pin" format="reference" />
<attr name="ic_subject" format="reference" />
<attr name="ic_close" format="reference" />
<attr name="ic_attach_camera" format="reference" />
<attr name="ic_attach_videocam" format="reference" />

View file

@ -55,4 +55,6 @@
<bool name="always_full_timestamps">false</bool>
<bool name="skip_image_editor_screen">false</bool>
<string name="avatar_shape">rounded_square</string>
<bool name="show_contact_status">true</bool>
<bool name="show_account_indicator">true</bool>
</resources>

View file

@ -612,6 +612,10 @@
<string name="pref_skip_image_editor_screen_summary">Dont open image editor screen automatically for single image attachments</string>
<string name="unable_to_connect_to_keychain">Could not connect to OpenKeychain</string>
<string name="this_device_is_no_longer_in_use">This device is no longer in use</string>
<string name="pref_show_contact_presence">Contact presence</string>
<string name="pref_show_contact_presence_details">Show contact presence nearby contact avatar</string>
<string name="pref_show_account_indicator">Account indicator</string>
<string name="pref_show_account_indicator_details">Mark conversations with different colors in case of several account</string>
<string name="type_pc">Computer</string>
<string name="type_phone">Mobile phone</string>
<string name="type_tablet">Tablet</string>
@ -1108,6 +1112,19 @@
<string name="avater_shape_rounded_square">Rounded Square</string>
<string name="avater_shape_square">Square</string>
<plurals name="x_participants">
<item quantity="one">%1$d participant</item>
<item quantity="other">%1$d participants</item>
</plurals>
<string name="online_right_now_short">online</string>
<string name="last_seen_now_short">just now</string>
<string name="last_seen_min_short">one minute ago</string>
<string name="last_seen_mins_short">%d minutes ago</string>
<string name="last_seen_hour_short">one hour ago</string>
<string name="last_seen_hours_short">%d hours ago</string>
<string name="last_seen_day_short">one day ago</string>
<string name="last_seen_days_short">%d days ago</string>
<string name="clarendon" translatable="false">Clarendon</string>
<string name="oldman" translatable="false">OldMan</string>

View file

@ -59,6 +59,7 @@
<item name="ic_attach_videocam" type="reference">@drawable/ic_attach_videocam</item>
<item name="ic_attach_document" type="reference">@drawable/ic_attach_document</item>
<item name="ic_pin" type="reference">@drawable/ic_pin_black</item>
<item name="ic_subject" type="reference">@drawable/ic_subject_black</item>
<item name="ic_close" type="reference">@drawable/ic_close_24dp_black</item>
<item name="ic_attach_location" type="reference">@drawable/ic_attach_location</item>
<item name="ic_attach_photo" type="reference">@drawable/ic_attach_photo</item>
@ -239,6 +240,7 @@
<item name="ic_attach_videocam" type="reference">@drawable/ic_attach_videocam_white</item>
<item name="ic_attach_document" type="reference">@drawable/ic_attach_document_white</item>
<item name="ic_pin" type="reference">@drawable/ic_pin_white</item>
<item name="ic_subject" type="reference">@drawable/ic_subject_white</item>
<item name="ic_close" type="reference">@drawable/ic_close_24dp</item>
<item name="ic_attach_location" type="reference">@drawable/ic_attach_location_white</item>
<item name="ic_attach_photo" type="reference">@drawable/ic_attach_photo_white</item>

View file

@ -64,6 +64,16 @@
android:key="always_full_timestamps"
android:summary="@string/pref_always_show_full_timestamps_summary"
android:title="@string/pref_always_show_full_timestamps" />
<CheckBoxPreference
android:defaultValue="@bool/use_green_background"
android:key="show_contact_status"
android:summary="@string/pref_show_contact_presence_details"
android:title="@string/pref_show_contact_presence" />
<CheckBoxPreference
android:defaultValue="@bool/use_green_background"
android:key="show_account_indicator"
android:summary="@string/pref_show_account_indicator_details"
android:title="@string/pref_show_account_indicator" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_navigation">