OSDN Git Service

initial commit
authorKoushik Dutta <koushd@gmail.com>
Sun, 13 Jan 2013 01:34:40 +0000 (17:34 -0800)
committerKoushik Dutta <koushd@gmail.com>
Sun, 13 Jan 2013 01:34:40 +0000 (17:34 -0800)
21 files changed:
.classpath [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.project [new file with mode: 0644]
AndroidManifest.xml [new file with mode: 0644]
gen/com/koushikdutta/widgets/BuildConfig.java [new file with mode: 0644]
gen/com/koushikdutta/widgets/R.java [new file with mode: 0644]
libs/android-support-v4.jar [new file with mode: 0644]
proguard-project.txt [new file with mode: 0644]
project.properties [new file with mode: 0644]
res/layout-v14/list_item.xml [new file with mode: 0644]
res/layout-v14/list_item_small.xml [new file with mode: 0644]
res/layout/activity_base_fragment.xml [new file with mode: 0644]
res/layout/list_header.xml [new file with mode: 0644]
res/layout/list_item.xml [new file with mode: 0644]
res/layout/list_item_small.xml [new file with mode: 0644]
res/values/color.xml [new file with mode: 0644]
src/com/koushikdutta/widgets/ActivityBase.java [new file with mode: 0644]
src/com/koushikdutta/widgets/ActivityBaseFragment.java [new file with mode: 0644]
src/com/koushikdutta/widgets/AnimatedView.java [new file with mode: 0644]
src/com/koushikdutta/widgets/ListItem.java [new file with mode: 0644]
src/com/koushikdutta/widgets/SeparatedListAdapter.java [new file with mode: 0644]

diff --git a/.classpath b/.classpath
new file mode 100644 (file)
index 0000000..a4763d1
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+       <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1746e32
--- /dev/null
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/.project b/.project
new file mode 100644 (file)
index 0000000..d9bad7b
--- /dev/null
+++ b/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>Widgets</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..0260295
--- /dev/null
@@ -0,0 +1,14 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.koushikdutta.widgets"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="16" />
+
+    <application
+        android:allowBackup="true">
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/gen/com/koushikdutta/widgets/BuildConfig.java b/gen/com/koushikdutta/widgets/BuildConfig.java
new file mode 100644 (file)
index 0000000..3d3d5bb
--- /dev/null
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package com.koushikdutta.widgets;
+
+public final class BuildConfig {
+    public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/gen/com/koushikdutta/widgets/R.java b/gen/com/koushikdutta/widgets/R.java
new file mode 100644 (file)
index 0000000..a620313
--- /dev/null
@@ -0,0 +1,35 @@
+/* AUTO-GENERATED FILE.  DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found.  It
+ * should not be modified by hand.
+ */
+
+package com.koushikdutta.widgets;
+
+public final class R {
+    public static final class attr {
+    }
+    public static final class color {
+        public static int holo_blue_bright=0x7f030002;
+        public static int holo_blue_dark=0x7f030001;
+        public static int holo_blue_light=0x7f030000;
+    }
+    public static final class id {
+        public static int checkbox=0x7f040008;
+        public static int empty=0x7f040002;
+        public static int footer_container=0x7f040003;
+        public static int image=0x7f040005;
+        public static int list_header_title=0x7f040004;
+        public static int listview=0x7f040001;
+        public static int summary=0x7f040007;
+        public static int title=0x7f040006;
+        public static int title_container=0x7f040000;
+    }
+    public static final class layout {
+        public static int activity_base_fragment=0x7f020000;
+        public static int list_header=0x7f020001;
+        public static int list_item=0x7f020002;
+        public static int list_item_small=0x7f020003;
+    }
+}
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
new file mode 100644 (file)
index 0000000..6080877
Binary files /dev/null and b/libs/android-support-v4.jar differ
diff --git a/proguard-project.txt b/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/project.properties b/project.properties
new file mode 100644 (file)
index 0000000..484dab0
--- /dev/null
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17
+android.library=true
diff --git a/res/layout-v14/list_item.xml b/res/layout-v14/list_item.xml
new file mode 100644 (file)
index 0000000..d7a192a
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="64dp"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="center_vertical"
+        android:layout_margin="2dp"
+        android:scaleType="fitCenter" >
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="4dp" >
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="2dp"
+            android:layout_marginRight="2dp"
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="2dp"
+            android:layout_marginRight="2dp"
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" />
+    </LinearLayout>
+
+    <Switch
+        android:id="@+id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:focusable="false"
+        android:focusableInTouchMode="false" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout-v14/list_item_small.xml b/res/layout-v14/list_item_small.xml
new file mode 100644 (file)
index 0000000..a6861f8
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="64dp"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="48dp"
+        android:layout_height="32dp"
+        android:layout_gravity="center_vertical"
+        android:layout_margin="2dp"
+        android:scaleType="fitCenter" >
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical" >
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="@android:style/TextAppearance.DeviceDefault.Medium" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="@android:style/TextAppearance.DeviceDefault.Small" />
+    </LinearLayout>
+
+    <CheckBox
+        android:id="@+id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:focusable="false"
+        android:focusableInTouchMode="false" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/activity_base_fragment.xml b/res/layout/activity_base_fragment.xml
new file mode 100644 (file)
index 0000000..c42cebb
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:id="@+id/title_container"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+
+    <ListView
+        android:id="@+id/listview"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_weight="1"
+        android:paddingLeft="10dp"
+        android:paddingRight="10dp" />
+
+    <TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/empty"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:visibility="gone" />
+
+    <LinearLayout
+        android:id="@+id/footer_container"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/list_header.xml b/res/layout/list_header.xml
new file mode 100644 (file)
index 0000000..81340ed
--- /dev/null
@@ -0,0 +1,9 @@
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_header_title"
+    style="?android:attr/listSeparatorTextViewStyle"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingBottom="2dip"
+    android:paddingLeft="5dip"
+    android:paddingTop="2dip"
+    android:textColor="@color/holo_blue_dark" />
diff --git a/res/layout/list_item.xml b/res/layout/list_item.xml
new file mode 100644 (file)
index 0000000..b3be504
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="64dp"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="center_vertical"
+        android:layout_margin="2dp"
+        android:scaleType="fitCenter" >
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="4dp" >
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="2dp"
+            android:layout_marginRight="2dp"
+            android:textColor="@android:color/primary_text_dark"
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="2dp"
+            android:layout_marginRight="2dp"
+            android:textColor="@android:color/secondary_text_dark"
+            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small" />
+    </LinearLayout>
+
+    <CheckBox
+        android:id="@+id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:focusable="false"
+        android:focusableInTouchMode="false" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/list_item_small.xml b/res/layout/list_item_small.xml
new file mode 100644 (file)
index 0000000..d9e51e8
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="64dp"
+    android:orientation="horizontal" >
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="48dp"
+        android:layout_height="32dp"
+        android:layout_gravity="center_vertical"
+        android:layout_margin="2dp"
+        android:scaleType="fitCenter" >
+    </ImageView>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical" >
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:textColor="@android:color/primary_text_dark"
+            android:textSize="18sp" />
+
+        <TextView
+            android:id="@+id/summary"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:textColor="@android:color/secondary_text_dark"
+            android:textSize="12sp" />
+    </LinearLayout>
+
+    <CheckBox
+        android:id="@+id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:focusable="false"
+        android:focusableInTouchMode="false" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/color.xml b/res/values/color.xml
new file mode 100644 (file)
index 0000000..4438241
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="holo_blue_light">#ff33b5e5</color>
+               <color name="holo_blue_dark">#ff0099cc</color>
+               <color name="holo_blue_bright">#ff00ddff</color>
+    
+</resources>
\ No newline at end of file
diff --git a/src/com/koushikdutta/widgets/ActivityBase.java b/src/com/koushikdutta/widgets/ActivityBase.java
new file mode 100644 (file)
index 0000000..da56120
--- /dev/null
@@ -0,0 +1,36 @@
+package com.koushikdutta.widgets;
+
+import android.support.v4.app.FragmentActivity;
+import android.view.View;
+
+
+
+public class ActivityBase extends FragmentActivity {
+    Class<? extends ActivityBaseFragment> clazz;
+    public ActivityBase(Class<? extends ActivityBaseFragment> clazz) {
+        super();
+        this.clazz = clazz;
+    }
+    
+    public ActivityBaseFragment getFragment() {
+        return fragment;        
+    }
+    
+    public View getView() {
+        return fragment.getView();
+    }
+    
+    ActivityBaseFragment fragment;
+    protected void onCreate(android.os.Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        try {
+            fragment = (ActivityBaseFragment)clazz.getConstructors()[0].newInstance();
+            fragment.setArguments(getIntent().getExtras());
+            getSupportFragmentManager().beginTransaction().add(android.R.id.content, fragment).commit();
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/src/com/koushikdutta/widgets/ActivityBaseFragment.java b/src/com/koushikdutta/widgets/ActivityBaseFragment.java
new file mode 100644 (file)
index 0000000..52dd94d
--- /dev/null
@@ -0,0 +1,220 @@
+package com.koushikdutta.widgets;
+
+import java.util.HashMap;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class ActivityBaseFragment extends Fragment {
+    protected boolean mDestroyed = false;
+    
+    protected ListView mListView;
+    protected MyAdapter mAdapter;
+    
+    protected class MyAdapter extends SeparatedListAdapter {
+        public MyAdapter(Context context) {
+            super(context);
+        }
+        
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+        
+        @Override
+        public boolean isEnabled(int position) {
+            if (!super.isEnabled(position))
+                return false;
+            ListItem item = (ListItem) getItem(position);
+            return item.getEnabled();
+        }
+    }
+    
+    public class MyListAdapter extends ArrayAdapter<ListItem> {
+        public MyListAdapter(Context context) {
+            super(context, 0);
+        }
+        
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            ListItem item = getItem(position);
+            return item.getView(getContext(), convertView);
+        }
+        
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+        
+        @Override
+        public boolean isEnabled(int position) {
+            ListItem item = getItem(position);
+            return item.getEnabled();
+        }
+    }
+    
+    HashMap<String, MyListAdapter> mAdapters = new HashMap<String, ActivityBaseFragment.MyListAdapter>();
+    
+    protected MyListAdapter ensureHeader(int sectionName) {
+        String sn = getString(sectionName);
+        MyListAdapter adapter = mAdapters.get(sn);
+        if (adapter == null) {
+            adapter = new MyListAdapter(getActivity());
+            mAdapters.put(sn, adapter);
+            mAdapter.addSection(sn, adapter);
+            mListView.setAdapter(null);
+            mListView.setAdapter(mAdapter);
+        }
+        return adapter;
+    }
+
+    protected ListItem addItem(int sectionName, ListItem item) {
+        return addItem(getString(sectionName), item);
+    }
+
+    protected ListItem addItem(int sectionName, ListItem item, int index) {
+        return addItem(getString(sectionName), item, index);
+    }
+    
+    protected ListItem addItem(String sectionName, ListItem item) {
+        return addItem(sectionName, item, -1);
+    }
+    
+    public int getSectionItemCount(int section) {
+        return getSectionItemCount(getString(section));
+    }
+    
+    public int getSectionItemCount(String section) {
+        MyListAdapter adapter = mAdapters.get(section);
+        if (adapter == null)
+            return 0;
+        return adapter.getCount();
+    }
+
+    protected ListItem addItem(String sectionName, ListItem item, int index) {
+        MyListAdapter adapter = mAdapters.get(sectionName);
+        if (adapter == null) {
+            adapter = new MyListAdapter(getActivity());
+            mAdapters.put(sectionName, adapter);
+            mAdapter.addSection(sectionName, adapter);
+            if (mListView != null) {
+                mListView.setAdapter(null);
+                mListView.setAdapter(mAdapter);
+            }
+//            mAdapter.notifyDataSetChanged();
+        }
+        
+        if (index != -1)
+            adapter.insert(item, index);
+        else
+            adapter.add(item);
+        
+        return item;
+    }
+    
+    protected ListItem findItem(int item) {
+        String text = getString(item);
+        
+        for (Adapter adapter: mAdapter.sections.values())
+        {
+            MyListAdapter m = (MyListAdapter)adapter;
+            for (int i = 0; i < m.getCount(); i++) {
+                ListItem li = m.getItem(i);
+                if (text.equals(li.getTitle()))
+                    return li;
+            }
+        }
+        
+        return null;
+    }
+    
+    protected void onCreate(Bundle savedInstanceState, View view) {
+    }
+    
+    TextView mEmpty;
+    @Override
+    public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        View ret = inflater.inflate(R.layout.activity_base_fragment, null);
+        
+        mListView = (ListView)ret.findViewById(R.id.listview);
+        mListView.setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+                Object item = mAdapter.getItem(arg2);
+                if (item instanceof ListItem) {
+                    ListItem li = (ListItem)item;
+                    li.onClickInternal(arg1);
+                }
+            }
+        });
+        
+        mListView.setOnItemLongClickListener(new OnItemLongClickListener() {
+
+            @Override
+            public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+                Object item = mAdapter.getItem(arg2);
+                if (item instanceof ListItem) {
+                    ListItem li = (ListItem)item;
+                    return li.onLongClick();
+                }
+                return false;
+            }
+        });
+        
+        mListView.setAdapter(mAdapter);
+        mEmpty = (TextView)ret.findViewById(R.id.empty);
+        
+        onCreate(savedInstanceState, ret);
+        return ret;
+    }
+
+    @Override
+    public final void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mAdapter = new MyAdapter(getActivity());
+    }
+
+    
+    Handler handler = new Handler();
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        
+        mDestroyed = true;
+    }
+    
+    public int getListItemResource() {
+        return R.layout.list_item_small;
+    }
+
+    protected void clear() {
+        mAdapter.clear();
+        mAdapters.clear();
+    }
+    
+    public void removeItem(ListItem item) {
+        for (MyListAdapter adapter: mAdapters.values()) {
+            adapter.remove(item);
+        }
+        mAdapter.notifyDataSetChanged();
+    }
+    
+    public void setEmpty(int res) {
+        mListView.setEmptyView(mEmpty);
+        mEmpty.setText(res);
+    }
+}
diff --git a/src/com/koushikdutta/widgets/AnimatedView.java b/src/com/koushikdutta/widgets/AnimatedView.java
new file mode 100644 (file)
index 0000000..28b078e
--- /dev/null
@@ -0,0 +1,20 @@
+package com.koushikdutta.widgets;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.ScaleAnimation;
+
+public final class AnimatedView {
+    public static void setOnClickListener(final View view, final OnClickListener listener) {
+        view.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ScaleAnimation scale = new ScaleAnimation(.95f, 1f, .95f, 1f, Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f);
+                scale.setDuration(250);
+                view.startAnimation(scale);
+                listener.onClick(view);
+            }
+        });
+    }
+}
diff --git a/src/com/koushikdutta/widgets/ListItem.java b/src/com/koushikdutta/widgets/ListItem.java
new file mode 100644 (file)
index 0000000..15153d8
--- /dev/null
@@ -0,0 +1,186 @@
+package com.koushikdutta.widgets;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class ListItem {
+    private String Title;
+    private String Summary;
+    private ActivityBaseFragment Context;
+    private boolean Enabled = true;
+
+    public int Icon;
+    
+    public void setEnabled(boolean enabled) {
+        Enabled = enabled;
+        Context.mAdapter.notifyDataSetChanged();
+    }
+    
+    public boolean getEnabled() {
+        return Enabled;
+    }
+    
+    public void setTitle(int title) {
+        if (title == 0)
+            setTitle(null);
+        else
+            setTitle(Context.getString(title));
+    }
+    
+    public String getTitle() {
+        return Title;
+    }
+    
+    public void setTitle(String title) {
+        Title = title;
+        Context.mAdapter.notifyDataSetChanged();
+    }
+
+    public void setSummary(int summary) {
+        if (summary == 0)
+            setSummary(null);
+        else
+            setSummary(Context.getString(summary));
+    }
+    
+    public void setSummary(String summary) {
+        Summary = summary;
+        Context.mAdapter.notifyDataSetChanged();
+    }
+    
+    public ListItem(ActivityBaseFragment context, int title, int summary) {
+        if (title != 0)
+            Title = context.getString(title);
+        if (summary != 0)
+            Summary = context.getString(summary);
+        Context = context;
+    }
+    
+    public ListItem(ActivityBaseFragment context, String title, String summary) {
+        Title = title;
+        Summary = summary;
+        Context = context;
+    }
+    
+    public ListItem(ActivityBaseFragment context, int title, int summary, int icon) {
+        this(context, title, summary);
+        Icon = icon;
+    }
+    
+    public ListItem(ActivityBaseFragment context, String title, String summary, int icon) {
+        this(context, title, summary);
+        Icon = icon;
+    }
+    
+    private boolean CheckboxVisible = false;
+    private boolean checked = false;
+    
+    public void setCheckboxVisible(boolean visible) {
+        CheckboxVisible = visible;
+        Context.mAdapter.notifyDataSetChanged();
+    }
+
+    public boolean getCheckboxVisible() {
+        return CheckboxVisible;
+    }
+    
+    public boolean getChecked() {
+        return checked;
+    }
+    
+    public void setChecked(boolean isChecked) {
+        checked = isChecked;
+        CheckboxVisible = true;
+        Context.mAdapter.notifyDataSetChanged();
+    }
+//    
+//    boolean mUseOnOff = false;
+//    public void useYesNo() {
+//        mUseOnOff = true;
+//    }
+//    
+//    private void setSwitch(View view) {
+//        Switch s = (Switch)view;
+//        s.setTextOn(Context.getString(R.string.yes).toUpperCase());
+//        s.setTextOff(Context.getString(R.string.no).toUpperCase());
+//        view.setTag(view);
+//    }
+    
+    public View getView(Context context, View convertView) {
+        if (convertView == null || convertView.getTag() != null)
+            convertView = LayoutInflater.from(context).inflate(Context.getListItemResource(), null);
+        
+        
+        TextView title = (TextView)convertView.findViewById(R.id.title);
+        TextView summary = (TextView)convertView.findViewById(R.id.summary);
+        CompoundButton cb = (CompoundButton)convertView.findViewById(R.id.checkbox);
+        cb.setOnCheckedChangeListener(null);
+        cb.setChecked(checked);
+        final View cv = convertView;
+        cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                checked = isChecked;
+                ListItem.this.onClick(cv);
+            }
+        });
+//        if (mUseOnOff && !(cb instanceof CheckBox)) {
+//            setSwitch(cb);
+//        }
+        cb.setVisibility(CheckboxVisible ? View.VISIBLE : View.GONE);
+        cb.setChecked(checked);
+
+        cb.setEnabled(Enabled);
+        title.setEnabled(Enabled);
+        summary.setEnabled(Enabled);
+
+        if (Title != null) {
+            title.setVisibility(View.VISIBLE);
+            title.setText(Title);
+        }
+        else
+            title.setVisibility(View.GONE);
+        if (Summary != null) {
+            summary.setVisibility(View.VISIBLE);
+            summary.setText(Summary);
+        }
+        else
+            summary.setVisibility(View.GONE);
+
+        ImageView iv = (ImageView)convertView.findViewById(R.id.image);
+        if (iv != null) {
+            if (Icon != 0) {
+                iv.setVisibility(View.VISIBLE);
+                iv.setImageResource(Icon);
+            }
+            else {
+                iv.setVisibility(View.GONE);
+            }
+        }
+        
+        return convertView;
+    }
+    
+    void onClickInternal(View view) {
+        if (CheckboxVisible) {
+            CompoundButton cb = (CompoundButton)view.findViewById(R.id.checkbox);
+            // this will trigger onclick
+            cb.setChecked(!cb.isChecked());
+        }
+        else {
+            onClick(view);
+        }
+    }
+    
+    public void onClick(View view) {
+    }
+    
+    public boolean onLongClick() {
+        return false;
+    }
+}
diff --git a/src/com/koushikdutta/widgets/SeparatedListAdapter.java b/src/com/koushikdutta/widgets/SeparatedListAdapter.java
new file mode 100644 (file)
index 0000000..1d53abc
--- /dev/null
@@ -0,0 +1,114 @@
+package com.koushikdutta.widgets;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Adapter;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+
+public class SeparatedListAdapter extends BaseAdapter {
+    public void clear() {
+        sections.clear();
+        headers.clear();
+        notifyDataSetChanged();
+    }
+
+    public final Map<String,Adapter> sections = new LinkedHashMap<String,Adapter>();
+    public final ArrayAdapter<String> headers;
+    public final static int TYPE_SECTION_HEADER = 0;
+
+    public SeparatedListAdapter(Context context) {
+        headers = new ArrayAdapter<String>(context, R.layout.list_header);
+    }
+
+    public void addSection(String section, Adapter adapter) {
+        this.headers.add(section);
+        this.sections.put(section, adapter);
+    }
+
+    @Override
+    public Object getItem(int position) {
+        for(Object section : this.sections.keySet()) {
+            Adapter adapter = sections.get(section);
+            int size = adapter.getCount() + 1;
+
+            // check if position inside this section
+            if(position == 0) return section;
+            if(position < size) return adapter.getItem(position - 1);
+
+            // otherwise jump into next section
+            position -= size;
+        }
+        return null;
+    }
+
+    public int getCount() {
+        // total together all sections, plus one for each section header
+        int total = 0;
+        for(Adapter adapter : this.sections.values())
+            total += adapter.getCount() + 1;
+        return total;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        // assume that headers count as one, and that there will be at least a itemViewType.
+        // then total all sections
+        int total = 2;
+        for(Adapter adapter : this.sections.values())
+            total += adapter.getViewTypeCount();
+        return total;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        int type = 1;
+        for(Object section : this.sections.keySet()) {
+            Adapter adapter = sections.get(section);
+            int size = adapter.getCount() + 1;
+
+            // check if position inside this section
+            if(position == 0) return TYPE_SECTION_HEADER;
+            if(position < size) return type + adapter.getItemViewType(position - 1);
+
+            // otherwise jump into next section
+            position -= size;
+            type += adapter.getViewTypeCount();
+        }
+        return -1;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return (getItemViewType(position) != TYPE_SECTION_HEADER);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        int sectionnum = 0;
+        for(Object section : this.sections.keySet()) {
+            Adapter adapter = sections.get(section);
+            int size = adapter.getCount() + 1;
+
+            int viewType = getItemViewType(position);
+            System.out.println(viewType);
+            // check if position inside this section
+            if(position == 0) return headers.getView(sectionnum, convertView, parent);
+            if(position < size) return adapter.getView(position - 1, convertView, parent);
+
+            // otherwise jump into next section
+            position -= size;
+            sectionnum++;
+        }
+        return null;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+}