Crazy Astrid 3 activity merged in. Does it work? not really. But it's cool that it's there.
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* See the file "LICENSE" for the full license governing this code.
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.filters;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.astrid.activity.FilterListActivity;
|
||||||
|
import com.todoroo.astrid.api.AstridApiConstants;
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
import com.todoroo.astrid.api.FilterListItem;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes Astrid's built in filters to the {@link FilterListActivity}
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FilterExposer extends BroadcastReceiver {
|
||||||
|
|
||||||
|
public static Filter buildInboxFilter(Resources r) {
|
||||||
|
return new Filter(r.getString(R.string.BFE_Inbox),
|
||||||
|
r.getString(R.string.BFE_Inbox),
|
||||||
|
/*String.format("WHERE %s AND %s ORDER BY CASE %s WHEN 0 THEN (%d + 1000 * %s) ELSE (%s + 1000 * %s) END ASC", //$NON-NLS-1$
|
||||||
|
TaskSql.isActive(), TaskSql.isVisible(DateUtilities.now()),
|
||||||
|
Task.DUE_DATE, DateUtilities.now() + 60 * 24 * 3600, Task.IMPORTANCE,
|
||||||
|
Task.DUE_DATE, Task.IMPORTANCE)*/ "",
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
Resources r = context.getResources();
|
||||||
|
|
||||||
|
// build filters
|
||||||
|
Filter inbox = buildInboxFilter(r);
|
||||||
|
|
||||||
|
Filter all = new Filter(r.getString(R.string.BFE_All),
|
||||||
|
r.getString(R.string.BFE_All),
|
||||||
|
String.format("ORDER BY %s DESC", //$NON-NLS-1$
|
||||||
|
Task.ID.name),
|
||||||
|
null);
|
||||||
|
|
||||||
|
// transmit filter list
|
||||||
|
FilterListItem[] list = new FilterListItem[2];
|
||||||
|
list[0] = inbox;
|
||||||
|
list[1] = all;
|
||||||
|
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
|
||||||
|
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ITEMS, list);
|
||||||
|
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:type="radial"
|
||||||
|
android:startColor="#373737"
|
||||||
|
android:endColor="#000000"
|
||||||
|
android:gradientRadius="300"
|
||||||
|
android:centerX="0.5"
|
||||||
|
android:centerY="0.5" />
|
||||||
|
</shape>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="#ffffffff"
|
||||||
|
android:centerColor="#ff000000"
|
||||||
|
android:endColor="#ffffffff"
|
||||||
|
android:angle="0" />
|
||||||
|
</shape>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 222 B |
@ -0,0 +1,20 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/none" />
|
||||||
|
</selector>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 169 B |
@ -0,0 +1,26 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:state_pressed="false" android:state_enabled="true"
|
||||||
|
android:state_focused="false" android:drawable="@drawable/ic_tasklist_back" />
|
||||||
|
<item android:state_pressed="true" android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/ic_tasklist_back_pressed" />
|
||||||
|
<item android:state_pressed="false" android:state_enabled="true"
|
||||||
|
android:state_focused="true" android:drawable="@drawable/ic_tasklist_back_selected" />
|
||||||
|
|
||||||
|
</selector>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="@drawable/background_gradient">
|
||||||
|
|
||||||
|
<!-- Loading Filters label -->
|
||||||
|
<TextView android:id="@android:id/empty"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:text="@string/FLA_loading"
|
||||||
|
style="@style/TextAppearance.TLA_NoItems"/>
|
||||||
|
|
||||||
|
<!-- List -->
|
||||||
|
<ExpandableListView android:id="@android:id/list"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="@null"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
|
||||||
|
Copyright (c) 2009 Tim Su
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
-->
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:background="@drawable/background_gradient">
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/event"
|
||||||
|
android:paddingRight="8px"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<TextView android:id="@+id/name_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/TEA_name_label"
|
||||||
|
style="@style/TextAppearance.GEN_EditLabel"/>
|
||||||
|
|
||||||
|
<EditText android:id="@+id/name"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/TEA_name_hint"
|
||||||
|
android:autoText="true"
|
||||||
|
android:capitalize="sentences"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/importance_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/TEA_importance_label"
|
||||||
|
style="@style/TextAppearance.GEN_EditLabel"/>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/importance_container"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/urgency_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/TEA_urgency_label"
|
||||||
|
style="@style/TextAppearance.GEN_EditLabel"/>
|
||||||
|
|
||||||
|
<Spinner android:id="@+id/urgency"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/fixedDate"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/hiddenUntil_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/TEA_hiddenUntil_label"
|
||||||
|
style="@style/TextAppearance.GEN_EditLabel"/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/hiddenUntil"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
<TextView android:id="@+id/plugins_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/TEA_plugins_label"
|
||||||
|
android:visibility="gone"
|
||||||
|
style="@style/TextAppearance.GEN_EditLabel"/>
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/plugins_container"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:background="@drawable/black_white_gradient"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="5dip"
|
||||||
|
android:baselineAligned="false">
|
||||||
|
|
||||||
|
<Button android:id="@+id/save"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/TEA_save_label"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button android:id="@+id/discard"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/TEA_discard_label"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/background_gradient">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@drawable/edit_header">
|
||||||
|
|
||||||
|
<!-- Back Button -->
|
||||||
|
<ImageView android:id="@+id/back"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:src="@drawable/tasklist_back"
|
||||||
|
android:paddingTop="8px"
|
||||||
|
android:paddingLeft="5px"/>
|
||||||
|
|
||||||
|
<!-- List Label -->
|
||||||
|
<TextView android:id="@+id/listLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="100"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:paddingTop="6px"
|
||||||
|
android:paddingRight="50px"
|
||||||
|
style="@style/TextAppearance.TLA_Header"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="100">
|
||||||
|
|
||||||
|
<!-- No Tasks label -->
|
||||||
|
<TextView android:id="@android:id/empty"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/TLA_no_items"
|
||||||
|
style="@style/TextAppearance.TLA_NoItems"/>
|
||||||
|
|
||||||
|
<!-- Task List -->
|
||||||
|
<ListView android:id="@android:id/list"
|
||||||
|
android:background="@null"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<!-- Quick Add Task -->
|
||||||
|
<EditText android:id="@+id/quickAddText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="100"
|
||||||
|
android:hint="@string/TLA_quick_add_hint"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:autoText="true"
|
||||||
|
android:capitalize="sentences"/>
|
||||||
|
|
||||||
|
<!-- Quick Add Button -->
|
||||||
|
<ImageButton android:id="@+id/quickAddButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:src="@android:drawable/ic_input_add"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/row_layout"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@android:drawable/list_selector_background"
|
||||||
|
android:focusable="true"
|
||||||
|
android:paddingTop="2px"
|
||||||
|
android:paddingLeft="6dip"
|
||||||
|
android:paddingRight="6dip"
|
||||||
|
android:paddingBottom="2px"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- completion check-box -->
|
||||||
|
<CheckBox android:id="@+id/completeBox"
|
||||||
|
android:layout_width="40px"
|
||||||
|
android:layout_height="45px"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingLeft="10px" />
|
||||||
|
|
||||||
|
<LinearLayout android:id="@+id/details"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="100"
|
||||||
|
android:paddingLeft="10px"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- task name -->
|
||||||
|
<TextView android:id="@+id/title"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TextAppearance.TAd_ItemTitle"
|
||||||
|
android:gravity="center_vertical"/>
|
||||||
|
|
||||||
|
<!-- due date -->
|
||||||
|
<TextView android:id="@+id/dueDate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"/>
|
||||||
|
|
||||||
|
<!-- other details go here -->
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- importance -->
|
||||||
|
<View android:id="@+id/importance"
|
||||||
|
android:layout_width="12px"
|
||||||
|
android:layout_height="fill_parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Resources for built-in filter plug-in -->
|
||||||
|
|
||||||
|
<!-- Inbox Filter -->
|
||||||
|
<string name="BFE_Inbox">Inbox</string>
|
||||||
|
|
||||||
|
<!-- Completed Filter -->
|
||||||
|
<string name="BFE_Completed">Completed</string>
|
||||||
|
|
||||||
|
<!-- All Tasks Filter -->
|
||||||
|
<string name="BFE_All">All Tasks</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- ============================ General ============================= -->
|
||||||
|
|
||||||
|
<style name="TextAppearance" parent="android:TextAppearance" />
|
||||||
|
|
||||||
|
<!-- generic style for labels above edit boxes -->
|
||||||
|
<style name="TextAppearance.GEN_EditLabel">
|
||||||
|
<item name="android:textSize">14sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme" parent="android:Theme">
|
||||||
|
<item name="android:windowBackground">@null</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--========================= TaskListActivity ======================== -->
|
||||||
|
|
||||||
|
<style name="TextAppearance.TLA_NoItems">
|
||||||
|
<item name="android:textSize">20sp</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TLA_Header">
|
||||||
|
<item name="android:textSize">24sp</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- =========================== TaskAdapter =========================== -->
|
||||||
|
|
||||||
|
<style name="TextAppearance.TAd_ItemTitle">
|
||||||
|
<item name="android:textSize">22sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TAd_ItemTitle_Completed" parent="TextAppearance.TAd_ItemTitle">
|
||||||
|
<item name="android:textColor">#ff555555</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TAd_ItemDetails">
|
||||||
|
<item name="android:textSize">14sp</item>
|
||||||
|
<item name="android:textColor">#ff777777</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TAd_ItemDueDate" parent="TextAppearance.TAd_ItemDetails">
|
||||||
|
<item name="android:textColor">#ff7777aa</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TAd_ItemDueDate_Overdue" parent="TextAppearance.TAd_ItemDueDate">
|
||||||
|
<item name="android:textColor">#ffee5555</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- ======================== FilterListAdapter ======================== -->
|
||||||
|
|
||||||
|
<style name="TextAppearance.FLA_Filter" parent="TextAppearance.TAd_ItemTitle">
|
||||||
|
<item name="android:textSize">22sp</item>
|
||||||
|
<item name="android:paddingTop">5px</item>
|
||||||
|
<item name="android:paddingBottom">5px</item>
|
||||||
|
<item name="android:paddingLeft">10px</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.FLA_Header" parent="TextAppearance.TAd_ItemTitle">
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
|
<item name="android:textColor">#ffdddddd</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.FLA_Category" parent="TextAppearance.TAd_ItemTitle">
|
||||||
|
<item name="android:textColor">#ff7ada24</item>
|
||||||
|
<item name="android:textStyle">bold|italic</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:label="@string/FLA_search_label"
|
||||||
|
android:hint="@string/FLA_search_hint">
|
||||||
|
</searchable>
|
||||||
|
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* See the file "LICENSE" for the full license governing this code.
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.todoroo.andlib.data.AbstractModel;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.service.ExceptionService;
|
||||||
|
import com.todoroo.astrid.dao.Database;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This activity displays a <code>WebView</code> that allows users to log in to the
|
||||||
|
* synchronization provider requested. A callback method determines whether
|
||||||
|
* their login was successful and therefore whether to dismiss the dialog.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract public class AbstractModelActivity<TYPE extends AbstractModel> extends AstridActivity {
|
||||||
|
|
||||||
|
// --- bundle arguments
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action Item ID
|
||||||
|
*/
|
||||||
|
public static final String ID_TOKEN = "i"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// --- instance variables
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected ExceptionService exceptionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected Database database;
|
||||||
|
|
||||||
|
protected TYPE model = null;
|
||||||
|
|
||||||
|
// --- abstract methods
|
||||||
|
|
||||||
|
abstract protected TYPE fetchModel(long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Bente Dependency Injector
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractModelActivity() {
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
loadItem(getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
loadItem(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads action item from the given intent
|
||||||
|
* @param intent
|
||||||
|
*/
|
||||||
|
protected void loadItem(Intent intent) {
|
||||||
|
long idParam = intent.getLongExtra(ID_TOKEN, -1L);
|
||||||
|
if(idParam == -1) {
|
||||||
|
exceptionService.reportError("AMA-no-token", null); //$NON-NLS-1$
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
database.openForReading();
|
||||||
|
model = fetchModel(idParam);
|
||||||
|
|
||||||
|
if(model == null) {
|
||||||
|
exceptionService.reportError("AMA-no-task", new NullPointerException("model")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* See the file "LICENSE" for the full license governing this code.
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.activity;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.flurry.android.FlurryAgent;
|
||||||
|
import com.todoroo.andlib.service.ContextManager;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
import com.todoroo.astrid.utility.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General helpers for Astrid activities
|
||||||
|
*/
|
||||||
|
abstract public class AstridActivity extends Activity {
|
||||||
|
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstridActivity() {
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
ContextManager.setContext(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
FlurryAgent.onStartSession(this, Constants.FLURRY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
FlurryAgent.onEndSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,361 @@
|
|||||||
|
/**
|
||||||
|
* See the file "LICENSE" for the full license governing this code.
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.activity;
|
||||||
|
|
||||||
|
import android.app.ExpandableListActivity;
|
||||||
|
import android.app.SearchManager;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ExpandableListView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||||
|
|
||||||
|
import com.flurry.android.FlurryAgent;
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.ContextManager;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.service.ExceptionService;
|
||||||
|
import com.todoroo.andlib.utility.DialogUtilities;
|
||||||
|
import com.todoroo.astrid.adapter.FilterAdapter;
|
||||||
|
import com.todoroo.astrid.api.AstridApiConstants;
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
import com.todoroo.astrid.api.FilterListItem;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
import com.todoroo.astrid.utility.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity that displays a user's task lists and allows users
|
||||||
|
* to filter their task list.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FilterListActivity extends ExpandableListActivity {
|
||||||
|
|
||||||
|
// --- menu codes
|
||||||
|
|
||||||
|
private static final int MENU_SEARCH_ID = Menu.FIRST + 0;
|
||||||
|
private static final int MENU_HELP_ID = Menu.FIRST + 1;
|
||||||
|
|
||||||
|
private static final int CONTEXT_MENU_SHORTCUT = Menu.FIRST + 2;
|
||||||
|
private static final int CONTEXT_MENU_INTENT = Menu.FIRST + 3;
|
||||||
|
|
||||||
|
// --- instance variables
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected ExceptionService exceptionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected DialogUtilities dialogUtilities;
|
||||||
|
|
||||||
|
FilterAdapter adapter = null;
|
||||||
|
String search = null;
|
||||||
|
FilterReceiver filterReceiver = new FilterReceiver();
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ======================================================= initialization
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterListActivity() {
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called when loading up the activity */
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
ContextManager.setContext(this);
|
||||||
|
|
||||||
|
setContentView(R.layout.filter_list_activity);
|
||||||
|
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
|
||||||
|
|
||||||
|
setTitle(R.string.FLA_title);
|
||||||
|
setUpList();
|
||||||
|
getLists();
|
||||||
|
|
||||||
|
onNewIntent(getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when receiving a new intent. Intents this class handles:
|
||||||
|
* <ul>
|
||||||
|
* <li>ACTION_SEARCH - displays a search bar
|
||||||
|
* <li>ACTION_ADD_LIST - adds new lists to the merge adapter
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
|
||||||
|
final String intentAction = intent.getAction();
|
||||||
|
if (Intent.ACTION_SEARCH.equals(intentAction)) {
|
||||||
|
search = intent.getStringExtra(SearchManager.QUERY);
|
||||||
|
dialogUtilities.okDialog(this, "TODO!", null); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
search = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create options menu (displayed when user presses menu key)
|
||||||
|
*
|
||||||
|
* @return true if menu should be displayed
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
if(menu.size() > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
MenuItem item;
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_SEARCH_ID, Menu.NONE,
|
||||||
|
R.string.FLA_menu_search);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_search);
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_HELP_ID, Menu.NONE,
|
||||||
|
R.string.FLA_menu_help);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_help);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ============================================================ lifecycle
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
FlurryAgent.onStartSession(this, Constants.FLURRY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
FlurryAgent.onEndSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
registerReceiver(filterReceiver,
|
||||||
|
new IntentFilter(AstridApiConstants.BROADCAST_SEND_FILTERS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
unregisterReceiver(filterReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receiver which receives intents to add items to the filter list
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected class FilterReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
try {
|
||||||
|
Parcelable[] filters = intent.getExtras().
|
||||||
|
getParcelableArray(AstridApiConstants.EXTRAS_ITEMS);
|
||||||
|
for (Parcelable item : filters) {
|
||||||
|
adapter.add((FilterListItem)item);
|
||||||
|
}
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
} catch (Exception e) {
|
||||||
|
exceptionService.reportError("receive-filter-" + //$NON-NLS-1$
|
||||||
|
intent.getStringExtra(AstridApiConstants.EXTRAS_PLUGIN), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ===================================================== populating lists
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/** Sets up the coach list adapter */
|
||||||
|
protected void setUpList() {
|
||||||
|
adapter = new FilterAdapter(this);
|
||||||
|
setListAdapter(adapter);
|
||||||
|
|
||||||
|
registerForContextMenu(getExpandableListView());
|
||||||
|
getExpandableListView().setGroupIndicator(
|
||||||
|
getResources().getDrawable(R.drawable.expander_group));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a request for lists. The request is sent to every
|
||||||
|
* application registered to listen for this broadcast. Each application
|
||||||
|
* can then add lists to the
|
||||||
|
*/
|
||||||
|
protected void getLists() {
|
||||||
|
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_FILTERS);
|
||||||
|
sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ============================================================== actions
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles items being clicked. Return true if item is handled.
|
||||||
|
*/
|
||||||
|
protected boolean onItemClicked(FilterListItem item) {
|
||||||
|
if(item instanceof Filter) {
|
||||||
|
Filter filter = (Filter)item;
|
||||||
|
Intent intent = new Intent(FilterListActivity.this, TaskListActivity.class);
|
||||||
|
intent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onChildClick(ExpandableListView parent, View v,
|
||||||
|
int groupPosition, int childPosition, long id) {
|
||||||
|
FilterListItem item = (FilterListItem) adapter.getChild(groupPosition,
|
||||||
|
childPosition);
|
||||||
|
return onItemClicked(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGroupExpand(int groupPosition) {
|
||||||
|
FilterListItem item = (FilterListItem) adapter.getGroup(groupPosition);
|
||||||
|
onItemClicked(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGroupCollapse(int groupPosition) {
|
||||||
|
FilterListItem item = (FilterListItem) adapter.getGroup(groupPosition);
|
||||||
|
onItemClicked(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenuInfo menuInfo) {
|
||||||
|
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
|
||||||
|
|
||||||
|
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||||
|
FilterListItem item;
|
||||||
|
if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
|
||||||
|
int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||||
|
int childPos = ExpandableListView.getPackedPositionChild(info.packedPosition);
|
||||||
|
item = (FilterListItem) adapter.getChild(groupPos, childPos);
|
||||||
|
} else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||||
|
int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||||
|
item = (FilterListItem) adapter.getGroup(groupPos);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem menuItem;
|
||||||
|
|
||||||
|
if(item instanceof Filter) {
|
||||||
|
Filter filter = (Filter) item;
|
||||||
|
info.targetView.setTag(filter);
|
||||||
|
menuItem = menu.add(0, CONTEXT_MENU_SHORTCUT, 0, R.string.FLA_context_shortcut);
|
||||||
|
Intent shortcutIntent = new Intent(this, TaskListActivity.class);
|
||||||
|
shortcutIntent.setAction(Intent.ACTION_VIEW);
|
||||||
|
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_TITLE, filter.title);
|
||||||
|
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_SQL, filter.sqlQuery);
|
||||||
|
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_NEW_TASK_SQL, filter.sqlForNewTasks);
|
||||||
|
menuItem.setIntent(shortcutIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < item.contextMenuLabels.length; i++) {
|
||||||
|
if(item.contextMenuIntents.length <= i)
|
||||||
|
break;
|
||||||
|
menuItem = menu.add(0, CONTEXT_MENU_INTENT, 0, item.contextMenuLabels[i]);
|
||||||
|
menuItem.setIntent(item.contextMenuIntents[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(menu.size() > 0)
|
||||||
|
menu.setHeaderTitle(item.listingTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemSelected(int featureId, final MenuItem item) {
|
||||||
|
|
||||||
|
// handle my own menus
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case MENU_SEARCH_ID: {
|
||||||
|
onSearchRequested();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MENU_HELP_ID: {
|
||||||
|
// TODO
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CONTEXT_MENU_SHORTCUT: {
|
||||||
|
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo)item.getMenuInfo();
|
||||||
|
|
||||||
|
final Intent shortcutIntent = item.getIntent();
|
||||||
|
Filter filter = (Filter)info.targetView.getTag();
|
||||||
|
|
||||||
|
String dialogText = getString(R.string.FLA_shortcut_dialog);
|
||||||
|
final EditText editText = new EditText(this);
|
||||||
|
editText.setText(filter.listingTitle);
|
||||||
|
|
||||||
|
dialogUtilities.viewDialog(this, dialogText, editText,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
String label = editText.getText().toString();
|
||||||
|
|
||||||
|
Intent createShortcutIntent = new Intent();
|
||||||
|
createShortcutIntent.putExtra(
|
||||||
|
Intent.EXTRA_SHORTCUT_INTENT,
|
||||||
|
shortcutIntent);
|
||||||
|
createShortcutIntent.putExtra(
|
||||||
|
Intent.EXTRA_SHORTCUT_NAME, label);
|
||||||
|
createShortcutIntent.putExtra(
|
||||||
|
Intent.EXTRA_SHORTCUT_ICON,
|
||||||
|
((BitmapDrawable) getResources().getDrawable(
|
||||||
|
R.drawable.icon_tag)).getBitmap());
|
||||||
|
createShortcutIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
sendBroadcast(createShortcutIntent);
|
||||||
|
Toast.makeText(
|
||||||
|
FilterListActivity.this,
|
||||||
|
getString(
|
||||||
|
R.string.FLA_toast_onCreateShortcut,
|
||||||
|
label), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CONTEXT_MENU_INTENT: {
|
||||||
|
Intent intent = item.getIntent();
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* ASTRID: Android's Simple Task Recording Dashboard
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 Tim Su
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.timsu.astrid.utilities.StartupReceiver;
|
||||||
|
import com.todoroo.andlib.service.ExceptionService.TodorooUncaughtExceptionHandler;
|
||||||
|
import com.todoroo.astrid.filters.FilterExposer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HomeActivity is the primary activity for Astrid and determines which activity
|
||||||
|
* to launch next.
|
||||||
|
* <p>
|
||||||
|
* If the user is completely new, it launches {@link IntroductionActivity}.
|
||||||
|
* <p>
|
||||||
|
* If the user needs to sign in, it launches {@link SignInActivity}.
|
||||||
|
* <p>
|
||||||
|
* If the user has no coaches nd no tasks, it launches
|
||||||
|
* {@link CoachSelectorActivity}
|
||||||
|
* <p>
|
||||||
|
* Otherwise, it launches {@link TaskListActivity}.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HomeActivity extends AstridActivity {
|
||||||
|
|
||||||
|
public static final int REQUEST_SIGN_IN = 1;
|
||||||
|
public static final int REQUEST_INTRODUCTION = 2;
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ======================================================= initialization
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/** Called when loading up the activity */
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// set uncaught exception handler
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(new TodorooUncaughtExceptionHandler());
|
||||||
|
|
||||||
|
// open controllers & perform application startup rituals
|
||||||
|
StartupReceiver.onStartupApplication(this);
|
||||||
|
|
||||||
|
performRedirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ======================================================= event handlers
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform redirection to next activity
|
||||||
|
*/
|
||||||
|
private void performRedirection() {
|
||||||
|
Intent intent = new Intent(this, TaskListActivity.class);
|
||||||
|
intent.putExtra(TaskListActivity.TOKEN_FILTER, FilterExposer.buildInboxFilter(getResources()));
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,495 @@
|
|||||||
|
package com.todoroo.astrid.activity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.AbsListView.OnScrollListener;
|
||||||
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||||
|
|
||||||
|
import com.flurry.android.FlurryAgent;
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.timsu.astrid.activities.EditPreferences;
|
||||||
|
import com.timsu.astrid.activities.TaskEdit;
|
||||||
|
import com.todoroo.andlib.data.TodorooCursor;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.service.ExceptionService;
|
||||||
|
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||||
|
import com.todoroo.andlib.utility.DialogUtilities;
|
||||||
|
import com.todoroo.andlib.utility.Pair;
|
||||||
|
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||||
|
import com.todoroo.astrid.adapter.TaskAdapter.ViewHolder;
|
||||||
|
import com.todoroo.astrid.api.AstridApiConstants;
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
import com.todoroo.astrid.api.TaskDetail;
|
||||||
|
import com.todoroo.astrid.dao.Database;
|
||||||
|
import com.todoroo.astrid.filters.FilterExposer;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||||
|
import com.todoroo.astrid.service.TaskService;
|
||||||
|
import com.todoroo.astrid.utility.Constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary activity for the Bente application. Shows a list of upcoming
|
||||||
|
* tasks and a user's coaches.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TaskListActivity extends ListActivity implements OnScrollListener {
|
||||||
|
|
||||||
|
// --- activities
|
||||||
|
|
||||||
|
static final int ACTIVITY_EDIT_TASK = 0;
|
||||||
|
static final int ACTIVITY_SETTINGS = 1;
|
||||||
|
static final int ACTIVITY_PLUGINS = 2;
|
||||||
|
|
||||||
|
// --- menu codes
|
||||||
|
|
||||||
|
private static final int MENU_ADD_TASK_ID = Menu.FIRST + 0;
|
||||||
|
private static final int MENU_PLUGINS_ID = Menu.FIRST + 1;
|
||||||
|
private static final int MENU_SETTINGS_ID = Menu.FIRST + 2;
|
||||||
|
private static final int MENU_HELP_ID = Menu.FIRST + 3;
|
||||||
|
private static final int MENU_PLUGIN_INTENT_ID = Menu.FIRST + 4;
|
||||||
|
|
||||||
|
private static final int CONTEXT_MENU_EDIT_TASK_ID = Menu.FIRST + 5;
|
||||||
|
private static final int CONTEXT_MENU_DELETE_TASK_ID = Menu.FIRST + 6;
|
||||||
|
private static final int CONTEXT_MENU_PLUGIN_INTENT_ID = Menu.FIRST + 7;
|
||||||
|
|
||||||
|
// --- constants
|
||||||
|
|
||||||
|
public static final String TOKEN_FILTER = "filter"; //$NON-NLS-1$
|
||||||
|
public static final String TOKEN_SHORTCUT_SQL = "query"; //$NON-NLS-1$
|
||||||
|
public static final String TOKEN_SHORTCUT_TITLE = "title"; //$NON-NLS-1$
|
||||||
|
public static final String TOKEN_SHORTCUT_NEW_TASK_SQL = "newsql"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// --- instance variables
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected ExceptionService exceptionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected TaskService taskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected DialogUtilities dialogUtilities;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected Database database;
|
||||||
|
|
||||||
|
protected TaskAdapter taskAdapter = null;
|
||||||
|
protected DetailReceiver detailReceiver = new DetailReceiver();
|
||||||
|
|
||||||
|
Filter filter;
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ======================================================= initialization
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Bente Dependency Injector
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
AstridDependencyInjector.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskListActivity() {
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called when loading up the activity */
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.task_list_activity);
|
||||||
|
|
||||||
|
Bundle extras = getIntent().getExtras();
|
||||||
|
if(extras.containsKey(TOKEN_FILTER)) {
|
||||||
|
filter = extras.getParcelable(TOKEN_FILTER);
|
||||||
|
} else if(extras.containsKey(TOKEN_SHORTCUT_SQL)) {
|
||||||
|
filter = new Filter();
|
||||||
|
filter.sqlQuery = extras.getString(TOKEN_SHORTCUT_SQL);
|
||||||
|
filter.title = extras.getString(TOKEN_SHORTCUT_TITLE);
|
||||||
|
filter.sqlForNewTasks = extras.getString(TOKEN_SHORTCUT_NEW_TASK_SQL);
|
||||||
|
} else {
|
||||||
|
filter = FilterExposer.buildInboxFilter(getResources());
|
||||||
|
}
|
||||||
|
|
||||||
|
database.openForWriting();
|
||||||
|
setUpUiComponents();
|
||||||
|
setUpTaskList();
|
||||||
|
|
||||||
|
// cache some stuff
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
loadContextMenuIntents();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create options menu (displayed when user presses menu key)
|
||||||
|
*
|
||||||
|
* @return true if menu should be displayed
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
if(menu.size() > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
MenuItem item;
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_ADD_TASK_ID, Menu.NONE,
|
||||||
|
R.string.TLA_menu_add);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_add);
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_PLUGINS_ID, Menu.NONE,
|
||||||
|
R.string.TLA_menu_plugins);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_set_as);
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_SETTINGS_ID, Menu.NONE,
|
||||||
|
R.string.TLA_menu_settings);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_preferences);
|
||||||
|
|
||||||
|
item = menu.add(Menu.NONE, MENU_HELP_ID, Menu.NONE,
|
||||||
|
R.string.TLA_menu_help);
|
||||||
|
item.setIcon(android.R.drawable.ic_menu_help);
|
||||||
|
|
||||||
|
// ask about plug-ins
|
||||||
|
Intent queryIntent = new Intent(AstridApiConstants.ACTION_TASK_LIST_MENU);
|
||||||
|
PackageManager pm = getPackageManager();
|
||||||
|
List<ResolveInfo> resolveInfoList = pm.queryIntentActivities(queryIntent, 0);
|
||||||
|
int length = resolveInfoList.size();
|
||||||
|
for(int i = 0; i < length; i++) {
|
||||||
|
ResolveInfo resolveInfo = resolveInfoList.get(i);
|
||||||
|
item = menu.add(Menu.NONE, MENU_PLUGIN_INTENT_ID, Menu.NONE,
|
||||||
|
resolveInfo.loadLabel(pm));
|
||||||
|
item.setIcon(resolveInfo.loadIcon(pm));
|
||||||
|
Intent intent = new Intent(AstridApiConstants.ACTION_TASK_LIST_MENU);
|
||||||
|
intent.setClassName(resolveInfo.activityInfo.packageName,
|
||||||
|
resolveInfo.activityInfo.name);
|
||||||
|
item.setIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpUiComponents() {
|
||||||
|
((ImageView)findViewById(R.id.back)).setOnClickListener(new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent intent = new Intent(TaskListActivity.this,
|
||||||
|
FilterListActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
((TextView)findViewById(R.id.listLabel)).setText(filter.title);
|
||||||
|
|
||||||
|
((ImageButton)findViewById(R.id.quickAddButton)).setOnClickListener(new OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
TextView quickAdd = (TextView)findViewById(R.id.quickAddText);
|
||||||
|
Task task = quickAddTask(quickAdd.getText().toString());
|
||||||
|
if(quickAdd.getText().length() > 0) {
|
||||||
|
quickAdd.setText(""); //$NON-NLS-1$
|
||||||
|
loadTaskListContent(true);
|
||||||
|
} else {
|
||||||
|
Intent intent = new Intent(TaskListActivity.this, TaskEdit.class);
|
||||||
|
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, task.getId());
|
||||||
|
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quick-add a new task
|
||||||
|
* @param title
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
protected Task quickAddTask(String title) {
|
||||||
|
try {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setValue(Task.TITLE, title);
|
||||||
|
/*task.setValue(Task.DUE_DATE, Task.initializeDueDate(
|
||||||
|
task.getValue(Task.URGENCY)));
|
||||||
|
taskService.save(task, false);
|
||||||
|
if(filter.sqlForNewTasks != null)
|
||||||
|
taskService.invokeSqlForNewTask(filter, task); */ // TODO
|
||||||
|
return task;
|
||||||
|
} catch (Exception e) {
|
||||||
|
exceptionService.displayAndReportError(this, "quick-add-task", e);
|
||||||
|
return new Task();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ============================================================ lifecycle
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
FlurryAgent.onStartSession(this, Constants.FLURRY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
FlurryAgent.onEndSession(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
registerReceiver(detailReceiver,
|
||||||
|
new IntentFilter(AstridApiConstants.BROADCAST_SEND_DETAILS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
unregisterReceiver(detailReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receiver which receives intents to add items to the filter list
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected class DetailReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
try {
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
long taskId = extras.getLong(AstridApiConstants.EXTRAS_TASK_ID);
|
||||||
|
Parcelable[] details = extras.getParcelableArray(AstridApiConstants.EXTRAS_ITEMS);
|
||||||
|
for(Parcelable detail : details)
|
||||||
|
taskAdapter.addDetails(getListView(), taskId, (TaskDetail)detail);
|
||||||
|
} catch (Exception e) {
|
||||||
|
exceptionService.reportError("receive-detail-" + //$NON-NLS-1$
|
||||||
|
intent.getStringExtra(AstridApiConstants.EXTRAS_PLUGIN), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
// if(requestCode == ACTIVITY_EDIT_TASK && resultCode != TaskEditActivity.RESULT_CODE_DISCARDED)
|
||||||
|
// loadTaskListContent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
|
||||||
|
int totalItemCount) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect when user is flinging the task, disable task adapter loading
|
||||||
|
* when this occurs to save resources and time.
|
||||||
|
*/
|
||||||
|
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||||
|
switch (scrollState) {
|
||||||
|
case OnScrollListener.SCROLL_STATE_IDLE:
|
||||||
|
if(taskAdapter.isFling)
|
||||||
|
taskAdapter.notifyDataSetChanged();
|
||||||
|
taskAdapter.isFling = false;
|
||||||
|
break;
|
||||||
|
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
|
||||||
|
if(taskAdapter.isFling)
|
||||||
|
taskAdapter.notifyDataSetChanged();
|
||||||
|
taskAdapter.isFling = false;
|
||||||
|
break;
|
||||||
|
case OnScrollListener.SCROLL_STATE_FLING:
|
||||||
|
taskAdapter.isFling = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* =================================================== managing list view
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load or re-load action items and update views
|
||||||
|
* @param requery
|
||||||
|
*/
|
||||||
|
public void loadTaskListContent(boolean requery) {
|
||||||
|
int oldListItemSelected = getListView().getSelectedItemPosition();
|
||||||
|
Cursor taskCursor = taskAdapter.getCursor();
|
||||||
|
|
||||||
|
if(requery) {
|
||||||
|
taskCursor.requery();
|
||||||
|
taskAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldListItemSelected != ListView.INVALID_POSITION &&
|
||||||
|
oldListItemSelected < taskCursor.getCount())
|
||||||
|
getListView().setSelection(oldListItemSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fill in the Action Item List with current items */
|
||||||
|
protected void setUpTaskList() {
|
||||||
|
// perform query
|
||||||
|
TodorooCursor<Task> currentCursor = taskService.fetchFiltered(
|
||||||
|
TaskAdapter.PROPERTIES, filter);
|
||||||
|
startManagingCursor(currentCursor);
|
||||||
|
|
||||||
|
// set up list adapters
|
||||||
|
taskAdapter = new TaskAdapter(this, R.layout.task_row,
|
||||||
|
currentCursor, false, null);
|
||||||
|
setListAdapter(taskAdapter);
|
||||||
|
getListView().setOnScrollListener(this);
|
||||||
|
registerForContextMenu(getListView());
|
||||||
|
|
||||||
|
loadTaskListContent(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ============================================================== actions
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
protected Pair<CharSequence, Intent>[] contextMenuItemCache = null;
|
||||||
|
|
||||||
|
protected void loadContextMenuIntents() {
|
||||||
|
Intent queryIntent = new Intent(AstridApiConstants.ACTION_TASK_CONTEXT_MENU);
|
||||||
|
PackageManager pm = getPackageManager();
|
||||||
|
List<ResolveInfo> resolveInfoList = pm.queryIntentActivities(queryIntent, 0);
|
||||||
|
int length = resolveInfoList.size();
|
||||||
|
contextMenuItemCache = new Pair[length];
|
||||||
|
for(int i = 0; i < length; i++) {
|
||||||
|
ResolveInfo resolveInfo = resolveInfoList.get(i);
|
||||||
|
Intent intent = new Intent(AstridApiConstants.ACTION_TASK_CONTEXT_MENU);
|
||||||
|
intent.setClassName(resolveInfo.activityInfo.packageName,
|
||||||
|
resolveInfo.activityInfo.name);
|
||||||
|
CharSequence title = resolveInfo.loadLabel(pm);
|
||||||
|
contextMenuItemCache[i] = Pair.create(title, intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenuInfo menuInfo) {
|
||||||
|
AdapterContextMenuInfo adapterInfo = (AdapterContextMenuInfo)menuInfo;
|
||||||
|
Task task = ((ViewHolder)adapterInfo.targetView.getTag()).task;
|
||||||
|
int id = (int)task.getId();
|
||||||
|
menu.setHeaderTitle(task.getValue(Task.TITLE));
|
||||||
|
|
||||||
|
menu.add(id, CONTEXT_MENU_EDIT_TASK_ID, Menu.NONE,
|
||||||
|
R.string.TAd_contextEditTask);
|
||||||
|
|
||||||
|
menu.add(id, CONTEXT_MENU_DELETE_TASK_ID, Menu.NONE,
|
||||||
|
R.string.TAd_contextDeleteTask);
|
||||||
|
|
||||||
|
if(contextMenuItemCache == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// ask about plug-ins
|
||||||
|
long taskId = task.getId();
|
||||||
|
for(int i = 0; i < contextMenuItemCache.length; i++) {
|
||||||
|
Intent intent = contextMenuItemCache[i].getRight();
|
||||||
|
MenuItem item = menu.add(id, CONTEXT_MENU_PLUGIN_INTENT_ID, Menu.NONE,
|
||||||
|
contextMenuItemCache[i].getLeft());
|
||||||
|
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||||
|
item.setIntent(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Show a dialog box and delete the task specified */
|
||||||
|
private void deleteTask(final long id) {
|
||||||
|
new AlertDialog.Builder(this).setTitle(R.string.DLG_confirm_title)
|
||||||
|
.setMessage(R.string.DLG_delete_this_task_question).setIcon(
|
||||||
|
android.R.drawable.ic_dialog_alert).setPositiveButton(
|
||||||
|
android.R.string.ok,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog,
|
||||||
|
int which) {
|
||||||
|
taskService.delete(id);
|
||||||
|
loadTaskListContent(true);
|
||||||
|
}
|
||||||
|
}).setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemSelected(int featureId, final MenuItem item) {
|
||||||
|
Intent intent;
|
||||||
|
long itemId;
|
||||||
|
|
||||||
|
// handle my own menus
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case MENU_ADD_TASK_ID:
|
||||||
|
intent = new Intent(TaskListActivity.this, TaskEdit.class);
|
||||||
|
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, Task.NO_ID);
|
||||||
|
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
|
||||||
|
return true;
|
||||||
|
case MENU_PLUGINS_ID:
|
||||||
|
dialogUtilities.okDialog(
|
||||||
|
this,
|
||||||
|
"if this were real life, I would display the Android " + //$NON-NLS-1$
|
||||||
|
"market with a search for plugins that you could install.", //$NON-NLS-1$
|
||||||
|
null);
|
||||||
|
return true;
|
||||||
|
case MENU_SETTINGS_ID:
|
||||||
|
intent = new Intent(this, EditPreferences.class);
|
||||||
|
startActivityForResult(intent, ACTIVITY_SETTINGS);
|
||||||
|
return true;
|
||||||
|
case MENU_HELP_ID:
|
||||||
|
// TODO
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
// context menu items
|
||||||
|
case CONTEXT_MENU_PLUGIN_INTENT_ID: {
|
||||||
|
intent = item.getIntent();
|
||||||
|
AndroidUtilities.startExternalIntent(this, intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CONTEXT_MENU_EDIT_TASK_ID: {
|
||||||
|
itemId = item.getGroupId();
|
||||||
|
intent = new Intent(TaskListActivity.this, TaskEdit.class);
|
||||||
|
intent.putExtra(TaskEdit.LOAD_INSTANCE_TOKEN, itemId);
|
||||||
|
startActivityForResult(intent, ACTIVITY_EDIT_TASK);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CONTEXT_MENU_DELETE_TASK_ID:
|
||||||
|
itemId = item.getGroupId();
|
||||||
|
deleteTask(itemId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
/**
|
||||||
|
* See the file "LICENSE" for the full license governing this code.
|
||||||
|
*/
|
||||||
|
package com.todoroo.astrid.adapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.BaseExpandableListAdapter;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
import com.todoroo.astrid.api.FilterCategory;
|
||||||
|
import com.todoroo.astrid.api.FilterListHeader;
|
||||||
|
import com.todoroo.astrid.api.FilterListItem;
|
||||||
|
|
||||||
|
public class FilterAdapter extends BaseExpandableListAdapter {
|
||||||
|
|
||||||
|
private final ArrayList<FilterListItem> items;
|
||||||
|
protected final Activity activity;
|
||||||
|
|
||||||
|
public FilterAdapter(Activity activity) {
|
||||||
|
super();
|
||||||
|
this.activity = activity;
|
||||||
|
this.items = new ArrayList<FilterListItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(FilterListItem item) {
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ========================================================== child nodes
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
public Object getChild(int groupPosition, int childPosition) {
|
||||||
|
FilterListItem item = items.get(groupPosition);
|
||||||
|
if(!(item instanceof FilterCategory))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return ((FilterCategory)item).children[childPosition];
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getChildId(int groupPosition, int childPosition) {
|
||||||
|
return childPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChildrenCount(int groupPosition) {
|
||||||
|
FilterListItem item = items.get(groupPosition);
|
||||||
|
if(!(item instanceof FilterCategory))
|
||||||
|
return 0;
|
||||||
|
return ((FilterCategory)item).children.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||||
|
View convertView, ViewGroup parent) {
|
||||||
|
FilterListItem item = (FilterListItem)getChild(groupPosition, childPosition);
|
||||||
|
View textView = getFilterView((Filter)item, true);
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ========================================================= parent nodes
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
public Object getGroup(int groupPosition) {
|
||||||
|
return items.get(groupPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGroupCount() {
|
||||||
|
return items.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGroupId(int groupPosition) {
|
||||||
|
return groupPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||||
|
ViewGroup parent) {
|
||||||
|
View view = getView((FilterListItem)getGroup(groupPosition), false, isExpanded);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ================================================================ views
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
public View getView(FilterListItem item, boolean isChild, boolean isExpanded) {
|
||||||
|
if(item instanceof FilterListHeader)
|
||||||
|
return getHeaderView((FilterListHeader)item, isChild);
|
||||||
|
else if(item instanceof FilterCategory)
|
||||||
|
return getCategoryView((FilterCategory)item, isExpanded);
|
||||||
|
else if(item instanceof Filter)
|
||||||
|
return getFilterView((Filter)item, isChild);
|
||||||
|
else
|
||||||
|
throw new UnsupportedOperationException("unknown item type"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getCategoryView(FilterCategory filter, boolean isExpanded) {
|
||||||
|
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT, 64);
|
||||||
|
|
||||||
|
FrameLayout layout = new FrameLayout(activity);
|
||||||
|
layout.setLayoutParams(lp);
|
||||||
|
|
||||||
|
ImageView image = new ImageView(activity);
|
||||||
|
if(isExpanded)
|
||||||
|
image.setImageResource(R.drawable.expander_ic_maximized);
|
||||||
|
else
|
||||||
|
image.setImageResource(R.drawable.expander_ic_minimized);
|
||||||
|
FrameLayout.LayoutParams llp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||||
|
LayoutParams.FILL_PARENT);
|
||||||
|
llp.gravity = Gravity.CENTER_VERTICAL;
|
||||||
|
image.setLayoutParams(llp);
|
||||||
|
layout.addView(image);
|
||||||
|
|
||||||
|
TextView textView = new TextView(activity);
|
||||||
|
textView.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
textView.setLayoutParams(llp);
|
||||||
|
textView.setPadding(40, 0, 0, 0);
|
||||||
|
textView.setText(filter.listingTitle);
|
||||||
|
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Category);
|
||||||
|
layout.addView(textView);
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getFilterView(Filter filter, boolean isChild) {
|
||||||
|
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT, 64);
|
||||||
|
|
||||||
|
TextView textView = new TextView(activity);
|
||||||
|
textView.setBackgroundDrawable(null);
|
||||||
|
textView.setLayoutParams(lp);
|
||||||
|
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
|
||||||
|
textView.setPadding(isChild ? 40 : 10, 0, 0, 0);
|
||||||
|
textView.setText(filter.listingTitle);
|
||||||
|
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Filter);
|
||||||
|
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getHeaderView(FilterListHeader header, boolean isChild) {
|
||||||
|
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.FILL_PARENT, 40);
|
||||||
|
|
||||||
|
TextView textView = new TextView(activity);
|
||||||
|
textView.setLayoutParams(lp);
|
||||||
|
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
|
||||||
|
textView.setPadding(isChild ? 40 : 10, 0, 0, 0);
|
||||||
|
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Header);
|
||||||
|
textView.setBackgroundResource(R.drawable.edit_titlebar);
|
||||||
|
textView.setText(header.listingTitle);
|
||||||
|
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,421 @@
|
|||||||
|
package com.todoroo.astrid.adapter;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
|
import android.view.View.OnCreateContextMenuListener;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CursorAdapter;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.timsu.astrid.R;
|
||||||
|
import com.todoroo.andlib.data.Property;
|
||||||
|
import com.todoroo.andlib.data.TodorooCursor;
|
||||||
|
import com.todoroo.andlib.service.Autowired;
|
||||||
|
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||||
|
import com.todoroo.andlib.service.ExceptionService;
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities;
|
||||||
|
import com.todoroo.andlib.utility.DialogUtilities;
|
||||||
|
import com.todoroo.astrid.api.AstridApiConstants;
|
||||||
|
import com.todoroo.astrid.api.TaskDetail;
|
||||||
|
import com.todoroo.astrid.model.Task;
|
||||||
|
import com.todoroo.astrid.service.TaskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for displaying a user's tasks as a list
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TaskAdapter extends CursorAdapter {
|
||||||
|
|
||||||
|
public interface OnCompletedTaskListener {
|
||||||
|
public void onCompletedTask(Task item, boolean newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- other constants
|
||||||
|
|
||||||
|
/** Properties that need to be read from the action item */
|
||||||
|
public static final Property<?>[] PROPERTIES = new Property<?>[] {
|
||||||
|
Task.ID,
|
||||||
|
Task.TITLE,
|
||||||
|
Task.IMPORTANCE,
|
||||||
|
Task.URGENCY,
|
||||||
|
Task.DUE_DATE,
|
||||||
|
Task.COMPLETION_DATE,
|
||||||
|
Task.HIDDEN_UNTIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int[] IMPORTANCE_COLORS = null;
|
||||||
|
|
||||||
|
// --- instance variables
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ExceptionService exceptionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
TaskService taskService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DialogUtilities dialogUtilities;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Boolean debug;
|
||||||
|
|
||||||
|
protected final Activity activity;
|
||||||
|
protected final HashMap<Long, Boolean> completedItems;
|
||||||
|
protected final HashMap<Long, ArrayList<TaskDetail>> detailCache;
|
||||||
|
public boolean isFling = false;
|
||||||
|
private final int resource;
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
protected OnCompletedTaskListener onCompletedTaskListener = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param activity
|
||||||
|
* @param resource
|
||||||
|
* layout resource to inflate
|
||||||
|
* @param c
|
||||||
|
* database cursor
|
||||||
|
* @param autoRequery
|
||||||
|
* whether cursor is automatically re-queried on changes
|
||||||
|
* @param onCompletedTaskListener
|
||||||
|
* task listener. can be null
|
||||||
|
*/
|
||||||
|
public TaskAdapter(Activity activity, int resource,
|
||||||
|
TodorooCursor<Task> c, boolean autoRequery,
|
||||||
|
OnCompletedTaskListener onCompletedTaskListener) {
|
||||||
|
super(activity, c, autoRequery);
|
||||||
|
DependencyInjectionService.getInstance().inject(this);
|
||||||
|
|
||||||
|
inflater = (LayoutInflater) activity.getSystemService(
|
||||||
|
Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
|
||||||
|
this.resource = resource;
|
||||||
|
this.activity = activity;
|
||||||
|
this.onCompletedTaskListener = onCompletedTaskListener;
|
||||||
|
|
||||||
|
completedItems = new HashMap<Long, Boolean>();
|
||||||
|
detailCache = new HashMap<Long, ArrayList<TaskDetail>>();
|
||||||
|
|
||||||
|
if(IMPORTANCE_COLORS == null) {
|
||||||
|
IMPORTANCE_COLORS = new int[] { Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN }; //Task.getImportanceColors(activity); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* =========================================================== view setup
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/** Creates a new view for use in the list view */
|
||||||
|
@Override
|
||||||
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
|
View view = inflater.inflate(resource, parent, false);
|
||||||
|
|
||||||
|
// create view holder
|
||||||
|
ViewHolder viewHolder = new ViewHolder();
|
||||||
|
viewHolder.task = new Task();
|
||||||
|
viewHolder.nameView = (TextView)view.findViewById(R.id.title);
|
||||||
|
viewHolder.completeBox = (CheckBox)view.findViewById(R.id.completeBox);
|
||||||
|
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
|
||||||
|
viewHolder.details = (LinearLayout)view.findViewById(R.id.details);
|
||||||
|
viewHolder.importance = (View)view.findViewById(R.id.importance);
|
||||||
|
view.setTag(viewHolder);
|
||||||
|
|
||||||
|
// add UI component listeners
|
||||||
|
addListeners(view);
|
||||||
|
|
||||||
|
// populate view content
|
||||||
|
bindView(view, context, cursor);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Populates a view with content */
|
||||||
|
@Override
|
||||||
|
public void bindView(View view, Context context, Cursor c) {
|
||||||
|
TodorooCursor<Task> cursor = (TodorooCursor<Task>)c;
|
||||||
|
Task actionItem = ((ViewHolder)view.getTag()).task;
|
||||||
|
actionItem.readFromCursor(cursor);
|
||||||
|
|
||||||
|
setFieldContentsAndVisibility(view, actionItem);
|
||||||
|
setTaskAppearance(view, actionItem.isCompleted());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method to set the visibility based on if there's stuff inside */
|
||||||
|
private static void setVisibility(TextView v) {
|
||||||
|
if(v.getText().length() > 0)
|
||||||
|
v.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
v.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View Holder saves a lot of findViewById lookups.
|
||||||
|
*
|
||||||
|
* @author Tim Su <tim@todoroo.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class ViewHolder {
|
||||||
|
public Task task;
|
||||||
|
public TextView nameView;
|
||||||
|
public CheckBox completeBox;
|
||||||
|
public TextView dueDate;
|
||||||
|
public LinearLayout details;
|
||||||
|
public View importance;
|
||||||
|
public TextView loadingDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method to set the contents and visibility of each field */
|
||||||
|
private void setFieldContentsAndVisibility(View view, Task task) {
|
||||||
|
Resources r = activity.getResources();
|
||||||
|
ViewHolder viewHolder = (ViewHolder)view.getTag();
|
||||||
|
|
||||||
|
// don't bother instantiating views if we're busy
|
||||||
|
if(isFling) {
|
||||||
|
viewHolder.details.removeViews(2, viewHolder.details.getChildCount() - 2);
|
||||||
|
viewHolder.dueDate.setVisibility(View.INVISIBLE);
|
||||||
|
viewHolder.nameView.setText(R.string.TAd_isFling);
|
||||||
|
viewHolder.importance.setVisibility(View.INVISIBLE);
|
||||||
|
viewHolder.completeBox.setVisibility(View.INVISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// name
|
||||||
|
final TextView nameView = viewHolder.nameView; {
|
||||||
|
String nameValue = task.getValue(Task.TITLE);
|
||||||
|
int hiddenUntil = task.getValue(Task.HIDDEN_UNTIL);
|
||||||
|
if(hiddenUntil > DateUtilities.now())
|
||||||
|
nameValue = r.getString(R.string.TAd_hiddenFormat, nameValue);
|
||||||
|
nameView.setText(nameValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete box
|
||||||
|
final CheckBox completeBox = viewHolder.completeBox; {
|
||||||
|
// show item as completed if it was recently checked
|
||||||
|
if(completedItems.containsKey(task.getId()))
|
||||||
|
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
|
||||||
|
completeBox.setChecked(task.isCompleted());
|
||||||
|
completeBox.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// due date / completion date
|
||||||
|
final TextView dueDateView = viewHolder.dueDate; {
|
||||||
|
if(!task.isCompleted() && task.hasDueDate()) {
|
||||||
|
int dueDate = task.getValue(Task.DUE_DATE);
|
||||||
|
int secondsLeft = dueDate - DateUtilities.now();
|
||||||
|
if(secondsLeft > 0) {
|
||||||
|
dueDateView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDueDate);
|
||||||
|
} else {
|
||||||
|
dueDateView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDueDate_Overdue);
|
||||||
|
}
|
||||||
|
|
||||||
|
String dateValue;
|
||||||
|
Date dueDateAsDate = DateUtilities.unixtimeToDate(dueDate);
|
||||||
|
dateValue = SimpleDateFormat.getDateInstance(
|
||||||
|
SimpleDateFormat.MEDIUM).format(dueDateAsDate);
|
||||||
|
|
||||||
|
if (task.getValue(Task.URGENCY) == Task.URGENCY_SPECIFIC_DAY_TIME) {
|
||||||
|
String timeValue = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
|
||||||
|
dueDateAsDate);
|
||||||
|
String string = r.getString(R.string.TAd_dueDateTime).replace(
|
||||||
|
"$D", dateValue).replace("$T", timeValue); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
dueDateView.setText(string);
|
||||||
|
} else {
|
||||||
|
String string = r.getString(R.string.TAd_dueDate).replace(
|
||||||
|
"$D", dateValue); //$NON-NLS-1$
|
||||||
|
dueDateView.setText(string);
|
||||||
|
}
|
||||||
|
setVisibility(dueDateView);
|
||||||
|
} else {
|
||||||
|
dueDateView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// other information - send out a request for it
|
||||||
|
final LinearLayout detailsView = viewHolder.details; {
|
||||||
|
detailsView.removeViews(2, detailsView.getChildCount() - 2);
|
||||||
|
if(detailCache.containsKey(task.getId())) {
|
||||||
|
ArrayList<TaskDetail> details = detailCache.get(task.getId());
|
||||||
|
int length = details.size();
|
||||||
|
for(int i = 0; i < length; i++)
|
||||||
|
detailsView.addView(detailToView(details.get(i)));
|
||||||
|
} else {
|
||||||
|
detailCache.put(task.getId(), new ArrayList<TaskDetail>());
|
||||||
|
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_DETAILS);
|
||||||
|
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
|
||||||
|
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||||
|
|
||||||
|
// add loading message
|
||||||
|
if(viewHolder.loadingDetails == null) {
|
||||||
|
viewHolder.loadingDetails = new TextView(activity);
|
||||||
|
viewHolder.loadingDetails.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDetails);
|
||||||
|
viewHolder.loadingDetails.setText(R.string.TAd_loading);
|
||||||
|
detailsView.addView(viewHolder.loadingDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// importance bar - must be set at end when view height is determined
|
||||||
|
final View importanceView = viewHolder.importance; {
|
||||||
|
int value = task.getValue(Task.IMPORTANCE);
|
||||||
|
importanceView.setBackgroundColor(IMPORTANCE_COLORS[value]);
|
||||||
|
importanceView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a request to add details for a task
|
||||||
|
*
|
||||||
|
* @param taskId
|
||||||
|
*/
|
||||||
|
public synchronized void addDetails(ListView list, long taskId, TaskDetail detail) {
|
||||||
|
if(detail == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ArrayList<TaskDetail> details = detailCache.get(taskId);
|
||||||
|
details.add(detail);
|
||||||
|
|
||||||
|
// update view if it is visible
|
||||||
|
int length = list.getChildCount();
|
||||||
|
for(int i = 0; i < length; i++) {
|
||||||
|
ViewHolder viewHolder = (ViewHolder) list.getChildAt(i).getTag();
|
||||||
|
if(viewHolder == null || viewHolder.task.getId() != taskId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
viewHolder.details.addView(detailToView(detail));
|
||||||
|
viewHolder.details.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
if(viewHolder.loadingDetails != null) {
|
||||||
|
viewHolder.details.removeView(viewHolder.loadingDetails);
|
||||||
|
viewHolder.loadingDetails = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new view for the given detail
|
||||||
|
*
|
||||||
|
* @param detail
|
||||||
|
*/
|
||||||
|
private View detailToView(TaskDetail detail) {
|
||||||
|
TextView textView = new TextView(activity);
|
||||||
|
textView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDetails);
|
||||||
|
textView.setText(detail.text);
|
||||||
|
if(detail.color != 0)
|
||||||
|
textView.setTextColor(detail.color);
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View.OnClickListener completeBoxListener = new View.OnClickListener() {
|
||||||
|
public void onClick(View v) {
|
||||||
|
View container = (View) v.getParent();
|
||||||
|
Task task = ((ViewHolder)container.getTag()).task;
|
||||||
|
|
||||||
|
completeTask(task, ((CheckBox)v).isChecked());
|
||||||
|
// set check box to actual action item state
|
||||||
|
setTaskAppearance(container, task.isCompleted());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected ContextMenuListener listener = new ContextMenuListener();
|
||||||
|
/**
|
||||||
|
* Set listeners for this view. This is called once per view when it is
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
private void addListeners(final View container) {
|
||||||
|
final CheckBox completeBox = ((CheckBox)container.findViewById(R.id.completeBox));
|
||||||
|
completeBox.setOnClickListener(completeBoxListener);
|
||||||
|
|
||||||
|
container.setOnCreateContextMenuListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContextMenuListener implements OnCreateContextMenuListener {
|
||||||
|
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||||
|
ContextMenuInfo menuInfo) {
|
||||||
|
// this is all a big sham. it's actually handled in Task List Activity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======================================================================
|
||||||
|
* ======================================================= event handlers
|
||||||
|
* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call me when the parent presses trackpad
|
||||||
|
*/
|
||||||
|
public void onTrackpadPressed(View container) {
|
||||||
|
if(container == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
final CheckBox completeBox = ((CheckBox)container.findViewById(R.id.completeBox));
|
||||||
|
completeBox.performClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method to adjust a tasks' appearance if the task is completed or
|
||||||
|
* uncompleted.
|
||||||
|
*
|
||||||
|
* @param actionItem
|
||||||
|
* @param name
|
||||||
|
* @param progress
|
||||||
|
*/
|
||||||
|
void setTaskAppearance(View container, boolean state) {
|
||||||
|
CheckBox completed = (CheckBox)container.findViewById(R.id.completeBox);
|
||||||
|
TextView name = (TextView)container.findViewById(R.id.title);
|
||||||
|
|
||||||
|
completed.setChecked(state);
|
||||||
|
|
||||||
|
if(state) {
|
||||||
|
name.setPaintFlags(name.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||||
|
name.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemTitle_Completed);
|
||||||
|
} else {
|
||||||
|
name.setPaintFlags(name.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
|
||||||
|
name.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when user completes a task via check box or other
|
||||||
|
* means
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* container for the action item
|
||||||
|
* @param newState
|
||||||
|
* state that this task should be set to
|
||||||
|
* @param completeBox
|
||||||
|
* the box that was clicked. can be null
|
||||||
|
*/
|
||||||
|
protected void completeTask(final Task actionItem, final boolean newState) {
|
||||||
|
if(actionItem == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (newState != actionItem.isCompleted()) {
|
||||||
|
completedItems.put(actionItem.getId(), newState);
|
||||||
|
taskService.setComplete(actionItem, newState);
|
||||||
|
|
||||||
|
if(onCompletedTaskListener != null)
|
||||||
|
onCompletedTaskListener.onCompletedTask(actionItem, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||