mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-04-15 17:00:36 +03:00
Add avatar support to the chat window, minor tweaks to the chat layout
This commit is contained in:
parent
d09c9499e6
commit
65aca2d8a7
@ -39,8 +39,9 @@
|
||||
|
||||
<ImageButton
|
||||
a:id="@+id/chat_send"
|
||||
a:layout_width="60dip"
|
||||
a:layout_width="55dip"
|
||||
a:layout_height="40dip"
|
||||
a:background="@color/transparent"
|
||||
a:src="?attr/chat_send" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,48 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:orientation="vertical" >
|
||||
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_username"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:layout_marginRight="6dip"
|
||||
a:ellipsize="marquee"
|
||||
a:singleLine="true"
|
||||
a:text="User"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:textStyle="bold" />
|
||||
<ImageView
|
||||
a:layout_width="50dip"
|
||||
a:layout_height="50dip"
|
||||
a:id="@+id/chat_avatar"/>
|
||||
|
||||
<LinearLayout
|
||||
a:id="@+id/chat_message_layout"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginTop="2dip"
|
||||
a:orientation="horizontal" >
|
||||
a:orientation="vertical"
|
||||
a:layout_toEndOf="@id/chat_avatar"
|
||||
a:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_time"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:singleLine="true"
|
||||
a:text="00:00"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_message"
|
||||
a:id="@+id/chat_username"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:layout_marginRight="6dip"
|
||||
a:autoLink="all"
|
||||
a:linksClickable="true"
|
||||
a:singleLine="false"
|
||||
a:text="Message Text Goes Here"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
</LinearLayout>
|
||||
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"/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
a:id="@+id/chat_message_layout"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginTop="2dip"
|
||||
a:orientation="horizontal"
|
||||
a:gravity="center_vertical|left"
|
||||
a:layout_gravity="left">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_time"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:singleLine="true"
|
||||
a:textIsSelectable="true"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="left"/>
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_message"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:layout_marginRight="6dip"
|
||||
a:textIsSelectable="true"
|
||||
a:linksClickable="true"
|
||||
a:singleLine="false"
|
||||
a:autoLink="all"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="left"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -1,51 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_username"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginRight="6dip"
|
||||
a:gravity="right"
|
||||
a:layout_gravity="right"
|
||||
a:ellipsize="marquee"
|
||||
a:singleLine="true"
|
||||
a:text="User"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:textStyle="bold" />
|
||||
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginTop="2dip"
|
||||
a:orientation="horizontal"
|
||||
a:layout_gravity="right" >
|
||||
a:orientation="vertical"
|
||||
a:layout_gravity="right"
|
||||
a:layout_alignParentEnd="false"
|
||||
a:layout_toStartOf="@id/chat_avatar"
|
||||
a:gravity="center_vertical|right">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_time"
|
||||
a:id="@+id/chat_username"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:singleLine="true"
|
||||
a:gravity="right"
|
||||
a:text="00:00"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_message"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:layout_marginRight="6dip"
|
||||
a:autoLink="all"
|
||||
a:linksClickable="true"
|
||||
a:singleLine="false"
|
||||
a:gravity="right"
|
||||
a:text="Chat message"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
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"/>
|
||||
|
||||
<LinearLayout
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginTop="2dip"
|
||||
a:orientation="horizontal"
|
||||
a:layout_gravity="right|end"
|
||||
a:gravity="center_vertical|right">
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_time"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:singleLine="true"
|
||||
a:gravity="center_vertical|right"
|
||||
a:textIsSelectable="true"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:layout_gravity="right"/>
|
||||
|
||||
<TextView
|
||||
a:id="@+id/chat_message"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_marginLeft="6dip"
|
||||
a:layout_marginRight="6dip"
|
||||
a:linksClickable="true"
|
||||
a:singleLine="false"
|
||||
a:autoLink="all"
|
||||
a:textIsSelectable="true"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center_vertical|right"
|
||||
a:layout_gravity="right"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
a:layout_width="50dip"
|
||||
a:layout_height="50dip"
|
||||
a:id="@+id/chat_avatar"
|
||||
a:layout_alignParentEnd="true"
|
||||
a:layout_toStartOf="@id/chat_avatar"/>
|
||||
|
||||
</RelativeLayout>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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<String> parameterNames;
|
||||
List<Object> parameterValues;
|
||||
|
||||
parameterNames = Collections.singletonList("username");
|
||||
parameterValues = Arrays.<Object>asList(username);
|
||||
|
||||
HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener);
|
||||
in = entity.getContent();
|
||||
|
||||
// If content type is XML, an error occurred. Get it.
|
||||
String contentType = Util.getContentType(entity);
|
||||
if (contentType != null && contentType.startsWith("text/xml"))
|
||||
{
|
||||
new ErrorParser(context).parse(new InputStreamReader(in, Constants.UTF_8));
|
||||
return null; // Never reached.
|
||||
}
|
||||
|
||||
byte[] bytes = Util.toByteArray(in);
|
||||
|
||||
// If we aren't allowing server-side scaling, always save the file to disk because it will be unmodified
|
||||
if (saveToFile)
|
||||
{
|
||||
OutputStream out = null;
|
||||
|
||||
try
|
||||
{
|
||||
out = new FileOutputStream(FileUtil.getAvatarFile(username));
|
||||
out.write(bytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Util.close(out);
|
||||
}
|
||||
}
|
||||
|
||||
bitmap = FileUtil.getSampledBitmap(bytes, size, highQuality);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Util.close(in);
|
||||
}
|
||||
}
|
||||
|
||||
// Return scaled bitmap
|
||||
return Util.scaleBitmap(bitmap, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,19 @@ public class FileUtil
|
||||
return getAlbumArtFile(albumDir);
|
||||
}
|
||||
|
||||
public static File getAvatarFile(String username)
|
||||
{
|
||||
File albumArtDir = getAlbumArtDirectory();
|
||||
|
||||
if (albumArtDir == null || username == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String md5Hex = Util.md5Hex(username);
|
||||
return new File(albumArtDir, String.format("%s.jpeg", md5Hex));
|
||||
}
|
||||
|
||||
public static File getAlbumArtFile(File albumDir)
|
||||
{
|
||||
File albumArtDir = getAlbumArtDirectory();
|
||||
@ -124,6 +137,76 @@ public class FileUtil
|
||||
return new File(albumArtDir, String.format("%s.jpeg", md5Hex));
|
||||
}
|
||||
|
||||
public static Bitmap getAvatarBitmap(String username, int size, boolean highQuality)
|
||||
{
|
||||
if (username == null) return null;
|
||||
|
||||
File avatarFile = getAvatarFile(username);
|
||||
|
||||
SubsonicTabActivity subsonicTabActivity = SubsonicTabActivity.getInstance();
|
||||
Bitmap bitmap = null;
|
||||
ImageLoader imageLoader = null;
|
||||
|
||||
if (subsonicTabActivity != null)
|
||||
{
|
||||
imageLoader = subsonicTabActivity.getImageLoader();
|
||||
|
||||
if (imageLoader != null)
|
||||
{
|
||||
bitmap = imageLoader.getImageBitmap(username, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (bitmap != null)
|
||||
{
|
||||
return bitmap.copy(bitmap.getConfig(), false);
|
||||
}
|
||||
|
||||
if (avatarFile != null && avatarFile.exists())
|
||||
{
|
||||
final BitmapFactory.Options opt = new BitmapFactory.Options();
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
opt.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(avatarFile.getPath(), opt);
|
||||
|
||||
if (highQuality)
|
||||
{
|
||||
opt.inDither = true;
|
||||
opt.inPreferQualityOverSpeed = true;
|
||||
}
|
||||
|
||||
opt.inPurgeable = true;
|
||||
opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size));
|
||||
opt.inJustDecodeBounds = false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bitmap = BitmapFactory.decodeFile(avatarFile.getPath(), opt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.e(TAG, "Exception in BitmapFactory.decodeFile()", ex);
|
||||
}
|
||||
|
||||
Log.i("getAvatarBitmap", String.valueOf(size));
|
||||
|
||||
if (bitmap != null)
|
||||
{
|
||||
if (imageLoader != null)
|
||||
{
|
||||
imageLoader.addImageToCache(bitmap, username, size);
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap == null ? null : bitmap;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bitmap getAlbumArtBitmap(Context context, MusicDirectory.Entry entry, int size, boolean highQuality)
|
||||
{
|
||||
if (entry == null) return null;
|
||||
|
@ -58,6 +58,7 @@ public class ImageLoader implements Runnable
|
||||
private int imageSizeDefault;
|
||||
private final int imageSizeLarge;
|
||||
private Bitmap largeUnknownImage;
|
||||
private Bitmap unknownAvatarImage;
|
||||
private Context context;
|
||||
private Collection<Thread> threads;
|
||||
private AtomicBoolean running = new AtomicBoolean();
|
||||
@ -80,6 +81,7 @@ public class ImageLoader implements Runnable
|
||||
|
||||
imageSizeLarge = Util.getMaxDisplayMetric(context);
|
||||
createLargeUnknownImage(context);
|
||||
createUnknownAvatarImage(context);
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning()
|
||||
@ -130,6 +132,41 @@ public class ImageLoader implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private void createUnknownAvatarImage(Context context)
|
||||
{
|
||||
Resources res = context.getResources();
|
||||
Drawable contact = res.getDrawable(R.drawable.ic_contact_picture);
|
||||
unknownAvatarImage = Util.createBitmapFromDrawable(contact);
|
||||
}
|
||||
|
||||
public void loadAvatarImage(View view, String username, boolean large, int size, boolean crossFade, boolean highQuality)
|
||||
{
|
||||
view.invalidate();
|
||||
|
||||
if (username == null)
|
||||
{
|
||||
setUnknownAvatarImage(view);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
size = large ? imageSizeLarge : imageSizeDefault;
|
||||
}
|
||||
|
||||
Bitmap bitmap = cache.get(getKey(username, size));
|
||||
|
||||
if (bitmap != null)
|
||||
{
|
||||
setAvatarImageBitmap(view, username, bitmap, crossFade);
|
||||
return;
|
||||
}
|
||||
|
||||
setUnknownAvatarImage(view);
|
||||
|
||||
queue.offer(new Task(view, username, size, large, crossFade, highQuality));
|
||||
}
|
||||
|
||||
public void loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossFade, boolean highQuality)
|
||||
{
|
||||
view.invalidate();
|
||||
@ -171,6 +208,19 @@ public class ImageLoader implements Runnable
|
||||
return String.format("%s:%d", coverArtId, size);
|
||||
}
|
||||
|
||||
public Bitmap getImageBitmap(String username, int size)
|
||||
{
|
||||
Bitmap bitmap = cache.get(getKey(username, size));
|
||||
|
||||
if (bitmap != null && !bitmap.isRecycled())
|
||||
{
|
||||
Bitmap.Config config = bitmap.getConfig();
|
||||
return bitmap.copy(config, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Bitmap getImageBitmap(MusicDirectory.Entry entry, boolean large, int size)
|
||||
{
|
||||
if (entry == null)
|
||||
@ -224,7 +274,7 @@ public class ImageLoader implements Runnable
|
||||
if (existingDrawable == null)
|
||||
{
|
||||
Bitmap emptyImage = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
existingDrawable = new BitmapDrawable(emptyImage);
|
||||
existingDrawable = new BitmapDrawable(context.getResources(), emptyImage);
|
||||
}
|
||||
|
||||
Drawable[] layers = new Drawable[]{existingDrawable, newDrawable};
|
||||
@ -240,6 +290,50 @@ public class ImageLoader implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private void setAvatarImageBitmap(View view, String username, Bitmap bitmap, boolean crossFade)
|
||||
{
|
||||
if (view instanceof ImageView)
|
||||
{
|
||||
ImageView imageView = (ImageView) view;
|
||||
|
||||
String tagEntry = (String) view.getTag();
|
||||
|
||||
// Only apply image to the view if the view is intended for this entry
|
||||
if (username != null && tagEntry != null && !username.equals(tagEntry))
|
||||
{
|
||||
Log.i(TAG, "View is no longer valid, not setting ImageBitmap");
|
||||
return;
|
||||
}
|
||||
|
||||
if (crossFade)
|
||||
{
|
||||
Drawable existingDrawable = imageView.getDrawable();
|
||||
Drawable newDrawable = Util.createDrawableFromBitmap(this.context, bitmap);
|
||||
|
||||
if (existingDrawable == null)
|
||||
{
|
||||
Bitmap emptyImage = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
existingDrawable = new BitmapDrawable(context.getResources(), emptyImage);
|
||||
}
|
||||
|
||||
Drawable[] layers = new Drawable[]{existingDrawable, newDrawable};
|
||||
|
||||
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
|
||||
imageView.setImageDrawable(transitionDrawable);
|
||||
transitionDrawable.startTransition(250);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setUnknownAvatarImage(View view)
|
||||
{
|
||||
setAvatarImageBitmap(view, null, unknownAvatarImage, false);
|
||||
}
|
||||
|
||||
public void setUnknownImage(View view, boolean large)
|
||||
{
|
||||
if (large)
|
||||
@ -264,6 +358,11 @@ public class ImageLoader implements Runnable
|
||||
cache.put(getKey(entry.getCoverArt(), size), bitmap);
|
||||
}
|
||||
|
||||
public void addImageToCache(Bitmap bitmap, String username, int size)
|
||||
{
|
||||
cache.put(getKey(username, size), bitmap);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
queue.clear();
|
||||
@ -295,6 +394,7 @@ public class ImageLoader implements Runnable
|
||||
{
|
||||
private final View view;
|
||||
private final MusicDirectory.Entry entry;
|
||||
private final String username;
|
||||
private final Handler handler;
|
||||
private final int size;
|
||||
private final boolean saveToFile;
|
||||
@ -305,6 +405,19 @@ public class ImageLoader implements Runnable
|
||||
{
|
||||
this.view = view;
|
||||
this.entry = entry;
|
||||
this.username = null;
|
||||
this.size = size;
|
||||
this.saveToFile = saveToFile;
|
||||
this.crossFade = crossFade;
|
||||
this.highQuality = highQuality;
|
||||
handler = new Handler();
|
||||
}
|
||||
|
||||
public Task(View view, String username, int size, boolean saveToFile, boolean crossFade, boolean highQuality)
|
||||
{
|
||||
this.view = view;
|
||||
this.entry = null;
|
||||
this.username = username;
|
||||
this.size = size;
|
||||
this.saveToFile = saveToFile;
|
||||
this.crossFade = crossFade;
|
||||
@ -317,16 +430,27 @@ public class ImageLoader implements Runnable
|
||||
try
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
|
||||
final Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, highQuality, null);
|
||||
final boolean isAvatar = this.username != null && this.entry == null;
|
||||
final Bitmap bitmap = this.entry != null ? musicService.getCoverArt(view.getContext(), entry, size, saveToFile, highQuality, null) : musicService.getAvatar(view.getContext(), username, size, saveToFile, highQuality, null);
|
||||
|
||||
addImageToCache(bitmap, entry, size);
|
||||
if (isAvatar)
|
||||
addImageToCache(bitmap, username, size);
|
||||
else
|
||||
addImageToCache(bitmap, entry, size);
|
||||
|
||||
handler.post(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
setImageBitmap(view, entry, bitmap, crossFade);
|
||||
if (isAvatar)
|
||||
{
|
||||
setAvatarImageBitmap(view, username, bitmap, crossFade);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImageBitmap(view, entry, bitmap, crossFade);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.AudioManager;
|
||||
@ -871,6 +872,19 @@ public class Util extends DownloadActivity
|
||||
return new BitmapDrawable(context.getResources(), bitmap);
|
||||
}
|
||||
|
||||
public static Bitmap createBitmapFromDrawable(Drawable drawable) {
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable)drawable).getBitmap();
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static WifiManager.WifiLock createWifiLock(Context context, String tag)
|
||||
{
|
||||
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
|
@ -6,34 +6,45 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.thejoshwa.ultrasonic.androidapp.R;
|
||||
import com.thejoshwa.ultrasonic.androidapp.activity.SubsonicTabActivity;
|
||||
import com.thejoshwa.ultrasonic.androidapp.domain.ChatMessage;
|
||||
import com.thejoshwa.ultrasonic.androidapp.util.ImageLoader;
|
||||
import com.thejoshwa.ultrasonic.androidapp.util.Util;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ChatAdapter extends ArrayAdapter<ChatMessage>
|
||||
{
|
||||
|
||||
private final SubsonicTabActivity activity;
|
||||
private ArrayList<ChatMessage> messages;
|
||||
private List<ChatMessage> messages;
|
||||
|
||||
private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})"; //you can just place your support phone here
|
||||
private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})";
|
||||
private static final Pattern phoneMatcher = Pattern.compile(phoneRegex);
|
||||
|
||||
public ChatAdapter(SubsonicTabActivity activity, ArrayList<ChatMessage> messages)
|
||||
public ChatAdapter(SubsonicTabActivity activity, List<ChatMessage> messages)
|
||||
{
|
||||
super(activity, R.layout.chat_item, messages);
|
||||
this.activity = activity;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
@ -65,16 +76,25 @@ public class ChatAdapter extends ArrayAdapter<ChatMessage>
|
||||
{
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
|
||||
if (holder.layout != layout)
|
||||
if (!holder.chatMessage.equals(message))
|
||||
{
|
||||
convertView = inflateView(layout, parent);
|
||||
holder = createViewHolder(layout, convertView);
|
||||
}
|
||||
}
|
||||
|
||||
holder.chatMessage = message;
|
||||
|
||||
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity);
|
||||
String messageTimeFormatted = String.format("[%s]", timeFormat.format(messageTime));
|
||||
|
||||
ImageLoader imageLoader = activity.getImageLoader();
|
||||
|
||||
if (imageLoader != null)
|
||||
{
|
||||
imageLoader.loadAvatarImage(holder.avatar, messageUser, false, holder.avatar.getWidth(), false, true);
|
||||
}
|
||||
|
||||
holder.username.setText(messageUser);
|
||||
holder.message.setText(messageText);
|
||||
holder.time.setText(messageTimeFormatted);
|
||||
@ -95,18 +115,20 @@ public class ChatAdapter extends ArrayAdapter<ChatMessage>
|
||||
TextView usernameView;
|
||||
TextView timeView;
|
||||
TextView messageView;
|
||||
ImageView imageView;
|
||||
|
||||
if (convertView != null)
|
||||
{
|
||||
usernameView = (TextView) convertView.findViewById(R.id.chat_username);
|
||||
timeView = (TextView) convertView.findViewById(R.id.chat_time);
|
||||
messageView = (TextView) convertView.findViewById(R.id.chat_message);
|
||||
imageView = (ImageView) convertView.findViewById(R.id.chat_avatar);
|
||||
|
||||
messageView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES);
|
||||
Linkify.addLinks(messageView, Linkify.WEB_URLS);
|
||||
Linkify.addLinks(messageView, Linkify.ALL);
|
||||
Linkify.addLinks(messageView, phoneMatcher, "tel:");
|
||||
|
||||
holder.avatar = imageView;
|
||||
holder.message = messageView;
|
||||
holder.username = usernameView;
|
||||
holder.time = timeView;
|
||||
@ -120,8 +142,10 @@ public class ChatAdapter extends ArrayAdapter<ChatMessage>
|
||||
private static class ViewHolder
|
||||
{
|
||||
int layout;
|
||||
ImageView avatar;
|
||||
TextView message;
|
||||
TextView username;
|
||||
TextView time;
|
||||
ChatMessage chatMessage;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user