diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 37f09d51bbc4..cfffcea88225 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -335,11 +335,8 @@ - - diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java index 5ffe91bbaa17..c64d8783f53c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java @@ -11,7 +11,6 @@ import org.wordpress.android.WordPress; import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.models.Blog; -import org.wordpress.android.models.Person; import org.wordpress.android.models.Post; import org.wordpress.android.networking.SSLCertsViewActivity; import org.wordpress.android.networking.SelfSignedSSLCertsManager; @@ -24,7 +23,6 @@ import org.wordpress.android.ui.media.MediaBrowserActivity; import org.wordpress.android.ui.media.WordPressMediaUtils; import org.wordpress.android.ui.people.PeopleManagementActivity; -import org.wordpress.android.ui.people.PersonActivity; import org.wordpress.android.ui.plans.PlansActivity; import org.wordpress.android.ui.posts.EditPostActivity; import org.wordpress.android.ui.posts.PostPreviewActivity; @@ -283,13 +281,6 @@ public static void addSelfHostedSiteForResult(Activity activity) { activity.startActivityForResult(intent, RequestCodes.ADD_ACCOUNT); } - public static void viewPersonDetails(Context context, Person person) { - Intent intent = new Intent(context, PersonActivity.class); - intent.putExtra(PersonActivity.EXTRA_PERSON_ID, person.getPersonID()); - intent.putExtra(PersonActivity.EXTRA_LOCAL_BLOG_ID, person.getLocalTableBlogId()); - slideInFromRight(context, intent); - } - public static void slideInFromRight(Context context, Intent intent) { if (context instanceof Activity) { intent.putExtra(ARG_DID_SLIDE_IN_FROM_RIGHT, true); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/SlidingRelativeLayout.java b/WordPress/src/main/java/org/wordpress/android/ui/SlidingRelativeLayout.java new file mode 100644 index 000000000000..caea2d5cbabb --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/SlidingRelativeLayout.java @@ -0,0 +1,51 @@ +package org.wordpress.android.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.ViewTreeObserver; +import android.widget.RelativeLayout; + +public class SlidingRelativeLayout extends RelativeLayout { + + private float mXFraction = 0; + + public SlidingRelativeLayout(Context context) { + super(context); + } + + public SlidingRelativeLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + private ViewTreeObserver.OnPreDrawListener mPreDrawListener = null; + + // This property is used by the objectAnimator for Fragment slide animations. ex: `fragment_slide_in_from_right.xml` + @SuppressWarnings("UnusedDeclaration") + public float getXFraction() { + return mXFraction; + } + + // This implementation fixes the first frame not being translated: http://trickyandroid.com/fragments-translate-animation/ + @SuppressWarnings("UnusedDeclaration") + public void setXFraction(float fraction) { + mXFraction = fraction; + + if (getWidth() == 0) { + if (mPreDrawListener == null) { + mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); + setXFraction(mXFraction); + return true; + } + }; + getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); + } + return; + } + + float translationX = getWidth() * fraction; + setTranslationX(translationX); + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleAdapter.java b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleAdapter.java index 4d1296560cd7..c21f31c47147 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleAdapter.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleAdapter.java @@ -30,6 +30,7 @@ public PeopleAdapter(Context context, List peopleList) { public void setPeopleList(List peopleList) { mPeopleList = peopleList; + notifyDataSetChanged(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleListFragment.java new file mode 100644 index 000000000000..6c37a6d8845c --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleListFragment.java @@ -0,0 +1,107 @@ +package org.wordpress.android.ui.people; + +import android.app.Activity; +import android.app.ListFragment; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; + +import org.wordpress.android.R; +import org.wordpress.android.datasets.PeopleTable; +import org.wordpress.android.models.Person; + +import java.util.List; + +public class PeopleListFragment extends ListFragment implements OnItemClickListener { + private static String ARG_LOCAL_TABLE_BLOG_ID = "local_table_blog_id"; + + private int mLocalTableBlogID; + private OnPersonSelectedListener mListener; + + public static PeopleListFragment newInstance(int localTableBlogID) { + PeopleListFragment peopleListFragment = new PeopleListFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(ARG_LOCAL_TABLE_BLOG_ID, localTableBlogID); + peopleListFragment.setArguments(bundle); + return peopleListFragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + try { + mListener = (OnPersonSelectedListener) context; + } catch (ClassCastException e) { + throw new ClassCastException(context.toString() + " must implement OnPersonSelectedListener"); + } + } + + // We need to override this for devices pre API 23 + @SuppressWarnings("deprecation") + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnPersonSelectedListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnPersonSelectedListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.people_list_fragment, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mLocalTableBlogID = getArguments().getInt(ARG_LOCAL_TABLE_BLOG_ID); + getListView().setOnItemClickListener(this); + } + + @Override + public void onResume() { + super.onResume(); + + refreshPeopleList(); + } + + public void refreshPeopleList() { + if (!isAdded()) return; + + List peopleList = PeopleTable.getPeople(mLocalTableBlogID); + + PeopleAdapter peopleAdapter = (PeopleAdapter) getListAdapter(); + if (peopleAdapter == null) { + peopleAdapter = new PeopleAdapter(getActivity(), peopleList); + setListAdapter(peopleAdapter); + } else { + peopleAdapter.setPeopleList(peopleList); + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (mListener != null) { + Person person = (Person) parent.getItemAtPosition(position); + mListener.onPersonSelected(person); + } + } + + // Container Activity must implement this interface + public interface OnPersonSelectedListener { + void onPersonSelected(Person person); + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleManagementActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleManagementActivity.java index 05cf4b9f9a2f..6392dc4e7b0e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleManagementActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/people/PeopleManagementActivity.java @@ -1,13 +1,11 @@ package org.wordpress.android.ui.people; -import android.app.Activity; +import android.app.FragmentManager; +import android.app.FragmentTransaction; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; import com.android.volley.VolleyError; @@ -23,17 +21,14 @@ import java.util.List; -public class PeopleManagementActivity extends AppCompatActivity { - - private PeopleAdapter mPeopleAdapter; +public class PeopleManagementActivity extends AppCompatActivity implements PeopleListFragment.OnPersonSelectedListener { + private static final String KEY_PEOPLE_LIST_FRAGMENT = "people-list-fragment"; + private static final String KEY_PERSON_DETAIL_FRAGMENT = "person-detail-fragment"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - int localBlogId = BlogUtils.getBlogLocalId(WordPress.getCurrentBlog()); - Blog blog = WordPress.getBlog(localBlogId); - ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setHomeButtonEnabled(true); @@ -41,23 +36,18 @@ public void onCreate(Bundle savedInstanceState) { } setContentView(R.layout.people_management_activity); - setTitle(R.string.people); + int localBlogId = BlogUtils.getBlogLocalId(WordPress.getCurrentBlog()); + Blog blog = WordPress.getBlog(localBlogId); + + if (savedInstanceState == null) { + PeopleListFragment peopleListFragment = PeopleListFragment.newInstance(localBlogId); - if (blog != null) { - ListView listView = (ListView)findViewById(android.R.id.list); - List peopleList = PeopleTable.getPeople(localBlogId); - mPeopleAdapter = new PeopleAdapter(this, peopleList); - listView.setAdapter(mPeopleAdapter); - - final Activity context = this; - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Person person = (Person) parent.getItemAtPosition(position); - ActivityLauncher.viewPersonDetails(context, person); - } - }); + getFragmentManager().beginTransaction() + .add(R.id.fragment_container, peopleListFragment, KEY_PEOPLE_LIST_FRAGMENT) + .commit(); + } + if (blog != null) { refreshUsersList(blog.getDotComBlogId(), localBlogId); } } @@ -68,6 +58,15 @@ public void finish() { ActivityLauncher.slideOutToRight(this); } + @Override + public void onBackPressed() { + if (getFragmentManager().getBackStackEntryCount() > 0 ){ + getFragmentManager().popBackStack(); + } else { + super.onBackPressed(); + } + } + @Override public boolean onOptionsItemSelected(final MenuItem item) { if (item.getItemId() == android.R.id.home) { @@ -77,13 +76,24 @@ public boolean onOptionsItemSelected(final MenuItem item) { return super.onOptionsItemSelected(item); } - private void refreshUsersList(String dotComBlogId, final int localBlogId) { - PeopleUtils.fetchUsers(dotComBlogId, localBlogId, new PeopleUtils.Callback() { + private void refreshUsersList(String dotComBlogId, final int localTableBlogId) { + PeopleUtils.fetchUsers(dotComBlogId, localTableBlogId, new PeopleUtils.Callback() { @Override public void onSuccess(List peopleList) { PeopleTable.savePeople(peopleList); - mPeopleAdapter.setPeopleList(peopleList); - mPeopleAdapter.notifyDataSetChanged(); + + FragmentManager fragmentManager = getFragmentManager(); + PeopleListFragment peopleListFragment = (PeopleListFragment) fragmentManager + .findFragmentByTag(KEY_PEOPLE_LIST_FRAGMENT); + PersonDetailFragment personDetailFragment = (PersonDetailFragment) fragmentManager + .findFragmentByTag(KEY_PERSON_DETAIL_FRAGMENT); + + if (peopleListFragment != null) { + peopleListFragment.refreshPeopleList(); + } + if (personDetailFragment != null) { + personDetailFragment.refreshPersonDetails(); + } } @Override @@ -97,4 +107,25 @@ public void onJSONException(JSONException exception) { } }); } + + @Override + public void onPersonSelected(Person person) { + FragmentManager fragmentManager = getFragmentManager(); + PersonDetailFragment personDetailFragment = (PersonDetailFragment) fragmentManager + .findFragmentByTag(KEY_PERSON_DETAIL_FRAGMENT); + + long personID = person.getPersonID(); + int localTableBlogID = person.getLocalTableBlogId(); + if (personDetailFragment == null) { + personDetailFragment = PersonDetailFragment.newInstance(personID, localTableBlogID); + } else { + personDetailFragment.setPersonDetails(personID, localTableBlogID); + } + if (!personDetailFragment.isAdded()) { + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.add(R.id.fragment_container, personDetailFragment, KEY_PERSON_DETAIL_FRAGMENT); + fragmentTransaction.addToBackStack(null); + fragmentTransaction.commit(); + } + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/people/PersonActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/people/PersonActivity.java deleted file mode 100644 index acae297c18d8..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/people/PersonActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.wordpress.android.ui.people; - -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; - -import org.wordpress.android.R; -import org.wordpress.android.datasets.PeopleTable; -import org.wordpress.android.models.Person; -import org.wordpress.android.models.Role; -import org.wordpress.android.ui.ActivityLauncher; -import org.wordpress.android.util.GravatarUtils; -import org.wordpress.android.widgets.WPNetworkImageView; - -public class PersonActivity extends AppCompatActivity { - public static final String EXTRA_PERSON_ID = "EXTRA_PERSON_ID"; - public static final String EXTRA_LOCAL_BLOG_ID = "EXTRA_LOCAL_BLOG_ID"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - long personId = getIntent().getExtras().getLong(EXTRA_PERSON_ID); - int localBlogId = getIntent().getExtras().getInt(EXTRA_LOCAL_BLOG_ID); - - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - } - setContentView(R.layout.person_activity); - - setTitle(R.string.edit_user); - - refreshUserDetails(personId, localBlogId); - } - - @Override - public void finish() { - super.finish(); - ActivityLauncher.slideOutToRight(this); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void refreshUserDetails(long personId, int localBlogId) { - WPNetworkImageView imgAvatar = (WPNetworkImageView) findViewById(R.id.person_avatar); - TextView txtDisplayName = (TextView) findViewById(R.id.person_display_name); - TextView txtUsername = (TextView) findViewById(R.id.person_username); - TextView txtRole = (TextView) findViewById(R.id.person_role); - TextView txtRemove = (TextView) findViewById(R.id.person_remove); - - Person person = PeopleTable.getPerson(personId, localBlogId); - - if (person != null) { - int avatarSz = getResources().getDimensionPixelSize(R.dimen.avatar_sz_large); - String avatarUrl = GravatarUtils.fixGravatarUrl(person.getAvatarUrl(), avatarSz); - - imgAvatar.setImageUrl(avatarUrl, WPNetworkImageView.ImageType.AVATAR); - txtDisplayName.setText(person.getDisplayName()); - txtUsername.setText(person.getUsername()); - txtRole.setText(Role.getLabel(this, person.getRole())); - txtRemove.setText(String.format(getString(R.string.remove_user), person.getFirstName().toUpperCase())); - - txtRemove.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // remove user - } - }); - } - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/people/PersonDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/people/PersonDetailFragment.java new file mode 100644 index 000000000000..7f65a208c769 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/people/PersonDetailFragment.java @@ -0,0 +1,109 @@ +package org.wordpress.android.ui.people; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.wordpress.android.R; +import org.wordpress.android.datasets.PeopleTable; +import org.wordpress.android.models.Person; +import org.wordpress.android.models.Role; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.GravatarUtils; +import org.wordpress.android.widgets.WPNetworkImageView; + +public class PersonDetailFragment extends Fragment { + private static String ARG_PERSON_ID = "person_id"; + private static String ARG_LOCAL_TABLE_BLOG_ID = "local_table_blog_id"; + + private long mPersonID; + private int mLocalTableBlogID; + + private WPNetworkImageView mAvatarImageView; + private TextView mDisplayNameTextView; + private TextView mUsernameTextView; + private TextView mRoleTextView; + private TextView mRemoveTextView; + + public static PersonDetailFragment newInstance(long personID, int localTableBlogID) { + PersonDetailFragment personDetailFragment = new PersonDetailFragment(); + Bundle bundle = new Bundle(); + bundle.putLong(ARG_PERSON_ID, personID); + bundle.putInt(ARG_LOCAL_TABLE_BLOG_ID, localTableBlogID); + personDetailFragment.setArguments(bundle); + return personDetailFragment; + } + + /** + * Sets the enter & pop animation for the fragment. In order to keep the animation even after the configuration + * changes, this method is used instead of FragmentTransaction for the animation. + */ + @Override + public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { + if (enter) { + return AnimatorInflater.loadAnimator(getActivity(), R.animator.fragment_slide_in_from_right); + } else { + return AnimatorInflater.loadAnimator(getActivity(), R.animator.fragment_slide_out_to_right); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.person_detail_fragment, container, false); + + mPersonID = getArguments().getLong(ARG_PERSON_ID); + mLocalTableBlogID = getArguments().getInt(ARG_LOCAL_TABLE_BLOG_ID); + + mAvatarImageView = (WPNetworkImageView) rootView.findViewById(R.id.person_avatar); + mDisplayNameTextView = (TextView) rootView.findViewById(R.id.person_display_name); + mUsernameTextView = (TextView) rootView.findViewById(R.id.person_username); + mRoleTextView = (TextView) rootView.findViewById(R.id.person_role); + mRemoveTextView = (TextView) rootView.findViewById(R.id.person_remove); + + return rootView; + } + + @Override + public void onResume() { + super.onResume(); + + refreshPersonDetails(); + } + + public void refreshPersonDetails() { + if (!isAdded()) return; + + Person person = PeopleTable.getPerson(mPersonID, mLocalTableBlogID); + if (person != null) { + int avatarSz = getResources().getDimensionPixelSize(R.dimen.avatar_sz_large); + String avatarUrl = GravatarUtils.fixGravatarUrl(person.getAvatarUrl(), avatarSz); + + mAvatarImageView.setImageUrl(avatarUrl, WPNetworkImageView.ImageType.AVATAR); + mDisplayNameTextView.setText(person.getDisplayName()); + mUsernameTextView.setText(person.getUsername()); + mRoleTextView.setText(Role.getLabel(getActivity(), person.getRole())); + mRemoveTextView.setText(String.format(getString(R.string.remove_user), person.getFirstName().toUpperCase())); + + mRemoveTextView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //TODO: remove user + } + }); + } else { + AppLog.w(AppLog.T.PEOPLE, "Person returned null from DB for personID: " + mPersonID + + " & localTableBlogID: " + mLocalTableBlogID); + } + } + + public void setPersonDetails(long personID, int localTableBlogID) { + mPersonID = personID; + mLocalTableBlogID = localTableBlogID; + refreshPersonDetails(); + } +} diff --git a/WordPress/src/main/res/animator/fragment_slide_in_from_right.xml b/WordPress/src/main/res/animator/fragment_slide_in_from_right.xml new file mode 100644 index 000000000000..2eb566a57307 --- /dev/null +++ b/WordPress/src/main/res/animator/fragment_slide_in_from_right.xml @@ -0,0 +1,9 @@ + + diff --git a/WordPress/src/main/res/animator/fragment_slide_out_to_right.xml b/WordPress/src/main/res/animator/fragment_slide_out_to_right.xml new file mode 100644 index 000000000000..75810cff31ae --- /dev/null +++ b/WordPress/src/main/res/animator/fragment_slide_out_to_right.xml @@ -0,0 +1,9 @@ + + diff --git a/WordPress/src/main/res/layout/people_list_fragment.xml b/WordPress/src/main/res/layout/people_list_fragment.xml new file mode 100644 index 000000000000..98e98a5e7578 --- /dev/null +++ b/WordPress/src/main/res/layout/people_list_fragment.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/WordPress/src/main/res/layout/people_management_activity.xml b/WordPress/src/main/res/layout/people_management_activity.xml index 08332b249e8c..f78b1f2c997e 100644 --- a/WordPress/src/main/res/layout/people_management_activity.xml +++ b/WordPress/src/main/res/layout/people_management_activity.xml @@ -1,16 +1,6 @@ - - - - - \ No newline at end of file + android:layout_height="match_parent"/> diff --git a/WordPress/src/main/res/layout/person_activity.xml b/WordPress/src/main/res/layout/person_detail_fragment.xml similarity index 90% rename from WordPress/src/main/res/layout/person_activity.xml rename to WordPress/src/main/res/layout/person_detail_fragment.xml index 9768ccd25f72..17ddd3ee5f5d 100644 --- a/WordPress/src/main/res/layout/person_activity.xml +++ b/WordPress/src/main/res/layout/person_detail_fragment.xml @@ -1,8 +1,14 @@ - + - + + diff --git a/WordPress/src/main/res/values/dimens.xml b/WordPress/src/main/res/values/dimens.xml index ce4c53f17c2a..33110aa1c98a 100644 --- a/WordPress/src/main/res/values/dimens.xml +++ b/WordPress/src/main/res/values/dimens.xml @@ -271,4 +271,5 @@ 84dp + 1dp