1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.support.content.demos;
18
19import android.database.Cursor;
20import android.net.Uri;
21import android.os.Bundle;
22import android.view.Menu;
23import android.view.MenuItem;
24import android.view.ViewGroup;
25import android.widget.TextView;
26
27import androidx.annotation.NonNull;
28import androidx.appcompat.app.AppCompatActivity;
29import androidx.appcompat.widget.Toolbar;
30import androidx.contentpager.content.ContentPager;
31import androidx.contentpager.content.ContentPager.ContentCallback;
32import androidx.contentpager.content.LoaderQueryRunner;
33import androidx.contentpager.content.Query;
34import androidx.recyclerview.widget.LinearLayoutManager;
35import androidx.recyclerview.widget.RecyclerView;
36
37import com.google.android.material.floatingactionbutton.FloatingActionButton;
38import com.google.android.material.snackbar.BaseTransientBottomBar;
39import com.google.android.material.snackbar.Snackbar;
40
41import java.util.Locale;
42
43/**
44 * ContentPager demo activity.
45 */
46public class ContentPagerDemoActivity extends AppCompatActivity {
47
48    private static final int PAGE_SIZE = 20;
49
50    private RecyclerView mRecycler;
51    private ContentPager mPager;
52    private Adapter mAdapter;
53    private FloatingActionButton mFab;
54    private Menu mMenu;
55    private int mCurrentPage = -1;
56
57    @Override
58    protected void onCreate(Bundle savedInstanceState) {
59        super.onCreate(savedInstanceState);
60        setContentView(R.layout.activity_demo);
61
62        ContentPager.QueryRunner runner = new LoaderQueryRunner(this, getLoaderManager());
63        mPager = new ContentPager(getContentResolver(), runner);
64        mAdapter = new Adapter(mPager, PAGE_SIZE);
65
66        mRecycler = (RecyclerView) findViewById(R.id.list);
67        mRecycler.setLayoutManager(new LinearLayoutManager(this));
68        mRecycler.setAdapter(mAdapter);
69        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
70        setSupportActionBar(toolbar);
71    }
72
73    @Override
74    protected void onDestroy() {
75        super.onDestroy();
76        mPager.reset();
77    }
78
79    @Override
80    public boolean onCreateOptionsMenu(Menu menu) {
81        // Inflate the menu; this adds items to the action bar if it is present.
82        getMenuInflater().inflate(R.menu.menu_demo, menu);
83        mMenu = menu;
84        return true;
85    }
86
87    @Override
88    public boolean onOptionsItemSelected(MenuItem item) {
89
90        switch (item.getItemId()) {
91            case R.id.action_load:
92                onLoadContent();
93                break;
94            case R.id.action_previous:
95                onLoadPreviousPage();
96                break;
97            case R.id.action_next:
98                onLoadNextPage();
99                break;
100        }
101        // Handle action bar item clicks here. The action bar will
102        // automatically handle clicks on the Home/Up button, so long
103        // as you specify a parent activity in AndroidManifest.xml.
104        int id = item.getItemId();
105
106        //noinspection SimplifiableIfStatement
107        if (id == R.id.action_load) {
108            return true;
109        }
110
111        return super.onOptionsItemSelected(item);
112    }
113
114    private void onLoadContent() {
115        mAdapter.reset(UnpagedDemoDataProvider.URI);
116        mCurrentPage = 0;
117        mAdapter.loadPage(mCurrentPage);
118
119        updateOptionsMenu();
120    }
121
122    private void onLoadNextPage() {
123        mAdapter.loadPage(mCurrentPage + 1);
124
125        updateOptionsMenu();
126    }
127
128    private void onLoadPreviousPage() {
129        mAdapter.loadPage(mCurrentPage - 1);
130
131        updateOptionsMenu();
132    }
133
134    private void updateOptionsMenu() {
135        MenuItem prev = mMenu.findItem(R.id.action_previous);
136        MenuItem next = mMenu.findItem(R.id.action_next);
137
138        int lastPage = (UnpagedDemoDataProvider.TOTAL_SIZE / PAGE_SIZE) - 1;
139        prev.setEnabled(mCurrentPage > 0);
140        next.setEnabled(mCurrentPage < lastPage);
141    }
142
143    private void msg(String msg) {
144        Snackbar.make(
145                mRecycler,
146                msg, BaseTransientBottomBar.LENGTH_LONG)
147                .setAction("Action", null).show();
148    }
149
150    private final class Adapter extends RecyclerView.Adapter<Holder> implements ContentCallback {
151
152        private final ContentPager mPager;
153        private final int mPageSize;
154
155        private Uri mUri;
156        private Cursor mCursor;
157
158        private Adapter(ContentPager pager, int pageSize) {
159            mPager = pager;
160            mPageSize = pageSize;
161        }
162
163        private void reset(Uri uri) {
164            mUri = uri;
165            mCursor = null;
166        }
167
168        void loadPage(int page) {
169            if (page < 0 || page >= (UnpagedDemoDataProvider.TOTAL_SIZE / PAGE_SIZE)) {
170                throw new IndexOutOfBoundsException();
171            }
172
173            mCurrentPage = page;
174            int offset = mCurrentPage * mPageSize;
175            mPager.query(mUri, null, ContentPager.createArgs(offset, mPageSize), null, this);
176        }
177
178        @Override
179        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
180            return new Holder(new TextView(ContentPagerDemoActivity.this));
181        }
182
183        @Override
184        public void onBindViewHolder(Holder holder, int position) {
185            if (!mCursor.moveToPosition(position)) {
186                holder.view.setText("Nope, couldn't position cursor to: " + position);
187                return;
188            }
189
190            holder.view.setText(String.format(Locale.US,
191                    "%d.%d (%d): %s",
192                    mCurrentPage,
193                    mCursor.getInt(0),
194                    mCursor.getLong(2),
195                    mCursor.getString(1)));
196        }
197
198        @Override
199        public int getItemCount() {
200            return mCursor == null ? 0 : mCursor.getCount();
201        }
202
203        @Override
204        public void onCursorReady(@NonNull Query query, Cursor cursor) {
205            if (cursor == null) {
206                msg("Content query returned a null cursor: " + query.getUri());
207            }
208
209            mCurrentPage = query.getOffset() / mPageSize;
210            mCursor = cursor;
211            notifyDataSetChanged();
212        }
213
214        private int getCorpusSize(Bundle extras) {
215            return extras.getInt(ContentPager.EXTRA_TOTAL_COUNT, -1);
216        }
217    }
218
219    private class Holder extends RecyclerView.ViewHolder {
220
221        public final TextView view;
222
223        private Holder(TextView view) {
224            super(view);
225            this.view = view;
226        }
227    }
228}
229