mirror of https://github.com/tasks/tasks
Remove unused classes
parent
6c97d5c501
commit
09eef62645
@ -1,379 +0,0 @@
|
|||||||
/***
|
|
||||||
Copyright (c) 2008-2009 CommonsWare, LLC
|
|
||||||
Portions (c) 2009 Google, Inc.
|
|
||||||
|
|
||||||
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 com.commonsware.cwac.merge;
|
|
||||||
|
|
||||||
import android.database.DataSetObserver;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.ListAdapter;
|
|
||||||
import android.widget.SectionIndexer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import com.commonsware.cwac.sacklist.SackOfViewsAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter that merges multiple child adapters and views
|
|
||||||
* into a single contiguous whole.
|
|
||||||
*
|
|
||||||
* Adapters used as pieces within MergeAdapter must
|
|
||||||
* have view type IDs monotonically increasing from 0. Ideally,
|
|
||||||
* adapters also have distinct ranges for their row ids, as
|
|
||||||
* returned by getItemId().
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class MergeAdapter extends BaseAdapter implements SectionIndexer {
|
|
||||||
protected ArrayList<ListAdapter> pieces=new ArrayList<ListAdapter>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stock constructor, simply chaining to the superclass.
|
|
||||||
*/
|
|
||||||
public MergeAdapter() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new adapter to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
* @param adapter Source for row views for this section
|
|
||||||
*/
|
|
||||||
public void addAdapter(ListAdapter adapter) {
|
|
||||||
pieces.add(adapter);
|
|
||||||
adapter.registerDataSetObserver(new CascadeDataSetObserver());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new View to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
* @param view Single view to add
|
|
||||||
*/
|
|
||||||
public void addView(View view) {
|
|
||||||
addView(view, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new View to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
* @param view Single view to add
|
|
||||||
* @param enabled false if views are disabled, true if enabled
|
|
||||||
*/
|
|
||||||
public void addView(View view, boolean enabled) {
|
|
||||||
ArrayList<View> list=new ArrayList<View>(1);
|
|
||||||
|
|
||||||
list.add(view);
|
|
||||||
|
|
||||||
addViews(list, enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of views to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
* @param views List of views to add
|
|
||||||
*/
|
|
||||||
public void addViews(List<View> views) {
|
|
||||||
addViews(views, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of views to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
* @param views List of views to add
|
|
||||||
* @param enabled false if views are disabled, true if enabled
|
|
||||||
*/
|
|
||||||
public void addViews(List<View> views, boolean enabled) {
|
|
||||||
if (enabled) {
|
|
||||||
addAdapter(new EnabledSackAdapter(views));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
addAdapter(new SackOfViewsAdapter(views));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data item associated with the specified
|
|
||||||
* position in the data set.
|
|
||||||
* @param position Position of the item whose data we want
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object getItem(int position) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
return(piece.getItem(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the adapter associated with the specified
|
|
||||||
* position in the data set.
|
|
||||||
* @param position Position of the item whose adapter we want
|
|
||||||
*/
|
|
||||||
public ListAdapter getAdapter(int position) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
return(piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How many items are in the data set represented by this
|
|
||||||
* Adapter.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
int total=0;
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
total+=piece.getCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return(total);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of types of Views that will be
|
|
||||||
* created by getView().
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getViewTypeCount() {
|
|
||||||
int total=0;
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
total+=piece.getViewTypeCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return(Math.max(total, 1)); // needed for setListAdapter() before content add'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the type of View that will be created by getView()
|
|
||||||
* for the specified item.
|
|
||||||
* @param position Position of the item whose data we want
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(int position) {
|
|
||||||
int typeOffset=0;
|
|
||||||
int result=-1;
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
result=typeOffset+piece.getItemViewType(position);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
typeOffset+=piece.getViewTypeCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are all items in this ListAdapter enabled? If yes it
|
|
||||||
* means all items are selectable and clickable.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean areAllItemsEnabled() {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the item at the specified position is
|
|
||||||
* not a separator.
|
|
||||||
* @param position Position of the item whose data we want
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled(int position) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
return(piece.isEnabled(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a View that displays the data at the specified
|
|
||||||
* position in the data set.
|
|
||||||
* @param position Position of the item whose data we want
|
|
||||||
* @param convertView View to recycle, if not null
|
|
||||||
* @param parent ViewGroup containing the returned View
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView,
|
|
||||||
ViewGroup parent) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
|
|
||||||
return(piece.getView(position, convertView, parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the row id associated with the specified position
|
|
||||||
* in the list.
|
|
||||||
* @param position Position of the item whose data we want
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
return(piece.getItemId(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPositionForSection(int section) {
|
|
||||||
int position=0;
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
if (piece instanceof SectionIndexer) {
|
|
||||||
Object[] sections=((SectionIndexer)piece).getSections();
|
|
||||||
int numSections=0;
|
|
||||||
|
|
||||||
if (sections!=null) {
|
|
||||||
numSections=sections.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section<numSections) {
|
|
||||||
return(position+((SectionIndexer)piece).getPositionForSection(section));
|
|
||||||
}
|
|
||||||
else if (sections!=null) {
|
|
||||||
section-=numSections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position+=piece.getCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionForPosition(int position) {
|
|
||||||
int section=0;
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
if (piece instanceof SectionIndexer) {
|
|
||||||
return(section+((SectionIndexer)piece).getSectionForPosition(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (piece instanceof SectionIndexer) {
|
|
||||||
Object[] sections=((SectionIndexer)piece).getSections();
|
|
||||||
|
|
||||||
if (sections!=null) {
|
|
||||||
section+=sections.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] getSections() {
|
|
||||||
ArrayList<Object> sections=new ArrayList<Object>();
|
|
||||||
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
if (piece instanceof SectionIndexer) {
|
|
||||||
Object[] curSections=((SectionIndexer)piece).getSections();
|
|
||||||
|
|
||||||
if (curSections!=null) {
|
|
||||||
for (Object section : curSections) {
|
|
||||||
sections.add(section);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sections.size()==0) {
|
|
||||||
return(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(sections.toArray(new Object[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class EnabledSackAdapter extends SackOfViewsAdapter {
|
|
||||||
public EnabledSackAdapter(List<View> views) {
|
|
||||||
super(views);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areAllItemsEnabled() {
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled(int position) {
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CascadeDataSetObserver extends DataSetObserver {
|
|
||||||
@Override
|
|
||||||
public void onChanged() {
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInvalidated() {
|
|
||||||
notifyDataSetInvalidated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.commonsware.cwac.merge;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ListAdapter;
|
|
||||||
import android.widget.SpinnerAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter that merges multiple child adapters into a single
|
|
||||||
* contiguous whole to be consumed by a Spinner.
|
|
||||||
*
|
|
||||||
* Adapters used as pieces within MergeSpinnerAdapter must
|
|
||||||
* have view type IDs monotonically increasing from 0.
|
|
||||||
* Ideally, adapters also have distinct ranges for their row
|
|
||||||
* ids, as returned by getItemId().
|
|
||||||
*
|
|
||||||
* All Adapters used as pieces within MergeSpinnerAdapter
|
|
||||||
* must be properly-configured implementations of
|
|
||||||
* SpinnerAdapter (e.g., ArrayAdapter, CursorAdapter).
|
|
||||||
*/
|
|
||||||
public class MergeSpinnerAdapter extends MergeAdapter {
|
|
||||||
/**
|
|
||||||
* Stock constructor, simply chaining to the superclass.
|
|
||||||
*/
|
|
||||||
public MergeSpinnerAdapter() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the drop-down View for a given position, by
|
|
||||||
* iterating over the pieces. Assumes that all pieces are
|
|
||||||
* implementations of SpinnerAdapter.
|
|
||||||
*
|
|
||||||
* @see android.widget.BaseAdapter#getDropDownView(int,
|
|
||||||
* android.view.View, android.view.ViewGroup)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View getDropDownView(int position, View convertView,
|
|
||||||
ViewGroup parent) {
|
|
||||||
for (ListAdapter piece : pieces) {
|
|
||||||
int size=piece.getCount();
|
|
||||||
|
|
||||||
if (position<size) {
|
|
||||||
return(((SpinnerAdapter)piece).getDropDownView(position,
|
|
||||||
convertView,
|
|
||||||
parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
position-=size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new View to the roster of things to appear in
|
|
||||||
* the aggregate list.
|
|
||||||
*
|
|
||||||
* @param view
|
|
||||||
* Single view to add
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addView(View view) {
|
|
||||||
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new View to the roster of things to appear in
|
|
||||||
* the aggregate list.
|
|
||||||
*
|
|
||||||
* @param view
|
|
||||||
* Single view to add
|
|
||||||
* @param enabled
|
|
||||||
* false if views are disabled, true if enabled
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addView(View view, boolean enabled) {
|
|
||||||
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of views to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
*
|
|
||||||
* @param views
|
|
||||||
* List of views to add
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addViews(List<View> views) {
|
|
||||||
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of views to the roster of things to appear
|
|
||||||
* in the aggregate list.
|
|
||||||
*
|
|
||||||
* @param views
|
|
||||||
* List of views to add
|
|
||||||
* @param enabled
|
|
||||||
* false if views are disabled, true if enabled
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addViews(List<View> views, boolean enabled) {
|
|
||||||
throw new RuntimeException("Not supported with MergeSpinnerAdapter");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package com.todoroo.astrid.actfm.sync.messages;
|
|
||||||
|
|
||||||
import org.apache.http.entity.mime.MultipartEntity;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import com.todoroo.astrid.dao.RemoteModelDao;
|
|
||||||
import com.todoroo.astrid.data.RemoteModel;
|
|
||||||
|
|
||||||
public class RequestDoubleCheck<TYPE extends RemoteModel> extends ClientToServerMessage<TYPE> {
|
|
||||||
|
|
||||||
public RequestDoubleCheck(long id, Class<TYPE> modelClass, RemoteModelDao<TYPE> modelDao) {
|
|
||||||
super(id, modelClass, modelDao);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean serializeExtrasToJSON(JSONObject serializeTo, MultipartEntity entity) throws JSONException {
|
|
||||||
// No extras
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getTypeString() {
|
|
||||||
return "RequestDoubleCheck"; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,360 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnCreateContextMenuListener;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.animation.AnimationUtils;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ExpandableListAdapter;
|
|
||||||
import android.widget.ExpandableListView;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ListAdapter;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class ExpandableListFragment extends Fragment
|
|
||||||
implements OnCreateContextMenuListener,
|
|
||||||
ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
|
|
||||||
ExpandableListView.OnGroupExpandListener
|
|
||||||
{
|
|
||||||
|
|
||||||
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
|
|
||||||
|
|
||||||
final private Handler mHandler = new Handler();
|
|
||||||
|
|
||||||
final private Runnable mRequestFocus = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mList.focusableViewAvailable(mList);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final private AdapterView.OnItemClickListener mOnClickListener
|
|
||||||
= new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
|
||||||
onListItemClick((ListView)parent, v, position, id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ExpandableListAdapter mAdapter;
|
|
||||||
ExpandableListView mList;
|
|
||||||
View mEmptyView;
|
|
||||||
TextView mStandardEmptyView;
|
|
||||||
boolean mSetEmptyText;
|
|
||||||
boolean mListShown;
|
|
||||||
boolean mFinishedStart = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide default implementation to return a simple list view. Subclasses
|
|
||||||
* can override to replace with their own layout. If doing so, the
|
|
||||||
* returned view hierarchy <em>must</em> have a ListView whose id
|
|
||||||
* is {@link android.R.id#list android.R.id.list} and can optionally
|
|
||||||
* have a sibling view id {@link android.R.id#empty android.R.id.empty}
|
|
||||||
* that is to be shown when the list is empty.
|
|
||||||
*
|
|
||||||
* <p>If you are overriding this method with your own custom content,
|
|
||||||
* consider including the standard layout {@link android.R.layout#list_content}
|
|
||||||
* in your layout file, so that you continue to retain all of the standard
|
|
||||||
* behavior of ListFragment. In particular, this is currently the only
|
|
||||||
* way to have the built-in indeterminant progress state be shown.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
FrameLayout root = new FrameLayout(getActivity());
|
|
||||||
|
|
||||||
TextView tv = new TextView(getActivity());
|
|
||||||
tv.setId(INTERNAL_EMPTY_ID);
|
|
||||||
tv.setGravity(Gravity.CENTER);
|
|
||||||
root.addView(tv, new FrameLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
|
|
||||||
|
|
||||||
ExpandableListView lv = new ExpandableListView(getActivity());
|
|
||||||
lv.setId(android.R.id.list);
|
|
||||||
lv.setDrawSelectorOnTop(false);
|
|
||||||
root.addView(lv, new FrameLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
|
|
||||||
|
|
||||||
ListView.LayoutParams lp = new ListView.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
|
|
||||||
root.setLayoutParams(lp);
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach to list view once Fragment is ready to run.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
ensureList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detach from list view.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
mHandler.removeCallbacks(mRequestFocus);
|
|
||||||
mList = null;
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will be called when an item in the list is selected.
|
|
||||||
* Subclasses should override. Subclasses can call
|
|
||||||
* getListView().getItemAtPosition(position) if they need to access the
|
|
||||||
* data associated with the selected item.
|
|
||||||
*
|
|
||||||
* @param l The ListView where the click happened
|
|
||||||
* @param v The view that was clicked within the ListView
|
|
||||||
* @param position The position of the view in the list
|
|
||||||
* @param id The row id of the item that was clicked
|
|
||||||
*/
|
|
||||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
|
||||||
// override me
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the cursor for the list view.
|
|
||||||
*/
|
|
||||||
public void setListAdapter(ExpandableListAdapter adapter) {
|
|
||||||
boolean hadAdapter = mAdapter != null;
|
|
||||||
mAdapter = adapter;
|
|
||||||
if (mList != null) {
|
|
||||||
mList.setAdapter(adapter);
|
|
||||||
if (!mListShown && !hadAdapter) {
|
|
||||||
// The list was hidden, and previously didn't have an
|
|
||||||
// adapter. It is now time to show it.
|
|
||||||
setListShown(true, getView().getWindowToken() != null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the currently selected list item to the specified
|
|
||||||
* position with the adapter's data
|
|
||||||
*
|
|
||||||
* @param position
|
|
||||||
*/
|
|
||||||
public void setSelection(int position) {
|
|
||||||
ensureList();
|
|
||||||
mList.setSelection(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getSelectedPosition() {
|
|
||||||
ensureList();
|
|
||||||
return mList.getSelectedPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the selection to the specified child. If the child is in a collapsed
|
|
||||||
* group, the group will only be expanded and child subsequently selected if
|
|
||||||
* shouldExpandGroup is set to true, otherwise the method will return false.
|
|
||||||
*
|
|
||||||
* @param groupPosition The position of the group that contains the child.
|
|
||||||
* @param childPosition The position of the child within the group.
|
|
||||||
* @param shouldExpandGroup Whether the child's group should be expanded if
|
|
||||||
* it is collapsed.
|
|
||||||
* @return Whether the selection was successfully set on the child.
|
|
||||||
*/
|
|
||||||
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
|
|
||||||
ensureList();
|
|
||||||
return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setItemChecked(int position, boolean value) {
|
|
||||||
ensureList();
|
|
||||||
mList.setItemChecked(position, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the selection to the specified group.
|
|
||||||
* @param groupPosition The position of the group that should be selected.
|
|
||||||
*/
|
|
||||||
public void setSelectedGroup(int groupPosition) {
|
|
||||||
mList.setSelectedGroup(groupPosition);
|
|
||||||
}
|
|
||||||
public long getSelectedId() {
|
|
||||||
ensureList();
|
|
||||||
return mList.getSelectedId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExpandableListView getExpandableListView() {
|
|
||||||
ensureList();
|
|
||||||
return mList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default content for a ListFragment has a TextView that can
|
|
||||||
* be shown when the list is empty. If you would like to have it
|
|
||||||
* shown, call this method to supply the text it should use.
|
|
||||||
*/
|
|
||||||
public void setEmptyText(CharSequence text) {
|
|
||||||
ensureList();
|
|
||||||
if (mStandardEmptyView == null) {
|
|
||||||
throw new IllegalStateException("Can't be used with a custom content view");
|
|
||||||
}
|
|
||||||
mStandardEmptyView.setText(text);
|
|
||||||
if (!mSetEmptyText) {
|
|
||||||
mList.setEmptyView(mStandardEmptyView);
|
|
||||||
mSetEmptyText = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control whether the list is being displayed. You can make it not
|
|
||||||
* displayed if you are waiting for the initial data to show in it. During
|
|
||||||
* this time an indeterminant progress indicator will be shown instead.
|
|
||||||
*
|
|
||||||
* <p>Applications do not normally need to use this themselves. The default
|
|
||||||
* behavior of ListFragment is to start with the list not being shown, only
|
|
||||||
* showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.
|
|
||||||
* If the list at that point had not been shown, when it does get shown
|
|
||||||
* it will be do without the user ever seeing the hidden state.
|
|
||||||
*
|
|
||||||
* @param shown If true, the list view is shown; if false, the progress
|
|
||||||
* indicator. The initial value is true.
|
|
||||||
*/
|
|
||||||
public void setListShown(boolean shown) {
|
|
||||||
setListShown(shown, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like {@link #setListShown(boolean)}, but no animation is used when
|
|
||||||
* transitioning from the previous state.
|
|
||||||
*/
|
|
||||||
public void setListShownNoAnimation(boolean shown) {
|
|
||||||
setListShown(shown, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Control whether the list is being displayed. You can make it not
|
|
||||||
* displayed if you are waiting for the initial data to show in it. During
|
|
||||||
* this time an indeterminant progress indicator will be shown instead.
|
|
||||||
*
|
|
||||||
* @param shown If true, the list view is shown; if false, the progress
|
|
||||||
* indicator. The initial value is true.
|
|
||||||
* @param animate If true, an animation will be used to transition to the
|
|
||||||
* new state.
|
|
||||||
*/
|
|
||||||
private void setListShown(boolean shown, boolean animate) {
|
|
||||||
ensureList();
|
|
||||||
if (mListShown == shown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mListShown = shown;
|
|
||||||
if (shown) {
|
|
||||||
if (animate) {
|
|
||||||
mList.startAnimation(AnimationUtils.loadAnimation(
|
|
||||||
getActivity(), android.R.anim.fade_in));
|
|
||||||
}
|
|
||||||
mList.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
if (animate) {
|
|
||||||
mList.startAnimation(AnimationUtils.loadAnimation(
|
|
||||||
getActivity(), android.R.anim.fade_out));
|
|
||||||
}
|
|
||||||
mList.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the ListAdapter associated with this activity's ListView.
|
|
||||||
*/
|
|
||||||
public ExpandableListAdapter getExpandableListAdapter() {
|
|
||||||
return mAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureList() {
|
|
||||||
if (mList != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
View root = getView();
|
|
||||||
if (root == null) {
|
|
||||||
throw new IllegalStateException("Content view not yet created");
|
|
||||||
}
|
|
||||||
if (root instanceof ExpandableListView) {
|
|
||||||
mList = (ExpandableListView)root;
|
|
||||||
} else {
|
|
||||||
mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID);
|
|
||||||
if (mStandardEmptyView == null) {
|
|
||||||
mEmptyView = root.findViewById(android.R.id.empty);
|
|
||||||
}
|
|
||||||
View rawListView = root.findViewById(android.R.id.list);
|
|
||||||
if (!(rawListView instanceof ExpandableListView)) {
|
|
||||||
if (rawListView == null) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Your content must have a ExpandableListView whose id attribute is " +
|
|
||||||
"'android.R.id.list'");
|
|
||||||
}
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Content has view with id attribute 'android.R.id.list' "
|
|
||||||
+ "that is not a ExpandableListView class");
|
|
||||||
}
|
|
||||||
mList = (ExpandableListView)rawListView;
|
|
||||||
if (mEmptyView != null) {
|
|
||||||
mList.setEmptyView(mEmptyView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mListShown = true;
|
|
||||||
mList.setOnItemClickListener(mOnClickListener);
|
|
||||||
if (mAdapter != null) {
|
|
||||||
setListAdapter(mAdapter);
|
|
||||||
} else {
|
|
||||||
// We are starting without an adapter, so assume we won't
|
|
||||||
// have our data right away and start with the progress indicator.
|
|
||||||
setListShown(false, false);
|
|
||||||
}
|
|
||||||
mHandler.post(mRequestFocus);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onContentChanged() {
|
|
||||||
View emptyView = getView().findViewById(android.R.id.empty);
|
|
||||||
mList = (ExpandableListView)getView().findViewById(android.R.id.list);
|
|
||||||
if (mList == null) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Your content must have a ExpandableListView whose id attribute is " +
|
|
||||||
"'android.R.id.list'");
|
|
||||||
}
|
|
||||||
if (emptyView != null) {
|
|
||||||
mList.setEmptyView(emptyView);
|
|
||||||
}
|
|
||||||
mList.setOnChildClickListener(this);
|
|
||||||
mList.setOnGroupExpandListener(this);
|
|
||||||
mList.setOnGroupCollapseListener(this);
|
|
||||||
|
|
||||||
if (mFinishedStart) {
|
|
||||||
setListAdapter(mAdapter);
|
|
||||||
}
|
|
||||||
mFinishedStart = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGroupExpand(int groupPosition) {
|
|
||||||
// override me
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGroupCollapse(int groupPosition) {
|
|
||||||
// override me
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onChildClick(ExpandableListView parent, View v,
|
|
||||||
int groupPosition, int childPosition, long id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.gtasks;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.tasks.R;
|
|
||||||
import com.todoroo.andlib.service.Autowired;
|
|
||||||
import com.todoroo.andlib.service.ContextManager;
|
|
||||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
|
||||||
import com.todoroo.astrid.api.AstridApiConstants;
|
|
||||||
import com.todoroo.astrid.api.SyncAction;
|
|
||||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes sync action
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class GtasksSyncActionExposer extends BroadcastReceiver {
|
|
||||||
|
|
||||||
@Autowired private GtasksPreferenceService gtasksPreferenceService;
|
|
||||||
|
|
||||||
static {
|
|
||||||
AstridDependencyInjector.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
ContextManager.setContext(context);
|
|
||||||
DependencyInjectionService.getInstance().inject(this);
|
|
||||||
|
|
||||||
// if we aren't logged in, don't expose sync action
|
|
||||||
if(!gtasksPreferenceService.isLoggedIn()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent syncIntent = new Intent(null, null,
|
|
||||||
context, GtasksBackgroundService.class);
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0, syncIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
SyncAction syncAction = new SyncAction(context.getString(R.string.gtasks_GPr_header),
|
|
||||||
pendingIntent);
|
|
||||||
|
|
||||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS);
|
|
||||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, GtasksPreferenceService.IDENTIFIER);
|
|
||||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, syncAction);
|
|
||||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.gtasks.api;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.google.api.services.tasks.model.Task;
|
|
||||||
/**
|
|
||||||
* Encapsulates a request to the api to move a task from one list to another
|
|
||||||
* @author Sam Bosley
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class MoveListRequest extends PushRequest {
|
|
||||||
|
|
||||||
private String idTaskToMove;
|
|
||||||
private String dstList;
|
|
||||||
private final String newParent;
|
|
||||||
|
|
||||||
public MoveListRequest(GtasksInvoker service, String idTask, String srcList, String dstList, String newParent) {
|
|
||||||
super(service, srcList, new Task());
|
|
||||||
this.idTaskToMove = idTask;
|
|
||||||
this.dstList = dstList;
|
|
||||||
this.newParent = newParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Task executePush() throws IOException {
|
|
||||||
Task localSave = service.getGtask(super.getListId(), idTaskToMove);
|
|
||||||
service.deleteGtask(super.getListId(), idTaskToMove);
|
|
||||||
transferProperties(localSave);
|
|
||||||
return service.createGtask(dstList, toPush);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void recover() {
|
|
||||||
//If there's a good way to recover, put it here
|
|
||||||
//Since MoveListRequest isn't actually used at the moment, it's probably fine for now
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transferProperties(Task local) {
|
|
||||||
toPush.setCompleted(local.getCompleted());
|
|
||||||
toPush.setDeleted(local.getDeleted());
|
|
||||||
toPush.setDue(local.getDue());
|
|
||||||
toPush.setHidden(local.getHidden());
|
|
||||||
toPush.setNotes(local.getNotes());
|
|
||||||
toPush.setStatus(local.getStatus());
|
|
||||||
toPush.setTitle(local.getTitle());
|
|
||||||
|
|
||||||
toPush.setParent(newParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIdTaskToMove() {
|
|
||||||
return idTaskToMove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIdTaskToMove(String idTaskToMove) {
|
|
||||||
this.idTaskToMove = idTaskToMove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDstList() {
|
|
||||||
return dstList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDstList(String dstList) {
|
|
||||||
this.dstList = dstList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.gtasks.api;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.google.api.services.tasks.model.Task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates a request to the api to update a task on the remote server
|
|
||||||
* @author Sam Bosley
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class UpdateRequest extends PushRequest {
|
|
||||||
|
|
||||||
public UpdateRequest(GtasksInvoker service, String listId, Task toUpdate) {
|
|
||||||
super(service, listId, toUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Task executePush() throws IOException {
|
|
||||||
return service.updateGtask(listId, toPush);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void recover() {
|
|
||||||
//Figure out a good way to recover!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* 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 com.todoroo.astrid.gtasks.auth;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Choose which account to upload track information to.
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
public class AccountChooser {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last selected account.
|
|
||||||
*/
|
|
||||||
private int selectedAccountIndex = -1;
|
|
||||||
private Account selectedAccount = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for receiving updates once the user has selected the account.
|
|
||||||
*/
|
|
||||||
public interface AccountHandler {
|
|
||||||
/**
|
|
||||||
* Handle the account being selected.
|
|
||||||
* @param account The selected account or null if none could be found
|
|
||||||
*/
|
|
||||||
public void handleAccountSelected(Account account);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chooses the best account to upload to.
|
|
||||||
* If no account is found the user will be alerted.
|
|
||||||
* If only one account is found that will be used.
|
|
||||||
* If multiple accounts are found the user will be allowed to choose.
|
|
||||||
*
|
|
||||||
* @param activity The parent activity
|
|
||||||
* @param handler The handler to be notified when an account has been selected
|
|
||||||
*/
|
|
||||||
public void chooseAccount(final Activity activity,
|
|
||||||
final AccountHandler handler) {
|
|
||||||
final Account[] accounts = AccountManager.get(activity)
|
|
||||||
.getAccountsByType("com.google"); //$NON-NLS-1$
|
|
||||||
if (accounts.length < 1) {
|
|
||||||
alertNoAccounts(activity, handler);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (accounts.length == 1) {
|
|
||||||
handler.handleAccountSelected(accounts[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO This should be read out of a preference.
|
|
||||||
if (selectedAccount != null) {
|
|
||||||
handler.handleAccountSelected(selectedAccount);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the user choose.
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
builder.setCancelable(false);
|
|
||||||
builder.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
selectedAccount = accounts[selectedAccountIndex];
|
|
||||||
handler.handleAccountSelected(selectedAccount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(android.R.string.cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
handler.handleAccountSelected(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
String[] choices = new String[accounts.length];
|
|
||||||
for (int i = 0; i < accounts.length; i++) {
|
|
||||||
choices[i] = accounts[i].name;
|
|
||||||
}
|
|
||||||
builder.setSingleChoiceItems(choices, selectedAccountIndex,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
selectedAccountIndex = which;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts up a dialog alerting the user that no suitable account was found.
|
|
||||||
*/
|
|
||||||
private void alertNoAccounts(final Activity activity,
|
|
||||||
final AccountHandler handler) {
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
builder.setMessage("No Accounts Found."); //$NON-NLS-1$
|
|
||||||
builder.setCancelable(true);
|
|
||||||
builder.setNegativeButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
handler.handleAccountSelected(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.show();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* 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 com.todoroo.astrid.gtasks.auth;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This interface describes a class that will fetch and maintain a Google
|
|
||||||
* authentication token.
|
|
||||||
*
|
|
||||||
* @author Sandor Dornbush
|
|
||||||
*/
|
|
||||||
public interface AuthManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the login process. The user should be asked to login if they
|
|
||||||
* haven't already. The {@link Runnable} provided will be executed when the
|
|
||||||
* auth token is successfully fetched.
|
|
||||||
*
|
|
||||||
* @param whenFinished A {@link Runnable} to execute when the auth token
|
|
||||||
* has been successfully fetched and is available via
|
|
||||||
* {@link #getAuthToken()}
|
|
||||||
*/
|
|
||||||
public abstract void doLogin(Runnable whenFinished, Object o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link android.app.Activity} owner of this class should call this
|
|
||||||
* function when it gets {@link android.app.Activity#onActivityResult} with
|
|
||||||
* the request code passed into the constructor. The resultCode and results
|
|
||||||
* should come directly from the {@link android.app.Activity#onActivityResult}
|
|
||||||
* function. This function will return true if an auth token was successfully
|
|
||||||
* fetched or the process is not finished.
|
|
||||||
*
|
|
||||||
* @param resultCode The result code passed in to the
|
|
||||||
* {@link android.app.Activity}'s
|
|
||||||
* {@link android.app.Activity#onActivityResult} function
|
|
||||||
* @param results The data passed in to the {@link android.app.Activity}'s
|
|
||||||
* {@link android.app.Activity#onActivityResult} function
|
|
||||||
* @return True if the auth token was fetched or we aren't done fetching
|
|
||||||
* the auth token, or False if there was an error or the request was
|
|
||||||
* canceled
|
|
||||||
*/
|
|
||||||
public abstract boolean authResult(int resultCode, Intent results);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current auth token. Response may be null if no valid auth
|
|
||||||
* token has been fetched.
|
|
||||||
*
|
|
||||||
* @return The current auth token or null if no auth token has been
|
|
||||||
* fetched
|
|
||||||
*/
|
|
||||||
public abstract String getAuthToken();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the existing auth token and request a new one. The
|
|
||||||
* {@link Runnable} provided will be executed when the new auth token is
|
|
||||||
* successfully fetched.
|
|
||||||
*
|
|
||||||
* @param whenFinished A {@link Runnable} to execute when a new auth token
|
|
||||||
* is successfully fetched
|
|
||||||
*/
|
|
||||||
public abstract void invalidateAndRefresh(Runnable whenFinished);
|
|
||||||
|
|
||||||
}
|
|
@ -1,231 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* 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 com.todoroo.astrid.gtasks.auth;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.AccountManager;
|
|
||||||
import android.accounts.AccountManagerCallback;
|
|
||||||
import android.accounts.AccountManagerFuture;
|
|
||||||
import android.accounts.AuthenticatorException;
|
|
||||||
import android.accounts.OperationCanceledException;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AuthManager keeps track of the current auth token for a user. The advantage
|
|
||||||
* over just passing around a String is that this class can renew the auth
|
|
||||||
* token if necessary, and it will change for all classes using this
|
|
||||||
* AuthManager.
|
|
||||||
*/
|
|
||||||
public class ModernAuthManager implements AuthManager {
|
|
||||||
protected static final int GET_LOGIN_REQUEST = 1;
|
|
||||||
|
|
||||||
/** The activity that will handle auth result callbacks. */
|
|
||||||
private final Activity activity;
|
|
||||||
|
|
||||||
/** The name of the service to authorize for. */
|
|
||||||
private final String service;
|
|
||||||
|
|
||||||
/** The most recently fetched auth token or null if none is available. */
|
|
||||||
private String authToken;
|
|
||||||
|
|
||||||
private final AccountManager accountManager;
|
|
||||||
|
|
||||||
private Runnable whenFinished;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AuthManager requires many of the same parameters as
|
|
||||||
* {@link com.google.android.googlelogindist.GoogleLoginServiceHelper
|
|
||||||
* #getCredentials(Activity, int, Bundle, boolean, String, boolean)}.
|
|
||||||
* The activity must have a handler in {@link Activity#onActivityResult} that
|
|
||||||
* calls {@link #authResult(int, Intent)} if the request code is the code
|
|
||||||
* given here.
|
|
||||||
*
|
|
||||||
* @param activity An activity with a handler in
|
|
||||||
* {@link Activity#onActivityResult} that calls
|
|
||||||
* {@link #authResult(int, Intent)} when {@literal code} is the request
|
|
||||||
* code
|
|
||||||
* @param code The request code to pass to
|
|
||||||
* {@link Activity#onActivityResult} when
|
|
||||||
* {@link #authResult(int, Intent)} should be called
|
|
||||||
* @param extras A {@link Bundle} of extras for
|
|
||||||
* {@link com.google.android.googlelogindist.GoogleLoginServiceHelper}
|
|
||||||
* @param requireGoogle True if the account must be a Google account
|
|
||||||
* @param service The name of the service to authenticate as
|
|
||||||
*/
|
|
||||||
public ModernAuthManager(Activity activity, int code, Bundle extras,
|
|
||||||
boolean requireGoogle, String service) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.service = service;
|
|
||||||
this.accountManager = AccountManager.get(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this to do the initial login. The user will be asked to login if
|
|
||||||
* they haven't already. The {@link Runnable} provided will be executed
|
|
||||||
* when the auth token is successfully fetched.
|
|
||||||
*
|
|
||||||
* @param runnable A {@link Runnable} to execute when the auth token
|
|
||||||
* has been successfully fetched and is available via
|
|
||||||
* {@link #getAuthToken()}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void doLogin(final Runnable runnable, Object o) {
|
|
||||||
this.whenFinished = runnable;
|
|
||||||
if (!(o instanceof Account)) {
|
|
||||||
throw new IllegalArgumentException("FroyoAuthManager requires an account.");
|
|
||||||
}
|
|
||||||
Account account = (Account) o;
|
|
||||||
accountManager.getAuthToken(account, service, true,
|
|
||||||
new AccountManagerCallback<Bundle>() {
|
|
||||||
@Override
|
|
||||||
public void run(AccountManagerFuture<Bundle> future) {
|
|
||||||
try {
|
|
||||||
Bundle result = future.getResult();
|
|
||||||
|
|
||||||
// AccountManager needs user to grant permission
|
|
||||||
if (result.containsKey(AccountManager.KEY_INTENT)) {
|
|
||||||
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
|
|
||||||
clearNewTaskFlag(intent);
|
|
||||||
activity.startActivityForResult(intent, GET_LOGIN_REQUEST);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken = result.getString(
|
|
||||||
AccountManager.KEY_AUTHTOKEN);
|
|
||||||
Log.e("gtasks-auth", "Got auth token.");
|
|
||||||
runWhenFinished();
|
|
||||||
} catch (OperationCanceledException e) {
|
|
||||||
Log.e("gtasks-auth", "Operation Canceled", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e("gtasks-auth", "IOException", e);
|
|
||||||
} catch (AuthenticatorException e) {
|
|
||||||
Log.e("gtasks-auth", "Authentication Failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, null /* handler */);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void clearNewTaskFlag(Intent intent) {
|
|
||||||
int flags = intent.getFlags();
|
|
||||||
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
|
|
||||||
intent.setFlags(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link Activity} passed into the constructor should call this
|
|
||||||
* function when it gets {@link Activity#onActivityResult} with the request
|
|
||||||
* code passed into the constructor. The resultCode and results should
|
|
||||||
* come directly from the {@link Activity#onActivityResult} function. This
|
|
||||||
* function will return true if an auth token was successfully fetched or
|
|
||||||
* the process is not finished.
|
|
||||||
*
|
|
||||||
* @param resultCode The result code passed in to the {@link Activity}'s
|
|
||||||
* {@link Activity#onActivityResult} function
|
|
||||||
* @param results The data passed in to the {@link Activity}'s
|
|
||||||
* {@link Activity#onActivityResult} function
|
|
||||||
* @return True if the auth token was fetched or we aren't done fetching
|
|
||||||
* the auth token, or False if there was an error or the request was
|
|
||||||
* canceled
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean authResult(int resultCode, Intent results) {
|
|
||||||
if (results != null) {
|
|
||||||
authToken = results.getStringExtra(
|
|
||||||
AccountManager.KEY_AUTHTOKEN);
|
|
||||||
Log.w("google-auth", "authResult: " + authToken);
|
|
||||||
} else {
|
|
||||||
Log.e("google-auth", "No auth result results!!");
|
|
||||||
}
|
|
||||||
runWhenFinished();
|
|
||||||
return authToken != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current auth token. Response may be null if no valid auth
|
|
||||||
* token has been fetched.
|
|
||||||
*
|
|
||||||
* @return The current auth token or null if no auth token has been
|
|
||||||
* fetched
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getAuthToken() {
|
|
||||||
return authToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the existing auth token and request a new one. The
|
|
||||||
* {@link Runnable} provided will be executed when the new auth token is
|
|
||||||
* successfully fetched.
|
|
||||||
*
|
|
||||||
* @param runnable A {@link Runnable} to execute when a new auth token
|
|
||||||
* is successfully fetched
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void invalidateAndRefresh(final Runnable runnable) {
|
|
||||||
this.whenFinished = runnable;
|
|
||||||
|
|
||||||
activity.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
accountManager.invalidateAuthToken("com.google", authToken); //$NON-NLS-1$
|
|
||||||
new AccountChooser().chooseAccount(activity,
|
|
||||||
new AccountChooser.AccountHandler() {
|
|
||||||
@Override
|
|
||||||
public void handleAccountSelected(Account account) {
|
|
||||||
if (account != null) {
|
|
||||||
doLogin(whenFinished, account);
|
|
||||||
} else {
|
|
||||||
runWhenFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runWhenFinished() {
|
|
||||||
if (whenFinished != null) {
|
|
||||||
(new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
whenFinished.run();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getAccounts(Activity activity) {
|
|
||||||
try {
|
|
||||||
GoogleAccountManager accountManager = new GoogleAccountManager(activity);
|
|
||||||
Account[] accounts = accountManager.getAccounts();
|
|
||||||
ArrayList<String> accountNames = new ArrayList<String>();
|
|
||||||
for (Account a : accounts) {
|
|
||||||
accountNames.add(a.name);
|
|
||||||
}
|
|
||||||
return accountNames.toArray(new String[accountNames.size()]);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return new String[] {}; // Empty array on failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,167 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.gtasks.sync;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.api.services.tasks.model.TaskList;
|
|
||||||
import com.google.api.services.tasks.model.TaskLists;
|
|
||||||
import com.google.api.services.tasks.model.Tasks;
|
|
||||||
import com.todoroo.andlib.data.TodorooCursor;
|
|
||||||
import com.todoroo.andlib.service.Autowired;
|
|
||||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
|
||||||
import com.todoroo.andlib.sql.Query;
|
|
||||||
import com.todoroo.andlib.utility.Preferences;
|
|
||||||
import com.todoroo.astrid.data.Metadata;
|
|
||||||
import com.todoroo.astrid.data.Task;
|
|
||||||
import com.todoroo.astrid.gtasks.GtasksListService;
|
|
||||||
import com.todoroo.astrid.gtasks.GtasksMetadata;
|
|
||||||
import com.todoroo.astrid.gtasks.GtasksMetadataService;
|
|
||||||
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
|
|
||||||
import com.todoroo.astrid.gtasks.api.GtasksInvoker;
|
|
||||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
|
||||||
import com.todoroo.astrid.service.MetadataService;
|
|
||||||
import com.todoroo.astrid.service.TaskService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to handle migration of legacy metadata (old remote ids) to new
|
|
||||||
* metadata based on the official remote ids returned by the api.
|
|
||||||
* @author Sam Bosley
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class GtasksLegacyMigrator {
|
|
||||||
|
|
||||||
@Autowired GtasksMetadataService gtasksMetadataService;
|
|
||||||
@Autowired TaskService taskService;
|
|
||||||
@Autowired MetadataService metadataService;
|
|
||||||
@Autowired GtasksListService gtasksListService;
|
|
||||||
@Autowired GtasksPreferenceService gtasksPreferenceService;
|
|
||||||
|
|
||||||
private final GtasksInvoker gtasksService;
|
|
||||||
private final GtasksListService listService;
|
|
||||||
private final TaskLists allLists;
|
|
||||||
|
|
||||||
static {
|
|
||||||
AstridDependencyInjector.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GtasksLegacyMigrator(GtasksInvoker service,GtasksListService listService, TaskLists allLists) {
|
|
||||||
DependencyInjectionService.getInstance().inject(this);
|
|
||||||
this.gtasksService = service;
|
|
||||||
this.listService = listService;
|
|
||||||
this.allLists = allLists;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkAndMigrateLegacy() throws IOException {
|
|
||||||
if (!gtasksPreferenceService.migrationHasOccurred()) {
|
|
||||||
|
|
||||||
//Fetch all tasks that have associated gtask metadata
|
|
||||||
String defaultListTitle = gtasksListService.getListName(Preferences.getStringValue(GtasksPreferenceService.PREF_DEFAULT_LIST));
|
|
||||||
String defaultListId = null;
|
|
||||||
|
|
||||||
TodorooCursor<Task> allTasksWithGtaskData = taskService.query(Query.select(Task.PROPERTIES).
|
|
||||||
where(Task.ID.in(
|
|
||||||
Query.select(Metadata.TASK).from(Metadata.TABLE).
|
|
||||||
where(Metadata.KEY.eq(GtasksMetadata.METADATA_KEY)))));
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (allTasksWithGtaskData.getCount() > 0) {
|
|
||||||
//Fetch all remote tasks from all remote lists (this may be an expensive operation)
|
|
||||||
//and map their titles to their real remote ids
|
|
||||||
HashMap<String, String> taskAndListTitlesToRemoteTaskIds = new HashMap<String, String>();
|
|
||||||
|
|
||||||
List<TaskList> items = allLists.getItems();
|
|
||||||
for (TaskList list : items) {
|
|
||||||
if (list.getTitle().equals(defaultListTitle)) {
|
|
||||||
defaultListId = list.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
Tasks allTasks = gtasksService.getAllGtasksFromListId(list.getId(), false, false, 0);
|
|
||||||
|
|
||||||
List<com.google.api.services.tasks.model.Task> tasksItems = allTasks.getItems();
|
|
||||||
if (tasksItems != null) {
|
|
||||||
for (com.google.api.services.tasks.model.Task t : tasksItems) {
|
|
||||||
String key = constructKeyFromTitles(t.getTitle(), list.getTitle());
|
|
||||||
taskAndListTitlesToRemoteTaskIds.put(key, t.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultListId == null) {
|
|
||||||
com.google.api.services.tasks.model.TaskList defaultList = gtasksService.getGtaskList("@default"); //$NON-NLS-1$
|
|
||||||
defaultListId = defaultList.getId();
|
|
||||||
}
|
|
||||||
Preferences.setString(GtasksPreferenceService.PREF_DEFAULT_LIST, defaultListId);
|
|
||||||
|
|
||||||
//For each local task, check to see if its title paired with any list title has a match in the map
|
|
||||||
for (allTasksWithGtaskData.moveToFirst(); !allTasksWithGtaskData.isAfterLast(); allTasksWithGtaskData.moveToNext()) {
|
|
||||||
GtasksTaskContainer container = gtasksMetadataService.readTaskAndMetadata(allTasksWithGtaskData);
|
|
||||||
// memorize the original listname for the case that the task is not matched,
|
|
||||||
// then it should at least be recreated in the correct list
|
|
||||||
String originalListName = gtasksListService.getListName(
|
|
||||||
container.gtaskMetadata.getValue(GtasksMetadata.LIST_ID));
|
|
||||||
String originalListId = null;
|
|
||||||
|
|
||||||
//Search through lists to see if one of them has match
|
|
||||||
String taskTitle = container.task.getValue(Task.TITLE);
|
|
||||||
boolean foundMatch = false;
|
|
||||||
items = allLists.getItems();
|
|
||||||
for (TaskList list : items) {
|
|
||||||
String expectedKey = constructKeyFromTitles(taskTitle, list.getTitle());
|
|
||||||
|
|
||||||
// save the new id of the current list
|
|
||||||
// if it matches the listname of the current task
|
|
||||||
if (list.getTitle() != null && list.getTitle().equals(originalListName)) {
|
|
||||||
originalListId = list.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taskAndListTitlesToRemoteTaskIds.containsKey(expectedKey)) {
|
|
||||||
foundMatch = true;
|
|
||||||
String newRemoteTaskId = taskAndListTitlesToRemoteTaskIds.get(expectedKey);
|
|
||||||
String newRemoteListId = list.getId();
|
|
||||||
|
|
||||||
container.gtaskMetadata.setValue(GtasksMetadata.ID, newRemoteTaskId);
|
|
||||||
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, newRemoteListId);
|
|
||||||
gtasksMetadataService.saveTaskAndMetadata(container);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundMatch) {
|
|
||||||
//For non-matches, make the task look newly created
|
|
||||||
container.gtaskMetadata = GtasksMetadata.createEmptyMetadata(container.task.getId());
|
|
||||||
container.gtaskMetadata.setValue(GtasksMetadata.ID, ""); //$NON-NLS-1$
|
|
||||||
if (originalListId != null) {
|
|
||||||
// set the list-id based on the original listname, saved above during for-loop
|
|
||||||
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, originalListId);
|
|
||||||
} else {
|
|
||||||
// remote list or local list was renamed, so put this unmatched task in the default list
|
|
||||||
container.gtaskMetadata.setValue(GtasksMetadata.LIST_ID, defaultListId);
|
|
||||||
}
|
|
||||||
gtasksMetadataService.saveTaskAndMetadata(container);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// migrate the list-id's afterwards, so that we can put the non-matched tasks in their original lists
|
|
||||||
// if the listnames didnt change before migration (defaultlist otherwise)
|
|
||||||
listService.migrateListIds(allLists);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
allTasksWithGtaskData.close();
|
|
||||||
}
|
|
||||||
Preferences.setBoolean(GtasksPreferenceService.PREF_MIGRATION_HAS_OCCURRED, true); //Record successful migration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String constructKeyFromTitles(String taskTitle, String listTitle) {
|
|
||||||
return taskTitle + "//" + listTitle; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.legacy;
|
|
||||||
|
|
||||||
/** Legacy alert class */
|
|
||||||
abstract public class LegacyAlertModel {
|
|
||||||
|
|
||||||
public static final String TASK = "task";
|
|
||||||
public static final String DATE = "date";
|
|
||||||
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.reminders;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
public class ReminderPlugin extends BroadcastReceiver {
|
|
||||||
|
|
||||||
static final String IDENTIFIER = "reminders"; //$NON-NLS-1$
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
/*Plugin plugin = new Plugin(IDENTIFIER, "Reminders", "Todoroo",
|
|
||||||
"Provides notification reminders for tasks");
|
|
||||||
|
|
||||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_PLUGINS);
|
|
||||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_PLUGIN, plugin);
|
|
||||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.ViewGroup.LayoutParams;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import org.tasks.R;
|
|
||||||
import com.todoroo.astrid.ui.CalendarView.OnSelectedDateListener;
|
|
||||||
|
|
||||||
public class CalendarDialog extends Dialog implements OnClickListener, OnSelectedDateListener {
|
|
||||||
|
|
||||||
private final Button cancelButton;
|
|
||||||
private Date calendarDate;
|
|
||||||
|
|
||||||
private final CalendarView calendarView;
|
|
||||||
|
|
||||||
public CalendarDialog(Context context, Date calendarDate) {
|
|
||||||
super(context);
|
|
||||||
this.calendarDate = calendarDate;
|
|
||||||
/** 'Window.FEATURE_NO_TITLE' - Used to hide the title */
|
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
/** Design the dialog in main.xml file */
|
|
||||||
setContentView(R.layout.calendar);
|
|
||||||
|
|
||||||
LayoutParams params = getWindow().getAttributes();
|
|
||||||
params.height = LayoutParams.FILL_PARENT;
|
|
||||||
params.width = LayoutParams.FILL_PARENT;
|
|
||||||
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
|
|
||||||
|
|
||||||
cancelButton = (Button) findViewById(R.id.CancelButton);
|
|
||||||
|
|
||||||
calendarView = (CalendarView) findViewById(R.id.CalendarView);
|
|
||||||
calendarView.setCalendarDate(calendarDate);
|
|
||||||
calendarView.setOnSelectedDateListener(this);
|
|
||||||
|
|
||||||
cancelButton.setOnClickListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (v == cancelButton) {
|
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSelectedDate(Date date) {
|
|
||||||
calendarDate = date;
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getCalendarDate() {
|
|
||||||
return calendarDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCalendarDate(Date calendarDate) {
|
|
||||||
this.calendarDate = calendarDate;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2007 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* 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 com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.TimePickerDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.format.DateFormat;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
|
||||||
import android.widget.TimePicker;
|
|
||||||
import android.widget.TimePicker.OnTimeChangedListener;
|
|
||||||
|
|
||||||
import org.tasks.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dialog that prompts the user for the time of day using a {@link TimePicker}.
|
|
||||||
* This is similar to the Android {@link TimePickerDialog} class
|
|
||||||
* except allows users to specify "no specific time".
|
|
||||||
*/
|
|
||||||
public class DeadlineTimePickerDialog extends AlertDialog implements OnClickListener,
|
|
||||||
OnTimeChangedListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The callback interface used to indicate the user is done filling in
|
|
||||||
* the time (they clicked on the 'Set' button).
|
|
||||||
*/
|
|
||||||
public interface OnDeadlineTimeSetListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param view The view associated with this listener.
|
|
||||||
* @param hasTime whether time is set
|
|
||||||
* @param hourOfDay The hour that was set.
|
|
||||||
* @param minute The minute that was set.
|
|
||||||
*/
|
|
||||||
void onTimeSet(TimePicker view, boolean hasTime, int hourOfDay, int minute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String HOUR = "hour";
|
|
||||||
private static final String MINUTE = "minute";
|
|
||||||
private static final String IS_24_HOUR = "is24hour";
|
|
||||||
|
|
||||||
private final TimePicker mTimePicker;
|
|
||||||
private final CheckBox mHasTime;
|
|
||||||
private final OnDeadlineTimeSetListener mCallback;
|
|
||||||
private final Calendar mCalendar;
|
|
||||||
private final java.text.DateFormat mDateFormat;
|
|
||||||
|
|
||||||
int mInitialHourOfDay;
|
|
||||||
int mInitialMinute;
|
|
||||||
boolean mIs24HourView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context Parent.
|
|
||||||
* @param callBack How parent is notified.
|
|
||||||
* @param hourOfDay The initial hour.
|
|
||||||
* @param minute The initial minute.
|
|
||||||
* @param is24HourView Whether this is a 24 hour view, or AM/PM.
|
|
||||||
*/
|
|
||||||
public DeadlineTimePickerDialog(Context context,
|
|
||||||
OnDeadlineTimeSetListener callBack,
|
|
||||||
int hourOfDay, int minute, boolean is24HourView, boolean hasTime) {
|
|
||||||
this(context, android.R.style.Theme_Dialog,
|
|
||||||
callBack, hourOfDay, minute, is24HourView, hasTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context Parent.
|
|
||||||
* @param theme the theme to apply to this dialog
|
|
||||||
* @param callBack How parent is notified.
|
|
||||||
* @param hourOfDay The initial hour.
|
|
||||||
* @param minute The initial minute.
|
|
||||||
* @param is24HourView Whether this is a 24 hour view, or AM/PM.
|
|
||||||
*/
|
|
||||||
public DeadlineTimePickerDialog(Context context,
|
|
||||||
int theme,
|
|
||||||
OnDeadlineTimeSetListener callBack,
|
|
||||||
int hourOfDay, int minute, boolean is24HourView, boolean hasTime) {
|
|
||||||
super(context, theme);
|
|
||||||
mCallback = callBack;
|
|
||||||
mInitialHourOfDay = hourOfDay;
|
|
||||||
mInitialMinute = minute;
|
|
||||||
mIs24HourView = is24HourView;
|
|
||||||
|
|
||||||
mDateFormat = DateFormat.getTimeFormat(context);
|
|
||||||
mCalendar = Calendar.getInstance();
|
|
||||||
|
|
||||||
setButton(context.getText(android.R.string.ok), this);
|
|
||||||
setButton2(context.getText(android.R.string.cancel), (OnClickListener) null);
|
|
||||||
setIcon(R.drawable.ic_dialog_time);
|
|
||||||
|
|
||||||
LayoutInflater inflater =
|
|
||||||
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
View view = inflater.inflate(R.layout.time_picker_dialog, null);
|
|
||||||
setView(view);
|
|
||||||
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
|
|
||||||
mHasTime = (CheckBox) view.findViewById(R.id.hasTime);
|
|
||||||
OnCheckedChangeListener listener = new OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton buttonView,
|
|
||||||
boolean isChecked) {
|
|
||||||
mTimePicker.setEnabled(isChecked);
|
|
||||||
if(isChecked) {
|
|
||||||
updateTitle();
|
|
||||||
} else {
|
|
||||||
setTitle(R.string.TEA_urgency_none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mHasTime.setOnCheckedChangeListener(listener);
|
|
||||||
mHasTime.setChecked(hasTime);
|
|
||||||
listener.onCheckedChanged(null, hasTime);
|
|
||||||
|
|
||||||
// initialize state
|
|
||||||
mTimePicker.setCurrentHour(mInitialHourOfDay);
|
|
||||||
mTimePicker.setCurrentMinute(mInitialMinute);
|
|
||||||
mTimePicker.setIs24HourView(mIs24HourView);
|
|
||||||
mTimePicker.setOnTimeChangedListener(this);
|
|
||||||
updateTitle();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
if (mCallback != null) {
|
|
||||||
mTimePicker.clearFocus();
|
|
||||||
mCallback.onTimeSet(mTimePicker,
|
|
||||||
mHasTime.isChecked(),
|
|
||||||
mTimePicker.getCurrentHour(),
|
|
||||||
mTimePicker.getCurrentMinute());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
|
|
||||||
updateTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateTime(int hourOfDay, int minutOfHour) {
|
|
||||||
mTimePicker.setCurrentHour(hourOfDay);
|
|
||||||
mTimePicker.setCurrentMinute(minutOfHour);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTitle() {
|
|
||||||
int hour = mTimePicker.getCurrentHour();
|
|
||||||
int minute = mTimePicker.getCurrentMinute();
|
|
||||||
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
|
|
||||||
mCalendar.set(Calendar.MINUTE, minute);
|
|
||||||
setTitle(mDateFormat.format(mCalendar.getTime()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Bundle onSaveInstanceState() {
|
|
||||||
Bundle state = super.onSaveInstanceState();
|
|
||||||
state.putInt(HOUR, mTimePicker.getCurrentHour());
|
|
||||||
state.putInt(MINUTE, mTimePicker.getCurrentMinute());
|
|
||||||
state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRestoreInstanceState(Bundle savedInstanceState) {
|
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
|
||||||
int hour = savedInstanceState.getInt(HOUR);
|
|
||||||
int minute = savedInstanceState.getInt(MINUTE);
|
|
||||||
mTimePicker.setCurrentHour(hour);
|
|
||||||
mTimePicker.setCurrentMinute(minute);
|
|
||||||
mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
|
|
||||||
mTimePicker.setOnTimeChangedListener(this);
|
|
||||||
updateTitle();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,353 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.widget.ImageButton;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.TextView.OnEditorActionListener;
|
|
||||||
|
|
||||||
import org.tasks.R;
|
|
||||||
import com.todoroo.andlib.service.ContextManager;
|
|
||||||
import com.todoroo.andlib.utility.Preferences;
|
|
||||||
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
|
|
||||||
import com.todoroo.astrid.helper.AsyncImageView;
|
|
||||||
import com.todoroo.astrid.utility.ResourceDrawableCache;
|
|
||||||
|
|
||||||
public class PeopleContainer extends LinearLayout {
|
|
||||||
|
|
||||||
private boolean completeTags = false;
|
|
||||||
|
|
||||||
protected OnAddNewPersonListener onAddNewPerson = null;
|
|
||||||
|
|
||||||
protected Resources resources;
|
|
||||||
|
|
||||||
// --- accessors and boilerplate
|
|
||||||
|
|
||||||
public PeopleContainer(Context arg0, AttributeSet attrs) {
|
|
||||||
super(arg0, attrs);
|
|
||||||
resources = arg0.getResources();
|
|
||||||
TypedArray a = getContext().obtainStyledAttributes(attrs,
|
|
||||||
R.styleable.ContactsAutoComplete);
|
|
||||||
completeTags = a.getBoolean(R.styleable.ContactsAutoComplete_completeTags, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PeopleContainer(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnAddNewPersonListener {
|
|
||||||
public void textChanged(String text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnAddNewPerson(OnAddNewPersonListener onAddNewPerson) {
|
|
||||||
this.onAddNewPerson = onAddNewPerson;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- methods
|
|
||||||
|
|
||||||
public TextView addPerson() {
|
|
||||||
return addPerson("", "", false); //$NON-NLS-1$ //$NON-NLS-2$
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Adds a tag to the tag field */
|
|
||||||
public TextView addPerson(String person, String image, boolean hideRemove) {
|
|
||||||
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
|
|
||||||
// check if already exists
|
|
||||||
for(int i = 0; i < getChildCount(); i++) {
|
|
||||||
View view = getChildAt(i);
|
|
||||||
TextView matching = (TextView) view.findViewById(R.id.text1);
|
|
||||||
if(matching.getText().equals(person)) {
|
|
||||||
return matching;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final View tagItem = inflater.inflate(R.layout.contact_edit_row, null);
|
|
||||||
if(person.length() == 0) {
|
|
||||||
addView(tagItem, getChildCount());
|
|
||||||
} else {
|
|
||||||
addView(tagItem);
|
|
||||||
}
|
|
||||||
final ContactsAutoComplete textView = (ContactsAutoComplete)tagItem.
|
|
||||||
findViewById(R.id.text1);
|
|
||||||
textView.setText(person);
|
|
||||||
textView.setHint(R.string.actfm_person_hint);
|
|
||||||
|
|
||||||
if(completeTags) {
|
|
||||||
textView.setCompleteSharedTags(true);
|
|
||||||
textView.setHint(R.string.actfm_person_or_tag_hint);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ImageButton removeButton = (ImageButton)tagItem.findViewById(R.id.button1);
|
|
||||||
if (hideRemove) {
|
|
||||||
removeButton.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
removeButton.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
TextView lastView = getLastTextView();
|
|
||||||
if (lastView == textView && textView.getText().length() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getChildCount() > 1) {
|
|
||||||
removeView(tagItem);
|
|
||||||
} else {
|
|
||||||
textView.setText(""); //$NON-NLS-1$
|
|
||||||
textView.setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
final AsyncImageView imageView = (AsyncImageView)tagItem.
|
|
||||||
findViewById(R.id.icon);
|
|
||||||
imageView.setUrl(image);
|
|
||||||
if (TextUtils.isEmpty(textView.getText())) {
|
|
||||||
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
|
|
||||||
removeButton.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
|
|
||||||
if (!hideRemove) {
|
|
||||||
removeButton.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
textView.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
|
||||||
int after) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before,
|
|
||||||
int count) {
|
|
||||||
if(count > 0 && getLastTextView() == textView) {
|
|
||||||
addPerson("", "", false);
|
|
||||||
}
|
|
||||||
if (TextUtils.isEmpty(textView.getText())) {
|
|
||||||
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact));
|
|
||||||
removeButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image));
|
|
||||||
removeButton.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(onAddNewPerson != null) {
|
|
||||||
onAddNewPerson.textChanged(s.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
textView.setOnEditorActionListener(new OnEditorActionListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) {
|
|
||||||
if(actionId != EditorInfo.IME_NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(getLastTextView().getText().length() != 0) {
|
|
||||||
addPerson("", "", false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return textView;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get tags container last text view. might be null
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private TextView getLastTextView() {
|
|
||||||
for(int i = getChildCount() - 1; i >= 0; i--) {
|
|
||||||
View lastItem = getChildAt(i);
|
|
||||||
TextView lastText = (TextView) lastItem.findViewById(R.id.text1);
|
|
||||||
if(lastText.isEnabled()) {
|
|
||||||
return lastText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextView getTextView(int index) {
|
|
||||||
View item = getChildAt(index);
|
|
||||||
return (TextView) item.findViewById(R.id.text1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return json array of people
|
|
||||||
*/
|
|
||||||
public JSONArray toJSONArray() {
|
|
||||||
JSONArray people = new JSONArray();
|
|
||||||
for(int i = 0; i < getChildCount(); i++) {
|
|
||||||
TextView textView = getTextView(i);
|
|
||||||
JSONObject person = PeopleContainer.createUserJson(textView);
|
|
||||||
if(person != null) {
|
|
||||||
String email = person.optString("email"); //$NON-NLS-1$
|
|
||||||
if (email.indexOf('@') != -1) {
|
|
||||||
people.put(person);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return people;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject parseSharedWithAndTags(Activity activity, boolean peopleAsJSON) throws
|
|
||||||
JSONException, ParseSharedException {
|
|
||||||
JSONObject sharedWith = new JSONObject();
|
|
||||||
|
|
||||||
HashSet<String> addedEmails = new HashSet<String>();
|
|
||||||
HashSet<Long> addedIds = new HashSet<Long>();
|
|
||||||
JSONArray peopleList = new JSONArray();
|
|
||||||
for(int i = 0; i < getChildCount(); i++) {
|
|
||||||
TextView textView = getTextView(i);
|
|
||||||
String text = textView.getText().toString();
|
|
||||||
|
|
||||||
if(text.length() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(text.indexOf('@') == -1 && textView.isEnabled()) {
|
|
||||||
throw new ParseSharedException(textView,
|
|
||||||
activity.getString(R.string.actfm_EPA_invalid_email, text));
|
|
||||||
}
|
|
||||||
if (peopleAsJSON) {
|
|
||||||
JSONObject person = PeopleContainer.createUserJson(textView);
|
|
||||||
if (person != null) {
|
|
||||||
if (person.optBoolean("owner")) //$NON-NLS-1$
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String email = person.optString("email");
|
|
||||||
Long id = person.optLong("id", -1);
|
|
||||||
if (!TextUtils.isEmpty(email) && !addedEmails.contains(email)) {
|
|
||||||
addedEmails.add(email);
|
|
||||||
if (id > 0) {
|
|
||||||
addedIds.add(id);
|
|
||||||
}
|
|
||||||
peopleList.put(person);
|
|
||||||
} else if (id > 0 && !addedIds.contains(id)) {
|
|
||||||
addedIds.add(id);
|
|
||||||
peopleList.put(person);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!addedEmails.contains(text)) {
|
|
||||||
addedEmails.add(text);
|
|
||||||
peopleList.put(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(peopleList.length() > 0) {
|
|
||||||
sharedWith.put("p", peopleList);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sharedWith;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ParseSharedException extends Exception {
|
|
||||||
private static final long serialVersionUID = -4135848250086302970L;
|
|
||||||
public TextView view;
|
|
||||||
public String message;
|
|
||||||
|
|
||||||
public ParseSharedException(TextView view, String message) {
|
|
||||||
this.view = view;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add people from JSON Array
|
|
||||||
* @param people
|
|
||||||
*/
|
|
||||||
public void fromJSONArray(JSONArray people) throws JSONException {
|
|
||||||
for(int i = 0; i < people.length(); i++) {
|
|
||||||
JSONObject person = people.getJSONObject(i);
|
|
||||||
TextView textView = null;
|
|
||||||
String imageURL = person.optString("picture", "");
|
|
||||||
boolean owner = person.optBoolean("owner");
|
|
||||||
boolean hideRemove = owner;
|
|
||||||
String name = "";
|
|
||||||
|
|
||||||
if(person.has("id") && ActFmPreferenceService.userId().equals(person.getString("id"))) {
|
|
||||||
name = Preferences.getStringValue(ActFmPreferenceService.PREF_NAME);
|
|
||||||
hideRemove = true;
|
|
||||||
} else if(!TextUtils.isEmpty(person.optString("name")) && !"null".equals(person.optString("name"))) {
|
|
||||||
name = person.getString("name");
|
|
||||||
} else if(!TextUtils.isEmpty(person.optString("email")) && !"null".equals(person.optString("email"))) {
|
|
||||||
name = person.getString("email");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner) {
|
|
||||||
name = name + " " + ContextManager.getString(R.string.actfm_list_owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
textView = addPerson(name, imageURL, hideRemove);
|
|
||||||
|
|
||||||
if(textView != null) {
|
|
||||||
textView.setTag(person);
|
|
||||||
textView.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning: user json may not have a valid email address.
|
|
||||||
* @param textView
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static JSONObject createUserJson(TextView textView) {
|
|
||||||
if(textView.isEnabled() == false) {
|
|
||||||
return (JSONObject) textView.getTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
String text = textView.getText().toString().trim();
|
|
||||||
if(text.length() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject user = new JSONObject();
|
|
||||||
int bracket = text.lastIndexOf('<');
|
|
||||||
try {
|
|
||||||
if(bracket > -1) {
|
|
||||||
user.put("name", text.substring(0, bracket - 1).trim());
|
|
||||||
user.put("email", text.substring(bracket + 1, text.length() - 1).trim());
|
|
||||||
} else {
|
|
||||||
user.put("email", text);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2012 Todoroo Inc
|
|
||||||
*
|
|
||||||
* See the file "LICENSE" for the full license governing this code.
|
|
||||||
*/
|
|
||||||
package com.todoroo.astrid.ui;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class TextViewWithMeasureListener extends TextView {
|
|
||||||
|
|
||||||
public interface OnTextMeasureListener {
|
|
||||||
public void onTextSizeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private OnTextMeasureListener listener;
|
|
||||||
|
|
||||||
|
|
||||||
public TextViewWithMeasureListener(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onTextSizeChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public OnTextMeasureListener getOnTextSizeChangedListener() {
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnTextSizeChangedListener(OnTextMeasureListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You 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 com.todoroo.astrid.utility;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Escapes and unescapes <code>String</code>s for
|
|
||||||
* Java, Java Script, HTML, XML, and SQL.</p>
|
|
||||||
*
|
|
||||||
* @author Apache Jakarta Turbine
|
|
||||||
* @author Purple Technology
|
|
||||||
* @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
|
|
||||||
* @author Antony Riley
|
|
||||||
* @author Helge Tesgaard
|
|
||||||
* @author <a href="sean@boohai.com">Sean Brown</a>
|
|
||||||
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
|
|
||||||
* @author Phil Steitz
|
|
||||||
* @author Pete Gieser
|
|
||||||
* @since 2.0
|
|
||||||
* @version $Id: StringEscapeUtils.java 2696 2007-06-20 13:24:53Z damencho $
|
|
||||||
*/
|
|
||||||
public class StringEscapeUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p><code>StringEscapeUtils</code> instances should NOT be constructed in
|
|
||||||
* standard programming.</p>
|
|
||||||
*
|
|
||||||
* <p>Instead, the class should be used as:
|
|
||||||
* <pre>StringEscapeUtils.escapeJava("foo");</pre></p>
|
|
||||||
*
|
|
||||||
* <p>This constructor is public to permit tools that require a JavaBean
|
|
||||||
* instance to operate.</p>
|
|
||||||
*/
|
|
||||||
public StringEscapeUtils() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* <p>Unescapes a string containing entity escapes to a string
|
|
||||||
* containing the actual Unicode characters corresponding to the
|
|
||||||
* escapes. Supports HTML 4.0 entities.</p>
|
|
||||||
*
|
|
||||||
* <p>For example, the string "&lt;Fran&ccedil;ais&gt;"
|
|
||||||
* will become "<Français>"</p>
|
|
||||||
*
|
|
||||||
* <p>If an entity is unrecognized, it is left alone, and inserted
|
|
||||||
* verbatim into the result string. e.g. "&gt;&zzzz;x" will
|
|
||||||
* become ">&zzzz;x".</p>
|
|
||||||
*
|
|
||||||
* @param str the <code>String</code> to unescape, may be null
|
|
||||||
* @return a new unescaped <code>String</code>, <code>null</code> if null string input
|
|
||||||
* @see #escapeHtml(Writer, String)
|
|
||||||
*/
|
|
||||||
public static String unescapeHtml(String str) {
|
|
||||||
if (str == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
StringWriter writer = new StringWriter ((int)(str.length() * 1.5));
|
|
||||||
unescapeHtml(writer, str);
|
|
||||||
return writer.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
//assert false;
|
|
||||||
//should be impossible
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Unescapes a string containing entity escapes to a string
|
|
||||||
* containing the actual Unicode characters corresponding to the
|
|
||||||
* escapes. Supports HTML 4.0 entities.</p>
|
|
||||||
*
|
|
||||||
* <p>For example, the string "&lt;Fran&ccedil;ais&gt;"
|
|
||||||
* will become "<Français>"</p>
|
|
||||||
*
|
|
||||||
* <p>If an entity is unrecognized, it is left alone, and inserted
|
|
||||||
* verbatim into the result string. e.g. "&gt;&zzzz;x" will
|
|
||||||
* become ">&zzzz;x".</p>
|
|
||||||
*
|
|
||||||
* @param writer the writer receiving the unescaped string, not null
|
|
||||||
* @param string the <code>String</code> to unescape, may be null
|
|
||||||
* @throws IllegalArgumentException if the writer is null
|
|
||||||
* @throws IOException if an IOException occurs
|
|
||||||
* @see #escapeHtml(String)
|
|
||||||
*/
|
|
||||||
public static void unescapeHtml(Writer writer, String string) throws IOException {
|
|
||||||
if (writer == null ) {
|
|
||||||
throw new IllegalArgumentException ("The Writer must not be null.");
|
|
||||||
}
|
|
||||||
if (string == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Entities.HTML40.unescape(writer, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
@ -1,65 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2008 The Android Open Source Project
|
|
||||||
|
|
||||||
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.
|
|
||||||
-->
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:astrid="http://schemas.android.com/apk/res/org.tasks"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical" >
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal" >
|
|
||||||
|
|
||||||
<com.todoroo.astrid.helper.AsyncImageView
|
|
||||||
android:id="@+id/icon"
|
|
||||||
android:layout_width="31dip"
|
|
||||||
android:layout_height="35dip"
|
|
||||||
android:layout_margin="5dip"
|
|
||||||
astrid:defaultSrc="@drawable/icn_default_person_image"
|
|
||||||
android:gravity="center"
|
|
||||||
android:scaleType="fitCenter" />
|
|
||||||
|
|
||||||
<com.todoroo.astrid.ui.ContactsAutoComplete
|
|
||||||
android:id="@+id/text1"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginLeft="5dip"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="#00000000"
|
|
||||||
android:hint="@string/actfm_person_hint"
|
|
||||||
style="@style/TextAppearance"
|
|
||||||
android:textCursorDrawable="@null"
|
|
||||||
android:textSize="15sp" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button1"
|
|
||||||
android:layout_width="32dip"
|
|
||||||
android:layout_height="32dip"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_margin="4dip"
|
|
||||||
android:background="@drawable/btn_dismiss" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/divider"
|
|
||||||
style="@style/TEA_Separator"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="1dip" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -1,41 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
**
|
|
||||||
** Copyright 2007, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="5dip"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TimePicker android:id="@+id/timePicker"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
<CheckBox android:id="@+id/hasTime"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/TEA_urgency_specific_time"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
|
Loading…
Reference in New Issue