summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2010-08-17 01:56:11 +0200
committerAlexander Sulfrian <alexander@sulfrian.net>2010-08-17 02:19:39 +0200
commitd773a39a1f07ae4b8021222a47c16b048d7fd435 (patch)
tree3558cbd77c8e6aa54f5593b556fcbf330fea0120
downloadAndMAL-d773a39a1f07ae4b8021222a47c16b048d7fd435.tar.gz
AndMAL-d773a39a1f07ae4b8021222a47c16b048d7fd435.tar.xz
AndMAL-d773a39a1f07ae4b8021222a47c16b048d7fd435.zip
initial commit
-rw-r--r--.classpath7
-rw-r--r--.gitignore2
-rw-r--r--.project39
-rw-r--r--AndroidManifest.xml20
-rw-r--r--default.properties13
-rw-r--r--res/drawable/icon.pngbin0 -> 2574 bytes
-rw-r--r--res/layout/list_header.xml10
-rw-r--r--res/layout/list_item.xml31
-rw-r--r--res/values/strings.xml5
-rw-r--r--src/de/animux/android/andmal/AnimeListActivity.java91
-rw-r--r--src/de/animux/android/andmal/api/anime/Anime.java197
-rw-r--r--src/de/animux/android/andmal/api/anime/AnimeList.java117
-rw-r--r--src/de/animux/android/andmal/api/anime/State.java36
-rw-r--r--src/de/animux/android/andmal/util/SeparatedListAdapter.java116
-rw-r--r--src/de/animux/android/andmal/util/SortedLinkedList.java40
15 files changed, 724 insertions, 0 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..609aa00
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+<?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="output" path="bin"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d6d6a17
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+bin/*
+gen/*
diff --git a/.project b/.project
new file mode 100644
index 0000000..e8640ee
--- /dev/null
+++ b/.project
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>AndMAL</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <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>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..a1db31e
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.animux.android.andmal"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application android:icon="@drawable/icon" android:label="@string/app_name">
+ <activity android:label="@string/app_name" android:name=".AnimeListActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+ <uses-sdk android:minSdkVersion="3" />
+
+
+
+<uses-permission android:name="android.permission.INTERNET"></uses-permission>
+</manifest> \ No newline at end of file
diff --git a/default.properties b/default.properties
new file mode 100644
index 0000000..a1ef8e9
--- /dev/null
+++ b/default.properties
@@ -0,0 +1,13 @@
+# 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 use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-3
diff --git a/res/drawable/icon.png b/res/drawable/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/res/drawable/icon.png
Binary files differ
diff --git a/res/layout/list_header.xml b/res/layout/list_header.xml
new file mode 100644
index 0000000..fcaf7a4
--- /dev/null
+++ b/res/layout/list_header.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_header_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:paddingLeft="5dip"
+ style="?android:attr/listSeparatorTextViewStyle" /> \ No newline at end of file
diff --git a/res/layout/list_item.xml b/res/layout/list_item.xml
new file mode 100644
index 0000000..6c0641d
--- /dev/null
+++ b/res/layout/list_item.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<TableLayout
+ android:id="@+id/TableLayout01"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:stretchColumns="1"
+ >
+ <TableRow>
+ <TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_item_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingTop="10dip"
+ android:paddingBottom="10dip"
+ android:paddingLeft="5dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_column="1"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@+id/list_item_other"
+ android:id="@+id/list_item_other"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:paddingRight="5dip"
+ android:gravity="right" />
+ </TableRow>
+</TableLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..89038cf
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Hello World, List!</string>
+ <string name="app_name">AndMAL</string>
+</resources>
diff --git a/src/de/animux/android/andmal/AnimeListActivity.java b/src/de/animux/android/andmal/AnimeListActivity.java
new file mode 100644
index 0000000..8db6635
--- /dev/null
+++ b/src/de/animux/android/andmal/AnimeListActivity.java
@@ -0,0 +1,91 @@
+package de.animux.android.andmal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import de.animux.android.andmal.api.anime.Anime;
+import de.animux.android.andmal.api.anime.AnimeList;
+import de.animux.android.andmal.api.anime.State;
+import de.animux.android.andmal.util.SeparatedListAdapter;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+public class AnimeListActivity extends Activity {
+
+ public final static String ITEM_TITLE = "title";
+ public final static String ITEM_CAPTION = "caption";
+
+ public final static int INITIAL_SYNC = 0;
+
+ public Map<String, ?> createItem(String title, String caption) {
+ Map<String, String> item = new HashMap<String, String>();
+ item.put(ITEM_TITLE, title);
+ item.put(ITEM_CAPTION, caption);
+ return item;
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ showDialog(INITIAL_SYNC);
+
+ AnimeList animeList = null;
+ try {
+ animeList = new AnimeList("AlexanderS");
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ dismissDialog(INITIAL_SYNC);
+
+ SeparatedListAdapter adapter = new SeparatedListAdapter(this);
+ Map<State, java.util.List<Anime>> animes = animeList.getAnimes();
+
+ for (State s : State.values())
+ addAnimes(adapter, animes.get(s), s.toString());
+
+ ListView list = new ListView(this);
+ list.setAdapter(adapter);
+ this.setContentView(list);
+ }
+
+ private void addAnimes(SeparatedListAdapter adapter,
+ Collection<Anime> animes, String sectionName) {
+ if (animes != null && animes.size() > 0) {
+ java.util.List<Map<String, ?>> listSection = new LinkedList<Map<String, ?>>();
+
+ for (Anime a : animes) {
+ listSection.add(createItem(a.getTitle(), a.getWatchedEpisodes()
+ + "/" + a.getEpisodes()));
+ }
+
+ adapter.addSection(sectionName, new SimpleAdapter(this,
+ listSection, R.layout.list_item, new String[] { ITEM_TITLE,
+ ITEM_CAPTION }, new int[] { R.id.list_item_title,
+ R.id.list_item_other }));
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case INITIAL_SYNC:
+ ProgressDialog dialog = ProgressDialog.show(this, "",
+ "Loading list. Please wait...", true);
+ return dialog;
+ default:
+ return super.onCreateDialog(id);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/de/animux/android/andmal/api/anime/Anime.java b/src/de/animux/android/andmal/api/anime/Anime.java
new file mode 100644
index 0000000..d4f542f
--- /dev/null
+++ b/src/de/animux/android/andmal/api/anime/Anime.java
@@ -0,0 +1,197 @@
+package de.animux.android.andmal.api.anime;
+
+public class Anime implements Comparable<Anime> {
+
+ private int id;
+ private String title;
+ private String synonyms;
+ private int type;
+ private int episodes;
+ private int status;
+ private String start;
+ private String end;
+ private String image;
+ private int myId;
+ private int watchedEpisodes;
+ private String myStart;
+ private String myEnd;
+ private int myScore;
+ private int myStatus;
+ private int rewatching;
+ private int rewatchingEpisodes;
+ private int lastUpdate;
+ private String tags;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getSynonyms() {
+ return synonyms;
+ }
+
+ public void setSynonyms(String synonyms) {
+ this.synonyms = synonyms;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public int getEpisodes() {
+ return episodes;
+ }
+
+ public void setEpisodes(int episodes) {
+ this.episodes = episodes;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public void setStart(String start) {
+ this.start = start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public void setEnd(String end) {
+ this.end = end;
+ }
+
+ public String getImage() {
+ return image;
+ }
+
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ public int getMyId() {
+ return myId;
+ }
+
+ public void setMyId(int myId) {
+ this.myId = myId;
+ }
+
+ public int getWatchedEpisodes() {
+ return watchedEpisodes;
+ }
+
+ public void setWatchedEpisodes(int watchedEpisodes) {
+ this.watchedEpisodes = watchedEpisodes;
+ }
+
+ public String getMyStart() {
+ return myStart;
+ }
+
+ public void setMyStart(String myStart) {
+ this.myStart = myStart;
+ }
+
+ public String getMyEnd() {
+ return myEnd;
+ }
+
+ public void setMyEnd(String myEnd) {
+ this.myEnd = myEnd;
+ }
+
+ public int getMyScore() {
+ return myScore;
+ }
+
+ public void setMyScore(int myScore) {
+ this.myScore = myScore;
+ }
+
+ public int getMyStatus() {
+ return myStatus;
+ }
+
+ public void setMyStatus(int myStatus) {
+ this.myStatus = myStatus;
+ }
+
+ public int getRewatching() {
+ return rewatching;
+ }
+
+ public void setRewatching(int rewatching) {
+ this.rewatching = rewatching;
+ }
+
+ public int getRewatchingEpisodes() {
+ return rewatchingEpisodes;
+ }
+
+ public void setRewatchingEpisodes(int rewatchingEpisodes) {
+ this.rewatchingEpisodes = rewatchingEpisodes;
+ }
+
+ public int getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(int lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+
+ public String getTags() {
+ return tags;
+ }
+
+ public void setTags(String tags) {
+ this.tags = tags;
+ }
+
+ @Override
+ public String toString() {
+ return getTitle();
+ }
+
+ @Override
+ public int compareTo(Anime arg0) {
+ int compareTitle = arg0.getTitle().compareTo(getTitle());
+ if (compareTitle != 0) {
+ return compareTitle;
+ }
+ else {
+ if (arg0.getId() != getId()) {
+ return getId() - arg0.getId();
+ }
+ }
+
+ return 0;
+ }
+
+}
diff --git a/src/de/animux/android/andmal/api/anime/AnimeList.java b/src/de/animux/android/andmal/api/anime/AnimeList.java
new file mode 100644
index 0000000..78a1e09
--- /dev/null
+++ b/src/de/animux/android/andmal/api/anime/AnimeList.java
@@ -0,0 +1,117 @@
+package de.animux.android.andmal.api.anime;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import de.animux.android.andmal.api.anime.State;
+import de.animux.android.andmal.util.SortedLinkedList;
+
+public class AnimeList extends DefaultHandler {
+
+ private Anime currentAnime;
+ private StringBuffer currentValue;
+
+ private HashMap<State,List<Anime>> animes;
+
+ public AnimeList(String user) throws IOException,
+ ParserConfigurationException, SAXException,
+ FactoryConfigurationError {
+ currentAnime = null;
+ currentValue = new StringBuffer();
+
+ animes = new HashMap<State, List<Anime>>();
+ animes.put(State.WATCHING, new SortedLinkedList<Anime>());
+ animes.put(State.COMPLETED, new SortedLinkedList<Anime>());
+ animes.put(State.ONHOLD, new SortedLinkedList<Anime>());
+ animes.put(State.DROPPED, new SortedLinkedList<Anime>());
+ animes.put(State.PLANTOWATCH, new SortedLinkedList<Anime>());
+
+ URL url = new URL("http://myanimelist.net/malappinfo.php?status=all&type=anime&u=" + user);
+ InputStream stream = url.openStream();
+
+ SAXParser sax = SAXParserFactory.newInstance().newSAXParser();
+ sax.parse(stream, this);
+ }
+
+ public Anime getCurrentAnime() {
+ return currentAnime;
+ }
+
+ public StringBuffer getCurrentValue() {
+ return currentValue;
+ }
+
+ public Map<State, List<Anime>> getAnimes() {
+ return animes;
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length)
+ throws SAXException {
+ currentValue.append(new String(ch).substring(start, length - start)
+ .replaceAll("&amp;", "&"));
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+
+ if (localName.equals("anime")) {
+ if (animes.containsKey(State.valueOf(currentAnime.getMyStatus()))) {
+ animes.get(State.valueOf(currentAnime.getMyStatus())).add(currentAnime);
+ }
+
+ } else if (localName.equals("series_animedb_id")) {
+ currentAnime.setId(Integer.valueOf(currentValue.toString()));
+ } else if (localName.equals("series_title")) {
+ currentAnime.setTitle(currentValue.toString());
+ } else if (localName.equals("series_synonyms")) {
+ currentAnime.setSynonyms(currentValue.toString());
+ } else if (localName.equals("series_type")) {
+ currentAnime.setType(Integer.valueOf(currentValue.toString()));
+ } else if (localName.equals("series_episodes")) {
+ currentAnime.setEpisodes(Integer.valueOf(currentValue.toString()));
+ } else if (localName.equals("series_status")) {
+ currentAnime.setStatus(Integer.valueOf(currentValue.toString()));
+ } else if (localName.equals("series_start")) {
+ currentAnime.setStart(currentValue.toString());
+ } else if (localName.equals("series_end")) {
+ currentAnime.setEnd(currentValue.toString());
+ } else if (localName.equals("series_image")) {
+ currentAnime.setImage(currentValue.toString());
+ } else if (localName.equals("my_id")) {
+ currentAnime.setMyId(Integer.valueOf(currentValue.toString()));
+ } else if (localName.equals("my_watched_episodes")) {
+ currentAnime.setWatchedEpisodes(Integer.valueOf(currentValue
+ .toString()));
+ } else if (localName.equals("my_status")) {
+ currentAnime.setMyStatus(Integer.valueOf(currentValue.toString()));
+ }
+
+ currentValue.setLength(0);
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+
+ currentValue.setLength(0);
+ if (localName.equals("anime")) {
+ currentAnime = new Anime();
+ }
+ }
+}
diff --git a/src/de/animux/android/andmal/api/anime/State.java b/src/de/animux/android/andmal/api/anime/State.java
new file mode 100644
index 0000000..639b761
--- /dev/null
+++ b/src/de/animux/android/andmal/api/anime/State.java
@@ -0,0 +1,36 @@
+package de.animux.android.andmal.api.anime;
+
+public enum State {
+ WATCHING (1, "Watching"),
+ COMPLETED (2, "Completed"),
+ ONHOLD (3, "On Hold"),
+ DROPPED (4, "Dropped"),
+ PLANTOWATCH (6, "Plan to watch");
+
+ private final int id;
+ private final String name;
+
+ State(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ static State valueOf(int id) {
+ for (State s : State.values()) {
+ if (s.getId() == id) {
+ return s;
+ }
+ }
+
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/de/animux/android/andmal/util/SeparatedListAdapter.java b/src/de/animux/android/andmal/util/SeparatedListAdapter.java
new file mode 100644
index 0000000..6320b0f
--- /dev/null
+++ b/src/de/animux/android/andmal/util/SeparatedListAdapter.java
@@ -0,0 +1,116 @@
+package de.animux.android.andmal.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import de.animux.android.andmal.R;
+
+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 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);
+ }
+
+ 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;
+ }
+
+ public int getViewTypeCount() {
+ // assume that headers count as one, then total all sections
+ int total = 1;
+ for (Adapter adapter : this.sections.values())
+ total += adapter.getViewTypeCount();
+ return total;
+ }
+
+ 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;
+ }
+
+ public boolean areAllItemsSelectable() {
+ return false;
+ }
+
+ 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;
+
+ // 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;
+ }
+} \ No newline at end of file
diff --git a/src/de/animux/android/andmal/util/SortedLinkedList.java b/src/de/animux/android/andmal/util/SortedLinkedList.java
new file mode 100644
index 0000000..974d3e5
--- /dev/null
+++ b/src/de/animux/android/andmal/util/SortedLinkedList.java
@@ -0,0 +1,40 @@
+package de.animux.android.andmal.util;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+public class SortedLinkedList<T extends Comparable<T>> extends LinkedList<T> {
+
+ private static final long serialVersionUID = 8263372892230475461L;
+
+ @Override
+ public boolean add(T object) {
+ ListIterator<T> it = listIterator();
+ while (it.hasNext()) {
+ if (object.compareTo(it.next()) > 0) {
+ break;
+ }
+ }
+
+ if (it.hasPrevious()) {
+ it.previous();
+ it.add(object);
+ }
+ else {
+ // insert at first position
+ listIterator().add(object);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> collection) {
+ for (T object : collection) {
+ add(object);
+ }
+
+ return true;
+ }
+}