Commit cbf41dbc authored by Sajal Narang's avatar Sajal Narang Committed by GitHub

Merge pull request #264 from wncc/recycle

Fix performance issues of BodyFragment
parents 538ed195 7f7508db
...@@ -54,6 +54,9 @@ public class Constants { ...@@ -54,6 +54,9 @@ public class Constants {
public static final String DATA_TYPE_NEWS = "newsentry"; public static final String DATA_TYPE_NEWS = "newsentry";
public static final String DATA_TYPE_PT = "blogentry"; public static final String DATA_TYPE_PT = "blogentry";
public static final String CARD_TYPE_TITLE = "card_type_title";
public static final String CARD_TYPE_BODY_HEAD = "card_type_body_head";
/* Map */ /* Map */
public static final double MAP_Xn = 19.134417, MAP_Yn = 72.901229, MAP_Zn = 1757, MAP_Zyn = 501; public static final double MAP_Xn = 19.134417, MAP_Yn = 72.901229, MAP_Zn = 1757, MAP_Zyn = 501;
public static final double[] MAP_WEIGHTS_X = {-11.392001766454612, -36.31634553309953, 73.91269388324432, -24.14021153064087, 3.4508817531539115, -0.1462262375477863, 5.532505074667804, -1.542391995870977, 36.14211738142935}; public static final double[] MAP_WEIGHTS_X = {-11.392001766454612, -36.31634553309953, 73.91269388324432, -24.14021153064087, 3.4508817531539115, -0.1462262375477863, 5.532505074667804, -1.542391995870977, 36.14211738142935};
......
...@@ -20,7 +20,6 @@ import com.google.gson.Gson; ...@@ -20,7 +20,6 @@ import com.google.gson.Gson;
import com.squareup.picasso.Callback; import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -39,6 +38,7 @@ import app.insti.fragment.UserFragment; ...@@ -39,6 +38,7 @@ import app.insti.fragment.UserFragment;
public final class Utils { public final class Utils {
public static UpdatableList<Event> eventCache = new UpdatableList<>(); public static UpdatableList<Event> eventCache = new UpdatableList<>();
public static UpdatableList<Notification> notificationCache = null; public static UpdatableList<Notification> notificationCache = null;
public static UpdatableList<Body> bodyCache = new UpdatableList<>();
private static String sessionId; private static String sessionId;
private static RetrofitInterface retrofitInterface; private static RetrofitInterface retrofitInterface;
......
...@@ -16,11 +16,14 @@ import com.squareup.picasso.RequestCreator; ...@@ -16,11 +16,14 @@ import com.squareup.picasso.RequestCreator;
import java.util.List; import java.util.List;
import app.insti.Constants;
import app.insti.R; import app.insti.R;
import app.insti.Utils; import app.insti.Utils;
import app.insti.interfaces.CardInterface; import app.insti.interfaces.CardInterface;
import app.insti.utils.BodyHeadCard;
import app.insti.utils.BodyHeadViewHolder;
public abstract class CardAdapter<T extends CardInterface> extends RecyclerView.Adapter<CardAdapter<T>.ViewHolder> { public abstract class CardAdapter<T extends CardInterface> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<T> tList; private List<T> tList;
private Fragment mFragment; private Fragment mFragment;
...@@ -45,12 +48,23 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView. ...@@ -45,12 +48,23 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView.
@Override @Override
@NonNull @NonNull
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, final int i) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, final int viewType) {
Context context = viewGroup.getContext(); Context context = viewGroup.getContext();
LayoutInflater inflater = LayoutInflater.from(context); LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == 2) {
View titleView = inflater.inflate(R.layout.title_card, viewGroup, false);
return new TitleViewHolder(titleView);
}
if (viewType == 4) {
View bodyView = inflater.inflate(R.layout.body_head_view, viewGroup, false);
return new BodyHeadViewHolder(bodyView);
}
View postView = inflater.inflate(R.layout.feed_card, viewGroup, false); View postView = inflater.inflate(R.layout.feed_card, viewGroup, false);
final ViewHolder postViewHolder = new ViewHolder(postView); final CardViewHolder postViewHolder = new CardViewHolder(postView);
postView.setOnClickListener(new View.OnClickListener() { postView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
...@@ -63,50 +77,69 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView. ...@@ -63,50 +77,69 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView.
} }
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int i) {
T t = tList.get(i);
viewHolder.title.setText(t.getTitle()); switch (holder.getItemViewType()) {
viewHolder.subtitle.setText(t.getSubtitle()); case 0:
CardViewHolder viewHolder = (CardViewHolder) holder;
// Set transition names T t = tList.get(i);
viewHolder.avatar.setTransitionName(uid + Integer.toString((int) t.getId()) + "_sharedAvatar"); viewHolder.title.setText(t.getTitle());
viewHolder.subtitle.setText(t.getSubtitle());
if (getBigImageUrl(t) != null) {
// Show big image, hide avatar // Set transition names
viewHolder.bigPicture.setVisibility(View.VISIBLE); viewHolder.avatar.setTransitionName(uid + Integer.toString((int) t.getId()) + "_sharedAvatar");
viewHolder.bigPicture.setTransitionName(uid + Integer.toString((int) t.getId()) + "_sharedBigPicture");
viewHolder.avatar.setVisibility(View.GONE); if (getBigImageUrl(t) != null) {
// Show big image, hide avatar
// Load big image with low resolution as avatar viewHolder.bigPicture.setVisibility(View.VISIBLE);
Utils.loadImageWithPlaceholder(viewHolder.bigPicture, getBigImageUrl(t)); viewHolder.bigPicture.setTransitionName(uid + Integer.toString((int) t.getId()) + "_sharedBigPicture");
} else { viewHolder.avatar.setVisibility(View.GONE);
// Build basic request
RequestCreator requestCreator; // Load big image with low resolution as avatar
if (t.getAvatarUrl() != null) Utils.loadImageWithPlaceholder(viewHolder.bigPicture, getBigImageUrl(t));
requestCreator = Picasso.get().load(Utils.resizeImageUrl(t.getAvatarUrl())); } else {
else if (getAvatarPlaceholder(t) != 0) { // Make sure avatar is visible for recycled views
requestCreator = Picasso.get().load(getAvatarPlaceholder(t)); viewHolder.bigPicture.setVisibility(View.GONE);
} else { viewHolder.avatar.setVisibility(View.VISIBLE);
// Build basic request
RequestCreator requestCreator;
if (t.getAvatarUrl() != null)
requestCreator = Picasso.get().load(Utils.resizeImageUrl(t.getAvatarUrl()));
else if (getAvatarPlaceholder(t) != 0) {
requestCreator = Picasso.get().load(getAvatarPlaceholder(t));
} else {
return;
}
// Check if we have a placeholder
if (getAvatarPlaceholder(t) != 0) {
requestCreator.placeholder(getAvatarPlaceholder(t));
}
// Load the image
requestCreator.into(viewHolder.avatar);
}
return;
case 2:
TitleViewHolder titleViewHolder = (TitleViewHolder) holder;
titleViewHolder.title.setText(tList.get(i).getTitle());
return;
case 4:
((BodyHeadCard) tList.get(i)).bindView((BodyHeadViewHolder) holder, mFragment);
return;
default:
return; return;
}
// Check if we have a placeholder
if (getAvatarPlaceholder(t) != 0) {
requestCreator.placeholder(getAvatarPlaceholder(t));
}
// Load the image
requestCreator.into(viewHolder.avatar);
} }
} }
public class ViewHolder extends RecyclerView.ViewHolder { public class CardViewHolder extends RecyclerView.ViewHolder {
private ImageView avatar; private ImageView avatar;
private TextView title; private TextView title;
private TextView subtitle; private TextView subtitle;
private ImageView bigPicture; private ImageView bigPicture;
public ViewHolder(View itemView) { public CardViewHolder(View itemView) {
super(itemView); super(itemView);
avatar = itemView.findViewById(R.id.object_picture); avatar = itemView.findViewById(R.id.object_picture);
...@@ -116,10 +149,25 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView. ...@@ -116,10 +149,25 @@ public abstract class CardAdapter<T extends CardInterface> extends RecyclerView.
} }
} }
public class TitleViewHolder extends RecyclerView.ViewHolder {
private TextView title;
public TitleViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title_text);
}
}
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (position == 0) return 1; if (tList.get(position) == null) return 0;
else return 2;
if (tList.get(position).getSubtitle().equals(Constants.CARD_TYPE_TITLE)) {
return 2;
} else if (tList.get(position).getSubtitle().equals(Constants.CARD_TYPE_BODY_HEAD)) {
return 4;
}
return 0;
} }
@Override @Override
......
...@@ -5,6 +5,7 @@ import android.support.annotation.NonNull; ...@@ -5,6 +5,7 @@ import android.support.annotation.NonNull;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import java.util.List; import java.util.List;
import java.util.Objects;
import app.insti.interfaces.CardInterface; import app.insti.interfaces.CardInterface;
...@@ -199,4 +200,12 @@ public class Body implements CardInterface { ...@@ -199,4 +200,12 @@ public class Body implements CardInterface {
public String getAvatarUrl() { public String getAvatarUrl() {
return getBodyImageURL(); return getBodyImageURL();
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Body body = (Body) o;
return Objects.equals(bodyID, body.getBodyID());
}
} }
\ No newline at end of file
...@@ -5,15 +5,13 @@ import android.animation.Animator; ...@@ -5,15 +5,13 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.widget.NestedScrollView;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
...@@ -22,11 +20,7 @@ import android.view.LayoutInflater; ...@@ -22,11 +20,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
...@@ -36,21 +30,19 @@ import java.util.List; ...@@ -36,21 +30,19 @@ import java.util.List;
import app.insti.Constants; import app.insti.Constants;
import app.insti.R; import app.insti.R;
import app.insti.ShareURLMaker;
import app.insti.Utils; import app.insti.Utils;
import app.insti.activity.MainActivity; import app.insti.activity.MainActivity;
import app.insti.adapter.BodyAdapter; import app.insti.adapter.GenericAdapter;
import app.insti.adapter.FeedAdapter;
import app.insti.adapter.UserAdapter;
import app.insti.api.RetrofitInterface; import app.insti.api.RetrofitInterface;
import app.insti.api.model.Body; import app.insti.api.model.Body;
import app.insti.api.model.Event;
import app.insti.api.model.Role; import app.insti.api.model.Role;
import app.insti.api.model.User; import app.insti.api.model.User;
import app.insti.interfaces.CardInterface;
import app.insti.utils.BodyHeadCard;
import app.insti.utils.TitleCard;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
import ru.noties.markwon.Markwon;
/** /**
* A simple {@link Fragment} subclass. * A simple {@link Fragment} subclass.
...@@ -58,32 +50,21 @@ import ru.noties.markwon.Markwon; ...@@ -58,32 +50,21 @@ import ru.noties.markwon.Markwon;
* create an instance of this fragment. * create an instance of this fragment.
*/ */
public class BodyFragment extends BackHandledFragment implements TransitionTargetFragment { public class BodyFragment extends BackHandledFragment implements TransitionTargetFragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
String TAG = "BodyFragment"; String TAG = "BodyFragment";
// TODO: Rename and change types of parameters
private Body min_body; private Body min_body;
private SwipeRefreshLayout bodySwipeRefreshLayout; private SwipeRefreshLayout bodySwipeRefreshLayout;
private ImageView bodyPicture;
private Body body;
private boolean bodyDisplayed = false;
private boolean transitionEnded = false;
// Hold a reference to the current animator,
// so that it can be canceled mid-way.
private Animator mCurrentAnimator; private Animator mCurrentAnimator;
// The system "short" animation time duration, in milliseconds. This
// duration is ideal for subtle animations or animations that occur
// very frequently.
private int mShortAnimationDuration; private int mShortAnimationDuration;
private boolean zoomMode; private boolean zoomMode;
private ImageView expandedImageView; private ImageView expandedImageView;
private Rect startBounds; private Rect startBounds;
private float startScaleFinal; private float startScaleFinal;
private ImageView bodyPicture;
private Body body;
private boolean bodyDisplayed = false;
private boolean transitionEnded = false;
public BodyFragment() { public BodyFragment() {
// Required empty public constructor // Required empty public constructor
...@@ -110,6 +91,13 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -110,6 +91,13 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
if (zoomMode) { if (zoomMode) {
zoomOut(expandedImageView, startBounds, startScaleFinal, bodyPicture); zoomOut(expandedImageView, startBounds, startScaleFinal, bodyPicture);
zoomMode = false; zoomMode = false;
/* Show fab if the user has access */
if (((MainActivity) getActivity()).editBodyAccess(body)) {
final FloatingActionButton fab = getView().findViewById(R.id.edit_fab);
fab.show();
}
return true; return true;
} }
return false; return false;
...@@ -137,10 +125,16 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -137,10 +125,16 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
/* Initialize */ /* Initialize */
bodyDisplayed = false; bodyDisplayed = false;
body = min_body;
displayBody();
updateBody(); int index = Utils.bodyCache.indexOf(min_body);
if (index < 0) {
body = min_body;
updateBody();
} else {
body = Utils.bodyCache.get(index);
}
displayBody();
bodySwipeRefreshLayout = getActivity().findViewById(R.id.body_swipe_refresh_layout); bodySwipeRefreshLayout = getActivity().findViewById(R.id.body_swipe_refresh_layout);
bodySwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { bodySwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
...@@ -167,54 +161,29 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -167,54 +161,29 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
public void onResponse(Call<Body> call, Response<Body> response) { public void onResponse(Call<Body> call, Response<Body> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
Body bodyResponse = response.body(); Body bodyResponse = response.body();
Utils.bodyCache.updateCache(response.body());
if (!bodyDisplayed) { if (!bodyDisplayed) {
body = bodyResponse; body = bodyResponse;
displayBody(); displayBody();
} }
if (bodySwipeRefreshLayout.isRefreshing()) bodySwipeRefreshLayout.setRefreshing(false);
bodySwipeRefreshLayout.setRefreshing(false);
} }
} }
@Override @Override
public void onFailure(Call<Body> call, Throwable t) { public void onFailure(Call<Body> call, Throwable t) {
bodySwipeRefreshLayout.setRefreshing(false); bodySwipeRefreshLayout.setRefreshing(false);
// Network Error
} }
}); });
} }
private void setVisibleIfHasElements(int[] viewIds, List list) {
if (list != null && list.size() > 0) {
for (int viewId : viewIds) {
getActivity().findViewById(viewId).setVisibility(View.VISIBLE);
}
}
}
private void displayBody() { private void displayBody() {
/* Skip if we're already destroyed */ /* Skip if we're already destroyed */
if (getActivity() == null || getView() == null) return; if (getActivity() == null || getView() == null) return;
if (!body.equals(min_body)) bodyDisplayed = true; if (body != min_body) bodyDisplayed = true;
TextView bodyName = (TextView) getView().findViewById(R.id.body_name);
TextView bodySubtitle = getView().findViewById(R.id.body_subtitle);
TextView bodyDescription = (TextView) getView().findViewById(R.id.body_description);
bodyPicture = (ImageView) getActivity().findViewById(R.id.body_picture); bodyPicture = (ImageView) getActivity().findViewById(R.id.body_picture);
ImageButton webBodyButton = getActivity().findViewById(R.id.web_body_button);
ImageButton shareBodyButton = getActivity().findViewById(R.id.share_body_button);
final Button followButton = getActivity().findViewById(R.id.follow_button);
/* Show relevant card titles */
setVisibleIfHasElements(new int[]{R.id.body_events_title, R.id.event_card_recycler_view}, body.getBodyEvents());
setVisibleIfHasElements(new int[]{R.id.body_orgs_title, R.id.org_card_recycler_view}, body.getBodyChildren());
setVisibleIfHasElements(new int[]{R.id.body_parents_title, R.id.parentorg_card_recycler_view}, body.getBodyParents());
setVisibleIfHasElements(new int[]{R.id.body_people_title, R.id.people_card_recycler_view}, body.getBodyRoles());
/* Set body information */
bodyName.setText(body.getBodyName());
bodySubtitle.setText(body.getBodyShortDescription());
/* Load only low res image if transition is not completed */ /* Load only low res image if transition is not completed */
if (transitionEnded) { if (transitionEnded) {
...@@ -223,86 +192,21 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -223,86 +192,21 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
Picasso.get().load(Utils.resizeImageUrl(body.getBodyImageURL())).into(bodyPicture); Picasso.get().load(Utils.resizeImageUrl(body.getBodyImageURL())).into(bodyPicture);
} }
/* Skip for min body */
if (body == min_body) {
return;
}
bodyPicture.setOnClickListener(new View.OnClickListener() { bodyPicture.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
zoomImageFromThumb(bodyPicture); zoomImageFromThumb(bodyPicture);
final FloatingActionButton fab = getView().findViewById(R.id.edit_fab);
fab.hide();
} }
}); });
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
/* Return if it's a min body */
if (body.getBodyDescription() == null) {
return;
}
Markwon.setMarkdown(bodyDescription, body.getBodyDescription());
/* Check if user is already following
* Initialize follow button */
followButton.setBackgroundColor(getResources().getColor(body.getBodyUserFollows() ? R.color.colorAccent : R.color.colorWhite));
followButton.setText(EventFragment.getCountBadgeSpannable("FOLLOW", body.getBodyFollowersCount()));
followButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
RetrofitInterface retrofitInterface = Utils.getRetrofitInterface();
retrofitInterface.updateBodyFollowing(Utils.getSessionIDHeader(), body.getBodyID(), body.getBodyUserFollows() ? 0 : 1).enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
body.setBodyUserFollows(!body.getBodyUserFollows());
body.setBodyFollowersCount(body.getBodyUserFollows()? body.getBodyFollowersCount()+1:body.getBodyFollowersCount()-1);
followButton.setBackgroundColor(getResources().getColor(body.getBodyUserFollows() ? R.color.colorAccent : R.color.colorWhite));
followButton.setText(EventFragment.getCountBadgeSpannable("FOLLOW", body.getBodyFollowersCount()));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
Toast.makeText(getContext(), "Network Error", Toast.LENGTH_LONG).show();
}
});
}
});
/* Initialize web button */
if (body.getBodyWebsiteURL() != null && !body.getBodyWebsiteURL().isEmpty()) {
webBodyButton.setVisibility(View.VISIBLE);
webBodyButton.setOnClickListener(new View.OnClickListener() {
String bodywebURL = body.getBodyWebsiteURL();
@Override
public void onClick(View view) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(bodywebURL));
startActivity(browserIntent);
}
});
}
/* Initialize share button */
shareBodyButton.setOnClickListener(new View.OnClickListener() {
String shareUrl = ShareURLMaker.getBodyURL(body);
@Override
public void onClick(View view) {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_SUBJECT, "Sharing URL");
i.putExtra(Intent.EXTRA_TEXT, shareUrl);
startActivity(Intent.createChooser(i, "Share URL"));
}
});
/* Initialize events */
final List<Event> eventList = body.getBodyEvents();
RecyclerView eventRecyclerView = (RecyclerView) getActivity().findViewById(R.id.event_card_recycler_view);
FeedAdapter eventAdapter = new FeedAdapter(eventList, this);
eventRecyclerView.setAdapter(eventAdapter);
eventRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
/* Get users from roles */
final List<Role> roles = body.getBodyRoles(); final List<Role> roles = body.getBodyRoles();
final List<User> users = new ArrayList<>(); final List<User> users = new ArrayList<>();
for (Role role : roles) { for (Role role : roles) {
...@@ -314,35 +218,29 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -314,35 +218,29 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
} }
} }
/* Initialize People */ final List<CardInterface> cards = new ArrayList<>();
RecyclerView userRecyclerView = (RecyclerView) getActivity().findViewById(R.id.people_card_recycler_view); cards.add(new BodyHeadCard(body));
UserAdapter userAdapter = new UserAdapter(users, this); addWithTitleCard(cards, body.getBodyEvents(), "Events");
userRecyclerView.setAdapter(userAdapter); addWithTitleCard(cards, users, "People");
userRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); addWithTitleCard(cards, body.getBodyChildren(), "Organizations");
addWithTitleCard(cards, body.getBodyParents(), "Part of");
/* Initialize Parent bodies */ final RecyclerView recyclerView = (RecyclerView) getActivity().findViewById(R.id.body_recycler_view);
RecyclerView parentsRecyclerView = (RecyclerView) getActivity().findViewById(R.id.parentorg_card_recycler_view); GenericAdapter genericAdapter = new GenericAdapter(cards, this);
BodyAdapter parentAdapter = new BodyAdapter(body.getBodyParents(), this); recyclerView.setAdapter(genericAdapter);
parentsRecyclerView.setAdapter(parentAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
parentsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
/* Initialize child bodies */
RecyclerView childrenRecyclerView = (RecyclerView) getActivity().findViewById(R.id.org_card_recycler_view);
BodyAdapter childrenAdapter = new BodyAdapter(body.getBodyChildren(), this);
childrenRecyclerView.setAdapter(childrenAdapter);
childrenRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
getActivity().findViewById(R.id.loadingPanel).setVisibility(View.GONE); getActivity().findViewById(R.id.loadingPanel).setVisibility(View.GONE);
/* Show update button if role */ /* Show update button if role */
if (((MainActivity) getActivity()).editBodyAccess(body)) { if (((MainActivity) getActivity()).editBodyAccess(body)) {
final FloatingActionButton fab = (FloatingActionButton) getView().findViewById(R.id.edit_fab); final FloatingActionButton fab = getView().findViewById(R.id.edit_fab);
fab.show(); fab.show();
NestedScrollView nsv = (NestedScrollView) getView().findViewById(R.id.body_scrollview); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
nsv.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
@Override @Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (scrollY > oldScrollY) fab.hide(); super.onScrolled(recyclerView, dx, dy);
if (dy > 0) fab.hide();
else fab.show(); else fab.show();
} }
}); });
...@@ -360,6 +258,12 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -360,6 +258,12 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
} }
} }
private <R extends CardInterface> void addWithTitleCard(List<CardInterface> cards, List<R> cardsToAdd, String title) {
if (cardsToAdd.size() == 0) return;
cards.add(new TitleCard(title));
cards.addAll(cardsToAdd);
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
...@@ -367,47 +271,6 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -367,47 +271,6 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
return inflater.inflate(R.layout.fragment_body, container, false); return inflater.inflate(R.layout.fragment_body, container, false);
} }
private void zoomOut(final ImageView expandedImageView, Rect startBounds, float startScaleFinal, final View thumbView) {
expandedImageView.setBackgroundColor(0x00000000);
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator
.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.Y, startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
private void zoomImageFromThumb(final ImageView thumbView) { private void zoomImageFromThumb(final ImageView thumbView) {
// If there's an animation in progress, cancel it // If there's an animation in progress, cancel it
// immediately and proceed with this one. // immediately and proceed with this one.
...@@ -416,7 +279,7 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -416,7 +279,7 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
} }
// Load the high-resolution "zoomed-in" image. // Load the high-resolution "zoomed-in" image.
expandedImageView = (ImageView) getActivity().findViewById( expandedImageView = (ImageView) getView().findViewById(
R.id.expanded_image_body); R.id.expanded_image_body);
expandedImageView.setImageDrawable(thumbView.getDrawable()); expandedImageView.setImageDrawable(thumbView.getDrawable());
...@@ -503,4 +366,45 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge ...@@ -503,4 +366,45 @@ public class BodyFragment extends BackHandledFragment implements TransitionTarge
startScaleFinal = startScale; startScaleFinal = startScale;
zoomMode = true; zoomMode = true;
} }
private void zoomOut(final ImageView expandedImageView, Rect startBounds, float startScaleFinal, final View thumbView) {
expandedImageView.setBackgroundColor(0x00000000);
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator
.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.Y, startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
} }
...@@ -100,7 +100,7 @@ public class EventFragment extends BackHandledFragment implements TransitionTarg ...@@ -100,7 +100,7 @@ public class EventFragment extends BackHandledFragment implements TransitionTarg
* @param count integer count to show in the badge * @param count integer count to show in the badge
* @return spannable to be used as view.setText(spannable) * @return spannable to be used as view.setText(spannable)
*/ */
static Spannable getCountBadgeSpannable(String text, Integer count) { public static Spannable getCountBadgeSpannable(String text, Integer count) {
// Check for nulls // Check for nulls
if (count == null) return new SpannableString(text); if (count == null) return new SpannableString(text);
......
package app.insti.utils;
import android.support.v4.app.Fragment;
import app.insti.Constants;
import app.insti.api.model.Body;
import app.insti.interfaces.CardInterface;
public class BodyHeadCard implements CardInterface {
private Body body;
public BodyHeadCard(Body mBody) {
body = mBody;
}
@Override
public long getId() {
return 0;
}
@Override
public String getTitle() {
return null;
}
@Override
public String getSubtitle() {
return Constants.CARD_TYPE_BODY_HEAD;
}
@Override
public String getAvatarUrl() {
return null;
}
public void bindView(BodyHeadViewHolder viewHolder, Fragment fragment) {
viewHolder.bindView(body, fragment);
}
}
package app.insti.utils;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import app.insti.R;
import app.insti.ShareURLMaker;
import app.insti.Utils;
import app.insti.api.RetrofitInterface;
import app.insti.api.model.Body;
import app.insti.fragment.EventFragment;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ru.noties.markwon.Markwon;
public class BodyHeadViewHolder extends RecyclerView.ViewHolder {
private TextView bodyName;
private TextView bodySubtitle;
private TextView bodyDescription;
private ImageButton webBodyButton;
private ImageButton shareBodyButton;
private final Button followButton;
public BodyHeadViewHolder(View itemView) {
super(itemView);
bodyName = itemView.findViewById(R.id.body_name);
bodySubtitle = itemView.findViewById(R.id.body_subtitle);
bodyDescription = itemView.findViewById(R.id.body_description);
webBodyButton = itemView.findViewById(R.id.web_body_button);
shareBodyButton = itemView.findViewById(R.id.share_body_button);
followButton = itemView.findViewById(R.id.follow_button);
}
public void bindView(final Body body, final Fragment fragment) {
/* Set body information */
bodyName.setText(body.getBodyName());
bodySubtitle.setText(body.getBodyShortDescription());
/* Return if it's a min body */
if (body.getBodyDescription() == null) {
return;
}
Markwon.setMarkdown(bodyDescription, body.getBodyDescription());
/* Check if user is already following
* Initialize follow button */
followButton.setBackgroundColor(fragment.getResources().getColor(body.getBodyUserFollows() ? R.color.colorAccent : R.color.colorWhite));
followButton.setText(EventFragment.getCountBadgeSpannable("FOLLOW", body.getBodyFollowersCount()));
followButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
RetrofitInterface retrofitInterface = Utils.getRetrofitInterface();
retrofitInterface.updateBodyFollowing(Utils.getSessionIDHeader(), body.getBodyID(), body.getBodyUserFollows() ? 0 : 1).enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
body.setBodyUserFollows(!body.getBodyUserFollows());
body.setBodyFollowersCount(body.getBodyUserFollows()? body.getBodyFollowersCount()+1:body.getBodyFollowersCount()-1);
followButton.setBackgroundColor(fragment.getResources().getColor(body.getBodyUserFollows() ? R.color.colorAccent : R.color.colorWhite));
followButton.setText(EventFragment.getCountBadgeSpannable("FOLLOW", body.getBodyFollowersCount()));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
Toast.makeText(fragment.getContext(), "Network Error", Toast.LENGTH_LONG).show();
}
});
}
});
/* Initialize web button */
if (body.getBodyWebsiteURL() != null && !body.getBodyWebsiteURL().isEmpty()) {
webBodyButton.setVisibility(View.VISIBLE);
webBodyButton.setOnClickListener(new View.OnClickListener() {
String bodywebURL = body.getBodyWebsiteURL();
@Override
public void onClick(View view) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(bodywebURL));
fragment.startActivity(browserIntent);
}
});
}
/* Initialize share button */
shareBodyButton.setOnClickListener(new View.OnClickListener() {
String shareUrl = ShareURLMaker.getBodyURL(body);
@Override
public void onClick(View view) {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_SUBJECT, "Sharing URL");
i.putExtra(Intent.EXTRA_TEXT, shareUrl);
fragment.startActivity(Intent.createChooser(i, "Share URL"));
}
});
}
}
package app.insti.utils;
import app.insti.Constants;
import app.insti.interfaces.CardInterface;
public class TitleCard implements CardInterface {
private String title;
public TitleCard(String mTitle) {
title = mTitle;
}
@Override
public long getId() {
return (getSubtitle() + getTitle()).hashCode();
}
@Override
public String getTitle() {
return title;
}
@Override
public String getSubtitle() {
return Constants.CARD_TYPE_TITLE;
}
@Override
public String getAvatarUrl() {
return null;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="12dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_weight="3"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/body_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="10"
android:text="Org Title"
android:textColor="@color/colorWhite"
android:textSize="21sp"
android:textStyle="bold" />
<ImageButton
android:id="@+id/web_body_button"
android:layout_width="10dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Org Website"
android:src="@drawable/ic_language_black_24dp"
android:tint="@color/colorWhite"
android:visibility="invisible" />
<ImageButton
android:id="@+id/share_body_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Share Body"
android:src="@drawable/ic_menu_share"
android:tint="@color/colorWhite" />
</LinearLayout>
<TextView
android:id="@+id/body_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite" />
</LinearLayout>
</android.support.v7.widget.CardView>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/follow_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:text="FOLLOW"
android:textAllCaps="false"
android:textColor="@color/secondaryTextColor" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#aaa">
</View>
<TextView
android:id="@+id/body_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="12dp"
android:textColor="?attr/themeColorInverse"
android:textColorLink="?attr/urlColor"
android:textSize="16sp" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container_body" android:id="@+id/container_body"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".fragment.BodyFragment"> tools:context=".fragment.BodyFragment"
android:background="?attr/themeColor">
<RelativeLayout <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout <android.support.design.widget.AppBarLayout
android:id="@+id/body_swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<android.support.v4.widget.NestedScrollView <android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/body_scrollview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:layout_weight="1" app:layout_scrollFlags="scroll|exitUntilCollapsed">
android:orientation="vertical">
<LinearLayout <!-- HEADER -->
android:layout_width="match_parent" <RelativeLayout
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:layout_width="wrap_content"
app:layout_collapseMode="parallax"
android:background="?attr/themeColor">
<ImageView <ImageView
android:id="@+id/body_picture" android:id="@+id/body_picture"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:transitionName="sharedAvatar" />
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/themeColor" android:adjustViewBounds="true"
android:orientation="vertical"> android:scaleType="centerCrop"
android:transitionName="sharedAvatar"
<android.support.v7.widget.CardView android:background="?attr/themeColor" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="12dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_weight="3"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/body_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="10"
android:text="Org Title"
android:textColor="@color/colorWhite"
android:textSize="21sp"
android:textStyle="bold" />
<ImageButton
android:id="@+id/web_body_button"
android:layout_width="10dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Org Website"
android:src="@drawable/ic_language_black_24dp"
android:tint="@color/colorWhite"
android:visibility="invisible" />
<ImageButton
android:id="@+id/share_body_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="Share Body"
android:src="@drawable/ic_menu_share"
android:tint="@color/colorWhite" />
</LinearLayout>
<TextView
android:id="@+id/body_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite" />
</LinearLayout>
</android.support.v7.widget.CardView>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/follow_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:text="FOLLOW"
android:textAllCaps="false"
android:textColor="@color/secondaryTextColor" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#aaa">
</View>
<TextView
android:id="@+id/body_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="12dp"
android:textColor="?attr/themeColorInverse"
android:textColorLink="?attr/urlColor"
android:textSize="16sp" />
<TextView
android:id="@+id/body_events_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:fontFamily="sans-serif-light"
android:text="Events"
android:textSize="20sp"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="@+id/event_card_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:nestedScrollingEnabled="false"
android:visibility="gone" />
<TextView
android:id="@+id/body_orgs_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:fontFamily="sans-serif-light"
android:text="Organizations"
android:textSize="20sp"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="@+id/org_card_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:nestedScrollingEnabled="false"
android:visibility="gone" />
<TextView
android:id="@+id/body_people_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:fontFamily="sans-serif-light"
android:text="People"
android:textSize="20sp"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:id="@+id/people_card_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:nestedScrollingEnabled="false"
android:visibility="gone" />
<TextView </RelativeLayout>
android:id="@+id/body_parents_title" </android.support.design.widget.CollapsingToolbarLayout>
android:layout_width="match_parent" </android.support.design.widget.AppBarLayout>
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:fontFamily="sans-serif-light"
android:text="Part of"
android:textSize="20sp"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView <android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/parentorg_card_recycler_view" android:id="@+id/body_swipe_refresh_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginBottom="10dp" app:layout_behavior="@string/appbar_scrolling_view_behavior">
android:nestedScrollingEnabled="false"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.v7.widget.RecyclerView
android:id="@+id/body_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton </android.support.design.widget.CoordinatorLayout>
android:id="@+id/edit_fab"
android:layout_width="wrap_content" <android.support.design.widget.FloatingActionButton
android:layout_height="wrap_content" android:id="@+id/edit_fab"
android:layout_alignParentBottom="true" android:layout_width="wrap_content"
android:layout_alignParentRight="true" android:layout_height="wrap_content"
android:layout_margin="16dp" android:layout_margin="16dp"
android:src="@drawable/ic_edit_black_24dp" android:src="@drawable/ic_edit_black_24dp"
android:tint="@android:color/black" android:tint="@android:color/black"
android:visibility="gone" /> android:visibility="visible"
android:layout_gravity="end|bottom" />
</RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/loadingPanel" android:id="@+id/loadingPanel"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:fontFamily="sans-serif-light"
android:textSize="20sp" />
</LinearLayout>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment