From d773a39a1f07ae4b8021222a47c16b048d7fd435 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 17 Aug 2010 01:56:11 +0200 Subject: initial commit --- .classpath | 7 + .gitignore | 2 + .project | 39 ++++ AndroidManifest.xml | 20 +++ default.properties | 13 ++ res/drawable/icon.png | Bin 0 -> 2574 bytes res/layout/list_header.xml | 10 ++ res/layout/list_item.xml | 31 ++++ res/values/strings.xml | 5 + .../animux/android/andmal/AnimeListActivity.java | 91 ++++++++++ src/de/animux/android/andmal/api/anime/Anime.java | 197 +++++++++++++++++++++ .../animux/android/andmal/api/anime/AnimeList.java | 117 ++++++++++++ src/de/animux/android/andmal/api/anime/State.java | 36 ++++ .../android/andmal/util/SeparatedListAdapter.java | 116 ++++++++++++ .../android/andmal/util/SortedLinkedList.java | 40 +++++ 15 files changed, 724 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 AndroidManifest.xml create mode 100644 default.properties create mode 100644 res/drawable/icon.png create mode 100644 res/layout/list_header.xml create mode 100644 res/layout/list_item.xml create mode 100644 res/values/strings.xml create mode 100644 src/de/animux/android/andmal/AnimeListActivity.java create mode 100644 src/de/animux/android/andmal/api/anime/Anime.java create mode 100644 src/de/animux/android/andmal/api/anime/AnimeList.java create mode 100644 src/de/animux/android/andmal/api/anime/State.java create mode 100644 src/de/animux/android/andmal/util/SeparatedListAdapter.java create mode 100644 src/de/animux/android/andmal/util/SortedLinkedList.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..609aa00 --- /dev/null +++ b/.classpath @@ -0,0 +1,7 @@ + + + + + + + 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 @@ + + + AndMAL + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..a1db31e --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + \ 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 Binary files /dev/null and b/res/drawable/icon.png 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 @@ + + \ 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 @@ + + + + + + + + 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 @@ + + + Hello World, List! + AndMAL + 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 createItem(String title, String caption) { + Map item = new HashMap(); + 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> 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 animes, String sectionName) { + if (animes != null && animes.size() > 0) { + java.util.List> listSection = new LinkedList>(); + + 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 { + + 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> animes; + + public AnimeList(String user) throws IOException, + ParserConfigurationException, SAXException, + FactoryConfigurationError { + currentAnime = null; + currentValue = new StringBuffer(); + + animes = new HashMap>(); + animes.put(State.WATCHING, new SortedLinkedList()); + animes.put(State.COMPLETED, new SortedLinkedList()); + animes.put(State.ONHOLD, new SortedLinkedList()); + animes.put(State.DROPPED, new SortedLinkedList()); + animes.put(State.PLANTOWATCH, new SortedLinkedList()); + + 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> 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("&", "&")); + } + + @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 sections = new LinkedHashMap(); + + public final ArrayAdapter headers; + + public final static int TYPE_SECTION_HEADER = 0; + + public SeparatedListAdapter(Context context) { + headers = new ArrayAdapter(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> extends LinkedList { + + private static final long serialVersionUID = 8263372892230475461L; + + @Override + public boolean add(T object) { + ListIterator 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 collection) { + for (T object : collection) { + add(object); + } + + return true; + } +} -- cgit v1.2.3