mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-25 03:09:05 +00:00
Fully colorize conversations.
1. Switch from 300 to 500 colors. 2. Colorize incoming conversation bubbles. 3. Colorize recipeint preference activity toolbar. 4. Support inverted colors in avatars. 5. Make status bar icons tint according to secondary color. // FREEBIE
This commit is contained in:
@@ -21,12 +21,14 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -44,33 +46,30 @@ public class Recipient {
|
||||
private String number;
|
||||
private String name;
|
||||
|
||||
private ContactPhoto contactPhoto;
|
||||
private Uri contactUri;
|
||||
private ContactPhoto contactPhoto;
|
||||
private Uri contactUri;
|
||||
private Optional<Integer> color;
|
||||
|
||||
Recipient(long recipientId, String number, ListenableFutureTask<RecipientDetails> future)
|
||||
{
|
||||
this.recipientId = recipientId;
|
||||
this.number = number;
|
||||
this.contactPhoto = ContactPhotoFactory.getLoadingPhoto();
|
||||
this.color = Optional.absent();
|
||||
|
||||
future.addListener(new FutureTaskListener<RecipientDetails>() {
|
||||
@Override
|
||||
public void onSuccess(RecipientDetails result) {
|
||||
if (result != null) {
|
||||
Set<RecipientModifiedListener> localListeners;
|
||||
|
||||
synchronized (Recipient.this) {
|
||||
Recipient.this.name = result.name;
|
||||
Recipient.this.number = result.number;
|
||||
Recipient.this.contactUri = result.contactUri;
|
||||
Recipient.this.contactPhoto = result.avatar;
|
||||
|
||||
localListeners = new HashSet<>(listeners);
|
||||
listeners.clear();
|
||||
Recipient.this.color = result.color;
|
||||
}
|
||||
|
||||
for (RecipientModifiedListener listener : localListeners)
|
||||
listener.onModified(Recipient.this);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +86,7 @@ public class Recipient {
|
||||
this.contactUri = details.contactUri;
|
||||
this.name = details.name;
|
||||
this.contactPhoto = details.avatar;
|
||||
this.color = details.color;
|
||||
}
|
||||
|
||||
public synchronized Uri getContactUri() {
|
||||
@@ -97,6 +97,20 @@ public class Recipient {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public synchronized @NonNull Optional<Integer> getColor() {
|
||||
if (color.isPresent()) return color;
|
||||
else if (name != null) return Optional.of(ContactColors.generateFor(name));
|
||||
else return Optional.of(ContactColors.UNKNOWN_COLOR);
|
||||
}
|
||||
|
||||
public void setColor(Optional<Integer> color) {
|
||||
synchronized (this) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
@@ -126,7 +140,9 @@ public class Recipient {
|
||||
}
|
||||
|
||||
public static Recipient getUnknownRecipient() {
|
||||
return new Recipient(-1, new RecipientDetails("Unknown", "Unknown", null, ContactPhotoFactory.getDefaultContactPhoto("Unknown")));
|
||||
return new Recipient(-1, new RecipientDetails("Unknown", "Unknown", null,
|
||||
ContactPhotoFactory.getDefaultContactPhoto("Unknown"),
|
||||
Optional.<Integer>absent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,6 +160,17 @@ public class Recipient {
|
||||
return 31 + (int)this.recipientId;
|
||||
}
|
||||
|
||||
private void notifyListeners() {
|
||||
Set<RecipientModifiedListener> localListeners;
|
||||
|
||||
synchronized (this) {
|
||||
localListeners = new HashSet<>(listeners);
|
||||
}
|
||||
|
||||
for (RecipientModifiedListener listener : localListeners)
|
||||
listener.onModified(Recipient.this);
|
||||
}
|
||||
|
||||
public interface RecipientModifiedListener {
|
||||
public void onModified(Recipient recipient);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
@@ -67,9 +68,9 @@ public class RecipientProvider {
|
||||
String number = CanonicalAddressDatabase.getInstance(context).getAddressFromId(recipientId);
|
||||
|
||||
if (asynchronous) {
|
||||
cachedRecipient = new Recipient(recipientId, number, getRecipientDetailsAsync(context, number));
|
||||
cachedRecipient = new Recipient(recipientId, number, getRecipientDetailsAsync(context, recipientId, number));
|
||||
} else {
|
||||
cachedRecipient = new Recipient(recipientId, getRecipientDetailsSync(context, number));
|
||||
cachedRecipient = new Recipient(recipientId, getRecipientDetailsSync(context, recipientId, number));
|
||||
}
|
||||
|
||||
recipientCache.put(recipientId, cachedRecipient);
|
||||
@@ -99,12 +100,13 @@ public class RecipientProvider {
|
||||
}
|
||||
|
||||
private @NonNull ListenableFutureTask<RecipientDetails> getRecipientDetailsAsync(final Context context,
|
||||
final long recipientId,
|
||||
final String number)
|
||||
{
|
||||
Callable<RecipientDetails> task = new Callable<RecipientDetails>() {
|
||||
@Override
|
||||
public RecipientDetails call() throws Exception {
|
||||
return getRecipientDetailsSync(context, number);
|
||||
return getRecipientDetailsSync(context, recipientId, number);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,15 +115,17 @@ public class RecipientProvider {
|
||||
return future;
|
||||
}
|
||||
|
||||
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, String number) {
|
||||
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, long recipientId, String number) {
|
||||
if (GroupUtil.isEncodedGroup(number)) return getGroupRecipientDetails(context, number);
|
||||
else return getIndividualRecipientDetails(context, number);
|
||||
else return getIndividualRecipientDetails(context, recipientId, number);
|
||||
}
|
||||
|
||||
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, String number) {
|
||||
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
||||
Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,
|
||||
null, null, null);
|
||||
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, long recipientId, String number) {
|
||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(new long[]{recipientId});
|
||||
Optional<Integer> color = preferences.isPresent() ? preferences.get().getColor() : Optional.<Integer>absent();
|
||||
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
||||
Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,
|
||||
null, null, null);
|
||||
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
@@ -131,14 +135,14 @@ public class RecipientProvider {
|
||||
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""),
|
||||
name);
|
||||
|
||||
return new RecipientDetails(cursor.getString(0), cursor.getString(3), contactUri, contactPhoto);
|
||||
return new RecipientDetails(cursor.getString(0), cursor.getString(3), contactUri, contactPhoto, color);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return new RecipientDetails(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null));
|
||||
return new RecipientDetails(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
|
||||
}
|
||||
|
||||
private @NonNull RecipientDetails getGroupRecipientDetails(Context context, String groupId) {
|
||||
@@ -148,13 +152,13 @@ public class RecipientProvider {
|
||||
|
||||
if (record != null) {
|
||||
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
|
||||
return new RecipientDetails(record.getTitle(), groupId, null, contactPhoto);
|
||||
return new RecipientDetails(record.getTitle(), groupId, null, contactPhoto, Optional.<Integer>absent());
|
||||
}
|
||||
|
||||
return new RecipientDetails(null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto());
|
||||
return new RecipientDetails(null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto(), Optional.<Integer>absent());
|
||||
} catch (IOException e) {
|
||||
Log.w("RecipientProvider", e);
|
||||
return new RecipientDetails(null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto());
|
||||
return new RecipientDetails(null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto(), Optional.<Integer>absent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,18 +182,21 @@ public class RecipientProvider {
|
||||
}
|
||||
|
||||
public static class RecipientDetails {
|
||||
@Nullable public final String name;
|
||||
@NonNull public final String number;
|
||||
@NonNull public final ContactPhoto avatar;
|
||||
@Nullable public final Uri contactUri;
|
||||
@Nullable public final String name;
|
||||
@NonNull public final String number;
|
||||
@NonNull public final ContactPhoto avatar;
|
||||
@Nullable public final Uri contactUri;
|
||||
@NonNull public final Optional<Integer> color;
|
||||
|
||||
public RecipientDetails(@Nullable String name, @NonNull String number,
|
||||
@Nullable Uri contactUri, @NonNull ContactPhoto avatar)
|
||||
@Nullable Uri contactUri, @NonNull ContactPhoto avatar,
|
||||
@NonNull Optional<Integer> color)
|
||||
{
|
||||
this.name = name;
|
||||
this.number = number;
|
||||
this.avatar = avatar;
|
||||
this.contactUri = contactUri;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Patterns;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||
@@ -51,11 +50,10 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
private final Set<RecipientsModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientsModifiedListener, Boolean>());
|
||||
private final List<Recipient> recipients;
|
||||
|
||||
private Uri ringtone = null;
|
||||
private long mutedUntil = 0;
|
||||
private boolean blocked = false;
|
||||
private VibrateState vibrate = VibrateState.DEFAULT;
|
||||
private Optional<Integer> color = Optional.absent();
|
||||
private Uri ringtone = null;
|
||||
private long mutedUntil = 0;
|
||||
private boolean blocked = false;
|
||||
private VibrateState vibrate = VibrateState.DEFAULT;
|
||||
|
||||
Recipients() {
|
||||
this(new LinkedList<Recipient>(), (RecipientsPreferences)null);
|
||||
@@ -69,7 +67,6 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
mutedUntil = preferences.getMuteUntil();
|
||||
vibrate = preferences.getVibrateState();
|
||||
blocked = preferences.isBlocked();
|
||||
color = preferences.getColor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +85,6 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
mutedUntil = result.getMuteUntil();
|
||||
vibrate = result.getVibrateState();
|
||||
blocked = result.isBlocked();
|
||||
color = result.getColor();
|
||||
|
||||
localListeners = new HashSet<>(listeners);
|
||||
}
|
||||
@@ -106,21 +102,6 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized Optional<Integer> getColor() {
|
||||
if (color.isPresent()) return color;
|
||||
else if (isGroupRecipient()) return Optional.absent();
|
||||
else if (recipients.get(0).getName() == null) return Optional.absent();
|
||||
else return Optional.of(ContactColors.generateFor(recipients.get(0).getName()));
|
||||
}
|
||||
|
||||
public void setColor(Optional<Integer> color) {
|
||||
synchronized (this) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public synchronized @Nullable Uri getRingtone() {
|
||||
return ringtone;
|
||||
}
|
||||
@@ -169,12 +150,22 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public @NonNull
|
||||
ContactPhoto getContactPhoto() {
|
||||
public @NonNull ContactPhoto getContactPhoto() {
|
||||
if (recipients.size() == 1) return recipients.get(0).getContactPhoto();
|
||||
else return ContactPhotoFactory.getDefaultGroupPhoto();
|
||||
}
|
||||
|
||||
public synchronized @NonNull Optional<Integer> getColor() {
|
||||
if (!isSingleRecipient() || isGroupRecipient()) return Optional.absent();
|
||||
else if (isEmpty()) return Optional.absent();
|
||||
else return recipients.get(0).getColor();
|
||||
}
|
||||
|
||||
public synchronized void setColor(Optional<Integer> color) {
|
||||
if (!isSingleRecipient() || isGroupRecipient()) throw new AssertionError("Groups don't have colors!");
|
||||
else if (!isEmpty()) recipients.get(0).setColor(color);
|
||||
}
|
||||
|
||||
public synchronized void addListener(RecipientsModifiedListener listener) {
|
||||
if (listeners.isEmpty()) {
|
||||
for (Recipient recipient : recipients) {
|
||||
|
||||
Reference in New Issue
Block a user