diff --git a/res/layout/chat.xml b/res/layout/chat.xml
index 0a04dfe8..8b8ea719 100644
--- a/res/layout/chat.xml
+++ b/res/layout/chat.xml
@@ -39,8 +39,9 @@
diff --git a/res/layout/chat_item.xml b/res/layout/chat_item.xml
index faaa2d64..3dad7870 100644
--- a/res/layout/chat_item.xml
+++ b/res/layout/chat_item.xml
@@ -1,48 +1,66 @@
-
+
-
+
+ a:orientation="vertical"
+ a:layout_toEndOf="@id/chat_avatar"
+ a:gravity="center_vertical">
-
-
-
+ a:ellipsize="marquee"
+ a:singleLine="true"
+ a:textIsSelectable="true"
+ a:textAppearance="?android:attr/textAppearanceMedium"
+ a:textStyle="bold"
+ a:layout_gravity="left"
+ a:gravity="center_vertical|left"/>
-
\ No newline at end of file
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/chat_item_reverse.xml b/res/layout/chat_item_reverse.xml
index c6206286..39ca0b0f 100644
--- a/res/layout/chat_item_reverse.xml
+++ b/res/layout/chat_item_reverse.xml
@@ -1,51 +1,71 @@
-
-
-
+
+ a:orientation="vertical"
+ a:layout_gravity="right"
+ a:layout_alignParentEnd="false"
+ a:layout_toStartOf="@id/chat_avatar"
+ a:gravity="center_vertical|right">
-
-
+ a:gravity="center_vertical|right"
+ a:layout_gravity="right"
+ a:ellipsize="marquee"
+ a:singleLine="true"
+ a:textIsSelectable="true"
+ a:textAppearance="?android:attr/textAppearanceMedium"
+ a:textStyle="bold"/>
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/com/thejoshwa/ultrasonic/androidapp/domain/ChatMessage.java b/src/com/thejoshwa/ultrasonic/androidapp/domain/ChatMessage.java
index e5b0adfc..258e2119 100644
--- a/src/com/thejoshwa/ultrasonic/androidapp/domain/ChatMessage.java
+++ b/src/com/thejoshwa/ultrasonic/androidapp/domain/ChatMessage.java
@@ -41,4 +41,24 @@ public class ChatMessage implements Serializable
{
this.message = message;
}
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ChatMessage that = (ChatMessage) o;
+
+ return message.equals(that.message) && time.equals(that.time) && username.equals(that.username);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = username.hashCode();
+ result = 31 * result + time.hashCode();
+ result = 31 * result + message.hashCode();
+ return result;
+ }
}
diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java
index f7884562..1a700357 100644
--- a/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java
+++ b/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java
@@ -526,4 +526,10 @@ public class CachedMusicService implements MusicService
{
musicService.updateShare(id, description, expires, context, progressListener);
}
+
+ @Override
+ public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
+ {
+ return musicService.getAvatar(context, username, size, saveToFile, highQuality, progressListener);
+ }
}
diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java
index f963e8cb..a082a855 100644
--- a/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java
+++ b/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java
@@ -147,4 +147,6 @@ public interface MusicService
void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception;
void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception;
+
+ Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception;
}
\ No newline at end of file
diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java
index 24de3c4d..1c89e2bf 100644
--- a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java
+++ b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java
@@ -328,6 +328,20 @@ public class OfflineMusicService extends RESTMusicService
return entry;
}
+ @Override
+ public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
+ {
+ try
+ {
+ Bitmap bitmap = FileUtil.getAvatarBitmap(username, size, highQuality);
+ return Util.scaleBitmap(bitmap, size);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
@Override
public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
{
diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java
index cb08e549..11935dc3 100644
--- a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java
+++ b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java
@@ -872,6 +872,13 @@ public class RESTMusicService implements MusicService
}
}
+ private static boolean checkServerVersion(Context context, String version)
+ {
+ Version serverVersion = Util.getServerRestVersion(context);
+ Version requiredVersion = new Version(version);
+ return serverVersion == null || serverVersion.compareTo(requiredVersion) >= 0;
+ }
+
@Override
public Bitmap getCoverArt(Context context, final MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
{
@@ -1659,4 +1666,79 @@ public class RESTMusicService implements MusicService
Util.close(reader);
}
}
+
+ @Override
+ public Bitmap getAvatar(Context context, String username, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception
+ {
+ // Return silently if server is too old
+ if (!checkServerVersion(context, "1.8"))
+ return null;
+
+ // Synchronize on the username so that we don't download concurrently for
+ // the same user.
+ if (username == null)
+ {
+ return null;
+ }
+
+ synchronized (username)
+ {
+ // Use cached file, if existing.
+ Bitmap bitmap = FileUtil.getAvatarBitmap(username, size, highQuality);
+
+ if (bitmap == null)
+ {
+ String url = Util.getRestUrl(context, "getAvatar");
+
+ InputStream in = null;
+
+ try
+ {
+ List parameterNames;
+ List