package com.distantfuture.videos.introactivity; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.Handler; import android.os.Looper; import android.text.format.DateFormat; import com.distantfuture.videos.R; import com.distantfuture.videos.content.Content; import com.distantfuture.videos.database.YouTubeData; import com.distantfuture.videos.imageutils.ToolbarIcons; import com.distantfuture.videos.misc.DUtils; import com.distantfuture.videos.misc.Utils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class IntroXMLParser { private final Context mContext; private IntroXMLParserListener mCallback; private IntroXMLParser(final Context context) { super(); mContext = context.getApplicationContext(); } public static void parseXML(Context context, IntroXMLParserListener callback) { new IntroXMLParser(context).parseXML(callback); } private static String parseDate(final Context context, final String dateString) { final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy"); try { final Date parsedDate = dateFormat.parse(dateString); return DateFormat.getDateFormat(context).format(parsedDate); } catch (ParseException ignored) { return dateString; } } private static IntroPage parsePageTag(Context context, final XmlPullParser resourceParser) throws XmlPullParserException, IOException { IntroPage result = null; String title, icon; List<IntroPageField> fields = new ArrayList<IntroPageField>(); title = resourceParser.getAttributeValue(null, "title"); icon = resourceParser.getAttributeValue(null, "icon"); int eventType = resourceParser.getEventType(); while (!(eventType == XmlPullParser.END_TAG && resourceParser.getName().equals("page"))) { if (eventType == XmlPullParser.START_TAG) { String name = resourceParser.getName(); String topMargin = resourceParser.getAttributeValue(null, "top_margin"); String append = resourceParser.getAttributeValue(null, "append"); if (name.equals("header")) { resourceParser.next(); String text = resourceParser.getText(); IntroPageField field = IntroPageField.newField(context, text, topMargin, append, IntroPageField.FieldType.HEADER); fields.add(field); } else if (name.equals("text")) { resourceParser.next(); String text = resourceParser.getText(); IntroPageField field = IntroPageField.newField(context, text, topMargin, append, IntroPageField.FieldType.TEXT); fields.add(field); } else if (name.equals("bullet")) { resourceParser.next(); String text = resourceParser.getText(); IntroPageField field = IntroPageField.newField(context, text, topMargin, append, IntroPageField.FieldType.BULLET); fields.add(field); } else if (name.equals("channels")) { resourceParser.next(); // channels should never be null since we don't start this activity until channels are initialized Content content = Content.instance(); List<YouTubeData> channels = content.channels(); if (channels != null) { for (YouTubeData channel : channels) { IntroPageField field = IntroPageField.newField(context, channel.mTitle, topMargin, append, IntroPageField.FieldType.BULLET); fields.add(field); } } } } eventType = resourceParser.next(); } return IntroPage.newPage(title, icon, fields); } private List<IntroPage> getHTMLChangelog(final int resourceId, final Resources resources) { List<IntroPage> result = new ArrayList(); final XmlResourceParser xml = resources.getXml(resourceId); try { int eventType = xml.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { if ((eventType == XmlPullParser.START_TAG) && (xml.getName().equals("page"))) { IntroPage page = parsePageTag(mContext, xml); result.add(page); } eventType = xml.next(); } } catch (XmlPullParserException e) { DUtils.log(e.getMessage() + e); } catch (IOException e) { DUtils.log(e.getMessage() + e); } finally { xml.close(); } return result; } private void parseXML(final IntroXMLParserListener callback) { final Resources resources = mContext.getResources(); new Thread(new Runnable() { @Override public void run() { final List<IntroPage> result = getHTMLChangelog(R.xml.quickguide, resources); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { callback.parseXMLDone(result); } }); } }).start(); } public interface IntroXMLParserListener { public void parseXMLDone(List<IntroPage> pages); } public static class IntroPage { public String title; public List<IntroPageField> fields; private String icon; public static IntroPage newPage(String title, String icon, List<IntroPageField> fields) { IntroPage result = new IntroPage(); result.title = title; result.icon = icon; result.fields = fields; return result; } public ToolbarIcons.IconID icon() { switch (icon) { case "quick": return ToolbarIcons.IconID.COGS; case "youtube": return ToolbarIcons.IconID.YOUTUBE; case "navigation": return ToolbarIcons.IconID.SITE_MAP; case "basics": return ToolbarIcons.IconID.ABOUT; case "video": return ToolbarIcons.IconID.FILM; case "why": return ToolbarIcons.IconID.QUESTION_MARK; case "suggestions": return ToolbarIcons.IconID.COMMENTS; case "find": return ToolbarIcons.IconID.SEARCH; case "editing": return ToolbarIcons.IconID.YOUTUBE; } // shouldn't get here return ToolbarIcons.IconID.ABOUT; } } public static class IntroPageField { public String text; public FieldType type; public int topMargin; public static IntroPageField newField(Context context, String text, String topMargin, String append, FieldType type) { IntroPageField result = new IntroPageField(); result.text = Utils.condenseWhiteSpace(text); // xml file can be reformatted by the IDE to add returns if (append != null && append.equals("app_name")) result.text += " " + Utils.getApplicationName(context); result.type = type; if (topMargin != null) result.topMargin = Integer.valueOf(topMargin); return result; } public int topMargin() { switch (type) { case TEXT: return 12; case BULLET: return 6; case HEADER: return 12; } return 0; } public boolean isText() { return type == FieldType.TEXT; } public boolean isBullet() { return type == FieldType.BULLET; } public boolean isHeader() { return type == FieldType.HEADER; } public enum FieldType {TEXT, HEADER, BULLET} } }