From 206810c69db517a07f16f123567ef1c5fc0497e6 Mon Sep 17 00:00:00 2001 From: tom79 Date: Sat, 14 Oct 2017 14:36:48 +0200 Subject: [PATCH] Recyclerview beginning --- app/build.gradle | 1 + .../mastodon/activities/HashTagActivity.java | 38 ++- .../activities/ShowConversationActivity.java | 17 +- .../mastodon/drawers/StatusListAdapter.java | 248 +++++++------- .../fragments/DisplayStatusFragment.java | 126 +++---- .../etalab/mastodon/helper/CrossActions.java | 314 ++++++++++++++---- .../gouv/etalab/mastodon/helper/Helper.java | 10 + app/src/main/res/layout/fragment_accounts.xml | 5 +- app/src/main/res/layout/fragment_status.xml | 2 +- 9 files changed, 470 insertions(+), 291 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 692663481..8c9e3f6de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,6 +35,7 @@ dependencies { compile 'com.android.support:design:26.0.2' compile 'com.android.support:support-v4:26.0.2' compile 'com.android.support:cardview-v7:26.0.2' + compile 'com.android.support:recyclerview-v7:26.0.2' compile 'com.loopj.android:android-async-http:1.4.9' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' compile 'com.evernote:android-job:1.1.11' diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/HashTagActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/HashTagActivity.java index 10d51b8e2..3ab4c8722 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/HashTagActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/HashTagActivity.java @@ -21,6 +21,8 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.MenuItem; import android.view.View; import android.widget.AbsListView; @@ -35,6 +37,7 @@ import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.Entities.Status; import fr.gouv.etalab.mastodon.drawers.StatusListAdapter; +import fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; import mastodon.etalab.gouv.fr.mastodon.R; @@ -93,7 +96,7 @@ public class HashTagActivity extends AppCompatActivity implements OnRetrieveFeed int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); - final ListView lv_status = (ListView) findViewById(R.id.lv_status); + final RecyclerView lv_status = (RecyclerView) findViewById(R.id.lv_status); tootsPerPage = sharedpreferences.getInt(Helper.SET_TOOTS_PER_PAGE, 40); mainLoader = (RelativeLayout) findViewById(R.id.loader); nextElementLoader = (RelativeLayout) findViewById(R.id.loading_next_status); @@ -123,23 +126,28 @@ public class HashTagActivity extends AppCompatActivity implements OnRetrieveFeed R.color.colorPrimaryD, R.color.colorPrimaryDarkD); } + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(this); + lv_status.setLayoutManager(mLayoutManager); + lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + if(dy > 0){ + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if(firstVisibleItem + visibleItemCount == totalItemCount ) { + if(!flag_loading ) { + flag_loading = true; + new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.TAG, tag,null, max_id, HashTagActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - lv_status.setOnScrollListener(new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - - } - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if(firstVisibleItem + visibleItemCount == totalItemCount ) { - if(!flag_loading ) { - flag_loading = true; - new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.TAG, tag,null, max_id, HashTagActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - - nextElementLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); } - } else { - nextElementLoader.setVisibility(View.GONE); } + } }); new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.TAG, tag,null, max_id, HashTagActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java index 60439e2a6..6d4dc92b9 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java @@ -25,6 +25,8 @@ import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; @@ -77,7 +79,7 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet private Status initialStatus; public static int position; private SwipeRefreshLayout swipeRefreshLayout; - private ListView lv_status; + private RecyclerView lv_status; private boolean isRefreshed; private TextView title; private ImageView pp_actionBar; @@ -179,13 +181,18 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false,false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); - lv_status = (ListView) findViewById(R.id.lv_status); + lv_status = (RecyclerView) findViewById(R.id.lv_status); + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(this); + lv_status.setLayoutManager(mLayoutManager); lv_status.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == android.view.MotionEvent.ACTION_UP) { - - if (lv_status.getLastVisiblePosition() == lv_status.getAdapter().getCount() -1 && lv_status.getFirstVisiblePosition() > 0 && + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem + visibleItemCount == lv_status.getAdapter().getItemCount() -1 && firstVisibleItem > 0 && lv_status.getChildAt(lv_status.getChildCount() - 1).getBottom() <= lv_status.getHeight()) { swipeRefreshLayout.setRefreshing(true); @@ -267,7 +274,7 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet lv_status.setVisibility(View.VISIBLE); if( isRefreshed){ position = statuses.size()-1; - lv_status.setSelection(position); + lv_status.scrollToPosition(position); }else { lv_status.smoothScrollToPosition(position); } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index 8777c2206..b500385fc 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -34,6 +34,7 @@ import android.os.CountDownTimer; import android.support.v4.content.ContextCompat; import android.support.v7.widget.CardView; import android.support.v7.widget.PopupMenu; +import android.support.v7.widget.RecyclerView; import android.text.Html; import android.text.SpannableString; import android.text.method.LinkMovementMethod; @@ -45,7 +46,6 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; @@ -105,14 +105,13 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; * Created by Thomas on 24/04/2017. * Adapter for Status */ -public class StatusListAdapter extends BaseAdapter implements OnPostActionInterface, OnTranslatedInterface, OnRetrieveFeedsInterface { +public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnTranslatedInterface, OnRetrieveFeedsInterface { private Context context; private List statuses; private LayoutInflater layoutInflater; private ImageLoader imageLoader; private DisplayImageOptions options; - private ViewHolder holder; private boolean isOnWifi; private int translator; private int behaviorWithAttachments; @@ -126,6 +125,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf private List pins; public StatusListAdapter(Context context, RetrieveFeedsAsyncTask.Type type, String targetedId, boolean isOnWifi, int behaviorWithAttachments, int translator, List statuses){ + super(); this.context = context; this.statuses = statuses; this.isOnWifi = isOnWifi; @@ -140,24 +140,117 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf - @Override - public int getCount() { - return statuses.size(); - } - - @Override - public Object getItem(int position) { - return statuses.get(position); - } - @Override public long getItemId(int position) { return position; } @Override - public int getViewTypeCount() { - return 2; + public int getItemCount() { + return statuses.size(); + } + + private class ViewHolderEmpty extends RecyclerView.ViewHolder{ + ViewHolderEmpty(View itemView) { + super(itemView); + } + } + + class ViewHolder extends RecyclerView.ViewHolder{ + LinearLayout status_content_container; + LinearLayout status_spoiler_container; + TextView status_spoiler; + Button status_spoiler_button; + CardView card_status_container; + TextView status_content; + TextView status_content_translated; + LinearLayout status_content_translated_container; + TextView status_account_username; + TextView status_account_displayname; + ImageView status_account_profile; + ImageView status_account_profile_boost; + ImageView status_account_profile_boost_by; + TextView status_favorite_count; + TextView status_reblog_count; + TextView status_toot_date; + TextView status_reblog_user; + Button status_show_more; + ImageView status_more; + LinearLayout status_document_container; + ImageView status_prev1; + ImageView status_prev2; + ImageView status_prev3; + ImageView status_prev4; + ImageView status_prev1_play; + ImageView status_prev2_play; + ImageView status_prev3_play; + ImageView status_prev4_play; + RelativeLayout status_prev4_container; + ImageView status_reply; + ImageView status_pin; + ImageView status_privacy; + FloatingActionButton status_translate; + LinearLayout status_container2; + LinearLayout status_container3; + LinearLayout main_container; + TextView yandex_translate; + TextView google_translate; + LinearLayout status_action_container; + LinearLayout status_replies; + LinearLayout status_replies_profile_pictures; + TextView status_replies_text; + LinearLayout loader_replies; + + ImageView new_element; + + ViewHolder(View itemView) { + super(itemView); + loader_replies = itemView.findViewById(R.id.loader_replies); + card_status_container = itemView.findViewById(R.id.card_status_container); + status_document_container = (LinearLayout) itemView.findViewById(R.id.status_document_container); + status_content = (TextView) itemView.findViewById(R.id.status_content); + status_content_translated = (TextView) itemView.findViewById(R.id.status_content_translated); + status_account_username = (TextView) itemView.findViewById(R.id.status_account_username); + status_account_displayname = (TextView) itemView.findViewById(R.id.status_account_displayname); + status_account_profile = (ImageView) itemView.findViewById(R.id.status_account_profile); + status_account_profile_boost = (ImageView) itemView.findViewById(R.id.status_account_profile_boost); + status_account_profile_boost_by = (ImageView) itemView.findViewById(R.id.status_account_profile_boost_by); + status_favorite_count = (TextView) itemView.findViewById(R.id.status_favorite_count); + status_reblog_count = (TextView) itemView.findViewById(R.id.status_reblog_count); + status_pin = (ImageView) itemView.findViewById(R.id.status_pin); + status_toot_date = (TextView) itemView.findViewById(R.id.status_toot_date); + status_show_more = (Button) itemView.findViewById(R.id.status_show_more); + status_more = (ImageView) itemView.findViewById(R.id.status_more); + status_reblog_user = (TextView) itemView.findViewById(R.id.status_reblog_user); + status_prev1 = (ImageView) itemView.findViewById(R.id.status_prev1); + status_prev2 = (ImageView) itemView.findViewById(R.id.status_prev2); + status_prev3 = (ImageView) itemView.findViewById(R.id.status_prev3); + status_prev4 = (ImageView) itemView.findViewById(R.id.status_prev4); + status_prev1_play = (ImageView) itemView.findViewById(R.id.status_prev1_play); + status_prev2_play = (ImageView) itemView.findViewById(R.id.status_prev2_play); + status_prev3_play = (ImageView) itemView.findViewById(R.id.status_prev3_play); + status_prev4_play = (ImageView) itemView.findViewById(R.id.status_prev4_play); + status_container2 = (LinearLayout) itemView.findViewById(R.id.status_container2); + status_container3 = (LinearLayout) itemView.findViewById(R.id.status_container3); + status_prev4_container = (RelativeLayout) itemView.findViewById(R.id.status_prev4_container); + status_reply = (ImageView) itemView.findViewById(R.id.status_reply); + status_privacy = (ImageView) itemView.findViewById(R.id.status_privacy); + status_translate = (FloatingActionButton) itemView.findViewById(R.id.status_translate); + status_content_translated_container = (LinearLayout) itemView.findViewById(R.id.status_content_translated_container); + main_container = (LinearLayout) itemView.findViewById(R.id.main_container); + status_spoiler_container = (LinearLayout) itemView.findViewById(R.id.status_spoiler_container); + status_content_container = (LinearLayout) itemView.findViewById(R.id.status_content_container); + status_spoiler = (TextView) itemView.findViewById(R.id.status_spoiler); + status_spoiler_button = (Button) itemView.findViewById(R.id.status_spoiler_button); + yandex_translate = (TextView) itemView.findViewById(R.id.yandex_translate); + google_translate = (TextView) itemView.findViewById(R.id.google_translate); + status_replies = (LinearLayout) itemView.findViewById(R.id.status_replies); + status_replies_profile_pictures = (LinearLayout) itemView.findViewById(R.id.status_replies_profile_pictures); + status_replies_text = (TextView) itemView.findViewById(R.id.status_replies_text); + new_element = (ImageView) itemView.findViewById(R.id.new_element); + status_action_container = (LinearLayout) itemView.findViewById(R.id.status_action_container); + + } } @Override @@ -175,13 +268,23 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf return DISPLAYED_STATUS; } } + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if( viewType == DISPLAYED_STATUS) + return new ViewHolder(layoutInflater.inflate(R.layout.drawer_status, parent, false)); + else + return new ViewHolderEmpty(layoutInflater.inflate(R.layout.drawer_status, parent, false)); + } + @Override - public View getView(final int position, View convertView, ViewGroup parent) { + public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { + + if( viewHolder.getItemViewType() == HIDDEN_STATUS){ - if( getItemViewType(position) == HIDDEN_STATUS){ - return new View(context); }else { + final ViewHolder holder = (ViewHolder) viewHolder; + holder.card_status_container.setVisibility(View.VISIBLE); final Status status = statuses.get(position); imageLoader = ImageLoader.getInstance(); File cacheDir = new File(context.getCacheDir(), context.getString(R.string.app_name)); @@ -197,57 +300,6 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false) .cacheOnDisk(true).resetViewBeforeLoading(true).build(); - if (convertView == null) { - convertView = layoutInflater.inflate(R.layout.drawer_status, parent, false); - holder = new ViewHolder(); - holder.loader_replies = (LinearLayout) convertView.findViewById(R.id.loader_replies); - holder.card_status_container = (CardView) convertView.findViewById(R.id.card_status_container); - holder.status_document_container = (LinearLayout) convertView.findViewById(R.id.status_document_container); - holder.status_content = (TextView) convertView.findViewById(R.id.status_content); - holder.status_content_translated = (TextView) convertView.findViewById(R.id.status_content_translated); - holder.status_account_username = (TextView) convertView.findViewById(R.id.status_account_username); - holder.status_account_displayname = (TextView) convertView.findViewById(R.id.status_account_displayname); - holder.status_account_profile = (ImageView) convertView.findViewById(R.id.status_account_profile); - holder.status_account_profile_boost = (ImageView) convertView.findViewById(R.id.status_account_profile_boost); - holder.status_account_profile_boost_by = (ImageView) convertView.findViewById(R.id.status_account_profile_boost_by); - holder.status_favorite_count = (TextView) convertView.findViewById(R.id.status_favorite_count); - holder.status_reblog_count = (TextView) convertView.findViewById(R.id.status_reblog_count); - holder.status_pin = (ImageView) convertView.findViewById(R.id.status_pin); - holder.status_toot_date = (TextView) convertView.findViewById(R.id.status_toot_date); - holder.status_show_more = (Button) convertView.findViewById(R.id.status_show_more); - holder.status_more = (ImageView) convertView.findViewById(R.id.status_more); - holder.status_reblog_user = (TextView) convertView.findViewById(R.id.status_reblog_user); - holder.status_prev1 = (ImageView) convertView.findViewById(R.id.status_prev1); - holder.status_prev2 = (ImageView) convertView.findViewById(R.id.status_prev2); - holder.status_prev3 = (ImageView) convertView.findViewById(R.id.status_prev3); - holder.status_prev4 = (ImageView) convertView.findViewById(R.id.status_prev4); - holder.status_prev1_play = (ImageView) convertView.findViewById(R.id.status_prev1_play); - holder.status_prev2_play = (ImageView) convertView.findViewById(R.id.status_prev2_play); - holder.status_prev3_play = (ImageView) convertView.findViewById(R.id.status_prev3_play); - holder.status_prev4_play = (ImageView) convertView.findViewById(R.id.status_prev4_play); - holder.status_container2 = (LinearLayout) convertView.findViewById(R.id.status_container2); - holder.status_container3 = (LinearLayout) convertView.findViewById(R.id.status_container3); - holder.status_prev4_container = (RelativeLayout) convertView.findViewById(R.id.status_prev4_container); - holder.status_reply = (ImageView) convertView.findViewById(R.id.status_reply); - holder.status_privacy = (ImageView) convertView.findViewById(R.id.status_privacy); - holder.status_translate = (FloatingActionButton) convertView.findViewById(R.id.status_translate); - holder.status_content_translated_container = (LinearLayout) convertView.findViewById(R.id.status_content_translated_container); - holder.main_container = (LinearLayout) convertView.findViewById(R.id.main_container); - holder.status_spoiler_container = (LinearLayout) convertView.findViewById(R.id.status_spoiler_container); - holder.status_content_container = (LinearLayout) convertView.findViewById(R.id.status_content_container); - holder.status_spoiler = (TextView) convertView.findViewById(R.id.status_spoiler); - holder.status_spoiler_button = (Button) convertView.findViewById(R.id.status_spoiler_button); - holder.yandex_translate = (TextView) convertView.findViewById(R.id.yandex_translate); - holder.google_translate = (TextView) convertView.findViewById(R.id.google_translate); - holder.status_replies = (LinearLayout) convertView.findViewById(R.id.status_replies); - holder.status_replies_profile_pictures = (LinearLayout) convertView.findViewById(R.id.status_replies_profile_pictures); - holder.status_replies_text = (TextView) convertView.findViewById(R.id.status_replies_text); - holder.new_element = (ImageView) convertView.findViewById(R.id.new_element); - holder.status_action_container = (LinearLayout) convertView.findViewById(R.id.status_action_container); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); @@ -902,7 +954,6 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf - final View finalConvertView = convertView; final View attached = holder.status_more; holder.status_more.setOnClickListener(new View.OnClickListener() { @Override @@ -986,7 +1037,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf @Override public void run() { - Bitmap bitmap = Helper.convertTootIntoBitmap(context, finalConvertView); + Bitmap bitmap = Helper.convertTootIntoBitmap(context, holder.card_status_container); status.setTakingScreenShot(false); statusListAdapter.notifyDataSetChanged(); Intent intent = new Intent(context, TootActivity.class); @@ -1086,14 +1137,17 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf } } }); - return convertView; } - } - private void loadAttachments(final Status status, ViewHolder holder){ + + + + + private void loadAttachments(final Status status, RecyclerView.ViewHolder viewHolder){ + final ViewHolder holder = (ViewHolder) viewHolder; List attachments = status.getMedia_attachments(); if( attachments != null && attachments.size() > 0){ int i = 0; @@ -1379,53 +1433,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf } - private class ViewHolder { - LinearLayout status_content_container; - LinearLayout status_spoiler_container; - TextView status_spoiler; - Button status_spoiler_button; - CardView card_status_container; - TextView status_content; - TextView status_content_translated; - LinearLayout status_content_translated_container; - TextView status_account_username; - TextView status_account_displayname; - ImageView status_account_profile; - ImageView status_account_profile_boost; - ImageView status_account_profile_boost_by; - TextView status_favorite_count; - TextView status_reblog_count; - TextView status_toot_date; - TextView status_reblog_user; - Button status_show_more; - ImageView status_more; - LinearLayout status_document_container; - ImageView status_prev1; - ImageView status_prev2; - ImageView status_prev3; - ImageView status_prev4; - ImageView status_prev1_play; - ImageView status_prev2_play; - ImageView status_prev3_play; - ImageView status_prev4_play; - RelativeLayout status_prev4_container; - ImageView status_reply; - ImageView status_pin; - ImageView status_privacy; - FloatingActionButton status_translate; - LinearLayout status_container2; - LinearLayout status_container3; - LinearLayout main_container; - TextView yandex_translate; - TextView google_translate; - LinearLayout status_action_container; - LinearLayout status_replies; - LinearLayout status_replies_profile_pictures; - TextView status_replies_text; - LinearLayout loader_replies; - ImageView new_element; - } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java index 215db5a59..09406ac96 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayStatusFragment.java @@ -25,6 +25,8 @@ import android.support.v4.app.Fragment; import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.ViewCompat; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -75,7 +77,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn private String targetedId; private String tag; private boolean swiped; - private ListView lv_status; + private RecyclerView lv_status; private boolean isOnWifi; private int behaviorWithAttachments; private boolean showMediaOnly, showPinned; @@ -128,7 +130,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); if( type == RetrieveFeedsAsyncTask.Type.HOME) lastReadStatus = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null); - lv_status = (ListView) rootView.findViewById(R.id.lv_status); + lv_status = (RecyclerView) rootView.findViewById(R.id.lv_status); mainLoader = (RelativeLayout) rootView.findViewById(R.id.loader); nextElementLoader = (RelativeLayout) rootView.findViewById(R.id.loading_next_status); textviewNoAction = (RelativeLayout) rootView.findViewById(R.id.no_action); @@ -142,47 +144,34 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn if (hideHeader && Build.VERSION.SDK_INT >= 21) ViewCompat.setNestedScrollingEnabled(lv_status, true); - lv_status.setOnScrollListener(new AbsListView.OnScrollListener() { - int lastFirstVisibleItem = 0; - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(context); + lv_status.setLayoutManager(mLayoutManager); - } - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (hideHeader && Build.VERSION.SDK_INT < 21) { - if(firstVisibleItem == 0 && Helper.listIsAtTop(lv_status)){ - Intent intent = new Intent(Helper.HEADER_ACCOUNT+instanceValue); - intent.putExtra("hide", false); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); - }else if (view.getId() == lv_status.getId() && totalItemCount > visibleItemCount) { - final int currentFirstVisibleItem = lv_status.getFirstVisiblePosition(); - if (currentFirstVisibleItem > lastFirstVisibleItem) { - Intent intent = new Intent(Helper.HEADER_ACCOUNT + instanceValue); - intent.putExtra("hide", true); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); - } else if (currentFirstVisibleItem < lastFirstVisibleItem) { - Intent intent = new Intent(Helper.HEADER_ACCOUNT + instanceValue); - intent.putExtra("hide", false); - LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + lv_status.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + if(dy > 0){ + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if(firstVisibleItem + visibleItemCount == totalItemCount ) { + if(!flag_loading ) { + flag_loading = true; + if( type == RetrieveFeedsAsyncTask.Type.USER) + asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else if( type == RetrieveFeedsAsyncTask.Type.TAG) + asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else + asyncTask = new RetrieveFeedsAsyncTask(context, type, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + nextElementLoader.setVisibility(View.VISIBLE); } - lastFirstVisibleItem = currentFirstVisibleItem; + } else { + nextElementLoader.setVisibility(View.GONE); } } - if(firstVisibleItem + visibleItemCount == totalItemCount ) { - if(!flag_loading ) { - flag_loading = true; - if( type == RetrieveFeedsAsyncTask.Type.USER) - asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else if( type == RetrieveFeedsAsyncTask.Type.TAG) - asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - else - asyncTask = new RetrieveFeedsAsyncTask(context, type, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - nextElementLoader.setVisibility(View.VISIBLE); - } - } else { - nextElementLoader.setVisibility(View.GONE); - } } }); @@ -336,9 +325,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn if (status != null) { //Update the id of the last toot retrieved MainActivity.lastHomeId = status.getId(); - int index = lv_status.getFirstVisiblePosition() + 1; - View v = lv_status.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); status.setReplies(new ArrayList()); statuses.add(0,status); SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); @@ -346,7 +332,6 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn if( !status.getAccount().getId().equals(userId)) MainActivity.countNewStatus++; statusListAdapter.notifyDataSetChanged(); - lv_status.setSelectionFromTop(index, top); if (textviewNoAction.getVisibility() == View.VISIBLE) textviewNoAction.setVisibility(View.GONE); } @@ -355,15 +340,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn return; //Avoids the array to be too big... if (status != null) { - if (lv_status.getFirstVisiblePosition() == 0) { - status.setReplies(new ArrayList()); - status.setNew(false); - statuses.add(0, status); - statusListAdapter.notifyDataSetChanged(); - } else { - status.setReplies(new ArrayList()); - statuses.add(0, status); - } + status.setReplies(new ArrayList()); + statuses.add(0, status); if (textviewNoAction.getVisibility() == View.VISIBLE) textviewNoAction.setVisibility(View.GONE); } @@ -374,11 +352,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn * Refresh status in list */ public void refreshFilter(){ - int index = lv_status.getFirstVisiblePosition() + 1; - View v = lv_status.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); statusListAdapter.notifyDataSetChanged(); - lv_status.setSelectionFromTop(index, top); } @Override @@ -543,39 +517,19 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn for (Status st : this.statuses) { knownId.add(st.getId()); } - if( lv_status.getFirstVisiblePosition() > 1 ) { - int index = lv_status.getFirstVisiblePosition() + statuses.size(); - View v = lv_status.getChildAt(0); - int top = (v == null) ? 0 : v.getTop(); - for (int i = statuses.size() - 1; i >= 0; i--) { - if (!knownId.contains(statuses.get(i).getId())) { - if (type == RetrieveFeedsAsyncTask.Type.HOME) - statuses.get(i).setNew(true); - statuses.get(i).setReplies(new ArrayList()); - this.statuses.add(0, statuses.get(i)); - SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - if (type == RetrieveFeedsAsyncTask.Type.HOME && !statuses.get(i).getAccount().getId().equals(userId)) - MainActivity.countNewStatus++; - } + for (int i = statuses.size() - 1; i >= 0; i--) { + if (!knownId.contains(statuses.get(i).getId())) { + if (type == RetrieveFeedsAsyncTask.Type.HOME) + statuses.get(i).setNew(true); + statuses.get(i).setReplies(new ArrayList()); + this.statuses.add(0, statuses.get(i)); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + if (type == RetrieveFeedsAsyncTask.Type.HOME && !statuses.get(i).getAccount().getId().equals(userId)) + MainActivity.countNewStatus++; } - statusListAdapter.notifyDataSetChanged(); - lv_status.setSelectionFromTop(index, top); - }else { - for (int i = statuses.size() - 1; i >= 0; i--) { - if (!knownId.contains(statuses.get(i).getId())) { - if (type == RetrieveFeedsAsyncTask.Type.HOME) - statuses.get(i).setNew(true); - statuses.get(i).setReplies(new ArrayList()); - this.statuses.add(0, statuses.get(i)); - SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); - String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); - if (type == RetrieveFeedsAsyncTask.Type.HOME && !statuses.get(i).getAccount().getId().equals(userId)) - MainActivity.countNewStatus++; - } - } - statusListAdapter.notifyDataSetChanged(); } + statusListAdapter.notifyDataSetChanged(); try { ((MainActivity) context).updateHomeCounter(); }catch (Exception ignored){} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/CrossActions.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/CrossActions.java index 7acbad4f5..2cc0fd40e 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/CrossActions.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/CrossActions.java @@ -24,6 +24,7 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; import android.text.Html; import android.util.Log; import android.widget.BaseAdapter; @@ -117,67 +118,6 @@ public class CrossActions { } } - public static void doCrossReply(final Context context, final Status status, final RetrieveFeedsAsyncTask.Type type, boolean limitedToOwner){ - List accounts = connectedAccounts(context, status, limitedToOwner); - - if( accounts.size() == 1) { - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - if( status.getReblog() != null ) - b.putParcelable("tootReply", status.getReblog()); - else - b.putParcelable("tootReply", status); - intent.putExtras(b); //Put your id to your next Intent - context.startActivity(intent); - if( type == RetrieveFeedsAsyncTask.Type.CONTEXT ){ - try { - //Avoid to open multi activities when replying in a conversation - ((ShowConversationActivity)context).finish(); - }catch (Exception ignored){} - - } - }else { - AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); - builderSingle.setTitle(context.getString(R.string.choose_accounts)); - final AccountsSearchAdapter accountsSearchAdapter = new AccountsSearchAdapter(context, accounts, true); - final Account[] accountArray = new Account[accounts.size()]; - int i = 0; - for(Account account: accounts){ - accountArray[i] = account; - i++; - } - builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - builderSingle.setAdapter(accountsSearchAdapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Account account = accountArray[which]; - Intent intent = new Intent(context, TootActivity.class); - Bundle b = new Bundle(); - if( status.getReblog() != null ) - b.putParcelable("tootReply", status.getReblog()); - else - b.putParcelable("tootReply", status); - b.putParcelable("accountReply", account); - intent.putExtras(b); //Put your id to your next Intent - context.startActivity(intent); - if( type == RetrieveFeedsAsyncTask.Type.CONTEXT ){ - try { - //Avoid to open multi activities when replying in a conversation - ((ShowConversationActivity)context).finish(); - }catch (Exception ignored){} - - } - dialog.dismiss(); - } - }); - builderSingle.show(); - } - } /** @@ -335,4 +275,256 @@ public class CrossActions { } + + + + + + + + + + + + + + + + + + + public static void doCrossAction(final Context context, final Status status, final API.StatusAction doAction, final RecyclerView.Adapter baseAdapter, final OnPostActionInterface onPostActionInterface, boolean limitedToOwner){ + List accounts = connectedAccounts(context, status, limitedToOwner); + final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); + + boolean undoAction = (doAction == API.StatusAction.UNPIN || doAction == API.StatusAction.UNREBLOG || doAction == API.StatusAction.UNFAVOURITE ); + //Undo actions won't ask for choosing a user + if( accounts.size() == 1 || undoAction ) { + + boolean confirmation = false; + if( doAction == API.StatusAction.UNFAVOURITE || doAction == API.StatusAction.FAVOURITE) + confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION_FAV, false); + else if( doAction == API.StatusAction.UNREBLOG || doAction == API.StatusAction.REBLOG ) + confirmation = sharedpreferences.getBoolean(Helper.SET_NOTIF_VALIDATION, true); + if (confirmation) + displayConfirmationDialog(context, doAction, status, baseAdapter, onPostActionInterface); + else { + if( doAction == API.StatusAction.REBLOG || doAction == API.StatusAction.UNREBLOG) + reblogAction(context, status, baseAdapter, onPostActionInterface); + else if( doAction == API.StatusAction.FAVOURITE || doAction == API.StatusAction.UNFAVOURITE) + favouriteAction(context, status, baseAdapter, onPostActionInterface); + else if ( doAction == API.StatusAction.PIN || doAction == API.StatusAction.UNPIN) + pinAction(context, status, baseAdapter, onPostActionInterface); + } + }else { + AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); + builderSingle.setTitle(context.getString(R.string.choose_accounts)); + final AccountsSearchAdapter accountsSearchAdapter = new AccountsSearchAdapter(context, accounts, true); + final Account[] accountArray = new Account[accounts.size()]; + int i = 0; + for(Account account: accounts){ + accountArray[i] = account; + i++; + } + builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + builderSingle.setAdapter(accountsSearchAdapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Account selectedAccount = accountArray[which]; + String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + SQLiteDatabase db = Sqlite.getInstance(context, Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + Account loggedAccount = new AccountDAO(context, db).getAccountByID(userId); + if(loggedAccount.getInstance().equals(selectedAccount.getInstance())){ + new PostActionAsyncTask(context, selectedAccount, doAction, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }else{ //Account is from another instance + new PostActionAsyncTask(context, selectedAccount, status, doAction, onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + if( selectedAccount.getInstance().equals(loggedAccount.getInstance()) && selectedAccount.getId().equals(loggedAccount.getId())) { + if (doAction == API.StatusAction.REBLOG) { + status.setReblogged(true); + } else if (doAction == API.StatusAction.FAVOURITE) { + status.setFavourited(true); + } else if (doAction == API.StatusAction.PIN) { + status.setPinned(true); + } + baseAdapter.notifyDataSetChanged(); + } + dialog.dismiss(); + } + }); + builderSingle.show(); + } + } + + public static void doCrossReply(final Context context, final Status status, final RetrieveFeedsAsyncTask.Type type, boolean limitedToOwner){ + List accounts = connectedAccounts(context, status, limitedToOwner); + + if( accounts.size() == 1) { + Intent intent = new Intent(context, TootActivity.class); + Bundle b = new Bundle(); + if( status.getReblog() != null ) + b.putParcelable("tootReply", status.getReblog()); + else + b.putParcelable("tootReply", status); + intent.putExtras(b); //Put your id to your next Intent + context.startActivity(intent); + if( type == RetrieveFeedsAsyncTask.Type.CONTEXT ){ + try { + //Avoid to open multi activities when replying in a conversation + ((ShowConversationActivity)context).finish(); + }catch (Exception ignored){} + + } + }else { + AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); + builderSingle.setTitle(context.getString(R.string.choose_accounts)); + final AccountsSearchAdapter accountsSearchAdapter = new AccountsSearchAdapter(context, accounts, true); + final Account[] accountArray = new Account[accounts.size()]; + int i = 0; + for(Account account: accounts){ + accountArray[i] = account; + i++; + } + builderSingle.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + builderSingle.setAdapter(accountsSearchAdapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Account account = accountArray[which]; + Intent intent = new Intent(context, TootActivity.class); + Bundle b = new Bundle(); + if( status.getReblog() != null ) + b.putParcelable("tootReply", status.getReblog()); + else + b.putParcelable("tootReply", status); + b.putParcelable("accountReply", account); + intent.putExtras(b); //Put your id to your next Intent + context.startActivity(intent); + if( type == RetrieveFeedsAsyncTask.Type.CONTEXT ){ + try { + //Avoid to open multi activities when replying in a conversation + ((ShowConversationActivity)context).finish(); + }catch (Exception ignored){} + + } + dialog.dismiss(); + } + }); + builderSingle.show(); + } + } + + + /** + * Display a validation message + * @param action int + * @param status Status + */ + private static void displayConfirmationDialog(final Context context, final API.StatusAction action, final Status status, final RecyclerView.Adapter baseAdapter, final OnPostActionInterface onPostActionInterface){ + + String title = null; + if( action == API.StatusAction.FAVOURITE){ + title = context.getString(R.string.favourite_add); + }else if( action == API.StatusAction.UNFAVOURITE){ + title = context.getString(R.string.favourite_remove); + }else if( action == API.StatusAction.REBLOG){ + title = context.getString(R.string.reblog_add); + }else if(action == API.StatusAction.UNREBLOG){ + title = context.getString(R.string.reblog_remove); + }else if ( action == API.StatusAction.PIN) { + title = context.getString(R.string.pin_add); + }else if (action == API.StatusAction.UNPIN) { + title = context.getString(R.string.pin_remove); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + builder.setMessage(Html.fromHtml(status.getContent(), Html.FROM_HTML_MODE_LEGACY)); + else + //noinspection deprecation + builder.setMessage(Html.fromHtml(status.getContent())); + builder.setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(title) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if( action == API.StatusAction.REBLOG || action == API.StatusAction.UNREBLOG) + reblogAction(context, status, baseAdapter, onPostActionInterface); + else if( action == API.StatusAction.FAVOURITE || action == API.StatusAction.UNFAVOURITE) + favouriteAction(context, status, baseAdapter, onPostActionInterface); + else if ( action == API.StatusAction.PIN || action == API.StatusAction.UNPIN) + pinAction(context, status, baseAdapter, onPostActionInterface); + dialog.dismiss(); + } + }) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + + }) + .show(); + } + + /** + * Favourites/Unfavourites a status + * @param status Status + */ + private static void favouriteAction(Context context, Status status, RecyclerView.Adapter baseAdapter, OnPostActionInterface onPostActionInterface){ + if( status.isFavourited() || (status.getReblog() != null && status.getReblog().isFavourited())){ + new PostActionAsyncTask(context, API.StatusAction.UNFAVOURITE, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setFavourited(false); + }else{ + new PostActionAsyncTask(context, API.StatusAction.FAVOURITE, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setFavourited(true); + } + baseAdapter.notifyDataSetChanged(); + } + + /** + * Reblog/Unreblog a status + * @param status Status + */ + private static void reblogAction(Context context, Status status, RecyclerView.Adapter baseAdapter, OnPostActionInterface onPostActionInterface){ + if( status.isReblogged() || (status.getReblog()!= null && status.getReblog().isReblogged())){ + String statusId = status.getReblog()!=null?status.getReblog().getId():status.getId(); + new PostActionAsyncTask(context, API.StatusAction.UNREBLOG, statusId, onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setReblogged(false); + }else{ + new PostActionAsyncTask(context, API.StatusAction.REBLOG, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setReblogged(true); + } + baseAdapter.notifyDataSetChanged(); + } + + /** + * Pin or unpin a status + * @param status Status + */ + private static void pinAction(Context context, Status status, RecyclerView.Adapter baseAdapter, OnPostActionInterface onPostActionInterface) { + + if (status.isPinned()) { + new PostActionAsyncTask(context, API.StatusAction.UNPIN, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setPinned(false); + } else { + new PostActionAsyncTask(context, API.StatusAction.PIN, status.getId(), onPostActionInterface).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + status.setPinned(true); + } + baseAdapter.notifyDataSetChanged(); + } + + + + } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index 6431b3b9d..977fd9583 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -58,6 +58,7 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; +import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.text.Html; import android.text.SpannableString; @@ -1527,6 +1528,15 @@ public class Helper { } } + /** + * Returns true if a ListView is at its top position + * @param listView ListView + * @return boolean + */ + public static boolean listIsAtTop(RecyclerView listView) { + return listView.getChildCount() == 0 || listView.getChildAt(0).getTop() == 0; + } + /** * Returns true if a ListView is at its top position * @param listView ListView diff --git a/app/src/main/res/layout/fragment_accounts.xml b/app/src/main/res/layout/fragment_accounts.xml index 977406ff7..53f206078 100644 --- a/app/src/main/res/layout/fragment_accounts.xml +++ b/app/src/main/res/layout/fragment_accounts.xml @@ -27,14 +27,13 @@ android:layout_width="match_parent" android:id="@+id/swipeContainer" android:layout_height="match_parent"> - - + /> -