2
2
3
3
import android .support .annotation .NonNull ;
4
4
import android .support .annotation .Nullable ;
5
+ import android .support .v7 .widget .RecyclerView ;
5
6
import android .util .Log ;
6
7
7
- import com .firebase .ui .common .ChangeEventType ;
8
+ import com .google .android .gms .tasks .OnCompleteListener ;
9
+ import com .google .android .gms .tasks .Task ;
8
10
import com .google .firebase .firestore .DocumentSnapshot ;
9
- import com .google .firebase .firestore .FirebaseFirestoreException ;
10
11
import com .google .firebase .firestore .Query ;
12
+ import com .google .firebase .firestore .QuerySnapshot ;
11
13
12
14
import java .util .ArrayList ;
13
15
import java .util .Collections ;
14
16
import java .util .List ;
15
17
18
+ // TODO: There is no reason for this to be an OSA
16
19
public class FirestoreInfiniteArray <T > extends ObservableSnapshotArray <T > {
17
20
18
21
private static final String TAG = "FirestoreInfiniteArray" ;
19
22
20
23
private SnapshotParser <T > mParser ;
21
24
25
+ private RecyclerView .Adapter mAdapter ;
22
26
private Query mForwardQuery ;
23
27
private Query mReverseQuery ;
24
28
@@ -34,18 +38,58 @@ public FirestoreInfiniteArray(Query forwardQuery, Query reverseQuery, SnapshotPa
34
38
mReverseQuery = reverseQuery ;
35
39
36
40
Page page = new Page (0 , queryAfter (null ));
41
+ page .load ();
42
+
37
43
mPages .add (page );
38
44
}
39
45
40
- public void loadNextPage () {
41
- Page lastPage = getLastPage ();
46
+ public void setAdapter (RecyclerView .Adapter adapter ) {
47
+ // TODO: yikes
48
+ mAdapter = adapter ;
49
+ }
50
+
51
+ public int getPagesLoaded () {
52
+ int count = 0 ;
53
+ for (Page page : mPages ) {
54
+ if (page .getState () == PageState .LOADED ) {
55
+ count ++;
56
+ }
57
+ }
42
58
43
- if (lastPage .getState () == PageState .LOADING ) {
44
- Log .d (TAG , "Skipping double-load." );
59
+ return count ;
60
+ }
61
+
62
+ public void unloadPage () {
63
+ // Find first loaded page
64
+ int firstLoaded = findFirstOfState (PageState .LOADED );
65
+ if (firstLoaded != -1 ) {
66
+ mPages .get (firstLoaded ).unload ();
67
+ Log .d (TAG , "unloadPage: unloading page " + firstLoaded );
68
+ Log .d (TAG , "unloadPage: new size = " + size ());
69
+ }
70
+ }
71
+
72
+ public void loadPrevPage () {
73
+ if (countState (PageState .LOADING ) > 0 ) {
45
74
return ;
46
75
}
47
76
48
- int size = size ();
77
+ // Find first unloaded page
78
+ int lastUnloaded = findLastOfState (PageState .UNLOADED );
79
+ if (lastUnloaded != -1 ) {
80
+ Log .d (TAG , "loadPrevPage: loading " + lastUnloaded );
81
+ mPages .get (lastUnloaded ).load ();
82
+ }
83
+
84
+ // TODO: What if we have to change the starting position of the next page
85
+ }
86
+
87
+ public void loadNextPage () {
88
+ if (countState (PageState .LOADING ) > 0 ) {
89
+ return ;
90
+ }
91
+
92
+ Page lastPage = getLastPage ();
49
93
DocumentSnapshot lastSnapshot = lastPage .getLast ();
50
94
51
95
if (lastSnapshot == null ) {
@@ -54,11 +98,65 @@ public void loadNextPage() {
54
98
}
55
99
56
100
Query nextQuery = queryAfter (lastSnapshot );
57
- Log .d (TAG , "loadNextPage: sizeBefore=" + size + ", lastId=" + lastSnapshot .getId ());
58
- Page nextPage = new Page (size , nextQuery );
101
+ Log .d (TAG , "loadNextPage: loading page " + mPages .size ());
102
+
103
+ // Add and start loading
104
+ int nextPageIndex = mPages .size ();
105
+ Page nextPage = new Page (nextPageIndex , nextQuery );
59
106
mPages .add (nextPage );
107
+ nextPage .load ();
60
108
}
61
109
110
+ private void onPageLoaded (int index , int size ) {
111
+ int itemsBefore = 0 ;
112
+ for (int i = 0 ; i < index ; i ++) {
113
+ itemsBefore += mPages .get (i ).size ();
114
+ }
115
+
116
+ mAdapter .notifyItemRangeInserted (itemsBefore , size );
117
+ }
118
+
119
+ private void onPageUnloaded (int index , int size ) {
120
+ int itemsBefore = 0 ;
121
+ for (int i = 0 ; i < index ; i ++) {
122
+ itemsBefore += mPages .get (i ).size ();
123
+ }
124
+
125
+ mAdapter .notifyItemRangeRemoved (itemsBefore , size );
126
+ }
127
+
128
+ private int findFirstOfState (PageState state ) {
129
+ for (int i = 0 ; i < mPages .size (); i ++) {
130
+ Page page = mPages .get (i );
131
+ if (page .getState () == state ) {
132
+ return i ;
133
+ }
134
+ }
135
+
136
+ return -1 ;
137
+ }
138
+
139
+ private int findLastOfState (PageState state ) {
140
+ for (int i = mPages .size () - 1 ; i >= 0 ; i --) {
141
+ Page page = mPages .get (i );
142
+ if (page .getState () == state ) {
143
+ return i ;
144
+ }
145
+ }
146
+
147
+ return -1 ;
148
+ }
149
+
150
+ private int countState (PageState state ) {
151
+ int count = 0 ;
152
+ for (Page page : mPages ) {
153
+ if (page .getState () == state ) {
154
+ count ++;
155
+ }
156
+ }
157
+
158
+ return count ;
159
+ }
62
160
63
161
@ NonNull
64
162
@ Override
@@ -118,66 +216,60 @@ private Query queryAfter(@Nullable DocumentSnapshot snapshot) {
118
216
119
217
private enum PageState {
120
218
LOADING ,
121
- LOADED
219
+ LOADED ,
220
+ UNLOADED
122
221
}
123
222
124
- private class Page implements ChangeEventListener {
223
+ private class Page implements OnCompleteListener < QuerySnapshot > {
125
224
126
225
// TODO: state
127
226
128
- private PageState mState = PageState .LOADING ;
129
-
130
- public final int mStartingPosition ;
227
+ private PageState mState ;
228
+ public final int mIndex ;
131
229
public final Query mQuery ;
132
- public final FirestoreArray <T > mItems ;
230
+
231
+ private DocumentSnapshot mFirstInPage ;
133
232
134
233
private List <DocumentSnapshot > mSnapshots = new ArrayList <>();
135
234
136
- public Page (int startingPosition , Query query ) {
137
- mStartingPosition = startingPosition ;
235
+ public Page (int index , Query query ) {
236
+ mIndex = index ;
138
237
mQuery = query ;
139
238
140
- mItems = new FirestoreArray <>(query , mParser );
141
- mItems .addChangeEventListener (this );
239
+ mState = PageState .UNLOADED ;
142
240
}
143
241
144
- @ Override
145
- public void onChildChanged (@ NonNull ChangeEventType type ,
146
- @ NonNull DocumentSnapshot snapshot ,
147
- int newIndex ,
148
- int oldIndex ) {
149
- switch (type ) {
150
- // TODO: Implement all types
151
- case ADDED :
152
- int newIndexAdjusted = newIndex + mStartingPosition ;
153
- int oldIndexAdjusted = oldIndex == -1
154
- ? -1
155
- : oldIndex + mStartingPosition ;
156
-
157
- Log .d (TAG , "onChildAdded, old=" + oldIndexAdjusted + ", new=" + newIndexAdjusted );
158
- notifyOnChildChanged (type , snapshot , newIndexAdjusted , oldIndexAdjusted );
159
- mSnapshots .add (snapshot );
160
- break ;
161
- case MOVED :
162
- break ;
163
- case CHANGED :
164
- break ;
165
- case REMOVED :
166
- break ;
167
- }
242
+ public void load () {
243
+ // TODO: start and end
244
+ mState = PageState .LOADING ;
245
+ mQuery .get ().addOnCompleteListener (this );
168
246
}
169
247
170
- @ Override
171
- public void onDataChanged () {
172
- // TODO
173
- Log .d (TAG , "onDataChanged" );
174
- mState = PageState .LOADED ;
248
+ public void unload () {
249
+ int size = mSnapshots .size ();
250
+ mSnapshots .clear ();
251
+
252
+ onPageUnloaded (mIndex , size );
253
+ mState = PageState .UNLOADED ;
175
254
}
176
255
177
256
@ Override
178
- public void onError (@ NonNull FirebaseFirestoreException e ) {
179
- // TODO
257
+ public void onComplete (@ NonNull Task < QuerySnapshot > task ) {
258
+ // TODO: Better error handling
180
259
mState = PageState .LOADED ;
260
+
261
+ if (!task .isSuccessful ()) {
262
+ Log .w (TAG , "Failed to get page" , task .getException ());
263
+ }
264
+
265
+ Log .d (TAG , "pageLoaded: " + mIndex );
266
+
267
+ // Add all snapshots
268
+ mSnapshots .addAll (task .getResult ().getDocuments ());
269
+
270
+ // TODO
271
+ // Range insert
272
+ onPageLoaded (mIndex , mSnapshots .size ());
181
273
}
182
274
183
275
public PageState getState () {
0 commit comments