From fe78f858bacf54f8285db31b7d6aa65ff3628f15 Mon Sep 17 00:00:00 2001 From: steckbrief Date: Mon, 16 May 2016 01:35:46 +0200 Subject: avatar displayed as a circle, positioning adjusted, colors changed back to correct ones, positioning moved to own class file --- .../conversationsplus/services/AvatarService.java | 26 +++++- .../conversationsplus/ui/ConversationActivity.java | 96 ++++++++++------------ .../listeners/AvatarLogoPositioningListener.java | 57 +++++++++++++ .../conversationsplus/utils/ImageUtil.java | 32 ++++++++ .../actionbar_space_between_icon_and_title.xml | 8 -- src/main/res/layout/title.xml | 15 ++++ src/main/res/values-land/dimens.xml | 4 + src/main/res/values/dimens.xml | 1 + src/main/res/values/themes.xml | 11 +-- 9 files changed, 182 insertions(+), 68 deletions(-) create mode 100644 src/main/java/de/thedevstack/conversationsplus/ui/listeners/AvatarLogoPositioningListener.java delete mode 100644 src/main/res/drawable/actionbar_space_between_icon_and_title.xml create mode 100644 src/main/res/layout/title.xml create mode 100644 src/main/res/values-land/dimens.xml diff --git a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java b/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java index ed9c259f..1ab1dfd6 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java @@ -156,8 +156,32 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { } } + public Bitmap getCircled(Conversation conversation, int size) { + return getCircled(conversation, size, false); + } + + private Bitmap getCircled(Conversation conversation, int size, boolean cachedOnly) { + Bitmap squareAvatar = get(conversation, size, cachedOnly); + String key = ""; + if (conversation.getMode() == Conversation.MODE_SINGLE) { + key = key(conversation.getContact(), size); + } else { + key = key(conversation.getMucOptions(), size); + } + key += "_circle"; + + Bitmap circleAvatar = ImageUtil.getBitmapFromCache(key); + if (null != circleAvatar || cachedOnly) { + return circleAvatar; + } + circleAvatar = ImageUtil.getCircleBitmap(squareAvatar); + ImageUtil.addBitmapToCache(key, circleAvatar); + + return circleAvatar; + } + public Bitmap get(Conversation conversation, int size) { - return get(conversation,size,false); + return get(conversation, size, false); } public Bitmap get(Conversation conversation, int size, boolean cachedOnly) { diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java index 7138f8e3..71db3e3a 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java @@ -28,7 +28,6 @@ import android.view.MenuItem; import android.view.Surface; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; @@ -36,6 +35,7 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; +import android.widget.TextView; import android.widget.Toast; import net.java.otr4j.session.SessionStatus; @@ -51,6 +51,7 @@ import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import de.thedevstack.conversationsplus.services.AvatarService; import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.AvatarLogoPositioningListener; import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; import de.thedevstack.conversationsplus.utils.ConversationUtil; import de.timroes.android.listview.EnhancedListView; @@ -118,6 +119,7 @@ public class ConversationActivity extends XmppActivity private View mContentView; private View avatarLogoView; + private View titleView; private List conversationList = new ArrayList<>(); private Conversation swipedConversation = null; @@ -131,7 +133,7 @@ public class ConversationActivity extends XmppActivity private AtomicBoolean mRedirected = new AtomicBoolean(false); private Pair mPostponedActivityResult; - public Conversation getSelectedConversation() { + public Conversation getSelectedConversation() { return this.mSelectedConversation; } @@ -354,81 +356,73 @@ public class ConversationActivity extends XmppActivity private void updateActionBarTitle(boolean titleShouldBeName) { final ActionBar ab = getActionBar(); - final Conversation conversation = getSelectedConversation(); if (ab != null) { + if (null == this.titleView || null == this.avatarLogoView) { + this.initializeCustomActionBarViews(ab); + } + TextView title = (TextView) this.titleView.findViewById(R.id.conversationsTitle); + final Conversation conversation = getSelectedConversation(); if (titleShouldBeName && conversation != null) { - this.updateLogoAvatar(true); + this.toggleShowCustomActionBarView(ab, true); + this.showLogoAvatar(); ab.setDisplayHomeAsUpEnabled(true); ab.setHomeButtonEnabled(true); + if (conversation.getMode() == Conversation.MODE_SINGLE || ConversationsPlusPreferences.useSubject()) { - ab.setTitle(conversation.getName()); + title.setText(conversation.getName()); } else { - ab.setTitle(conversation.getJid().toBareJid().toString()); + title.setText(conversation.getJid().toBareJid().toString()); } } else { + this.toggleShowCustomActionBarView(ab, false); ab.setDisplayHomeAsUpEnabled(false); ab.setHomeButtonEnabled(false); - ab.setTitle(R.string.app_name); - this.updateLogoAvatar(false); + title.setText(R.string.app_name); + this.hideLogoAvatar(); } } } - private void updateLogoAvatar(boolean show) { + private void toggleShowCustomActionBarView(ActionBar ab, boolean show) { + if (show) { + ab.setDisplayShowTitleEnabled(false); + ab.setDisplayShowCustomEnabled(true); + } else { + ab.setDisplayShowTitleEnabled(true); + ab.setDisplayShowCustomEnabled(false); + } + } + + private void initializeCustomActionBarViews(ActionBar ab) { + if (null == this.titleView) { + this.titleView = LayoutInflater.from(this).inflate(R.layout.title, null); + ab.setCustomView(this.titleView); + } if (null == this.avatarLogoView) { this.avatarLogoView = LayoutInflater.from(this).inflate(R.layout.logo_view, null, false); ViewGroup decorViewGroup = (ViewGroup) getWindow().getDecorView(); decorViewGroup.addView(avatarLogoView); int resId = getResources().getIdentifier("action_bar_container", "id", "android"); final View actionBarView = decorViewGroup.findViewById(resId); - final View iconPlaceholderView = decorViewGroup.findViewById(R.id.icon_placeholder); if (actionBarView != null) { - actionBarView.getViewTreeObserver().addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - public void onGlobalLayout() { - // Remove the listener - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - actionBarView.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } else { - actionBarView.getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - - // Measure views - int[] location = new int[2]; - actionBarView.getLocationOnScreen(location); - - int[] logoLocation = new int[2]; - avatarLogoView.getLocationOnScreen(logoLocation); - - int[] iconPlaceHolderLocation = new int[2]; - if (null != iconPlaceholderView) { - iconPlaceholderView.getLocationOnScreen(iconPlaceHolderLocation); - }else { - iconPlaceHolderLocation[0] = 0; - } - - // Add top padding if necessary - if (location[1] > logoLocation[1]) { - avatarLogoView.setPadding(iconPlaceHolderLocation[0], actionBarView.getMeasuredHeight() / 4 + location[1] - logoLocation[1], 0, 0); - } - /*if (iconPlaceHolderLocation[0] > logoLocation[0]) { - avatarLogoView.setPadding - }*/ - } - } - ); + actionBarView.getViewTreeObserver().addOnGlobalLayoutListener(new AvatarLogoPositioningListener(actionBarView, avatarLogoView)); } } - if (show) { - ImageView avatarView = (ImageView) this.avatarLogoView.findViewById(R.id.logoViewAvatar); - avatarView.setImageBitmap(AvatarService.getInstance().get(getSelectedConversation(), getPixel(56))); - //avatarView.setAlpha(0.5f); - avatarLogoView.setVisibility(View.VISIBLE); - } else { - avatarLogoView.setVisibility(View.GONE); + } + + private void hideLogoAvatar() { + if (null != this.avatarLogoView) { + this.avatarLogoView.setVisibility(View.GONE); } } + private void showLogoAvatar() { + ImageView avatarView = (ImageView) this.avatarLogoView.findViewById(R.id.logoViewAvatar); + avatarView.setImageBitmap(AvatarService.getInstance().getCircled(getSelectedConversation(), getPixel(56))); + //avatarView.setAlpha(0.5f); + avatarLogoView.setVisibility(View.VISIBLE); + } + private void openConversation() { this.updateActionBarTitle(); this.invalidateOptionsMenu(); diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/AvatarLogoPositioningListener.java b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/AvatarLogoPositioningListener.java new file mode 100644 index 00000000..e6846d9b --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/AvatarLogoPositioningListener.java @@ -0,0 +1,57 @@ +package de.thedevstack.conversationsplus.ui.listeners; + +import android.os.Build; +import android.view.View; +import android.view.ViewTreeObserver; + +import de.thedevstack.conversationsplus.R; + +/** + * This listener aims to position the avatar logo. + */ +public class AvatarLogoPositioningListener implements ViewTreeObserver.OnGlobalLayoutListener { + private View actionBarView; + private View avatarLogoView; + + public AvatarLogoPositioningListener(View actionBarView, View avatarLogoView) { + this.actionBarView = actionBarView; + this.avatarLogoView = avatarLogoView; + } + + @Override + public void onGlobalLayout() { + // Measure views + int[] location = new int[2]; + this.actionBarView.getLocationOnScreen(location); + + int[] logoLocation = new int[2]; + this.avatarLogoView.getLocationOnScreen(logoLocation); + + int[] titleViewLocation = new int[2]; + View titleView = this.actionBarView.findViewById(R.id.conversationsTitle); + int oldTitleViewLeftPadding = 0; + if (null != titleView) { + // Remove the listener only if all necessary view elements are there + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + this.actionBarView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } else { + this.actionBarView.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + + titleView.getLocationOnScreen(titleViewLocation); + int avatarWidth = (int) (58 * titleView.getResources().getDisplayMetrics().density); + int newTitleViewLeftPadding = titleViewLocation[0] + avatarWidth; + titleView.setPadding(newTitleViewLeftPadding, titleView.getPaddingTop(), 0, 0); + oldTitleViewLeftPadding = titleViewLocation[0]; + } + + // Add top padding if necessary + if (location[1] > logoLocation[1]) { + int actionBarViewHeight = this.actionBarView.getMeasuredHeight(); + int newAvatarLogoTopPadding = location[1]; // Move to the top padding of the action bar (below the notification bar) + newAvatarLogoTopPadding += actionBarViewHeight; + newAvatarLogoTopPadding -= 58 * avatarLogoView.getResources().getDisplayMetrics().density * 0.6; + this.avatarLogoView.setPadding(oldTitleViewLeftPadding, newAvatarLogoTopPadding, 0, 0); + } + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/ImageUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/ImageUtil.java index bf79d7e0..18197e3b 100644 --- a/src/main/java/de/thedevstack/conversationsplus/utils/ImageUtil.java +++ b/src/main/java/de/thedevstack/conversationsplus/utils/ImageUtil.java @@ -4,6 +4,10 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; import android.media.ExifInterface; import android.net.Uri; @@ -365,6 +369,34 @@ public final class ImageUtil { return inSampleSize; } + /** + * Get a circled cut-out of a bitmap. + * @param bitmap the original bitmap + * @return the circled cut-out of the original bitmap + * @see http://stackoverflow.com/questions/11932805/cropping-circular-area-from-bitmap-in-android + */ + public static Bitmap getCircleBitmap(Bitmap bitmap) { + Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), + bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(output); + + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + // canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, + bitmap.getWidth() / 2, paint); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + //Bitmap _bmp = Bitmap.createScaledBitmap(output, 60, 60, false); + //return _bmp; + return output; + } + private ImageUtil() { // Static helper class } diff --git a/src/main/res/drawable/actionbar_space_between_icon_and_title.xml b/src/main/res/drawable/actionbar_space_between_icon_and_title.xml deleted file mode 100644 index 53285bc0..00000000 --- a/src/main/res/drawable/actionbar_space_between_icon_and_title.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/main/res/layout/title.xml b/src/main/res/layout/title.xml new file mode 100644 index 00000000..17ff1a5b --- /dev/null +++ b/src/main/res/layout/title.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/src/main/res/values-land/dimens.xml b/src/main/res/values-land/dimens.xml new file mode 100644 index 00000000..411fd575 --- /dev/null +++ b/src/main/res/values-land/dimens.xml @@ -0,0 +1,4 @@ + + + 16dp + \ No newline at end of file diff --git a/src/main/res/values/dimens.xml b/src/main/res/values/dimens.xml index d5d4aad4..99a292fd 100644 --- a/src/main/res/values/dimens.xml +++ b/src/main/res/values/dimens.xml @@ -9,4 +9,5 @@ 240dp 30dp 8dp + 18dp diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml index a157084f..0deb3a6e 100644 --- a/src/main/res/values/themes.xml +++ b/src/main/res/values/themes.xml @@ -44,16 +44,11 @@ - -