1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-17 04:00:48 +01:00

improved trends location dialog

This commit is contained in:
Mariotaku Lee 2016-03-30 21:31:12 +08:00
parent c9e241d7d3
commit 8406a55f01
4 changed files with 255 additions and 75 deletions

View File

@ -30,12 +30,14 @@ public class Location {
@JsonField(name = "woeid")
int woeid;
@JsonField(name = "parentid")
int parentId;
@JsonField(name = "country")
String countryName;
@JsonField(name = "countryCode")
String countryCode;
@JsonField(name = "placeType")
PlaceTypeImpl placeType;
PlaceType placeType;
@JsonField(name = "name")
String name;
@JsonField(name = "url")
@ -45,6 +47,10 @@ public class Location {
return woeid;
}
public long getParentId() {
return parentId;
}
public String getCountryName() {
return countryName;
}
@ -53,7 +59,7 @@ public class Location {
return countryCode;
}
public PlaceTypeImpl getPlaceType() {
public PlaceType getPlaceType() {
return placeType;
}
@ -65,11 +71,27 @@ public class Location {
return url;
}
@JsonObject
public static class PlaceTypeImpl {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Location location = (Location) o;
return woeid == location.woeid;
}
@Override
public int hashCode() {
return woeid;
}
@JsonObject
public static class PlaceType {
@JsonField(name = "name")
String name;
@JsonField(name = "code")
int code;
@ -80,5 +102,13 @@ public class Location {
public String getName() {
return name;
}
@Override
public String toString() {
return "PlaceType{" +
"name='" + name + '\'' +
", code=" + code +
'}';
}
}
}

View File

@ -19,42 +19,47 @@
package org.mariotaku.twidere.preference;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.SimpleArrayMap;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Location;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class TrendsLocationPreference extends Preference implements Constants, OnClickListener {
private int mCheckedWoeId = 1;
public class TrendsLocationPreference extends Preference implements Constants {
private static final long EMPTY = 0;
private static final long WORLDWIDE = 1;
private final ExpandableTrendLocationsListAdapter mAdapter;
private GetAvailableTrendsTask mGetAvailableTrendsTask;
private final AvailableTrendsAdapter mAdapter;
private AlertDialog mDialog;
public TrendsLocationPreference(final Context context) {
@ -67,23 +72,11 @@ public class TrendsLocationPreference extends Preference implements Constants, O
public TrendsLocationPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
mAdapter = new AvailableTrendsAdapter(context);
}
@Override
public void onClick(final DialogInterface dialog, final int which) {
final Location item = mAdapter.getItem(which);
if (item != null) {
persistInt(item.getWoeid());
}
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
mAdapter = new ExpandableTrendLocationsListAdapter(context);
}
@Override
protected void onClick() {
mCheckedWoeId = getPersistedInt(1);
if (mGetAvailableTrendsTask != null) {
mGetAvailableTrendsTask.cancel(false);
}
@ -91,64 +84,178 @@ public class TrendsLocationPreference extends Preference implements Constants, O
mGetAvailableTrendsTask.execute();
}
private static class AvailableTrendsAdapter extends ArrayAdapter<Location> {
static class ExpandableTrendLocationsListAdapter extends BaseExpandableListAdapter {
private final Context mContext;
private final LayoutInflater mInflater;
@Nullable
SimpleArrayMap<Location, List<Location>> mData;
public AvailableTrendsAdapter(final Context context) {
super(context, android.R.layout.simple_list_item_single_choice);
mContext = context;
}
public int findItemPosition(final int woeid) {
final int count = getCount();
for (int i = 0; i < count; i++) {
final Location item = getItem(i);
if (item.getWoeid() == woeid) return i;
}
return -1;
public ExpandableTrendLocationsListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
final TextView text = (TextView) (view instanceof TextView ? view : view.findViewById(android.R.id.text1));
final Location item = getItem(position);
if (item != null && text != null) {
text.setSingleLine();
text.setText(item.getName());
public int getGroupCount() {
if (mData == null) return 0;
return mData.size();
}
@Override
public int getChildrenCount(int groupPosition) {
if (mData == null) return 0;
return mData.valueAt(groupPosition).size();
}
@Override
public Location getGroup(int groupPosition) {
assert mData != null;
return mData.keyAt(groupPosition);
}
@Override
public Location getChild(int groupPosition, int childPosition) {
assert mData != null;
return mData.valueAt(groupPosition).get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return getGroup(groupPosition).getWoeid();
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return getChild(groupPosition, childPosition).getWoeid();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
}
((TextView) view.findViewById(android.R.id.text1)).setText(getGroup(groupPosition).getName());
return view;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
}
final Location location = getChild(groupPosition, childPosition);
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
if (location.getParentId() == 1) {
text1.setText(R.string.location_countrywide);
} else {
text1.setText(location.getName());
}
return view;
}
public void setData(final List<Location> data) {
clear();
if (data != null) {
addAll(data);
}
sort(new LocationComparator(mContext));
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void setData(@Nullable SimpleArrayMap<Location, List<Location>> data) {
mData = data;
notifyDataSetChanged();
}
}
static class LocationsMap {
final LongSparseArray<List<Location>> map = new LongSparseArray<>();
final LongSparseArray<Location> parents = new LongSparseArray<>();
private final LocationComparator comparator;
LocationsMap(Locale locale) {
comparator = new LocationComparator(Collator.getInstance(locale));
}
void put(Location location) {
final long parentId = location.getParentId();
if (parentId == EMPTY || parentId == WORLDWIDE) {
putParent(location);
} else {
putChild(parentId, location);
}
}
void putParent(Location location) {
final long woeid = location.getWoeid();
parents.put(woeid, location);
final List<Location> list = getList(woeid);
// Don't add child for 'worldwide'
if (woeid != WORLDWIDE) {
addToList(list, location);
}
}
void putChild(long parentId, Location location) {
addToList(getList(parentId), location);
}
List<Location> getList(long parentId) {
List<Location> list = map.get(parentId);
if (list == null) {
list = new ArrayList<>();
map.put(parentId, list);
}
return list;
}
void addToList(List<Location> list, Location location) {
int loc = Collections.binarySearch(list, location, comparator);
if (loc < 0) {
list.add(-(loc + 1), location);
}
}
SimpleArrayMap<Location, List<Location>> pack() {
SimpleArrayMap<Location, List<Location>> result = new SimpleArrayMap<>(map.size());
for (int i = 0, j = map.size(); i < j; i++) {
Location parent = parents.get(map.keyAt(i));
if (parent == null) continue;
result.put(parent, map.valueAt(i));
}
return result;
}
}
private static class LocationComparator implements Comparator<Location> {
private final Collator mCollator;
private final Collator collator;
LocationComparator(final Context context) {
mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
public LocationComparator(Collator collator) {
this.collator = collator;
}
private boolean isCountryOrWorldwide(Location location) {
final long parentId = location.getParentId();
return parentId == 0 || parentId == 1;
}
@Override
public int compare(final Location object1, final Location object2) {
if (object1.getWoeid() == 1) return Integer.MIN_VALUE;
if (object2.getWoeid() == 1) return Integer.MAX_VALUE;
return mCollator.compare(object1.getName(), object2.getName());
public int compare(Location lhs, Location rhs) {
if (isCountryOrWorldwide(lhs)) return Integer.MIN_VALUE;
if (isCountryOrWorldwide(rhs)) return Integer.MAX_VALUE;
return collator.compare(lhs.getName(), rhs.getName());
}
}
class GetAvailableTrendsTask extends AsyncTask<Object, Object, ResponseList<Location>> implements OnCancelListener {
class GetAvailableTrendsTask extends AsyncTask<Object, Object, SimpleArrayMap<Location,
List<Location>>> implements OnCancelListener {
private final ProgressDialog mProgress;
public GetAvailableTrendsTask(final Context context) {
@ -161,19 +268,25 @@ public class TrendsLocationPreference extends Preference implements Constants, O
}
@Override
protected ResponseList<Location> doInBackground(final Object... args) {
protected SimpleArrayMap<Location, List<Location>> doInBackground(final Object... args) {
final Twitter twitter = TwitterAPIFactory.getDefaultTwitterInstance(getContext(), false);
if (twitter == null) return null;
try {
return twitter.getAvailableTrends();
LocationsMap map = new LocationsMap(Locale.getDefault());
for (Location location : twitter.getAvailableTrends()) {
map.put(location);
}
return map.pack();
} catch (final TwitterException e) {
Log.w(LOGTAG, e);
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return null;
}
@Override
protected void onPostExecute(final ResponseList<Location> result) {
protected void onPostExecute(final SimpleArrayMap<Location, List<Location>> result) {
if (mProgress.isShowing()) {
mProgress.dismiss();
}
@ -181,14 +294,38 @@ public class TrendsLocationPreference extends Preference implements Constants, O
if (result == null) return;
final AlertDialog.Builder selectorBuilder = new AlertDialog.Builder(getContext());
selectorBuilder.setTitle(getTitle());
selectorBuilder.setSingleChoiceItems(mAdapter, mAdapter.findItemPosition(mCheckedWoeId),
TrendsLocationPreference.this);
selectorBuilder.setView(R.layout.dialog_trends_location_selector);
selectorBuilder.setNegativeButton(android.R.string.cancel, null);
mDialog = selectorBuilder.create();
final ListView lv = mDialog.getListView();
if (lv != null) {
lv.setFastScrollEnabled(true);
}
mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {
final Dialog dialog = (Dialog) dialogInterface;
final ExpandableListView listView = (ExpandableListView) dialog.findViewById(R.id.expandable_list);
listView.setAdapter(mAdapter);
listView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
final Location group = mAdapter.getGroup(groupPosition);
if (group.getWoeid() == WORLDWIDE) {
persistInt(group.getWoeid());
dialog.dismiss();
return true;
}
return false;
}
});
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
final Location child = mAdapter.getChild(groupPosition, childPosition);
persistInt(child.getWoeid());
dialog.dismiss();
return true;
}
});
}
});
mDialog.show();
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ExpandableListView
android:id="@+id/expandable_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

View File

@ -785,4 +785,5 @@
<!-- GNU social group like https://quitter.se/group/qvitter -->
<string name="group">Group</string>
<string name="your_coarse_location">Your coarse location</string>
<string name="location_countrywide">Countrywide</string>
</resources>