package com.distantfuture.videos.activities; import android.app.Activity; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.view.Gravity; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.distantfuture.videos.R; 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.util.ArrayList; import java.util.List; public class CreditsActivity extends Activity { private ViewGroup mContainer; public static void show(Activity activity) { // add animation, see finish below for the back transition ActivityOptions opts = ActivityOptions.makeCustomAnimation(activity, R.anim.scale_in, R.anim.scale_out); Intent intent = new Intent(); intent.setClass(activity, CreditsActivity.class); activity.startActivity(intent, opts.toBundle()); } @Override public void finish() { super.finish(); // animate out overridePendingTransition(R.anim.scale_out_rev, R.anim.scale_in_rev); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_credits); getActionBar().setDisplayHomeAsUpEnabled(true); mContainer = (ViewGroup) findViewById(R.id.credits_container); CreditsXMLParser.parseXML(this, new CreditsXMLParser.CreditsXMLParserListener() { @Override public void parseXMLDone(List<CreditsXMLParser.CreditsPage> newPages) { boolean alternate = true; int radius = (int) Utils.dpToPx(8f, CreditsActivity.this); for (CreditsXMLParser.CreditsPage page : newPages) { GradientDrawable background = null; if (page.alternating_background) { int color; if (page.group) { color = 0x88000000; } else { alternate = !alternate; if (alternate) { color = 0x05000000; } else { color = 0x10000000; } } background = new GradientDrawable(); background.setStroke(1, 0x10000000); background.setCornerRadius(radius); background.setColor(color); } LinearLayout linearLayout = new LinearLayout(CreditsActivity.this); linearLayout.setOrientation(LinearLayout.VERTICAL); LinearLayout.LayoutParams duhParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); int hMargin = (int) Utils.dpToPx(12f, CreditsActivity.this); int vMargin = (int) Utils.dpToPx(3f, CreditsActivity.this); duhParams.setMargins(hMargin, vMargin, hMargin, vMargin); linearLayout.setPadding(hMargin, vMargin, hMargin, vMargin); linearLayout.setLayoutParams(duhParams); linearLayout.setBackground(background); for (CreditsXMLParser.CreditsPageField field : page.fields) linearLayout.addView(createFieldView(field, page.group)); mContainer.addView(linearLayout); } } }); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // Respond to the action bar's Up/Home button case android.R.id.home: finish(); return true; } return super.onOptionsItemSelected(item); } private View createFieldView(CreditsXMLParser.CreditsPageField field, boolean group) { int textSize = 16; if (field.isHeader()) textSize = 20; if (field.size != null) textSize = Integer.parseInt(field.size); TextView textView = new TextView(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); textView.setLayoutParams(params); textView.setTextSize(textSize); int color = 0xaa000000; if (field.link != null) { color = 0xff0000ff; final Uri uri = Uri.parse(field.link); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Utils.openWebPage(CreditsActivity.this, uri); } }); } if (group) color = 0xaaffffff; if (field.copyRight != null) textView.setText(copyRightString(field.copyRight, field.text, color)); else { textView.setText(field.text); textView.setTextColor(color); } if (field.isHeader()) { textView.setTextSize(textSize); textView.setTypeface(Typeface.DEFAULT_BOLD); } textView.setGravity(Gravity.CENTER); LinearLayout linearLayout = new LinearLayout(this); LinearLayout.LayoutParams duhParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); int topMarginPx = (int) Utils.dpToPx(field.topMargin, this); duhParams.setMargins(0, topMarginPx, 0, 0); linearLayout.setLayoutParams(duhParams); linearLayout.setPadding(0, 4, 0, 4); linearLayout.addView(textView); return linearLayout; } private SpannableString copyRightString(String copyRight, String info, int infoColor) { // final StyleSpan mBoldSpan = new StyleSpan(Typeface.BOLD); final ForegroundColorSpan mColorSpan = new ForegroundColorSpan(infoColor); SpannableString result = new SpannableString(copyRight + info); // result.setSpan(mBoldSpan, 0, copyRight.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // result.setSpan(mBoldSpan, copyRight.length(), copyRight.length() + info.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); result.setSpan(mColorSpan, copyRight.length(), copyRight.length() + info.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return result; } // =================================================================================== // xml parser private static class CreditsXMLParser { private final Context mContext; private CreditsXMLParserListener mCallback; private CreditsXMLParser(final Context context) { super(); mContext = context.getApplicationContext(); } public static void parseXML(Context context, CreditsXMLParserListener callback) { new CreditsXMLParser(context).parseXML(callback); } private static CreditsPage parsePageTag(Context context, final XmlPullParser resourceParser) throws XmlPullParserException, IOException { List<CreditsPageField> fields = new ArrayList<CreditsPageField>(); String group = resourceParser.getAttributeValue(null, "group"); String no_background = resourceParser.getAttributeValue(null, "no_background"); int eventType = resourceParser.getEventType(); while (!(eventType == XmlPullParser.END_TAG && resourceParser.getName().equals("credit"))) { if (eventType == XmlPullParser.START_TAG) { String name = resourceParser.getName(); String topMargin = resourceParser.getAttributeValue(null, "top_margin"); String link = resourceParser.getAttributeValue(null, "link"); String size = resourceParser.getAttributeValue(null, "size"); String copyRight = resourceParser.getAttributeValue(null, "copy"); if (name.equals("header")) { resourceParser.next(); String text = resourceParser.getText(); CreditsPageField field = CreditsPageField.newField(context, text, link, size, copyRight, topMargin, CreditsPageField.FieldType.HEADER); fields.add(field); } else if (name.equals("text")) { resourceParser.next(); String text = resourceParser.getText(); CreditsPageField field = CreditsPageField.newField(context, text, link, size, copyRight, topMargin, CreditsPageField.FieldType.TEXT); fields.add(field); } else if (name.equals("group")) { resourceParser.next(); String text = resourceParser.getText(); CreditsPageField field = CreditsPageField.newField(context, text, link, size, copyRight, topMargin, CreditsPageField.FieldType.GROUP); fields.add(field); } } eventType = resourceParser.next(); } return CreditsPage.newPage(group, no_background, fields); } private List<CreditsPage> getHTMLChangelog(final int resourceId, final Resources resources) { List<CreditsPage> 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("credit"))) { CreditsPage 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 CreditsXMLParserListener callback) { final Resources resources = mContext.getResources(); new Thread(new Runnable() { @Override public void run() { final List<CreditsPage> result = getHTMLChangelog(R.xml.credits, resources); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { callback.parseXMLDone(result); } }); } }).start(); } public interface CreditsXMLParserListener { public void parseXMLDone(List<CreditsPage> pages); } // ====================================================================== // CreditsPage public static class CreditsPage { public String title; public List<CreditsPageField> fields; public boolean group; public boolean alternating_background; public static CreditsPage newPage(String group, String no_background, List<CreditsPageField> fields) { CreditsPage result = new CreditsPage(); result.group = group != null; result.alternating_background = no_background == null; result.fields = fields; return result; } } // ====================================================================== // CreditsPageField public static class CreditsPageField { public String text; public FieldType type; public int topMargin; public String link; public String size; public String copyRight; public static CreditsPageField newField(Context context, String text, String link, String size, String copyRight, String topMargin, FieldType type) { CreditsPageField result = new CreditsPageField(); result.text = Utils.condenseWhiteSpace(text); // xml file can be reformatted by the IDE to add returns result.type = type; result.link = link; result.size = size; if (copyRight != null) result.copyRight = "Copyright " + copyRight + " "; if (topMargin != null) result.topMargin = Integer.parseInt(topMargin); return result; } public boolean isText() { return type == FieldType.TEXT; } public boolean isHeader() { return type == FieldType.HEADER; } public boolean isGroupHeader() { return type == FieldType.GROUP; } public enum FieldType {TEXT, HEADER, GROUP} } } }