io.github.sin3hz.fastjumper.sample.AppListFragment.java Source code

Java tutorial

Introduction

Here is the source code for io.github.sin3hz.fastjumper.sample.AppListFragment.java

Source

/*
 * Copyright (C) 2016 sin3hz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.sin3hz.fastjumper.sample;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import io.github.sin3hz.fastjumper.FastJumper;
import io.github.sin3hz.fastjumper.callback.LinearScrollCalculator;
import io.github.sin3hz.fastjumper.callback.SpannableCallback;
import io.github.sin3hz.fastjumper.sample.utils.AlphabeticIndexCompat;
import io.github.sin3hz.fastjumper.sample.utils.DividerItemDecoration;

public class AppListFragment extends Fragment implements MainActivity.Listener {

    private static final String TAG = AppListFragment.class.getSimpleName();

    private static final int LOADER_PHOTO = 1;

    public static AppListFragment newInstance() {
        AppListFragment fragment = new AppListFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    private View mEmptyView;
    private View mContentView;
    private RecyclerView mRecyclerView;
    private SwipeRefreshLayout mSwipeRefreshLayout;

    private AppListAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private FastJumper mFastJumper;
    private SpannableCallback mJumperCallback;
    private FloatingActionButton mFab;

    private DividerItemDecoration mDividerDecoration;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_app_list, container, false);
        mEmptyView = view.findViewById(R.id.empty);
        mContentView = view.findViewById(R.id.content);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.list);
        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe);
        mFab = (FloatingActionButton) getActivity().findViewById(R.id.fab);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                getLoaderManager().restartLoader(0, null, mLoaderCallbacks);
            }
        });
        mAdapter = new AppListAdapter();
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mLayoutManager = new LinearLayoutManager(getContext());
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setHasFixedSize(true);
        mDividerDecoration = new DividerItemDecoration(getContext());
        setupFastJumper();
    }

    private void setupFastJumper() {
        mJumperCallback = new SpannableCallback() {

            @Override
            public boolean isSectionEnable() {
                return true;
            }

            @Override
            public String getSection(int position) {
                return mAdapter.getSection(position);
            }
        };
        mJumperCallback.setScrollCalculator(new LinearScrollCalculator(mRecyclerView) {
            @Override
            public int getItemHeight(int position) {
                return mAdapter.getItemHeight(position);
            }
        });
        mFastJumper = new FastJumper(mJumperCallback);
        //mFastJumper = new FastJumper(new SimpleCallback());
        mFastJumper.attachToRecyclerView(mRecyclerView);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(LOADER_PHOTO, null, mLoaderCallbacks);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_app_list, menu);
    }

    private boolean mUseDivider;
    private boolean mLoadMore;

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        menu.findItem(R.id.action_use_divider).setChecked(mUseDivider);
        menu.findItem(R.id.action_load_more).setChecked(mLoadMore);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_use_divider: {
            mUseDivider = !item.isChecked();
            item.setChecked(mUseDivider);
            setupDivider();
            return true;
        }
        case R.id.action_load_more: {
            mLoadMore = !item.isChecked();
            return true;
        }
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void setupDivider() {
        if (mUseDivider) {
            mRecyclerView.addItemDecoration(mDividerDecoration, 0);
        } else {
            mRecyclerView.removeItemDecoration(mDividerDecoration);
        }
        // Item height changed, invalidate ScrollerCalculator to clear its cache.
        mJumperCallback.getScrollCalculator().invalidateCache();
        // Invalidate FastJumper to update scroller's position.
        mFastJumper.invalidate();
    }

    private LoaderManager.LoaderCallbacks<List<AppInfo>> mLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<AppInfo>>() {

        @Override
        public Loader<List<AppInfo>> onCreateLoader(int id, Bundle args) {
            return new AppLoader(getContext());
        }

        @Override
        public void onLoadFinished(Loader<List<AppInfo>> loader, final List<AppInfo> data) {
            mSwipeRefreshLayout.setRefreshing(false);
            //mAppInfoList.clear();
            mAppInfoList.addAll(data);
            mAdapter.notifyDataSetChanged();
            if (data.size() == 0) {
                showEmptyView();
            } else {
                showContentView();
            }
        }

        @Override
        public void onLoaderReset(Loader<List<AppInfo>> loader) {

        }
    };

    private List<AppInfo> mAppInfoList = new ArrayList<>();

    private static class AppInfo implements Comparable<AppInfo> {
        String name;
        Drawable icon;
        String section;

        public AppInfo() {
        }

        @Override
        public int compareTo(@NonNull AppInfo another) {
            return this.section.compareTo(another.section);
        }
    }

    private static class AppLoader extends AsyncTaskLoader<List<AppInfo>> {

        private AlphabeticIndexCompat mIndexer;
        private final PackageManager mPackageManager;
        private List<AppInfo> mApps;

        public AppLoader(Context context) {
            super(context);
            mPackageManager = getContext().getPackageManager();
            mIndexer = new AlphabeticIndexCompat(context);
        }

        @Override
        public List<AppInfo> loadInBackground() {
            List<ApplicationInfo> apps = mPackageManager.getInstalledApplications(0);

            if (apps == null) {
                apps = new ArrayList<>();
            }

            List<AppInfo> appInfos = new ArrayList<>(apps.size());
            for (int i = 0; i < apps.size(); i++) {
                AppInfo appInfo = new AppInfo();
                appInfo.icon = apps.get(i).loadIcon(mPackageManager);
                appInfo.name = apps.get(i).loadLabel(mPackageManager).toString();
                appInfo.section = mIndexer.computeSectionName(appInfo.name);
                appInfos.add(appInfo);
            }
            Collections.sort(appInfos);
            return appInfos;
        }

        @Override
        public void deliverResult(List<AppInfo> apps) {
            if (isReset()) {
                if (apps != null) {
                    releaseResources(apps);
                    return;
                }
            }

            List<AppInfo> oldApps = mApps;
            mApps = apps;

            if (isStarted()) {
                super.deliverResult(apps);
            }

            if (oldApps != null && oldApps != apps) {
                releaseResources(oldApps);
            }
        }

        @Override
        protected void onStartLoading() {
            if (mApps != null) {
                deliverResult(mApps);
            }

            if (takeContentChanged()) {
                forceLoad();
            } else if (mApps == null) {
                forceLoad();
            }
        }

        @Override
        protected void onStopLoading() {
            cancelLoad();
        }

        @Override
        protected void onReset() {
            onStopLoading();
            if (mApps != null) {
                releaseResources(mApps);
                mApps = null;
            }
        }

        @Override
        public void onCanceled(List<AppInfo> apps) {
            super.onCanceled(apps);
            releaseResources(apps);
        }

        @Override
        public void forceLoad() {
            super.forceLoad();
        }

        private void releaseResources(List<AppInfo> apps) {

        }
    }

    private class AppListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        private int mItemHeight = getResources().getDimensionPixelSize(R.dimen.app_item_height);

        class ViewHolder extends RecyclerView.ViewHolder {
            ImageView icon;
            TextView title;
            TextView subtitle;

            public ViewHolder(View itemView) {
                super(itemView);
                icon = (ImageView) itemView.findViewById(R.id.icon);
                title = (TextView) itemView.findViewById(R.id.text_title);
                subtitle = (TextView) itemView.findViewById(R.id.text_subtitle);
            }
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
            final ViewHolder vh = (ViewHolder) holder;
            AppInfo appInfo = getItem(position);
            vh.title.setText(appInfo.name);
            vh.icon.setImageDrawable(appInfo.icon);
            vh.subtitle.setText(getIndexSection(holder.getAdapterPosition()));
            vh.subtitle.setVisibility(View.GONE);
            if (mLoadMore && holder.getAdapterPosition() == mAppInfoList.size() - 1) {
                getLoaderManager().restartLoader(LOADER_PHOTO, null, mLoaderCallbacks);
            }
        }

        @Override
        public int getItemCount() {
            return mAppInfoList.size();
        }

        public AppInfo getItem(int position) {
            return mAppInfoList.get(position);
        }

        public int getItemHeight(int position) {
            return mItemHeight + (mUseDivider ? mDividerDecoration.getDividerHeight() : 0);
        }

        public String getSection(int position) {
            return getAlphabetSection(position);
        }

        public String getAlphabetSection(int position) {
            return getItem(position).section;
        }

        public String getIndexSection(int position) {
            return "#" + position;
        }
    }

    private void showContentView() {
        mContentView.setVisibility(View.VISIBLE);
        mEmptyView.setVisibility(View.GONE);
    }

    private void showEmptyView() {
        mContentView.setVisibility(View.GONE);
        mEmptyView.setVisibility(View.VISIBLE);
    }

    @Override
    public void onAppBarCollapse(boolean isCollapsed) {
        mSwipeRefreshLayout.setEnabled(!isCollapsed);
    }

    @Override
    public void onPageScrolling(boolean scrolling) {
        if (scrolling) {
            mFastJumper.hide();
        }
    }

    @Override
    public void onScrollToTop() {
        mRecyclerView.smoothScrollToPosition(0);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && mFab != null) {
            mFab.hide();
        }
    }
}