From e2e24317ca31f6e07371f330a639bb48dfac89d0 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Mon, 23 May 2016 13:00:16 +0800 Subject: [PATCH 01/10] feat: add GIF supported AvatarView --- Habitica/build.gradle | 7 + Habitica/res/values/attrs_avatar_view.xml | 7 + .../android/habitica/ui/AvatarView.java | 452 ++++++++++++++++++ .../lib/models/HabitRPGUser.java | 70 +++ .../habitrpgwrapper/lib/models/Hair.java | 4 + .../habitrpgwrapper/lib/models/Outfit.java | 5 + 6 files changed, 545 insertions(+) create mode 100644 Habitica/res/values/attrs_avatar_view.xml create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 3c0d94e5f..5a50b6d4d 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -117,6 +117,13 @@ dependencies { //Analytics compile 'com.amplitude:android-sdk:2.7.1' + // Fresco Image Management Library + compile('com.facebook.fresco:fresco:0.10.0') { + exclude module: 'bolts-android' + } + compile('com.facebook.fresco:animated-gif:0.10.0') { + exclude module: 'bolts-android' + } //Tests testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' testCompile 'org.robolectric:robolectric:3.0' diff --git a/Habitica/res/values/attrs_avatar_view.xml b/Habitica/res/values/attrs_avatar_view.xml new file mode 100644 index 000000000..595b30f9d --- /dev/null +++ b/Habitica/res/values/attrs_avatar_view.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java new file mode 100644 index 000000000..957b4978b --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java @@ -0,0 +1,452 @@ +package com.habitrpg.android.habitica.ui; + +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.drawee.controller.BaseControllerListener; +import com.facebook.drawee.generic.GenericDraweeHierarchy; +import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; +import com.facebook.drawee.interfaces.DraweeController; +import com.facebook.drawee.view.DraweeHolder; +import com.facebook.drawee.view.MultiDraweeHolder; +import com.facebook.imagepipeline.image.ImageInfo; +import com.habitrpg.android.habitica.R; +import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class AvatarView extends View { + public static final String IMAGE_URI_ROOT = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"; + private static final String TAG = "AvatarView"; + private static final Map sFilenameMap; + private static final Rect sFullHeroRect = new Rect(0, 0, 140, 147); + private static final Rect sCompactHeroRect = new Rect(0, 0, 114, 114); + private static final Rect sHeroOnlyRect = new Rect(0, 0, 90, 90); + + static { + Map tempMap = new HashMap<>(); + tempMap.put("head_special_1", "ContributorOnly-Equip-CrystalHelmet.gif"); + tempMap.put("armor_special_1", "ContributorOnly-Equip-CrystalArmor.gif"); + tempMap.put("weapon_special_critical", "weapon_special_critical.gif"); + tempMap.put("Pet-Wolf-Cerberus", "Pet-Wolf-Cerberus.gif"); + sFilenameMap = Collections.unmodifiableMap(tempMap); + } + + private boolean mShowBackground = true; + private boolean mShowMount = true; + private boolean mShowPet = true; + private boolean mHasBackground; + private boolean mHasMount; + private boolean mHasPet; + private boolean mIsOrphan; + private MultiDraweeHolder mMultiDraweeHolder = new MultiDraweeHolder<>(); + private HabitRPGUser mUser; + private RectF mAvatarRectF; + private Matrix mMatrix = new Matrix(); + private AtomicInteger mNumberLayersInProcess = new AtomicInteger(0); + private Consumer mAvatarImageConsumer; + private Bitmap mAvatarBitmap; + private Canvas mAvatarCanvas; + + public AvatarView(Context context) { + super(context); + init(null, 0); + } + + public AvatarView(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs, 0); + } + + public AvatarView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs, defStyle); + } + + public AvatarView(Context context, boolean showBackground, boolean showMount, boolean showPet) { + super(context); + + mShowBackground = showBackground; + mShowMount = showMount; + mShowPet = showPet; + mIsOrphan = true; + } + + private void init(AttributeSet attrs, int defStyle) { + // Load attributes + final TypedArray a = getContext().obtainStyledAttributes( + attrs, R.styleable.AvatarView, defStyle, 0); + + try { + mShowBackground = a.getBoolean(R.styleable.AvatarView_showBackground, true); + mShowMount = a.getBoolean(R.styleable.AvatarView_showMount, true); + mShowPet = a.getBoolean(R.styleable.AvatarView_showPet, true); + } finally { + a.recycle(); + } + } + + private void showLayers(@NonNull Map layerMap) { + if (mMultiDraweeHolder.size() > 0) return; + int i = 0; + + mNumberLayersInProcess.set(layerMap.size()); + + for (Map.Entry entry : layerMap.entrySet()) { + final LayerType layerKey = entry.getKey(); + final String layerName = entry.getValue(); + final int layerNumber = i++; + + GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(getResources()) + .setFadeDuration(0) + .build(); + + DraweeHolder draweeHolder = DraweeHolder.create(hierarchy, getContext()); + draweeHolder.getTopLevelDrawable().setCallback(this); + mMultiDraweeHolder.add(draweeHolder); + + DraweeController controller = Fresco.newDraweeControllerBuilder() + .setUri(IMAGE_URI_ROOT + getFileName(layerName)) + .setControllerListener(new BaseControllerListener() { + @Override + public void onFinalImageSet( + String id, + ImageInfo imageInfo, + Animatable anim) { + if (imageInfo != null) { + mMultiDraweeHolder.get(layerNumber).getTopLevelDrawable().setBounds(getLayerBounds(layerKey, layerName, imageInfo)); + onLayerComplete(); + } + } + + @Override + public void onFailure(String id, Throwable throwable) { + Log.e(TAG, "Error loading layer: " + layerName, throwable); + onLayerComplete(); + } + }) + .setAutoPlayAnimations(!mIsOrphan) + .build(); + draweeHolder.setController(controller); + } + + if (mIsOrphan) mMultiDraweeHolder.onAttach(); + } + + private Map getLayerMap() { + assert mUser != null; + return getLayerMap(mUser, true); + } + + private Map getLayerMap(@NonNull HabitRPGUser user, boolean resetHasAttributes) { + EnumMap layerMap = user.getAvatarLayerMap(); + + if (resetHasAttributes) mHasBackground = mHasMount = mHasPet = false; + + String mountName = user.getItems().getCurrentMount(); + if (mShowMount && !TextUtils.isEmpty(mountName)) { + layerMap.put(LayerType.MOUNT_BODY, "Mount_Body_" + mountName); + layerMap.put(LayerType.MOUNT_HEAD, "Mount_Head_" + mountName); + if (resetHasAttributes) mHasMount = true; + } + + String petName = user.getItems().getCurrentPet(); + if (mShowPet && !TextUtils.isEmpty(petName)) { + layerMap.put(LayerType.PET, "Pet-" + petName); + if (resetHasAttributes) mHasPet = true; + } + + String backgroundName = user.getPreferences().getBackground(); + if (mShowBackground && !TextUtils.isEmpty(backgroundName)) { + layerMap.put(LayerType.BACKGROUND, "background_" + backgroundName); + if (resetHasAttributes) mHasBackground = true; + } + return layerMap; + } + + private Rect getLayerBounds(@NonNull LayerType layerType, @NonNull String layerName, @NonNull ImageInfo layerImageInfo) { + PointF offset = null; + Rect bounds = new Rect(0, 0, layerImageInfo.getWidth(), layerImageInfo.getHeight()); + RectF boundsF = new RectF(bounds); + + // lookup layer specific offset + switch (layerName) { + case "weapon_special_critical": + if (mShowMount || mShowPet) { + // full hero box + if (mHasMount) { + offset = new PointF(13.0f, 12.0f); + } else if (mHasPet) { + offset = new PointF(13.0f, 24.5f + 12.0f); + } else { + offset = new PointF(13.0f, 28.0f + 12.0f); + } + } else if (mShowBackground) { + // compact hero box + offset = new PointF(-12.0f, 18.0f + 12.0f); + } else { + // hero only box + offset = new PointF(-12.0f, 12.0f); + } + break; + default: + break; + } + + // otherwise lookup default layer type based offset + if (offset == null) { + switch (layerType) { + case BACKGROUND: + if (!(mShowMount || mShowPet)) { + offset = new PointF(-25.0f, 0.0f); // compact hero box + } + break; + case MOUNT_BODY: + case MOUNT_HEAD: + offset = new PointF(25.0f, 18.0f); // full hero box + break; + case BACK: + case SKIN: + case SHIRT: + case ARMOR: + case BODY: + case HEAD_0: + case HAIR_BASE: + case HAIR_BANGS: + case HAIR_MUSTACHE: + case HAIR_BEARD: + case EYEWEAR: + case HEAD: + case HEAD_ACCESSORY: + case HAIR_FLOWER: + case SHIELD: + case WEAPON: + case ZZZ: + if (mShowMount || mShowPet) { + // full hero box + if (mHasMount) { + offset = new PointF(25.0f, 0); + } else if (mHasPet) { + offset = new PointF(25.0f, 24.5f); + } else { + offset = new PointF(25.0f, 28.0f); + } + } else if (mShowBackground) { + // compact hero box + offset = new PointF(0.0f, 18.0f); + } + break; + case PET: + offset = new PointF(0, sFullHeroRect.height() - layerImageInfo.getHeight()); + break; + default: + break; + } + } + + if (offset != null) { + Matrix translateMatrix = new Matrix(); + translateMatrix.setTranslate(offset.x, offset.y); + translateMatrix.mapRect(boundsF); + } + + // resize bounds to fit and keep original aspect ratio + mMatrix.mapRect(boundsF); + boundsF.round(bounds); + + return bounds; + } + + private String getFileName(@NonNull String imageName) { + if (sFilenameMap.containsKey(imageName)) { + return sFilenameMap.get(imageName); + } + + return imageName + ".png"; + } + + private void onLayerComplete() { + if (mNumberLayersInProcess.decrementAndGet() == 0) { + if (mAvatarImageConsumer != null) { + mAvatarImageConsumer.accept(getAvatarImage()); + } + } + } + + public void onAvatarImageReady(@NonNull Consumer consumer) { + mAvatarImageConsumer = consumer; + if (mMultiDraweeHolder.size() > 0 && mNumberLayersInProcess.get() == 0) { + mAvatarImageConsumer.accept(getAvatarImage()); + } else { + initAvatarRectMatrix(); + showLayers(getLayerMap()); + } + } + + public void setUser(@NonNull HabitRPGUser user) { + HabitRPGUser oldUser = mUser; + mUser = user; + + if (oldUser != null) { + Map currentLayerMap = getLayerMap(oldUser, false); + Map newLayerMap = getLayerMap(user, false); + if (!currentLayerMap.equals(newLayerMap)) { + mMultiDraweeHolder.clear(); + mNumberLayersInProcess.set(0); + } + } + invalidate(); + } + + private Rect getOriginalRect() { + return (mShowMount || mShowPet) ? sFullHeroRect : ((mShowBackground) ? sCompactHeroRect : sHeroOnlyRect); + } + + private Bitmap getAvatarImage() { + assert mUser != null; + assert mAvatarRectF != null; + Rect canvasRect = new Rect(); + mAvatarRectF.round(canvasRect); + mAvatarBitmap = Bitmap.createBitmap(canvasRect.width(), canvasRect.height(), Bitmap.Config.ARGB_8888); + mAvatarCanvas = new Canvas(mAvatarBitmap); + draw(mAvatarCanvas); + + return mAvatarBitmap; + } + + private void initAvatarRectMatrix() { + if (mAvatarRectF == null) { + Rect srcRect = getOriginalRect(); + + if (mIsOrphan) { + mAvatarRectF = new RectF(srcRect); + + // change scale to not be 1:1 + // a quick fix as fresco AnimatedDrawable/ScaleTypeDrawable + // will not translate matrix properly + mMatrix.setScale(1.2f, 1.2f); + mMatrix.mapRect(mAvatarRectF); + } else { + // full hero box when showMount and showPet is enabled (140w * 147h) + // compact hero box when only showBackground is enabled (114w * 114h) + // hero only box when all show settings disabled (90w * 90h) + mAvatarRectF = new RectF(0, 0, getWidth(), getHeight()); + mMatrix.setRectToRect(new RectF(srcRect), mAvatarRectF, Matrix.ScaleToFit.START); // TODO support other ScaleToFit + mAvatarRectF = new RectF(srcRect); + mMatrix.mapRect(mAvatarRectF); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + initAvatarRectMatrix(); + + // draw only when user is set + if (mUser == null) return; + + // request image layers if not yet processed + if (mMultiDraweeHolder.size() == 0) { + showLayers(getLayerMap()); + } + + // manually call onAttach/onDetach if view is without parent as they will never be called otherwise + if (mIsOrphan) mMultiDraweeHolder.onAttach(); + mMultiDraweeHolder.draw(canvas); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mMultiDraweeHolder.onDetach(); + } + + @Override + public void onStartTemporaryDetach() { + super.onStartTemporaryDetach(); + mMultiDraweeHolder.onDetach(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mMultiDraweeHolder.onAttach(); + } + + @Override + public void onFinishTemporaryDetach() { + super.onFinishTemporaryDetach(); + mMultiDraweeHolder.onAttach(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return mMultiDraweeHolder.onTouchEvent(event) || super.onTouchEvent(event); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return mMultiDraweeHolder.verifyDrawable(who) || super.verifyDrawable(who); + } + + @Override + public void invalidateDrawable(@NonNull Drawable drawable) { + invalidate(); + if (mAvatarCanvas != null) draw(mAvatarCanvas); + } + + public enum LayerType { + BACKGROUND(0), + MOUNT_BODY(1), + BACK(2), + SKIN(3), + SHIRT(4), + ARMOR(5), + BODY(6), + HEAD_0(7), + HAIR_BASE(8), + HAIR_BANGS(9), + HAIR_MUSTACHE(10), + HAIR_BEARD(11), + EYEWEAR(12), + HEAD(13), + HEAD_ACCESSORY(14), + HAIR_FLOWER(15), + SHIELD(16), + WEAPON(17), + MOUNT_HEAD(18), + ZZZ(19), + PET(20); + + final int order; + + LayerType(int order) { + this.order = order; + } + } + + public interface Consumer { + void accept(T t); + } +} diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java index c602d8feb..8eb02b879 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java @@ -3,6 +3,7 @@ package com.magicmicky.habitrpgwrapper.lib.models; import com.google.gson.annotations.SerializedName; import com.habitrpg.android.habitica.HabitDatabase; +import com.habitrpg.android.habitica.ui.AvatarView; import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task; import com.magicmicky.habitrpgwrapper.lib.models.tasks.TasksOrder; import com.raizlabs.android.dbflow.annotation.Column; @@ -15,8 +16,12 @@ import com.raizlabs.android.dbflow.sql.builder.Condition; import com.raizlabs.android.dbflow.sql.language.Select; import com.raizlabs.android.dbflow.structure.BaseModel; +import android.text.TextUtils; + import java.util.ArrayList; +import java.util.EnumMap; import java.util.List; +import java.util.Map; @Table(databaseName = HabitDatabase.NAME) public class HabitRPGUser extends BaseModel { @@ -365,4 +370,69 @@ public class HabitRPGUser extends BaseModel { return layerNames; } + + public EnumMap getAvatarLayerMap() { + EnumMap layerMap = new EnumMap<>(AvatarView.LayerType.class); + + Preferences prefs = getPreferences(); + Outfit outfit = (prefs.getCostume()) ? getItems().getGear().getCostume() : getItems().getGear().getEquipped(); + + if (outfit != null) { + if (!TextUtils.isEmpty(outfit.getBack())) { + layerMap.put(AvatarView.LayerType.BACK, outfit.getBack()); + } + if (outfit.isAvailable(outfit.getArmor())) { + layerMap.put(AvatarView.LayerType.ARMOR, prefs.getSize() + "_" + outfit.getArmor()); + } + if (outfit.isAvailable(outfit.getBody())) { + layerMap.put(AvatarView.LayerType.BODY, outfit.getBody()); + } + if (outfit.isAvailable(outfit.getEyeWear())) { + layerMap.put(AvatarView.LayerType.EYEWEAR, outfit.getEyeWear()); + } + if (outfit.isAvailable(outfit.getHead())) { + layerMap.put(AvatarView.LayerType.HEAD, outfit.getHead()); + } + if (outfit.isAvailable(outfit.getHeadAccessory())) { + layerMap.put(AvatarView.LayerType.HEAD_ACCESSORY, outfit.getHeadAccessory()); + } + if (outfit.isAvailable(outfit.getShield())) { + layerMap.put(AvatarView.LayerType.SHIELD, outfit.getShield()); + } + if (outfit.isAvailable(outfit.getWeapon())) { + layerMap.put(AvatarView.LayerType.WEAPON, outfit.getWeapon()); + } + } + + layerMap.put(AvatarView.LayerType.SKIN, "skin_" + prefs.getSkin() + ((prefs.getSleep()) ? "_sleep" : "")); + layerMap.put(AvatarView.LayerType.SHIRT, prefs.getSize() + "_shirt_" + prefs.getShirt()); + layerMap.put(AvatarView.LayerType.HEAD_0, "head_0"); + + Hair hair = prefs.getHair(); + if (hair != null) { + String hairColor = hair.getColor(); + + if (hair.isAvailable(hair.getBase())) { + layerMap.put(AvatarView.LayerType.HAIR_BASE, "hair_base_" + hair.getBase() + "_" + hairColor); + } + if (hair.isAvailable(hair.getBangs())) { + layerMap.put(AvatarView.LayerType.HAIR_BANGS, "hair_bangs_" + hair.getBangs() + "_" + hairColor); + } + if (hair.isAvailable(hair.getMustache())) { + layerMap.put(AvatarView.LayerType.HAIR_MUSTACHE, "hair_mustache_" + hair.getMustache() + "_" + hairColor); + } + if (hair.isAvailable(hair.getBeard())) { + layerMap.put(AvatarView.LayerType.HAIR_BEARD, "hair_beard_" + hair.getBeard() + "_" + hairColor); + } + if (hair.isAvailable(hair.getFlower())) { + layerMap.put(AvatarView.LayerType.HAIR_FLOWER, "hair_flower_" + hair.getFlower()); + } + } + + if (prefs.getSleep()) { + layerMap.put(AvatarView.LayerType.ZZZ, "zzz"); + } + + return layerMap; + } } diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Hair.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Hair.java index 6829241d5..69dc72e6a 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Hair.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Hair.java @@ -75,4 +75,8 @@ public class Hair extends BaseModel { public int getFlower() { return flower; } public void setFlower(int flower) { this.flower = flower; } + + public boolean isAvailable(int hairId) { + return hairId > 0; + } } diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Outfit.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Outfit.java index ff92c63e7..ba899a95c 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Outfit.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Outfit.java @@ -9,6 +9,8 @@ import com.raizlabs.android.dbflow.annotation.PrimaryKey; import com.raizlabs.android.dbflow.annotation.Table; import com.raizlabs.android.dbflow.structure.BaseModel; +import android.text.TextUtils; + /** * Created by viirus on 20/07/15. */ @@ -54,4 +56,7 @@ public class Outfit extends BaseModel { public String getWeapon() {return weapon;} public void setWeapon(String weapon) {this.weapon = weapon;} + public boolean isAvailable(String outfit) { + return !TextUtils.isEmpty(outfit) && !outfit.endsWith("base_0"); + } } From 2ba99901713ec4babd29ec28cad8a885cc632205 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Mon, 23 May 2016 14:00:24 +0800 Subject: [PATCH 02/10] change AvatarWithBarsViewModel to use AvatarView --- Habitica/res/layout/avatar_with_bars.xml | 13 +++++++------ .../android/habitica/HabiticaApplication.java | 3 +++ .../habitica/ui/AvatarWithBarsViewModel.java | 11 +++-------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Habitica/res/layout/avatar_with_bars.xml b/Habitica/res/layout/avatar_with_bars.xml index e4843ea64..7e86c534b 100644 --- a/Habitica/res/layout/avatar_with_bars.xml +++ b/Habitica/res/layout/avatar_with_bars.xml @@ -1,6 +1,7 @@ - + android:layout_marginRight="16dp" + app:showBackground="true" + app:showMount="true" + app:showPet="true" /> Date: Mon, 23 May 2016 14:02:00 +0800 Subject: [PATCH 03/10] change MainActivity to use AvatarView --- Habitica/res/layout/dialog_faint.xml | 8 +++- Habitica/res/layout/dialog_levelup.xml | 8 +++- .../habitica/ui/activities/MainActivity.java | 42 +++++++++---------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Habitica/res/layout/dialog_faint.xml b/Habitica/res/layout/dialog_faint.xml index 86c1b6507..04fa5ae14 100644 --- a/Habitica/res/layout/dialog_faint.xml +++ b/Habitica/res/layout/dialog_faint.xml @@ -1,5 +1,6 @@ - + android:layout_gravity="center_horizontal" + app:showBackground="false" + app:showMount="false" + app:showPet="false" /> - + android:layout_gravity="center_horizontal" + app:showBackground="false" + app:showMount="false" + app:showPet="false" /> , Ha private APIHelper apiHelper; private AlertDialog faintDialog; - private UserPicture sideUserPicture; - private UserPicture dialogUserPicture; + private AvatarView mSideAvatarView; + private AvatarView mDialogAvatarView; private Date lastSync; @@ -199,8 +199,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha drawer = MainDrawerBuilder.CreateDefaultBuilderSettings(this, toolbar, accountHeader) .build(); drawer.setSelectionAtPosition(1, false); - this.sideUserPicture = new UserPicture(this, true, false); - this.dialogUserPicture = new UserPicture(this, false, false); + mSideAvatarView = new AvatarView(this, true, false, false); if (this.filterDrawer == null) { filterDrawer = new DrawerBuilder() @@ -579,9 +578,9 @@ public class MainActivity extends BaseActivity implements Action1, Ha } } profile.withName(user.getProfile().getName()); - sideUserPicture.setUser(this.user); - sideUserPicture.setPictureWithRunnable(avatar -> { - profile.withIcon(avatar); + mSideAvatarView.setUser(user); + mSideAvatarView.onAvatarImageReady(avatarImage -> { + profile.withIcon(avatarImage); accountHeader.updateProfile(profile); }); accountHeader.updateProfile(profile); @@ -993,9 +992,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha hpBar.setPartyMembers(true); AvatarWithBarsViewModel.setHpBarData(hpBar, user.getStats(), this); - ImageView avatarView = (ImageView) customView.findViewById(R.id.avatarView); - this.dialogUserPicture.setUser(this.user); - this.dialogUserPicture.setPictureOn(avatarView); + mDialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); + mDialogAvatarView.setUser(user); } this.faintDialog = new AlertDialog.Builder(this) @@ -1027,11 +1025,16 @@ public class MainActivity extends BaseActivity implements Action1, Ha if (customView != null) { TextView detailView = (TextView) customView.findViewById(R.id.levelupDetail); detailView.setText(this.getString(R.string.levelup_detail, level)); - ImageView avatarView = (ImageView) customView.findViewById(R.id.avatarView); - this.dialogUserPicture.setUser(this.user); - this.dialogUserPicture.setPictureOn(avatarView); + mDialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); + mDialogAvatarView.setUser(user); } + final ShareEvent event = new ShareEvent(); + event.sharedMessage = getString(R.string.share_levelup, level) + " https://habitica.com/social/level-up"; + AvatarView avatarView = new AvatarView(this, true, true, true); + avatarView.setUser(user); + avatarView.onAvatarImageReady(avatarImage -> event.shareImage = avatarImage); + AlertDialog alert = new AlertDialog.Builder(this) .setTitle(R.string.levelup_header) .setView(customView) @@ -1039,15 +1042,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha checkClassSelection(); }) .setNeutralButton(R.string.share, (dialog, which) -> { - ShareEvent event = new ShareEvent(); - event.sharedMessage = getString(R.string.share_levelup, level) + " https://habitica.com/social/level-up"; - UserPicture picture = new UserPicture(this, true, true); - picture.setUser(this.user); - picture.setPictureWithRunnable(avatarBitmap -> { - event.shareImage = avatarBitmap; - EventBus.getDefault().post(event); - dialog.dismiss(); - }); + EventBus.getDefault().post(event); + dialog.dismiss(); }) .create(); From 7de73c589f3820d13e44ec5f64dc1cba175ab0a8 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Mon, 23 May 2016 14:02:34 +0800 Subject: [PATCH 04/10] change AvatarSetupFragment to use AvatarView --- Habitica/res/layout/fragment_setup_avatar.xml | 8 ++++++-- .../ui/fragments/setup/AvatarSetupFragment.java | 14 +++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Habitica/res/layout/fragment_setup_avatar.xml b/Habitica/res/layout/fragment_setup_avatar.xml index f924ca80b..19b807668 100644 --- a/Habitica/res/layout/fragment_setup_avatar.xml +++ b/Habitica/res/layout/fragment_setup_avatar.xml @@ -1,5 +1,6 @@ @@ -8,10 +9,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + app:showBackground="true" + app:showMount="true" + app:showPet="true" /> Date: Mon, 23 May 2016 14:03:49 +0800 Subject: [PATCH 05/10] change PartyMemberRecyclerViewAdapter to use AvatarView --- Habitica/res/layout-w320dp/party_member.xml | 14 ++++++++------ Habitica/res/layout/party_member.xml | 14 ++++++++------ .../PartyMemberRecyclerViewAdapter.java | 19 ++++--------------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/Habitica/res/layout-w320dp/party_member.xml b/Habitica/res/layout-w320dp/party_member.xml index b45981566..c859cfa3f 100644 --- a/Habitica/res/layout-w320dp/party_member.xml +++ b/Habitica/res/layout-w320dp/party_member.xml @@ -1,5 +1,6 @@ @@ -10,13 +11,14 @@ android:layout_margin="5dp" android:orientation="horizontal"> - + android:layout_height="147dp" + android:layout_marginRight="5dp" + app:showBackground="true" + app:showMount="true" + app:showPet="true" /> @@ -10,13 +11,14 @@ style="@style/CardContent" android:orientation="horizontal"> - + android:layout_height="90dp" + android:layout_marginRight="5dp" + app:showBackground="false" + app:showMount="false" + app:showPet="false" /> = 320) { - userPicture = new UserPicture(itemView.getContext(), true, true); - } else { - userPicture = new UserPicture(itemView.getContext(), false, false); - } } public void bind(HabitRPGUser user) { android.content.Context ctx = itemView.getContext(); - userPicture.setUser(user); - userPicture.setPictureOn(imageView); + avatarView.setUser(user); AvatarWithBarsViewModel.setHpBarData(hpBar, user.getStats(), ctx); From 5c077e7489b6934fda507f241b66cc7940d85fc0 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Mon, 23 May 2016 14:04:51 +0800 Subject: [PATCH 06/10] change ClassSelectionActivity to use AvatarView --- .../res/layout/activity_class_selection.xml | 27 +++++++------- .../ui/activities/ClassSelectionActivity.java | 35 +++++++------------ 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Habitica/res/layout/activity_class_selection.xml b/Habitica/res/layout/activity_class_selection.xml index b7bd15251..38940b7fa 100644 --- a/Habitica/res/layout/activity_class_selection.xml +++ b/Habitica/res/layout/activity_class_selection.xml @@ -1,6 +1,7 @@ - + android:layout_height="@dimen/avatar_header_height" /> - + android:layout_height="@dimen/avatar_header_height" /> - + android:layout_height="@dimen/avatar_header_height" /> - + android:layout_height="@dimen/avatar_header_height" /> Date: Tue, 24 May 2016 06:42:10 +0800 Subject: [PATCH 07/10] add avatar wheelchair support --- .../android/habitica/ui/AvatarView.java | 40 ++++++++++--------- .../lib/models/HabitRPGUser.java | 4 ++ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java index 957b4978b..302b0c727 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java @@ -224,6 +224,7 @@ public class AvatarView extends View { case MOUNT_HEAD: offset = new PointF(25.0f, 18.0f); // full hero box break; + case CHAIR: case BACK: case SKIN: case SHIRT: @@ -419,25 +420,26 @@ public class AvatarView extends View { public enum LayerType { BACKGROUND(0), MOUNT_BODY(1), - BACK(2), - SKIN(3), - SHIRT(4), - ARMOR(5), - BODY(6), - HEAD_0(7), - HAIR_BASE(8), - HAIR_BANGS(9), - HAIR_MUSTACHE(10), - HAIR_BEARD(11), - EYEWEAR(12), - HEAD(13), - HEAD_ACCESSORY(14), - HAIR_FLOWER(15), - SHIELD(16), - WEAPON(17), - MOUNT_HEAD(18), - ZZZ(19), - PET(20); + CHAIR(2), + BACK(3), + SKIN(4), + SHIRT(5), + ARMOR(6), + BODY(7), + HEAD_0(8), + HAIR_BASE(9), + HAIR_BANGS(10), + HAIR_MUSTACHE(11), + HAIR_BEARD(12), + EYEWEAR(13), + HEAD(14), + HEAD_ACCESSORY(15), + HAIR_FLOWER(16), + SHIELD(17), + WEAPON(18), + MOUNT_HEAD(19), + ZZZ(20), + PET(21); final int order; diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java index 8eb02b879..8a1fb062b 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java @@ -377,6 +377,10 @@ public class HabitRPGUser extends BaseModel { Preferences prefs = getPreferences(); Outfit outfit = (prefs.getCostume()) ? getItems().getGear().getCostume() : getItems().getGear().getEquipped(); + if (!TextUtils.isEmpty(prefs.getChair())) { + layerMap.put(AvatarView.LayerType.CHAIR, prefs.getChair()); + } + if (outfit != null) { if (!TextUtils.isEmpty(outfit.getBack())) { layerMap.put(AvatarView.LayerType.BACK, outfit.getBack()); From 4931517b334d3f9643cff7d91d6568b88b868f07 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Wed, 25 May 2016 12:27:34 +0800 Subject: [PATCH 08/10] fix wheelchair `chair_none` problem --- .../magicmicky/habitrpgwrapper/lib/models/Preferences.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java index a7723ca6c..f336c1e0b 100644 --- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java +++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/Preferences.java @@ -190,10 +190,10 @@ public class Preferences extends BaseModel { } public String getChair() { - if (chair != null) { + if (chair != null && !chair.equals("none")) { return "chair_"+chair; } - return chair; + return null; } public void setChair(String chair) { From 5d65f03ebf36ee55ad89bcff580934a3fd6ceeb0 Mon Sep 17 00:00:00 2001 From: nivl4 Date: Wed, 25 May 2016 13:38:38 +0800 Subject: [PATCH 09/10] remove Hungarian notation --- .../android/habitica/ui/AvatarView.java | 186 +++++++++--------- .../habitica/ui/AvatarWithBarsViewModel.java | 6 +- .../habitica/ui/activities/MainActivity.java | 18 +- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java index 302b0c727..aaa9cc064 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.java @@ -37,10 +37,10 @@ import java.util.concurrent.atomic.AtomicInteger; public class AvatarView extends View { public static final String IMAGE_URI_ROOT = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"; private static final String TAG = "AvatarView"; - private static final Map sFilenameMap; - private static final Rect sFullHeroRect = new Rect(0, 0, 140, 147); - private static final Rect sCompactHeroRect = new Rect(0, 0, 114, 114); - private static final Rect sHeroOnlyRect = new Rect(0, 0, 90, 90); + private static final Map FILENAME_MAP; + private static final Rect FULL_HERO_RECT = new Rect(0, 0, 140, 147); + private static final Rect COMPACT_HERO_RECT = new Rect(0, 0, 114, 114); + private static final Rect HERO_ONLY_RECT = new Rect(0, 0, 90, 90); static { Map tempMap = new HashMap<>(); @@ -48,24 +48,24 @@ public class AvatarView extends View { tempMap.put("armor_special_1", "ContributorOnly-Equip-CrystalArmor.gif"); tempMap.put("weapon_special_critical", "weapon_special_critical.gif"); tempMap.put("Pet-Wolf-Cerberus", "Pet-Wolf-Cerberus.gif"); - sFilenameMap = Collections.unmodifiableMap(tempMap); + FILENAME_MAP = Collections.unmodifiableMap(tempMap); } - private boolean mShowBackground = true; - private boolean mShowMount = true; - private boolean mShowPet = true; - private boolean mHasBackground; - private boolean mHasMount; - private boolean mHasPet; - private boolean mIsOrphan; - private MultiDraweeHolder mMultiDraweeHolder = new MultiDraweeHolder<>(); - private HabitRPGUser mUser; - private RectF mAvatarRectF; - private Matrix mMatrix = new Matrix(); - private AtomicInteger mNumberLayersInProcess = new AtomicInteger(0); - private Consumer mAvatarImageConsumer; - private Bitmap mAvatarBitmap; - private Canvas mAvatarCanvas; + private boolean showBackground = true; + private boolean showMount = true; + private boolean showPet = true; + private boolean hasBackground; + private boolean hasMount; + private boolean hasPet; + private boolean isOrphan; + private MultiDraweeHolder multiDraweeHolder = new MultiDraweeHolder<>(); + private HabitRPGUser user; + private RectF avatarRectF; + private Matrix matrix = new Matrix(); + private AtomicInteger numberLayersInProcess = new AtomicInteger(0); + private Consumer avatarImageConsumer; + private Bitmap avatarBitmap; + private Canvas avatarCanvas; public AvatarView(Context context) { super(context); @@ -85,10 +85,10 @@ public class AvatarView extends View { public AvatarView(Context context, boolean showBackground, boolean showMount, boolean showPet) { super(context); - mShowBackground = showBackground; - mShowMount = showMount; - mShowPet = showPet; - mIsOrphan = true; + this.showBackground = showBackground; + this.showMount = showMount; + this.showPet = showPet; + isOrphan = true; } private void init(AttributeSet attrs, int defStyle) { @@ -97,19 +97,19 @@ public class AvatarView extends View { attrs, R.styleable.AvatarView, defStyle, 0); try { - mShowBackground = a.getBoolean(R.styleable.AvatarView_showBackground, true); - mShowMount = a.getBoolean(R.styleable.AvatarView_showMount, true); - mShowPet = a.getBoolean(R.styleable.AvatarView_showPet, true); + showBackground = a.getBoolean(R.styleable.AvatarView_showBackground, true); + showMount = a.getBoolean(R.styleable.AvatarView_showMount, true); + showPet = a.getBoolean(R.styleable.AvatarView_showPet, true); } finally { a.recycle(); } } private void showLayers(@NonNull Map layerMap) { - if (mMultiDraweeHolder.size() > 0) return; + if (multiDraweeHolder.size() > 0) return; int i = 0; - mNumberLayersInProcess.set(layerMap.size()); + numberLayersInProcess.set(layerMap.size()); for (Map.Entry entry : layerMap.entrySet()) { final LayerType layerKey = entry.getKey(); @@ -122,7 +122,7 @@ public class AvatarView extends View { DraweeHolder draweeHolder = DraweeHolder.create(hierarchy, getContext()); draweeHolder.getTopLevelDrawable().setCallback(this); - mMultiDraweeHolder.add(draweeHolder); + multiDraweeHolder.add(draweeHolder); DraweeController controller = Fresco.newDraweeControllerBuilder() .setUri(IMAGE_URI_ROOT + getFileName(layerName)) @@ -133,7 +133,7 @@ public class AvatarView extends View { ImageInfo imageInfo, Animatable anim) { if (imageInfo != null) { - mMultiDraweeHolder.get(layerNumber).getTopLevelDrawable().setBounds(getLayerBounds(layerKey, layerName, imageInfo)); + multiDraweeHolder.get(layerNumber).getTopLevelDrawable().setBounds(getLayerBounds(layerKey, layerName, imageInfo)); onLayerComplete(); } } @@ -144,41 +144,41 @@ public class AvatarView extends View { onLayerComplete(); } }) - .setAutoPlayAnimations(!mIsOrphan) + .setAutoPlayAnimations(!isOrphan) .build(); draweeHolder.setController(controller); } - if (mIsOrphan) mMultiDraweeHolder.onAttach(); + if (isOrphan) multiDraweeHolder.onAttach(); } private Map getLayerMap() { - assert mUser != null; - return getLayerMap(mUser, true); + assert user != null; + return getLayerMap(user, true); } private Map getLayerMap(@NonNull HabitRPGUser user, boolean resetHasAttributes) { EnumMap layerMap = user.getAvatarLayerMap(); - if (resetHasAttributes) mHasBackground = mHasMount = mHasPet = false; + if (resetHasAttributes) hasBackground = hasMount = hasPet = false; String mountName = user.getItems().getCurrentMount(); - if (mShowMount && !TextUtils.isEmpty(mountName)) { + if (showMount && !TextUtils.isEmpty(mountName)) { layerMap.put(LayerType.MOUNT_BODY, "Mount_Body_" + mountName); layerMap.put(LayerType.MOUNT_HEAD, "Mount_Head_" + mountName); - if (resetHasAttributes) mHasMount = true; + if (resetHasAttributes) hasMount = true; } String petName = user.getItems().getCurrentPet(); - if (mShowPet && !TextUtils.isEmpty(petName)) { + if (showPet && !TextUtils.isEmpty(petName)) { layerMap.put(LayerType.PET, "Pet-" + petName); - if (resetHasAttributes) mHasPet = true; + if (resetHasAttributes) hasPet = true; } String backgroundName = user.getPreferences().getBackground(); - if (mShowBackground && !TextUtils.isEmpty(backgroundName)) { + if (showBackground && !TextUtils.isEmpty(backgroundName)) { layerMap.put(LayerType.BACKGROUND, "background_" + backgroundName); - if (resetHasAttributes) mHasBackground = true; + if (resetHasAttributes) hasBackground = true; } return layerMap; } @@ -191,16 +191,16 @@ public class AvatarView extends View { // lookup layer specific offset switch (layerName) { case "weapon_special_critical": - if (mShowMount || mShowPet) { + if (showMount || showPet) { // full hero box - if (mHasMount) { + if (hasMount) { offset = new PointF(13.0f, 12.0f); - } else if (mHasPet) { + } else if (hasPet) { offset = new PointF(13.0f, 24.5f + 12.0f); } else { offset = new PointF(13.0f, 28.0f + 12.0f); } - } else if (mShowBackground) { + } else if (showBackground) { // compact hero box offset = new PointF(-12.0f, 18.0f + 12.0f); } else { @@ -216,7 +216,7 @@ public class AvatarView extends View { if (offset == null) { switch (layerType) { case BACKGROUND: - if (!(mShowMount || mShowPet)) { + if (!(showMount || showPet)) { offset = new PointF(-25.0f, 0.0f); // compact hero box } break; @@ -242,22 +242,22 @@ public class AvatarView extends View { case SHIELD: case WEAPON: case ZZZ: - if (mShowMount || mShowPet) { + if (showMount || showPet) { // full hero box - if (mHasMount) { + if (hasMount) { offset = new PointF(25.0f, 0); - } else if (mHasPet) { + } else if (hasPet) { offset = new PointF(25.0f, 24.5f); } else { offset = new PointF(25.0f, 28.0f); } - } else if (mShowBackground) { + } else if (showBackground) { // compact hero box offset = new PointF(0.0f, 18.0f); } break; case PET: - offset = new PointF(0, sFullHeroRect.height() - layerImageInfo.getHeight()); + offset = new PointF(0, FULL_HERO_RECT.height() - layerImageInfo.getHeight()); break; default: break; @@ -271,32 +271,32 @@ public class AvatarView extends View { } // resize bounds to fit and keep original aspect ratio - mMatrix.mapRect(boundsF); + matrix.mapRect(boundsF); boundsF.round(bounds); return bounds; } private String getFileName(@NonNull String imageName) { - if (sFilenameMap.containsKey(imageName)) { - return sFilenameMap.get(imageName); + if (FILENAME_MAP.containsKey(imageName)) { + return FILENAME_MAP.get(imageName); } return imageName + ".png"; } private void onLayerComplete() { - if (mNumberLayersInProcess.decrementAndGet() == 0) { - if (mAvatarImageConsumer != null) { - mAvatarImageConsumer.accept(getAvatarImage()); + if (numberLayersInProcess.decrementAndGet() == 0) { + if (avatarImageConsumer != null) { + avatarImageConsumer.accept(getAvatarImage()); } } } public void onAvatarImageReady(@NonNull Consumer consumer) { - mAvatarImageConsumer = consumer; - if (mMultiDraweeHolder.size() > 0 && mNumberLayersInProcess.get() == 0) { - mAvatarImageConsumer.accept(getAvatarImage()); + avatarImageConsumer = consumer; + if (multiDraweeHolder.size() > 0 && numberLayersInProcess.get() == 0) { + avatarImageConsumer.accept(getAvatarImage()); } else { initAvatarRectMatrix(); showLayers(getLayerMap()); @@ -304,56 +304,56 @@ public class AvatarView extends View { } public void setUser(@NonNull HabitRPGUser user) { - HabitRPGUser oldUser = mUser; - mUser = user; + HabitRPGUser oldUser = this.user; + this.user = user; if (oldUser != null) { Map currentLayerMap = getLayerMap(oldUser, false); Map newLayerMap = getLayerMap(user, false); if (!currentLayerMap.equals(newLayerMap)) { - mMultiDraweeHolder.clear(); - mNumberLayersInProcess.set(0); + multiDraweeHolder.clear(); + numberLayersInProcess.set(0); } } invalidate(); } private Rect getOriginalRect() { - return (mShowMount || mShowPet) ? sFullHeroRect : ((mShowBackground) ? sCompactHeroRect : sHeroOnlyRect); + return (showMount || showPet) ? FULL_HERO_RECT : ((showBackground) ? COMPACT_HERO_RECT : HERO_ONLY_RECT); } private Bitmap getAvatarImage() { - assert mUser != null; - assert mAvatarRectF != null; + assert user != null; + assert avatarRectF != null; Rect canvasRect = new Rect(); - mAvatarRectF.round(canvasRect); - mAvatarBitmap = Bitmap.createBitmap(canvasRect.width(), canvasRect.height(), Bitmap.Config.ARGB_8888); - mAvatarCanvas = new Canvas(mAvatarBitmap); - draw(mAvatarCanvas); + avatarRectF.round(canvasRect); + avatarBitmap = Bitmap.createBitmap(canvasRect.width(), canvasRect.height(), Bitmap.Config.ARGB_8888); + avatarCanvas = new Canvas(avatarBitmap); + draw(avatarCanvas); - return mAvatarBitmap; + return avatarBitmap; } private void initAvatarRectMatrix() { - if (mAvatarRectF == null) { + if (avatarRectF == null) { Rect srcRect = getOriginalRect(); - if (mIsOrphan) { - mAvatarRectF = new RectF(srcRect); + if (isOrphan) { + avatarRectF = new RectF(srcRect); // change scale to not be 1:1 // a quick fix as fresco AnimatedDrawable/ScaleTypeDrawable // will not translate matrix properly - mMatrix.setScale(1.2f, 1.2f); - mMatrix.mapRect(mAvatarRectF); + matrix.setScale(1.2f, 1.2f); + matrix.mapRect(avatarRectF); } else { // full hero box when showMount and showPet is enabled (140w * 147h) // compact hero box when only showBackground is enabled (114w * 114h) // hero only box when all show settings disabled (90w * 90h) - mAvatarRectF = new RectF(0, 0, getWidth(), getHeight()); - mMatrix.setRectToRect(new RectF(srcRect), mAvatarRectF, Matrix.ScaleToFit.START); // TODO support other ScaleToFit - mAvatarRectF = new RectF(srcRect); - mMatrix.mapRect(mAvatarRectF); + avatarRectF = new RectF(0, 0, getWidth(), getHeight()); + matrix.setRectToRect(new RectF(srcRect), avatarRectF, Matrix.ScaleToFit.START); // TODO support other ScaleToFit + avatarRectF = new RectF(srcRect); + matrix.mapRect(avatarRectF); } } } @@ -365,56 +365,56 @@ public class AvatarView extends View { initAvatarRectMatrix(); // draw only when user is set - if (mUser == null) return; + if (user == null) return; // request image layers if not yet processed - if (mMultiDraweeHolder.size() == 0) { + if (multiDraweeHolder.size() == 0) { showLayers(getLayerMap()); } // manually call onAttach/onDetach if view is without parent as they will never be called otherwise - if (mIsOrphan) mMultiDraweeHolder.onAttach(); - mMultiDraweeHolder.draw(canvas); + if (isOrphan) multiDraweeHolder.onAttach(); + multiDraweeHolder.draw(canvas); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mMultiDraweeHolder.onDetach(); + multiDraweeHolder.onDetach(); } @Override public void onStartTemporaryDetach() { super.onStartTemporaryDetach(); - mMultiDraweeHolder.onDetach(); + multiDraweeHolder.onDetach(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mMultiDraweeHolder.onAttach(); + multiDraweeHolder.onAttach(); } @Override public void onFinishTemporaryDetach() { super.onFinishTemporaryDetach(); - mMultiDraweeHolder.onAttach(); + multiDraweeHolder.onAttach(); } @Override public boolean onTouchEvent(MotionEvent event) { - return mMultiDraweeHolder.onTouchEvent(event) || super.onTouchEvent(event); + return multiDraweeHolder.onTouchEvent(event) || super.onTouchEvent(event); } @Override protected boolean verifyDrawable(Drawable who) { - return mMultiDraweeHolder.verifyDrawable(who) || super.verifyDrawable(who); + return multiDraweeHolder.verifyDrawable(who) || super.verifyDrawable(who); } @Override public void invalidateDrawable(@NonNull Drawable drawable) { invalidate(); - if (mAvatarCanvas != null) draw(mAvatarCanvas); + if (avatarCanvas != null) draw(avatarCanvas); } public enum LayerType { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java index 6deaeb0c8..aeed50b34 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.java @@ -29,7 +29,7 @@ public class AvatarWithBarsViewModel implements View.OnClickListener { private ValueBarBinding xpBar; private ValueBarBinding mpBar; - private AvatarView mAvatarView; + private AvatarView avatarView; private android.content.res.Resources res; @@ -56,7 +56,7 @@ public class AvatarWithBarsViewModel implements View.OnClickListener { gemsText = (TextView) v.findViewById(R.id.gems_tv); View hpBarView = v.findViewById(R.id.hpBar); - mAvatarView = (AvatarView) v.findViewById(R.id.avatarView); + avatarView = (AvatarView) v.findViewById(R.id.avatarView); hpBar = DataBindingUtil.bind(hpBarView); xpBar = DataBindingUtil.bind(v.findViewById(R.id.xpBar)); mpBar = DataBindingUtil.bind(v.findViewById(R.id.mpBar)); @@ -79,7 +79,7 @@ public class AvatarWithBarsViewModel implements View.OnClickListener { int gp = (stats.getGp().intValue()); int sp = (int) ((stats.getGp() - gp) * 100); - mAvatarView.setUser(user); + avatarView.setUser(user); if (stats.get_class() != null) { userClass += stats.getCleanedClassName(); diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java index 596e2b66d..a58dbeb14 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java @@ -164,8 +164,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha private APIHelper apiHelper; private AlertDialog faintDialog; - private AvatarView mSideAvatarView; - private AvatarView mDialogAvatarView; + private AvatarView sideAvatarView; + private AvatarView dialogAvatarView; private Date lastSync; @@ -199,7 +199,7 @@ public class MainActivity extends BaseActivity implements Action1, Ha drawer = MainDrawerBuilder.CreateDefaultBuilderSettings(this, toolbar, accountHeader) .build(); drawer.setSelectionAtPosition(1, false); - mSideAvatarView = new AvatarView(this, true, false, false); + sideAvatarView = new AvatarView(this, true, false, false); if (this.filterDrawer == null) { filterDrawer = new DrawerBuilder() @@ -578,8 +578,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha } } profile.withName(user.getProfile().getName()); - mSideAvatarView.setUser(user); - mSideAvatarView.onAvatarImageReady(avatarImage -> { + sideAvatarView.setUser(user); + sideAvatarView.onAvatarImageReady(avatarImage -> { profile.withIcon(avatarImage); accountHeader.updateProfile(profile); }); @@ -992,8 +992,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha hpBar.setPartyMembers(true); AvatarWithBarsViewModel.setHpBarData(hpBar, user.getStats(), this); - mDialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); - mDialogAvatarView.setUser(user); + dialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); + dialogAvatarView.setUser(user); } this.faintDialog = new AlertDialog.Builder(this) @@ -1025,8 +1025,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha if (customView != null) { TextView detailView = (TextView) customView.findViewById(R.id.levelupDetail); detailView.setText(this.getString(R.string.levelup_detail, level)); - mDialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); - mDialogAvatarView.setUser(user); + dialogAvatarView = (AvatarView) customView.findViewById(R.id.avatarView); + dialogAvatarView.setUser(user); } final ShareEvent event = new ShareEvent(); From 97d26d5aac1aece22ba24406f1636af4df23fd4c Mon Sep 17 00:00:00 2001 From: nivl4 Date: Thu, 26 May 2016 10:42:29 +0800 Subject: [PATCH 10/10] fix Travis CI build Android SDK Tools, revision 24.4.1 needed in order to install the required Android SDK Build-tools, revision 23.0.3. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ae6569942..678714f62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ android: # Uncomment the lines below if you want to # use the latest revision of Android SDK Tools # - platform-tools - # - tools + - tools # The BuildTools version used by your project - build-tools-23.0.3