Skip to content

Commit dcd91cf

Browse files
committed
Support filtering the repositories page list
This required a bit of reworking of the adapters to use a list instead of an array and that changed the signature of the base class constructor which required updates to all list adapters even those unaffected by the addition of repository filtering.
1 parent 3e2eaf4 commit dcd91cf

37 files changed

+397
-137
lines changed

app/res/layout/item_filter_list.xml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2012 GitHub Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:layout_width="match_parent"
19+
android:layout_height="match_parent" >
20+
21+
<EditText
22+
android:id="@+id/et_filter"
23+
style="@style/EditText"
24+
android:layout_width="match_parent"
25+
android:layout_alignParentLeft="true"
26+
android:layout_alignParentTop="true"
27+
android:layout_margin="2dp"
28+
android:hint="@string/find_a_repository"
29+
android:inputType="text|textNoSuggestions"
30+
android:padding="6dp"
31+
android:singleLine="true"
32+
android:visibility="gone" />
33+
34+
<ListView
35+
android:id="@android:id/list"
36+
style="@style/ListView"
37+
android:layout_width="match_parent"
38+
android:layout_height="match_parent"
39+
android:layout_below="@id/et_filter"
40+
android:visibility="gone" />
41+
42+
<TextView
43+
android:id="@android:id/empty"
44+
style="@style/ListSubtitleText"
45+
android:layout_width="match_parent"
46+
android:layout_height="match_parent"
47+
android:gravity="center"
48+
android:visibility="gone" />
49+
50+
<ProgressBar
51+
android:id="@+id/pb_loading"
52+
style="@style/Spinner"
53+
android:layout_width="64dp"
54+
android:layout_height="64dp"
55+
android:layout_centerInParent="true" />
56+
57+
</RelativeLayout>

app/res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,6 @@
207207
<string name="authenticator_conflict_title">App Conflict</string>
208208
<string name="authenticator_conflict_message">Another installed app is already configured for GitHub authentication.\n\nYou must remove the other app from the Accounts &amp; sync settings and uninstall it before the GitHub app can be used.</string>
209209
<string name="opening_repository">"Opening {0}…"</string>
210+
<string name="find_a_repository">Find a Repository…</string>
210211

211212
</resources>

app/res/values/styles.xml

+8-5
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@
4747
<item name="android:divider">@null</item>
4848
</style>
4949

50-
<style name="EditText">
50+
<style name="Global">
51+
<item name="android:layout_width">wrap_content</item>
52+
<item name="android:layout_height">wrap_content</item>
53+
</style>
54+
55+
<style name="EditText" parent="Global">
5156
<item name="android:textColor">@color/text</item>
5257
<item name="android:textCursorDrawable">@drawable/edit_text_cursor</item>
5358
<item name="android:textSize">14sp</item>
@@ -125,8 +130,7 @@
125130
<item name="android:singleLine">true</item>
126131
</style>
127132

128-
<style name="ListTitleText" parent="TitleText">
129-
</style>
133+
<style name="ListTitleText" parent="TitleText"></style>
130134

131135
<style name="SubtitleText">
132136
<item name="android:textSize">14sp</item>
@@ -135,8 +139,7 @@
135139
<item name="android:layout_width">wrap_content</item>
136140
</style>
137141

138-
<style name="ListSubtitleText" parent="SubtitleText">
139-
</style>
142+
<style name="ListSubtitleText" parent="SubtitleText"></style>
140143

141144
<style name="ListNumericSubtitleText" parent="ListSubtitleText">
142145
<item name="android:singleLine">true</item>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2012 GitHub Inc.
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+
package com.github.mobile.ui;
17+
18+
import static java.util.Locale.US;
19+
import android.text.TextUtils;
20+
import android.widget.Filter;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
/**
26+
* Item filter
27+
*
28+
* @param <V>
29+
*/
30+
public abstract class ItemFilter<V> extends Filter {
31+
32+
private final ItemListAdapter<V, ?> adapter;
33+
34+
/**
35+
* Create item filter
36+
*
37+
* @param adapter
38+
*/
39+
public ItemFilter(ItemListAdapter<V, ?> adapter) {
40+
this.adapter = adapter;
41+
}
42+
43+
/**
44+
* Does the value contain the filter text?
45+
*
46+
* @param filter
47+
* @param value
48+
* @return true if contains, false otherwise
49+
*/
50+
protected boolean contains(final String filter, final String value) {
51+
if (TextUtils.isEmpty(value))
52+
return false;
53+
54+
final int fLength = filter.length();
55+
final int vLength = value.length();
56+
if (fLength > vLength)
57+
return false;
58+
59+
int fIndex = 0;
60+
int vIndex = 0;
61+
while (vIndex < vLength)
62+
if (filter.charAt(fIndex) == Character.toUpperCase(value
63+
.charAt(vIndex))) {
64+
vIndex++;
65+
fIndex++;
66+
if (fIndex == fLength)
67+
return true;
68+
} else {
69+
vIndex += fIndex + 1;
70+
fIndex = 0;
71+
}
72+
return false;
73+
}
74+
75+
/**
76+
* Is item match for prefix?
77+
*
78+
* @param prefix
79+
* @param upperCasePrefix
80+
* @param item
81+
* @return true if match, false otherwise
82+
*/
83+
protected abstract boolean isMatch(CharSequence prefix,
84+
String upperCasePrefix, V item);
85+
86+
@Override
87+
protected FilterResults performFiltering(CharSequence prefix) {
88+
FilterResults results = new FilterResults();
89+
if (TextUtils.isEmpty(prefix))
90+
return results;
91+
92+
final List<V> initial = adapter.getInitialItems();
93+
String upperPrefix = prefix.toString().toUpperCase(US);
94+
List<V> filtered = new ArrayList<V>();
95+
for (V item : initial)
96+
if (isMatch(prefix, upperPrefix, item))
97+
filtered.add(item);
98+
99+
results.values = filtered;
100+
results.count = filtered.size();
101+
return results;
102+
}
103+
104+
@SuppressWarnings("unchecked")
105+
@Override
106+
protected void publishResults(CharSequence constraint, FilterResults results) {
107+
if (results.values != null)
108+
adapter.setFilteredItems((List<V>) results.values);
109+
else
110+
adapter.setItems(adapter.getInitialItems());
111+
112+
if (results.count == 0)
113+
adapter.notifyDataSetInvalidated();
114+
}
115+
}

app/src/main/java/com/github/mobile/ui/ItemListAdapter.java

+55-18
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
import android.view.View;
2020
import android.view.ViewGroup;
2121
import android.widget.BaseAdapter;
22+
import android.widget.Filter;
23+
import android.widget.Filterable;
24+
25+
import java.util.Collections;
26+
import java.util.List;
2227

2328
/**
2429
* List adapter for items of a specific type
@@ -27,13 +32,15 @@
2732
* @param <V>
2833
*/
2934
public abstract class ItemListAdapter<I, V extends ItemView> extends
30-
BaseAdapter {
35+
BaseAdapter implements Filterable {
3136

3237
private final LayoutInflater inflater;
3338

3439
private final int viewId;
3540

36-
private Object[] elements;
41+
private List<I> items;
42+
43+
private List<I> initialItems;
3744

3845
/**
3946
* Create empty adapter
@@ -50,16 +57,17 @@ public ItemListAdapter(final int viewId, final LayoutInflater inflater) {
5057
*
5158
* @param viewId
5259
* @param inflater
53-
* @param elements
60+
* @param items
5461
*/
5562
public ItemListAdapter(final int viewId, final LayoutInflater inflater,
56-
final I[] elements) {
63+
final List<I> items) {
5764
this.viewId = viewId;
5865
this.inflater = inflater;
59-
if (elements != null)
60-
this.elements = elements;
66+
if (items != null)
67+
this.items = items;
6168
else
62-
this.elements = new Object[0];
69+
this.items = Collections.emptyList();
70+
this.initialItems = this.items;
6371
}
6472

6573
@Override
@@ -68,37 +76,60 @@ public boolean hasStableIds() {
6876
}
6977

7078
/**
79+
* Get items being displayed
80+
*
7181
* @return items
7282
*/
73-
@SuppressWarnings("unchecked")
74-
protected I[] getItems() {
75-
return (I[]) elements;
83+
public List<I> getItems() {
84+
return items;
7685
}
7786

7887
public int getCount() {
79-
return elements.length;
88+
return items.size();
8089
}
8190

82-
@SuppressWarnings("unchecked")
8391
public I getItem(int position) {
84-
return (I) elements[position];
92+
return items.get(position);
8593
}
8694

8795
public long getItemId(int position) {
88-
return elements[position].hashCode();
96+
return getItem(position).hashCode();
97+
}
98+
99+
/**
100+
* @return initialItems
101+
*/
102+
protected List<I> getInitialItems() {
103+
return initialItems;
89104
}
90105

91106
/**
92107
* Set items
93108
*
94109
* @param items
95-
* @return items
110+
* @return this adapter
111+
*/
112+
public ItemListAdapter<I, V> setItems(final List<I> items) {
113+
if (items != null)
114+
this.items = items;
115+
else
116+
this.items = Collections.emptyList();
117+
initialItems = this.items;
118+
notifyDataSetChanged();
119+
return this;
120+
}
121+
122+
/**
123+
* Set filtered items to display
124+
*
125+
* @param items
126+
* @return this adapter
96127
*/
97-
public ItemListAdapter<I, V> setItems(final Object[] items) {
128+
public ItemListAdapter<I, V> setFilteredItems(final List<I> items) {
98129
if (items != null)
99-
elements = items;
130+
this.items = items;
100131
else
101-
elements = new Object[0];
132+
this.items = Collections.emptyList();
102133
notifyDataSetChanged();
103134
return this;
104135
}
@@ -120,6 +151,7 @@ public ItemListAdapter<I, V> setItems(final Object[] items) {
120151
*/
121152
protected abstract V createView(View view);
122153

154+
@Override
123155
public View getView(final int position, View convertView,
124156
final ViewGroup parent) {
125157
@SuppressWarnings("unchecked")
@@ -132,4 +164,9 @@ public View getView(final int position, View convertView,
132164
update(position, view, getItem(position));
133165
return convertView;
134166
}
167+
168+
@Override
169+
public Filter getFilter() {
170+
return null;
171+
}
135172
}

app/src/main/java/com/github/mobile/ui/ItemListFragment.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public void onLoadFinished(Loader<List<E>> loader, List<E> items) {
215215
}
216216

217217
this.items = items;
218-
getListAdapter().getWrappedAdapter().setItems(items.toArray());
218+
getListAdapter().getWrappedAdapter().setItems(items);
219219
showList();
220220
}
221221

app/src/main/java/com/github/mobile/ui/NewsFragment.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ protected void viewIssue(Issue issue) {
166166
@Override
167167
protected ItemListAdapter<Event, ? extends ItemView> createAdapter(
168168
List<Event> items) {
169-
return new NewsListAdapter(getActivity().getLayoutInflater(),
170-
items.toArray(new Event[items.size()]), avatars);
169+
return new NewsListAdapter(getActivity().getLayoutInflater(), items,
170+
avatars);
171171
}
172172

173173
@Override

app/src/main/java/com/github/mobile/ui/comment/CommentListAdapter.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.github.mobile.util.TimeUtils;
2525
import com.viewpagerindicator.R.layout;
2626

27+
import java.util.List;
28+
2729
import org.eclipse.egit.github.core.Comment;
2830

2931
/**
@@ -44,7 +46,7 @@ public class CommentListAdapter extends
4446
* @param avatars
4547
* @param imageGetter
4648
*/
47-
public CommentListAdapter(LayoutInflater inflater, Comment[] elements,
49+
public CommentListAdapter(LayoutInflater inflater, List<Comment> elements,
4850
AvatarLoader avatars, HttpImageGetter imageGetter) {
4951
super(layout.comment_item, inflater, elements);
5052

0 commit comments

Comments
 (0)