diff --git a/.gitignore b/.gitignore
index 3c71575..6ac2e3f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,17 @@
-.gradle
-gradle*
-/gradle
-/local.properties
-.idea/*
-.DS_Store
+*.iml
+*.apk
+*.DS_Store
+
+/*.png
+
+/.gradle
+/.idea
/build
/captures
-app/build/
-/libraries/
-/gen/
-/release
-*.iml
\ No newline at end of file
+/gradle
+/gradlew
+/gradlew.bat
+/local.properties
+
+/app/build
+/library/build
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 5f431ec..1b86e35 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2015 Raphaël Bussa
+Copyright (c) 2017 Raphaël Bussa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/app/.gitignore b/app/.gitignore
deleted file mode 100644
index 796b96d..0000000
--- a/app/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/app/app-release.apk b/app/app-release.apk
deleted file mode 100644
index 61ad99f..0000000
Binary files a/app/app-release.apk and /dev/null differ
diff --git a/app/build.gradle b/app/build.gradle
index ab8366f..08d89bc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,16 +1,42 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
apply plugin: 'com.android.application'
android {
- compileSdkVersion 23
- buildToolsVersion '23.0.3'
+
+ compileSdkVersion var.compileSdk
+ buildToolsVersion var.buildTools
defaultConfig {
applicationId "rebus.header.view.sample"
- minSdkVersion 8
- targetSdkVersion 23
- versionCode 3
- versionName "1.1.1"
+ minSdkVersion var.minSdk
+ targetSdkVersion var.targetSdk
+ versionCode 1
+ versionName "${var.version}"
}
+
buildTypes {
release {
minifyEnabled false
@@ -20,8 +46,9 @@ android {
}
dependencies {
- compile project(':headerview')
- compile 'com.android.support:appcompat-v7:23.4.0'
- compile 'com.android.support:design:23.4.0'
- compile 'com.squareup.picasso:picasso:2.5.2'
+ compile project(':library')
+ compile "com.android.support:appcompat-v7:${var.supportLib}"
+ compile "com.android.support:design:${var.supportLib}"
+
+ compile 'com.github.bumptech.glide:glide:3.7.0'
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 61f4730..fd8637f 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,6 +1,6 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
-# in C:\Users\Raphaël\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
+# in /Users/raphaelbussa/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
diff --git a/app/src/androidTest/java/rebus/header/view/sample/ApplicationTest.java b/app/src/androidTest/java/rebus/header/view/sample/ApplicationTest.java
deleted file mode 100644
index a0bee04..0000000
--- a/app/src/androidTest/java/rebus/header/view/sample/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package rebus.header.view.sample;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * Testing Fundamentals
- */
-public class ApplicationTest extends ApplicationTestCase {
- public ApplicationTest() {
- super(Application.class);
- }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/rebus/header/view/sample/ExampleInstrumentedTest.java b/app/src/androidTest/java/rebus/header/view/sample/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..b479db8
--- /dev/null
+++ b/app/src/androidTest/java/rebus/header/view/sample/ExampleInstrumentedTest.java
@@ -0,0 +1,5 @@
+package rebus.header.view.sample;
+
+public class ExampleInstrumentedTest {
+
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8d4a5f8..bf4e016 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,7 +2,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_header_below_toolbar.xml b/app/src/main/res/layout/activity_header_below_toolbar.xml
deleted file mode 100644
index ee264e5..0000000
--- a/app/src/main/res/layout/activity_header_below_toolbar.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_header_compact.xml b/app/src/main/res/layout/activity_header_compact.xml
deleted file mode 100644
index 6ab6990..0000000
--- a/app/src/main/res/layout/activity_header_compact.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_header_compact_below_toolbar.xml b/app/src/main/res/layout/activity_header_compact_below_toolbar.xml
deleted file mode 100644
index ee264e5..0000000
--- a/app/src/main/res/layout/activity_header_compact_below_toolbar.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 6a3ea46..8d099e9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,7 +1,8 @@
+
-
+ android:fitsSystemWindows="true">
-
+ android:layout_height="match_parent">
-
+
-
+
-
+
-
+
+
+
-
+
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/layout/header_drawer.xml
similarity index 68%
rename from app/src/main/res/values-w820dp/dimens.xml
rename to app/src/main/res/layout/header_drawer.xml
index 156a2f8..8e3dbc2 100644
--- a/app/src/main/res/values-w820dp/dimens.xml
+++ b/app/src/main/res/layout/header_drawer.xml
@@ -1,7 +1,8 @@
+
-
-
- 64dp
-
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml
index 6447efb..df86499 100644
--- a/app/src/main/res/menu/drawer.xml
+++ b/app/src/main/res/menu/drawer.xml
@@ -2,7 +2,7 @@
- #3F51B5
- #303F9F
- #C5CAE9
- #FF9800
- #212121
- #727272
- #FFFFFF
- #B6B6B6
-
\ No newline at end of file
+ #3F51B5
+ #303F9F
+ #FF4081
+
+ @color/colorAccent
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 078bcf4..6de430d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,55 +1,5 @@
-
-
- Header View Sample
-
- Info
- Close
- MainActivity
- Header Normal
- Header Below Toolbar
- Header Compact
- Header Compact Below Toolbar
-
- https://pbs.twimg.com/profile_images/685737193558675456/olNBVUfj_400x400.jpg
- https://pbs.twimg.com/profile_banners/390983842/1452327403/1500x500
-
+ Header View
Search
-
-
- Raphaël Bussa
- GitHub Twitter Google+ Linkedin
- Third party libraries used in this sample: Picasso
- ]]>
-
-
- Raphaël Bussa
- raphaelbussa@gmail.com
-
- Avatar clicked!
- Arrow clicked!
- On Long Click Header
+ Account
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e247cc5..c9070c8 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,7 +1,7 @@
-
-
- 16dp
- 16dp
-
+
+
+
+
+
diff --git a/headerview/src/main/java/rebus/header/view/HeaderInterface.java b/library/src/main/java/rebus/header/view/HeaderCallback.java
similarity index 73%
rename from headerview/src/main/java/rebus/header/view/HeaderInterface.java
rename to library/src/main/java/rebus/header/view/HeaderCallback.java
index 69c60a1..a042913 100644
--- a/headerview/src/main/java/rebus/header/view/HeaderInterface.java
+++ b/library/src/main/java/rebus/header/view/HeaderCallback.java
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2015 Raphaël Bussa
+ * Copyright (c) 2017 Raphaël Bussa
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,24 +24,25 @@
package rebus.header.view;
-import android.view.View;
-
-public class HeaderInterface {
+/**
+ * Created by raphaelbussa on 18/01/17.
+ */
- public interface OnHeaderClickListener {
- void onClick(View view);
- }
+public class HeaderCallback implements ProfileChooserCallback {
- public interface OnHeaderLongClickListener {
- void onLongClick(View view);
+ @Override
+ public boolean onSelect(int id, boolean isActive) {
+ return false;
}
- public interface OnAvatarClickListener {
- void onClick(View view);
+ @Override
+ public boolean onItem(int id) {
+ return false;
}
- public interface OnArrowClickListener {
- void onClick(View view);
+ @Override
+ public boolean onAdd() {
+ return false;
}
}
diff --git a/library/src/main/java/rebus/header/view/HeaderView.java b/library/src/main/java/rebus/header/view/HeaderView.java
new file mode 100644
index 0000000..6db658d
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/HeaderView.java
@@ -0,0 +1,678 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import de.hdodenhof.circleimageview.CircleImageView;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+/**
+ * Created by raphaelbussa on 11/01/17.
+ */
+
+public class HeaderView extends ViewGroup implements ProfileChooserCallback {
+
+ public static final int STYLE_NORMAL = 1;
+ public static final int STYLE_COMPACT = 2;
+ public static final int THEME_LIGHT = 1;
+ public static final int THEME_DARK = 2;
+ private static final String TAG = HeaderView.class.getName();
+ private int statusBarHeight;
+
+ private CircleImageView avatar;
+ private CircleImageView avatar2;
+ private CircleImageView avatar3;
+ private ImageView background;
+ private View gradient;
+ private View selector;
+ private TextView username;
+ private TextView email;
+ private ImageView arrow;
+
+ private int hvAvatarDimen;
+ private int hvMarginDimen;
+ private int hvTextDimen;
+ private int hvArrowDimen;
+ private int hvAvatarMiniDimen;
+ private int hvTextColor;
+ private int hvStyle;
+ private int hvTheme;
+ @ColorInt
+ private int hvBackgroundColor;
+ @ColorInt
+ private int hvHighlightColor;
+ private boolean hvBelowToolbar;
+ private boolean hvShowGradient;
+ private boolean hvShowAddButton;
+ private boolean hvShowArrow;
+ @DrawableRes
+ private int hvAddIconDrawable;
+ private String hvDialogTitle;
+
+ private SparseArray profileSparseArray = new SparseArray<>();
+ private ArrayList- itemArrayList = new ArrayList<>();
+
+ private HeaderCallback headerCallback;
+ private FragmentManager hvFragmentManager;
+
+ public HeaderView(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public HeaderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyle) {
+ Log.d(TAG, "init");
+ setupAttributeSet(attrs, defStyle);
+ setupResources();
+ addBackground();
+ addGradient();
+ addSelector();
+ addAvatar();
+ addUsername();
+ addEmail();
+ addArrow();
+ addAvatar2();
+ addAvatar3();
+ setDefaultValues();
+ }
+
+ public void setStyle(@Style int style) {
+ hvStyle = style;
+ }
+
+ public void setTheme(@Theme int theme) {
+ hvTheme = theme;
+ if (hvTheme == THEME_LIGHT) {
+ hvTextColor = Color.WHITE;
+ }
+ if (hvTheme == THEME_DARK) {
+ hvTextColor = Color.BLACK;
+ }
+ username.setTextColor(hvTextColor);
+ email.setTextColor(hvTextColor);
+ arrow.setColorFilter(hvTextColor);
+ }
+
+ public void setCallback(HeaderCallback headerCallback) {
+ this.headerCallback = headerCallback;
+ }
+
+ public void clearProfile() {
+ profileSparseArray.clear();
+ populateAvatar();
+ }
+
+ public void addProfile(List profiles) {
+ for (Profile profile : profiles) {
+ profileSparseArray.put(profile.getId(), profile);
+ }
+ populateAvatar();
+ Log.d(TAG, profileSparseArray.toString());
+ }
+
+ public void addProfile(Profile... profiles) {
+ for (Profile profile : profiles) {
+ profileSparseArray.put(profile.getId(), profile);
+ }
+ populateAvatar();
+ Log.d(TAG, profileSparseArray.toString());
+ }
+
+ public void addDialogItem(Item... item) {
+ itemArrayList.clear();
+ Collections.addAll(itemArrayList, item);
+ }
+
+ public void addDialogItem(List
- items) {
+ itemArrayList.clear();
+ itemArrayList.addAll(items);
+ }
+
+ public void removeProfile(int id) {
+ for (int i = 0; i < profileSparseArray.size(); i++) {
+ Profile profile = profileSparseArray.valueAt(i);
+ if (profile.getId() == id) {
+ profileSparseArray.removeAt(i);
+ populateAvatar();
+ return;
+ }
+ }
+ }
+
+ public int getProfileActive() {
+ return profileSparseArray.valueAt(0).getId();
+ }
+
+ public void setProfileActive(int id) {
+ for (int i = 0; i < profileSparseArray.size(); i++) {
+ Profile profile = profileSparseArray.valueAt(i);
+ if (profile.getId() == id) {
+ swapProfiles(i);
+ return;
+ }
+ }
+ }
+
+ public void setShowArrow(boolean showArrow) {
+ hvShowArrow = showArrow;
+ addArrow();
+ }
+
+ public void setShowGradient(boolean showGradient) {
+ hvShowGradient = showGradient;
+ addGradient();
+ }
+
+ /**
+ * @param addIconDrawable replace default add icon, param 14dp icon and 16dp padding
+ */
+ public void setAddIconDrawable(@DrawableRes int addIconDrawable) {
+ hvAddIconDrawable = addIconDrawable;
+ }
+
+ public void setFragmentManager(FragmentManager fragmentManager) {
+ hvFragmentManager = fragmentManager;
+ }
+
+ public void setShowAddButton(boolean showAddButton) {
+ hvShowAddButton = showAddButton;
+ }
+
+ public void setBackgroundColor(@ColorInt int color) {
+ background.setBackgroundColor(color);
+ }
+
+ public void setBackgroundColorRes(@ColorRes int color) {
+ background.setBackgroundColor(Utils.getColor(getContext(), color));
+ }
+
+ public void setOnAvatarClickListener(View.OnClickListener onClickListener) {
+ avatar.setOnClickListener(onClickListener);
+ }
+
+ public void setOnLongAvatarClickListener(View.OnLongClickListener onLongClickListener) {
+ avatar.setOnLongClickListener(onLongClickListener);
+ }
+
+ public void setOnHeaderClickListener(OnClickListener onClickListener) {
+ selector.setOnClickListener(onClickListener);
+ }
+
+ public void setOnLongHeaderClickListener(View.OnLongClickListener onLongClickListener) {
+ selector.setOnLongClickListener(onLongClickListener);
+ }
+
+ public void setHighlightColor(int highlightColor) {
+ hvHighlightColor = highlightColor;
+ }
+
+ public void setDialogTitle(String dialogTitle) {
+ hvDialogTitle = dialogTitle;
+ }
+
+ private void populateAvatar() {
+ int size = profileSparseArray.size();
+ Log.d(TAG, "profileSparseArray.size() [" + profileSparseArray.size() + "]");
+ if (size >= 3) {
+ size = 3;
+ }
+ avatar.setVisibility(INVISIBLE);
+ username.setVisibility(INVISIBLE);
+ email.setVisibility(INVISIBLE);
+ background.setImageDrawable(null);
+
+ avatar2.setVisibility(INVISIBLE);
+ avatar3.setVisibility(INVISIBLE);
+ for (int i = 0; i < size; i++) {
+ Profile profile = profileSparseArray.valueAt(i);
+ Log.d(TAG, "pos [" + i + "] " + profile.getUsername());
+ switch (i) {
+ case 0:
+ setFirstProfile(profile);
+ break;
+ case 1:
+ setSecondProfile(profile);
+ break;
+ case 2:
+ setThirdProfile(profile);
+ break;
+ }
+ }
+ }
+
+ private void setDefaultValues() {
+ headerCallback = new HeaderCallback();
+ populateAvatar();
+ setBackgroundColor(hvBackgroundColor);
+ }
+
+ private void setFirstProfile(Profile profile) {
+ username.setText(profile.getUsername());
+ email.setText(profile.getEmail());
+ if (profile.getAvatarDrawable() != null)
+ avatar.setImageDrawable(profile.getAvatarDrawable());
+ if (profile.getBackgroundDrawable() != null)
+ background.setImageDrawable(profile.getBackgroundDrawable());
+ if (profile.getAvatarUri() != null)
+ ImageLoader.loadImage(profile.getAvatarUri(), avatar, ImageLoader.AVATAR);
+ if (profile.getBackgroundUri() != null)
+ ImageLoader.loadImage(profile.getBackgroundUri(), background, ImageLoader.HEADER);
+ avatar.setVisibility(VISIBLE);
+ username.setVisibility(VISIBLE);
+ email.setVisibility(VISIBLE);
+ avatar.setTag(R.id.hv_first_profile, profile.getId());
+ avatar.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ headerCallback.onSelect((int) v.getTag(R.id.hv_first_profile), true);
+ }
+ });
+ }
+
+ private void setSecondProfile(Profile profile) {
+ if (profile.getAvatarDrawable() != null)
+ avatar2.setImageDrawable(profile.getAvatarDrawable());
+ if (profile.getAvatarUri() != null)
+ ImageLoader.loadImage(profile.getAvatarUri(), avatar2, ImageLoader.AVATAR);
+ avatar2.setVisibility(VISIBLE);
+ avatar2.setTag(R.id.hv_second_profile, profile.getId());
+ avatar2.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ headerCallback.onSelect((int) v.getTag(R.id.hv_second_profile), false);
+ swapProfiles(1);
+ }
+ });
+ }
+
+ private void setThirdProfile(Profile profile) {
+ if (profile.getAvatarDrawable() != null)
+ avatar3.setImageDrawable(profile.getAvatarDrawable());
+ if (profile.getAvatarUri() != null)
+ ImageLoader.loadImage(profile.getAvatarUri(), avatar3, ImageLoader.AVATAR);
+ avatar3.setVisibility(VISIBLE);
+ avatar3.setTag(R.id.hv_third_profile, profile.getId());
+ avatar3.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ headerCallback.onSelect((int) v.getTag(R.id.hv_third_profile), false);
+ swapProfiles(2);
+ }
+ });
+ }
+
+ private void swapProfiles(int pos) {
+ if (pos == 0) return;
+ Profile newFirst = profileSparseArray.valueAt(pos);
+ Profile oldFirst = profileSparseArray.valueAt(0);
+ profileSparseArray.setValueAt(0, newFirst);
+ profileSparseArray.setValueAt(pos, oldFirst);
+ populateAvatar();
+ }
+
+ @SuppressWarnings("Range")
+ private void setupAttributeSet(AttributeSet attrs, int defStyle) {
+
+ String hvUsername;
+ String hvEmail;
+ int hvAvatar;
+ int hvBackground;
+
+ if (attrs == null) {
+
+ hvUsername = "";
+ hvEmail = "";
+ hvAvatar = 0;
+ hvBackground = 0;
+
+ hvBackgroundColor = Color.TRANSPARENT;
+ hvHighlightColor = Color.BLACK;
+ hvBelowToolbar = false;
+ hvStyle = STYLE_NORMAL;
+ hvTheme = THEME_LIGHT;
+ hvShowGradient = true;
+ hvShowArrow = true;
+ hvShowAddButton = true;
+ hvDialogTitle = "Account";
+ hvAddIconDrawable = R.drawable.hv_add_profile;
+ } else {
+ TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HeaderView, defStyle, 0);
+
+ hvUsername = typedArray.getString(R.styleable.HeaderView_hv_profile_username);
+ hvEmail = typedArray.getString(R.styleable.HeaderView_hv_profile_email);
+ hvAvatar = typedArray.getResourceId(R.styleable.HeaderView_hv_profile_avatar, 0);
+ hvBackground = typedArray.getResourceId(R.styleable.HeaderView_hv_profile_background, 0);
+
+ hvBackgroundColor = typedArray.getColor(R.styleable.HeaderView_hv_background_color, Color.TRANSPARENT);
+ hvHighlightColor = typedArray.getColor(R.styleable.HeaderView_hv_highlight_color, Color.BLACK);
+ hvBelowToolbar = typedArray.getBoolean(R.styleable.HeaderView_hv_below_toolbar, false);
+ hvStyle = typedArray.getInt(R.styleable.HeaderView_hv_style, STYLE_NORMAL);
+ hvTheme = typedArray.getInt(R.styleable.HeaderView_hv_theme, THEME_LIGHT);
+ hvShowGradient = typedArray.getBoolean(R.styleable.HeaderView_hv_show_gradient, true);
+ hvShowArrow = typedArray.getBoolean(R.styleable.HeaderView_hv_show_arrow, true);
+ hvShowAddButton = typedArray.getBoolean(R.styleable.HeaderView_hv_show_add_button, true);
+ hvDialogTitle = typedArray.getString(R.styleable.HeaderView_hv_dialog_title);
+ hvAddIconDrawable = typedArray.getResourceId(R.styleable.HeaderView_hv_add_icon, R.drawable.hv_add_profile);
+ typedArray.recycle();
+ }
+
+ if ((hvUsername != null && !hvUsername.isEmpty()) || (hvEmail != null && !hvEmail.isEmpty()) || hvAvatar != 0 || hvBackground != 0) {
+ Log.d(TAG, "profile created from XML");
+ Profile profile = new Profile.Builder()
+ .setId(1)
+ .setUsername(hvUsername)
+ .setEmail(hvEmail)
+ .setAvatar(Utils.getDrawable(getContext(), hvAvatar))
+ .setBackground(Utils.getDrawable(getContext(), hvBackground))
+ .build();
+
+ profileSparseArray.put(profile.getId(), profile);
+ }
+
+ }
+
+ private void setupResources() {
+ statusBarHeight = Utils.getStatusBarHeight(getContext());
+ hvAvatarDimen = getResources().getDimensionPixelSize(R.dimen.hv_avatar);
+ hvAvatarMiniDimen = getResources().getDimensionPixelSize(R.dimen.hv_avatar_mini);
+ hvMarginDimen = getResources().getDimensionPixelSize(R.dimen.hv_margin);
+ hvTextDimen = getResources().getDimensionPixelSize(R.dimen.hv_text);
+ hvArrowDimen = getResources().getDimensionPixelSize(R.dimen.hv_arrow);
+ if (hvTheme == THEME_LIGHT) {
+ hvTextColor = Color.WHITE;
+ }
+ if (hvTheme == THEME_DARK) {
+ hvTextColor = Color.BLACK;
+ }
+ }
+
+ private void addBackground() {
+ LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ background = new ImageView(getContext());
+ background.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ addView(background, 0, layoutParams);
+ }
+
+ private void addSelector() {
+ selector = new View(getContext());
+ selector.setBackgroundResource(Utils.selectableItemBackground(getContext()));
+ addView(selector, 2);
+ }
+
+ private void addGradient() {
+ gradient = new View(getContext());
+ gradient.setBackgroundColor(Color.parseColor("#38000000"));
+ addView(gradient, 1);
+ gradient.setVisibility(hvShowGradient ? VISIBLE : GONE);
+ }
+
+ private void addAvatar() {
+ LayoutParams layoutParams = new LayoutParams(hvAvatarDimen, hvAvatarDimen);
+ avatar = new CircleImageView(getContext());
+ avatar.setBackgroundResource(Utils.selectableItemBackgroundBorderless(getContext()));
+ addView(avatar, 3, layoutParams);
+ }
+
+ private void addUsername() {
+ username = new TextView(getContext());
+ username.setTextColor(hvTextColor);
+ username.setTypeface(Typeface.DEFAULT_BOLD);
+ username.setGravity(Gravity.CENTER_VERTICAL);
+ username.setMaxLines(1);
+ username.setEllipsize(TextUtils.TruncateAt.END);
+ addView(username, 4);
+ }
+
+ private void addEmail() {
+ email = new TextView(getContext());
+ email.setTextColor(hvTextColor);
+ email.setGravity(Gravity.CENTER_VERTICAL);
+ email.setMaxLines(1);
+ email.setEllipsize(TextUtils.TruncateAt.END);
+ addView(email, 5);
+ }
+
+ private void addArrow() {
+ arrow = new ImageView(getContext());
+ arrow.setImageResource(R.drawable.hv_arrow);
+ arrow.setBackgroundResource(Utils.selectableItemBackground(getContext()));
+ arrow.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (hvFragmentManager != null) {
+ ProfileChooserFragment profileChooserFragment = ProfileChooserFragment.newInstance(profileSparseArray, itemArrayList, hvHighlightColor, hvShowAddButton, hvDialogTitle, hvAddIconDrawable);
+ profileChooserFragment.setCallback(HeaderView.this);
+ profileChooserFragment.show(hvFragmentManager, "ProfileChooserFragment");
+ } else {
+ ProfileChooser profileChooser = new ProfileChooser(getContext(), profileSparseArray, itemArrayList, hvHighlightColor, hvShowAddButton, hvDialogTitle, hvAddIconDrawable);
+ profileChooser.setCallback(HeaderView.this);
+ profileChooser.show();
+ }
+ }
+ });
+ arrow.setVisibility(hvShowArrow ? VISIBLE : GONE);
+ addView(arrow, 6);
+ }
+
+ private void addAvatar2() {
+ LayoutParams layoutParams = new LayoutParams(hvAvatarMiniDimen, hvAvatarMiniDimen);
+ avatar2 = new CircleImageView(getContext());
+ avatar2.setVisibility(INVISIBLE);
+ avatar2.setBackgroundResource(Utils.selectableItemBackgroundBorderless(getContext()));
+ addView(avatar2, 7, layoutParams);
+ }
+
+ private void addAvatar3() {
+ LayoutParams layoutParams = new LayoutParams(hvAvatarMiniDimen, hvAvatarMiniDimen);
+ avatar3 = new CircleImageView(getContext());
+ avatar3.setVisibility(INVISIBLE);
+ avatar3.setBackgroundResource(Utils.selectableItemBackgroundBorderless(getContext()));
+ addView(avatar3, 8, layoutParams);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ Log.d(TAG, "onLayout changed [" + changed + "]");
+ if (!changed) return;
+ background.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ if (hvShowGradient) {
+ gradient.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+ selector.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ avatar.layout(hvMarginDimen,
+ getDimensionFix(hvMarginDimen),
+ hvMarginDimen + hvAvatarDimen,
+ getDimensionFix(hvAvatarDimen + hvMarginDimen));
+ if (hvStyle == STYLE_NORMAL) {
+ avatar2.layout(getMeasuredWidth() - hvMarginDimen - hvAvatarMiniDimen,
+ getDimensionFix(hvMarginDimen),
+ getMeasuredWidth() - hvMarginDimen,
+ getDimensionFix(hvAvatarMiniDimen + hvMarginDimen));
+ avatar3.layout(avatar2.getLeft() - hvMarginDimen - hvAvatarMiniDimen,
+ getDimensionFix(hvMarginDimen),
+ avatar2.getLeft() - hvMarginDimen,
+ getDimensionFix(hvAvatarMiniDimen + hvMarginDimen));
+ arrow.layout(getMeasuredWidth() - hvArrowDimen,
+ getMeasuredHeight() - hvArrowDimen,
+ getMeasuredWidth(),
+ getMeasuredHeight());
+ username.layout(hvMarginDimen,
+ avatar.getBottom() + hvMarginDimen,
+ arrow.getLeft(),
+ avatar.getBottom() + hvMarginDimen + hvTextDimen);
+ email.layout(hvMarginDimen,
+ username.getBottom(),
+ arrow.getLeft(),
+ username.getBottom() + hvTextDimen);
+ }
+ if (hvStyle == STYLE_COMPACT) {
+ avatar3.layout(0, 0, 0, 0);
+ avatar2.layout(0, 0, 0, 0);
+ arrow.layout(getMeasuredWidth() - hvArrowDimen,
+ getDimensionFix(getMeasuredHeight()) / 2 - hvArrowDimen / 2,
+ getMeasuredWidth(),
+ getDimensionFix(getMeasuredHeight()) / 2 + hvArrowDimen / 2);
+ username.layout(avatar.getRight() + hvMarginDimen,
+ getDimensionFix(getMeasuredHeight()) / 2 - hvTextDimen,
+ arrow.getLeft(),
+ getDimensionFix(getMeasuredHeight()) / 2);
+ email.layout(avatar.getRight() + hvMarginDimen,
+ getDimensionFix(getMeasuredHeight()) / 2,
+ arrow.getLeft(),
+ getDimensionFix(getMeasuredHeight()) / 2 + hvTextDimen);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ Log.d(TAG, "onMeasure");
+ setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getHeaderHeight(heightMeasureSpec));
+ }
+
+ private int getDimensionFix(int dimen) {
+ if (hvBelowToolbar) {
+ return dimen;
+ } else {
+ return dimen + statusBarHeight;
+ }
+ }
+
+ private int getHeaderHeight(int heightMeasureSpec) {
+ if (hvStyle == STYLE_NORMAL) {
+ if (hvBelowToolbar) {
+ return getResources().getDimensionPixelSize(R.dimen.hv_normal);
+ } else {
+ return getResources().getDimensionPixelSize(R.dimen.hv_normal) + statusBarHeight;
+ }
+ }
+ if (hvStyle == STYLE_COMPACT) {
+ if (hvBelowToolbar) {
+ return getResources().getDimensionPixelSize(R.dimen.hv_compact);
+ } else {
+ return getResources().getDimensionPixelSize(R.dimen.hv_compact) + statusBarHeight;
+ }
+ }
+ return getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Log.d(TAG, "onSaveInstanceState");
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("superState", super.onSaveInstanceState());
+ //STORE CUSTOM VALUES
+ bundle.putSparseParcelableArray("PROFILE_LIST", profileSparseArray);
+ return bundle;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ Log.d(TAG, "onRestoreInstanceState");
+ if (state instanceof Bundle) {
+ Bundle bundle = (Bundle) state;
+ state = bundle.getParcelable("superState");
+ //RESTORE CUSTOM VALUES
+ profileSparseArray = bundle.getSparseParcelableArray("PROFILE_LIST");
+ populateAvatar();
+ }
+ if (hvFragmentManager != null) {
+ ProfileChooserFragment profileChooserFragment = (ProfileChooserFragment) hvFragmentManager.findFragmentByTag("ProfileChooserFragment");
+ if (profileChooserFragment != null) {
+ profileChooserFragment.setCallback(HeaderView.this);
+ }
+ }
+ super.onRestoreInstanceState(state);
+ }
+
+ @Override
+ public boolean onSelect(int id, boolean selected) {
+ setProfileActive(id);
+ return headerCallback.onSelect(id, selected);
+ }
+
+ @Override
+ public boolean onItem(int id) {
+ return headerCallback.onItem(id);
+ }
+
+ @Override
+ public boolean onAdd() {
+ return headerCallback.onAdd();
+ }
+
+ @RestrictTo(LIBRARY_GROUP)
+ @IntDef({STYLE_NORMAL, STYLE_COMPACT})
+ @IntRange(from = 1, to = 2)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Style {
+ }
+
+ @RestrictTo(LIBRARY_GROUP)
+ @IntDef({THEME_LIGHT, THEME_DARK})
+ @IntRange(from = 1, to = 2)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Theme {
+ }
+
+}
diff --git a/library/src/main/java/rebus/header/view/ImageLoader.java b/library/src/main/java/rebus/header/view/ImageLoader.java
new file mode 100644
index 0000000..1d7468a
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/ImageLoader.java
@@ -0,0 +1,79 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.net.Uri;
+import android.support.annotation.IntDef;
+import android.support.annotation.IntRange;
+import android.support.annotation.RestrictTo;
+import android.widget.ImageView;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+/**
+ * Created by raphaelbussa on 13/01/17.
+ */
+public class ImageLoader {
+
+ public static final int AVATAR = 1;
+ public static final int HEADER = 2;
+
+ private static ImageLoader instance;
+ private ImageLoaderInterface imageLoaderInterface;
+
+ public static ImageLoader init(ImageLoaderInterface imageLoaderInterface) {
+ if (instance == null) {
+ instance = new ImageLoader();
+ }
+ instance.setImageLoaderInterface(imageLoaderInterface);
+ return instance;
+ }
+
+ static void loadImage(Uri url, ImageView imageView, @Type int type) {
+ if (instance == null) {
+ throw new RuntimeException("ImageLoader must be implemented for use setAvatarUrl and setBackgroundUrl methods");
+ }
+ instance.imageLoaderInterface.loadImage(url, imageView, type);
+ }
+
+ private void setImageLoaderInterface(ImageLoaderInterface imageLoaderInterface) {
+ this.imageLoaderInterface = imageLoaderInterface;
+ }
+
+ public interface ImageLoaderInterface {
+ void loadImage(Uri url, ImageView imageView, @Type int type);
+ }
+
+ @RestrictTo(LIBRARY_GROUP)
+ @IntDef({AVATAR, HEADER})
+ @IntRange(from = 1, to = 2)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {
+ }
+
+}
diff --git a/library/src/main/java/rebus/header/view/Item.java b/library/src/main/java/rebus/header/view/Item.java
new file mode 100644
index 0000000..a3a94b7
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/Item.java
@@ -0,0 +1,104 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Created by raphaelbussa on 14/01/17.
+ */
+
+public class Item implements Parcelable {
+
+ public static final Creator
- CREATOR = new Creator
- () {
+ @Override
+ public Item createFromParcel(Parcel in) {
+ return new Item(in);
+ }
+
+ @Override
+ public Item[] newArray(int size) {
+ return new Item[size];
+ }
+ };
+ private int id;
+ private String title;
+
+ private Item(int id, String title) {
+ this.id = id;
+ this.title = title;
+ }
+
+ protected Item(Parcel in) {
+ id = in.readInt();
+ title = in.readString();
+ }
+
+ int getId() {
+ return id;
+ }
+
+ String getTitle() {
+ return title;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(id);
+ dest.writeString(title);
+ }
+
+ public static class Builder {
+
+ private int id;
+ private String title;
+
+ public Builder() {
+ }
+
+ public Builder setId(int id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setTitle(String title) {
+ this.title = title;
+ return this;
+ }
+
+ public Item build() {
+ return new Item(id, title);
+ }
+
+ }
+
+
+}
diff --git a/library/src/main/java/rebus/header/view/Profile.java b/library/src/main/java/rebus/header/view/Profile.java
new file mode 100644
index 0000000..cbd7ba2
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/Profile.java
@@ -0,0 +1,232 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.text.Spanned;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+/**
+ * Created by raphaelbussa on 14/01/17.
+ */
+
+public class Profile implements Parcelable {
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Profile createFromParcel(Parcel in) {
+ return new Profile(in);
+ }
+
+ @Override
+ public Profile[] newArray(int size) {
+ return new Profile[size];
+ }
+ };
+ @IdValue
+ private int id;
+ private Uri avatarUri;
+ private Drawable avatarDrawable;
+ private Uri backgroundUri;
+ private Drawable backgroundDrawable;
+ private Spanned username;
+ private Spanned email;
+
+ private Profile(int id, Uri avatarUri, Drawable avatarDrawable, Uri backgroundUri, Drawable backgroundDrawable, Spanned username, Spanned email) {
+ this.id = id;
+ this.avatarUri = avatarUri;
+ this.avatarDrawable = avatarDrawable;
+ this.backgroundUri = backgroundUri;
+ this.backgroundDrawable = backgroundDrawable;
+ this.username = username;
+ this.email = email;
+ }
+
+ private Profile(Parcel in) {
+ id = in.readInt();
+ avatarUri = (Uri) in.readValue(Uri.class.getClassLoader());
+ avatarDrawable = (Drawable) in.readValue(Drawable.class.getClassLoader());
+ backgroundUri = (Uri) in.readValue(Uri.class.getClassLoader());
+ backgroundDrawable = (Drawable) in.readValue(Drawable.class.getClassLoader());
+ username = (Spanned) in.readValue(Spanned.class.getClassLoader());
+ email = (Spanned) in.readValue(Spanned.class.getClassLoader());
+ }
+
+ int getId() {
+ return id;
+ }
+
+ Uri getAvatarUri() {
+ return avatarUri;
+ }
+
+ Drawable getAvatarDrawable() {
+ return avatarDrawable;
+ }
+
+ Uri getBackgroundUri() {
+ return backgroundUri;
+ }
+
+ Drawable getBackgroundDrawable() {
+ return backgroundDrawable;
+ }
+
+ Spanned getUsername() {
+ return username;
+ }
+
+ Spanned getEmail() {
+ return email;
+ }
+
+ @Override
+ public String toString() {
+ return "Profile{" +
+ "id=" + id +
+ ", avatarUri=" + avatarUri +
+ ", avatarDrawable=" + avatarDrawable +
+ ", backgroundUri=" + backgroundUri +
+ ", backgroundDrawable=" + backgroundDrawable +
+ ", username=" + username +
+ ", email=" + email +
+ '}';
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(id);
+ dest.writeValue(avatarUri);
+ dest.writeValue(avatarDrawable);
+ dest.writeValue(backgroundUri);
+ dest.writeValue(backgroundDrawable);
+ dest.writeValue(username);
+ dest.writeValue(email);
+ }
+
+ @RestrictTo(LIBRARY_GROUP)
+ @IntRange(from = 2)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IdValue {
+ }
+
+ public static class Builder {
+
+ @IdValue
+ private int id;
+ private Uri avatarUri;
+ private Drawable avatarDrawable;
+ private Uri backgroundUri;
+ private Drawable backgroundDrawable;
+ private Spanned username;
+ private Spanned email;
+
+ public Builder() {
+ }
+
+ public Builder setId(@IdValue int id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setAvatar(Uri avatar) {
+ this.avatarUri = avatar;
+ this.avatarDrawable = null;
+ return this;
+ }
+
+ public Builder setAvatar(@NonNull String avatar) {
+ this.avatarUri = Uri.parse(avatar);
+ this.avatarDrawable = null;
+ return this;
+ }
+
+ public Builder setAvatar(Drawable avatar) {
+ this.avatarDrawable = avatar;
+ this.avatarUri = null;
+ return this;
+ }
+
+ public Builder setBackground(Uri background) {
+ this.backgroundUri = background;
+ this.backgroundDrawable = null;
+ return this;
+ }
+
+ public Builder setBackground(@NonNull String background) {
+ this.backgroundUri = Uri.parse(background);
+ this.backgroundDrawable = null;
+ return this;
+ }
+
+ public Builder setBackground(Drawable background) {
+ this.backgroundDrawable = background;
+ this.backgroundUri = null;
+ return this;
+ }
+
+ public Builder setUsername(Spanned username) {
+ this.username = username;
+ return this;
+ }
+
+ public Builder setEmail(Spanned email) {
+ this.email = email;
+ return this;
+ }
+
+ public Builder setUsername(String username) {
+ this.username = Utils.fromHtml(username);
+ return this;
+ }
+
+ public Builder setEmail(String email) {
+ this.email = Utils.fromHtml(email);
+ return this;
+ }
+
+ public Profile build() {
+ return new Profile(id, avatarUri, avatarDrawable, backgroundUri, backgroundDrawable, username, email);
+ }
+
+ }
+
+
+}
diff --git a/library/src/main/java/rebus/header/view/ProfileChooser.java b/library/src/main/java/rebus/header/view/ProfileChooser.java
new file mode 100644
index 0000000..5d6b39e
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/ProfileChooser.java
@@ -0,0 +1,119 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+
+import android.app.Dialog;
+import android.content.Context;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * Created by raphaelbussa on 17/01/17.
+ */
+
+class ProfileChooser extends Dialog {
+
+ private ProfileChooserCallback callback;
+
+ ProfileChooser(Context context, SparseArray profileSparseArray, ArrayList
- items, int accent, boolean showAdd, String titleValue, int icon) {
+ super(context);
+ this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ this.setContentView(R.layout.hw_account_chooser);
+ LinearLayout linearLayout = (LinearLayout) findViewById(R.id.hw_profile_container);
+ LinearLayout linearLayout1 = (LinearLayout) findViewById(R.id.hw_action_container);
+ TextView title = (TextView) findViewById(R.id.hw_dialog_title);
+ ImageView add = (ImageView) findViewById(R.id.hv_add_profile);
+ add.setImageResource(icon);
+ title.setTextColor(Utils.getTextColorPrimary(context));
+ title.setText(titleValue);
+ add.setVisibility(showAdd ? View.VISIBLE : View.INVISIBLE);
+ add.setColorFilter(Utils.getTextColorPrimary(context));
+ add.setBackgroundResource(Utils.selectableItemBackgroundBorderless(context));
+ add.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (callback != null) {
+ if (callback.onAdd()) {
+ dismiss();
+ }
+ }
+ }
+ });
+ for (int i = 0; i < profileSparseArray.size(); i++) {
+ RowProfileView profileView = new RowProfileView(context);
+ profileView.setProfile(profileSparseArray.valueAt(i), i == 0);
+ profileView.setAccent(accent);
+ profileView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ RowProfileView rowProfileView = (RowProfileView) v;
+ if (callback != null) {
+ if (callback.onSelect(rowProfileView.getProfile().getId(), rowProfileView.isActive())) {
+ dismiss();
+ }
+ }
+ }
+ });
+ linearLayout.addView(profileView);
+ }
+ int padding = context.getResources().getDimensionPixelSize(R.dimen.hv_item_padding);
+ ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ for (Item item : items) {
+ TextView textView = new TextView(context);
+ textView.setText(item.getTitle());
+ textView.setTag(item.getId());
+ textView.setBackgroundResource(Utils.selectableItemBackground(context));
+ textView.setPadding(padding, padding / 2, padding, padding / 2);
+ textView.setTextColor(Utils.getTextColorSecondary(context));
+ textView.setGravity(Gravity.CENTER_VERTICAL);
+ textView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int id = (int) v.getTag();
+ if (callback != null) {
+ if (callback.onItem(id)) {
+ dismiss();
+ }
+ }
+ }
+ });
+ linearLayout1.addView(textView, layoutParams);
+ }
+ }
+
+ void setCallback(ProfileChooserCallback callback) {
+ this.callback = callback;
+ }
+
+}
diff --git a/library/src/main/java/rebus/header/view/ProfileChooserCallback.java b/library/src/main/java/rebus/header/view/ProfileChooserCallback.java
new file mode 100644
index 0000000..8e0eee0
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/ProfileChooserCallback.java
@@ -0,0 +1,39 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+/**
+ * Created by raphaelbussa on 21/01/17.
+ */
+
+interface ProfileChooserCallback {
+
+ boolean onSelect(int id, boolean isActive);
+
+ boolean onItem(int id);
+
+ boolean onAdd();
+
+}
diff --git a/library/src/main/java/rebus/header/view/ProfileChooserFragment.java b/library/src/main/java/rebus/header/view/ProfileChooserFragment.java
new file mode 100644
index 0000000..24ea85d
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/ProfileChooserFragment.java
@@ -0,0 +1,156 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by raphaelbussa on 21/01/17.
+ */
+
+public class ProfileChooserFragment extends DialogFragment {
+
+ private LinearLayout linearLayout;
+ private LinearLayout linearLayout1;
+ private TextView title;
+ private ImageView add;
+
+ private ProfileChooserCallback callback;
+
+ public static ProfileChooserFragment newInstance(SparseArray profileSparseArray, ArrayList
- items, int accent, boolean showAdd, String titleValue, int icon) {
+ Bundle bundle = new Bundle();
+ bundle.putSparseParcelableArray("profileSparseArray", profileSparseArray);
+ bundle.putParcelableArrayList("items", items);
+ bundle.putInt("accent", accent);
+ bundle.putBoolean("showAdd", showAdd);
+ bundle.putString("titleValue", titleValue);
+ bundle.putInt("icon", icon);
+ ProfileChooserFragment fragment = new ProfileChooserFragment();
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.hw_account_chooser, container, false);
+ linearLayout = (LinearLayout) rootView.findViewById(R.id.hw_profile_container);
+ linearLayout1 = (LinearLayout) rootView.findViewById(R.id.hw_action_container);
+ title = (TextView) rootView.findViewById(R.id.hw_dialog_title);
+ add = (ImageView) rootView.findViewById(R.id.hv_add_profile);
+ return rootView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ Bundle bundle = getArguments();
+ SparseArray profileSparseArray = bundle.getSparseParcelableArray("profileSparseArray");
+ List
- items = bundle.getParcelableArrayList("items");
+ int accent = bundle.getInt("accent");
+ boolean showAdd = bundle.getBoolean("showAdd");
+ String titleValue = bundle.getString("titleValue");
+ int icon = bundle.getInt("icon");
+
+ add.setImageResource(icon);
+ title.setTextColor(Utils.getTextColorPrimary(getActivity()));
+ title.setText(titleValue);
+ add.setVisibility(showAdd ? View.VISIBLE : View.INVISIBLE);
+ add.setColorFilter(Utils.getTextColorPrimary(getActivity()));
+ add.setBackgroundResource(Utils.selectableItemBackgroundBorderless(getActivity()));
+ add.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (callback != null) {
+ if (callback.onAdd()) {
+ dismiss();
+ }
+ }
+ }
+ });
+ if (profileSparseArray != null) {
+ for (int i = 0; i < profileSparseArray.size(); i++) {
+ RowProfileView profileView = new RowProfileView(getActivity());
+ profileView.setProfile(profileSparseArray.valueAt(i), i == 0);
+ profileView.setAccent(accent);
+ profileView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ RowProfileView rowProfileView = (RowProfileView) v;
+ if (callback != null) {
+ if (callback.onSelect(rowProfileView.getProfile().getId(), rowProfileView.isActive())) {
+ dismiss();
+ }
+ }
+ }
+ });
+ linearLayout.addView(profileView);
+ }
+ }
+ if (items != null) {
+ int padding = getActivity().getResources().getDimensionPixelSize(R.dimen.hv_item_padding);
+ ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ for (Item item : items) {
+ TextView textView = new TextView(getActivity());
+ textView.setText(item.getTitle());
+ textView.setTag(item.getId());
+ textView.setBackgroundResource(Utils.selectableItemBackground(getActivity()));
+ textView.setPadding(padding, padding / 2, padding, padding / 2);
+ textView.setTextColor(Utils.getTextColorSecondary(getActivity()));
+ textView.setGravity(Gravity.CENTER_VERTICAL);
+ textView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int id = (int) v.getTag();
+ if (callback != null) {
+ if (callback.onItem(id)) {
+ dismiss();
+ }
+ }
+ }
+ });
+ linearLayout1.addView(textView, layoutParams);
+ }
+ }
+ }
+
+ public void setCallback(ProfileChooserCallback callback) {
+ this.callback = callback;
+ }
+
+}
diff --git a/library/src/main/java/rebus/header/view/RowProfileView.java b/library/src/main/java/rebus/header/view/RowProfileView.java
new file mode 100644
index 0000000..1888908
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/RowProfileView.java
@@ -0,0 +1,181 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.support.annotation.ColorInt;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import de.hdodenhof.circleimageview.CircleImageView;
+
+/**
+ * Created by raphaelbussa on 16/01/17.
+ */
+
+class RowProfileView extends ViewGroup {
+
+ private CircleImageView avatar;
+ private TextView username;
+ private TextView email;
+ private ImageView check;
+
+ private int hvAvatarRowDimen;
+ private int hvRowHeightDimen;
+ private int hvRowMarginDimen;
+ private int hvRowCheckDimen;
+ private int hvRowMarginTextDimen;
+ private int hvTextDimen;
+ private int hvRowAvatarBorderDimen;
+
+ private Profile hvProfile;
+ private boolean hvActive;
+
+ private int accent = Color.BLACK;
+
+ public RowProfileView(Context context) {
+ super(context);
+ init();
+ }
+
+ public RowProfileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public RowProfileView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ setBackgroundResource(Utils.selectableItemBackground(getContext()));
+ setupResources();
+ addViews();
+ }
+
+ public void setAccent(@ColorInt int accentColor) {
+ accent = accentColor;
+ avatar.setBorderColor(accent);
+ check.setColorFilter(accent);
+ }
+
+ public boolean isActive() {
+ return hvActive;
+ }
+
+ public Profile getProfile() {
+ return hvProfile;
+ }
+
+ public void setProfile(Profile profile, boolean active) {
+ hvActive = active;
+ hvProfile = profile;
+ avatar.setBorderWidth(active ? hvRowAvatarBorderDimen : 0);
+ if (hvActive) {
+ avatar.setPadding(0, 0, 0, 0);
+ } else {
+ avatar.setPadding(hvRowAvatarBorderDimen, hvRowAvatarBorderDimen, hvRowAvatarBorderDimen, hvRowAvatarBorderDimen);
+ }
+ check.setVisibility(hvActive ? VISIBLE : INVISIBLE);
+ username.setTypeface(active ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
+ email.setTypeface(active ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
+ username.setText(hvProfile.getUsername());
+ email.setText(hvProfile.getEmail());
+ if (hvProfile.getAvatarDrawable() != null)
+ avatar.setImageDrawable(hvProfile.getAvatarDrawable());
+ if (hvProfile.getAvatarUri() != null)
+ ImageLoader.loadImage(hvProfile.getAvatarUri(), avatar, ImageLoader.AVATAR);
+ }
+
+ private void addViews() {
+ LayoutParams avatarLayoutParams = new LayoutParams(hvAvatarRowDimen, hvAvatarRowDimen);
+ LayoutParams checkLayoutParams = new LayoutParams(hvRowCheckDimen, hvRowCheckDimen);
+ avatar = new CircleImageView(getContext());
+ avatar.setBorderColor(accent);
+ avatar.setBorderWidth(hvRowAvatarBorderDimen);
+ check = new ImageView(getContext());
+ check.setImageResource(R.drawable.hv_profile_check);
+ check.setColorFilter(accent);
+ username = new TextView(getContext());
+ username.setTextColor(Utils.getTextColorPrimary(getContext()));
+ username.setGravity(Gravity.CENTER_VERTICAL);
+ username.setMaxLines(1);
+ username.setEllipsize(TextUtils.TruncateAt.END);
+ email = new TextView(getContext());
+ email.setTextColor(Utils.getTextColorSecondary(getContext()));
+ email.setGravity(Gravity.CENTER_VERTICAL);
+ email.setMaxLines(1);
+ email.setEllipsize(TextUtils.TruncateAt.END);
+ addView(avatar, avatarLayoutParams);
+ addView(check, checkLayoutParams);
+ addView(username);
+ addView(email);
+ }
+
+ private void setupResources() {
+ accent = Color.BLACK;
+ hvAvatarRowDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_avatar);
+ hvRowHeightDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_height);
+ hvRowMarginDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_margin);
+ hvRowCheckDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_check);
+ hvRowMarginTextDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_margin_text);
+ hvTextDimen = getResources().getDimensionPixelSize(R.dimen.hv_text);
+ hvRowAvatarBorderDimen = getResources().getDimensionPixelSize(R.dimen.hv_row_avatar_border);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), hvRowHeightDimen);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ if (!changed) return;
+ avatar.layout(hvRowMarginDimen,
+ getMeasuredHeight() / 2 - hvAvatarRowDimen / 2,
+ hvRowMarginDimen + hvAvatarRowDimen,
+ getMeasuredHeight() / 2 + hvAvatarRowDimen / 2);
+ check.layout(getMeasuredWidth() - hvRowMarginDimen - hvRowCheckDimen,
+ getMeasuredHeight() / 2 - hvRowCheckDimen / 2,
+ getMeasuredWidth() - hvRowMarginDimen,
+ getMeasuredHeight() / 2 + hvRowCheckDimen / 2);
+ username.layout(avatar.getRight() + hvRowMarginTextDimen,
+ getMeasuredHeight() / 2 - hvTextDimen,
+ check.getLeft() - hvRowMarginTextDimen,
+ getMeasuredHeight() / 2);
+ email.layout(avatar.getRight() + hvRowMarginTextDimen,
+ getMeasuredHeight() / 2,
+ check.getLeft() - hvRowMarginTextDimen,
+ getMeasuredHeight() / 2 + hvTextDimen);
+ }
+
+}
diff --git a/library/src/main/java/rebus/header/view/Utils.java b/library/src/main/java/rebus/header/view/Utils.java
new file mode 100644
index 0000000..400c683
--- /dev/null
+++ b/library/src/main/java/rebus/header/view/Utils.java
@@ -0,0 +1,118 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Raphaël Bussa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package rebus.header.view;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.text.Html;
+import android.text.Spanned;
+import android.util.TypedValue;
+
+/**
+ * Created by raphaelbussa on 13/01/17.
+ */
+
+class Utils {
+
+ static int getTextColorPrimary(Context context) {
+ TypedValue typedValue = new TypedValue();
+ TypedArray typedArray = context.obtainStyledAttributes(typedValue.data, new int[]{16842806});
+ int value = typedArray.getColor(0, 0);
+ typedArray.recycle();
+ return value;
+ }
+
+ static int getTextColorSecondary(Context context) {
+ TypedValue typedValue = new TypedValue();
+ TypedArray typedArray = context.obtainStyledAttributes(typedValue.data, new int[]{16842808});
+ int value = typedArray.getColor(0, 0);
+ typedArray.recycle();
+ return value;
+ }
+
+ static int selectableItemBackgroundBorderless(Context context) {
+ TypedValue outValue = new TypedValue();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ context.getTheme().resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, outValue, true);
+ } else {
+ context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
+ }
+ return outValue.resourceId;
+ }
+
+ static int selectableItemBackground(Context context) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
+ return outValue.resourceId;
+ }
+
+ static int getStatusBarHeight(Context context) {
+ int result = 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ result = context.getResources().getDimensionPixelSize(resourceId);
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ static int getColor(Context context, @ColorRes int color) {
+ if (color == 0) return -1;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return context.getResources().getColor(color, context.getTheme());
+ } else {
+ return context.getResources().getColor(color);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ static Drawable getDrawable(Context context, @DrawableRes int drawable) {
+ if (drawable == 0) return null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return context.getResources().getDrawable(drawable, context.getTheme());
+ } else {
+ return context.getResources().getDrawable(drawable);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ static Spanned fromHtml(String value) {
+ if (value == null || value.isEmpty()) {
+ value = "";
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return Html.fromHtml(value, Html.FROM_HTML_MODE_LEGACY);
+ } else {
+ return Html.fromHtml(value);
+ }
+ }
+
+}
diff --git a/library/src/main/res/drawable-hdpi/hv_add_profile.png b/library/src/main/res/drawable-hdpi/hv_add_profile.png
new file mode 100755
index 0000000..9f88868
Binary files /dev/null and b/library/src/main/res/drawable-hdpi/hv_add_profile.png differ
diff --git a/library/src/main/res/drawable-hdpi/hv_arrow.png b/library/src/main/res/drawable-hdpi/hv_arrow.png
new file mode 100755
index 0000000..0217ae0
Binary files /dev/null and b/library/src/main/res/drawable-hdpi/hv_arrow.png differ
diff --git a/library/src/main/res/drawable-hdpi/hv_profile_check.png b/library/src/main/res/drawable-hdpi/hv_profile_check.png
new file mode 100755
index 0000000..27a49db
Binary files /dev/null and b/library/src/main/res/drawable-hdpi/hv_profile_check.png differ
diff --git a/library/src/main/res/drawable-mdpi/hv_add_profile.png b/library/src/main/res/drawable-mdpi/hv_add_profile.png
new file mode 100755
index 0000000..d03763c
Binary files /dev/null and b/library/src/main/res/drawable-mdpi/hv_add_profile.png differ
diff --git a/library/src/main/res/drawable-mdpi/hv_arrow.png b/library/src/main/res/drawable-mdpi/hv_arrow.png
new file mode 100755
index 0000000..224c94c
Binary files /dev/null and b/library/src/main/res/drawable-mdpi/hv_arrow.png differ
diff --git a/library/src/main/res/drawable-mdpi/hv_profile_check.png b/library/src/main/res/drawable-mdpi/hv_profile_check.png
new file mode 100755
index 0000000..216b591
Binary files /dev/null and b/library/src/main/res/drawable-mdpi/hv_profile_check.png differ
diff --git a/library/src/main/res/drawable-xhdpi/hv_add_profile.png b/library/src/main/res/drawable-xhdpi/hv_add_profile.png
new file mode 100755
index 0000000..d0006c9
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/hv_add_profile.png differ
diff --git a/library/src/main/res/drawable-xhdpi/hv_arrow.png b/library/src/main/res/drawable-xhdpi/hv_arrow.png
new file mode 100755
index 0000000..dc6da60
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/hv_arrow.png differ
diff --git a/library/src/main/res/drawable-xhdpi/hv_profile_check.png b/library/src/main/res/drawable-xhdpi/hv_profile_check.png
new file mode 100755
index 0000000..5b095a1
Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/hv_profile_check.png differ
diff --git a/library/src/main/res/drawable-xxhdpi/hv_add_profile.png b/library/src/main/res/drawable-xxhdpi/hv_add_profile.png
new file mode 100755
index 0000000..741cf62
Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/hv_add_profile.png differ
diff --git a/library/src/main/res/drawable-xxhdpi/hv_arrow.png b/library/src/main/res/drawable-xxhdpi/hv_arrow.png
new file mode 100755
index 0000000..0dd2eb6
Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/hv_arrow.png differ
diff --git a/library/src/main/res/drawable-xxhdpi/hv_profile_check.png b/library/src/main/res/drawable-xxhdpi/hv_profile_check.png
new file mode 100755
index 0000000..921a67d
Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/hv_profile_check.png differ
diff --git a/library/src/main/res/drawable-xxxhdpi/hv_add_profile.png b/library/src/main/res/drawable-xxxhdpi/hv_add_profile.png
new file mode 100755
index 0000000..fb7d000
Binary files /dev/null and b/library/src/main/res/drawable-xxxhdpi/hv_add_profile.png differ
diff --git a/library/src/main/res/drawable-xxxhdpi/hv_arrow.png b/library/src/main/res/drawable-xxxhdpi/hv_arrow.png
new file mode 100755
index 0000000..7ae3297
Binary files /dev/null and b/library/src/main/res/drawable-xxxhdpi/hv_arrow.png differ
diff --git a/library/src/main/res/drawable-xxxhdpi/hv_profile_check.png b/library/src/main/res/drawable-xxxhdpi/hv_profile_check.png
new file mode 100755
index 0000000..f316450
Binary files /dev/null and b/library/src/main/res/drawable-xxxhdpi/hv_profile_check.png differ
diff --git a/library/src/main/res/layout/hw_account_chooser.xml b/library/src/main/res/layout/hw_account_chooser.xml
new file mode 100644
index 0000000..52203cc
--- /dev/null
+++ b/library/src/main/res/layout/hw_account_chooser.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..d464257
--- /dev/null
+++ b/library/src/main/res/values/attrs.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main.xml b/library/src/main/res/values/dimens.xml
similarity index 60%
rename from app/src/main/res/menu/main.xml
rename to library/src/main/res/values/dimens.xml
index cfedb9b..53d857a 100644
--- a/app/src/main/res/menu/main.xml
+++ b/library/src/main/res/values/dimens.xml
@@ -1,7 +1,8 @@
-
-
\ No newline at end of file
+ 147dp
+ 92dp
+
+ 76dp
+ 16dp
+ 16dp
+ 8dp
+ 3dp
+ 48dp
+
+ 24dp
+
+
\ No newline at end of file
diff --git a/headerview/src/main/res/values/dimens.xml b/library/src/main/res/values/ids.xml
similarity index 84%
rename from headerview/src/main/res/values/dimens.xml
rename to library/src/main/res/values/ids.xml
index d1d962f..cedabb0 100644
--- a/headerview/src/main/res/values/dimens.xml
+++ b/library/src/main/res/values/ids.xml
@@ -2,7 +2,7 @@
+
+
+ year;owner
+ Raphaël Bussa
+ http://rebus007.altervista.org
+ Header View
+ Create an header for android.support.design.widget.NavigationView
+ http://rebus007.github.io/HeaderView/
+ @string/version
+ true
+ https://github.com/rebus007/HeaderView
+ mit
+ Raphaël Bussa
+ 2017
+
diff --git a/settings.gradle b/settings.gradle
index 419979e..3306997 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':headerview'
+include ':app', ':library'