package mehdi.sakout.aboutpage; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.DrawableRes; import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v4.widget.TextViewCompat; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; /** * The main class of this library with many predefined methods to add Elements for common items in * an About page. This class creates a {@link android.view.View} that can be passed as the root view * in {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)} or passed to the {@link android.app.Activity#setContentView(View)} * in an activity's {@link android.app.Activity#onCreate(Bundle)} method * <p> * To create a custom item in the about page, pass an instance of {@link mehdi.sakout.aboutpage.Element} * to the {@link AboutPage#addItem(Element)} method. * * @see Element */ public class AboutPage { private final Context mContext; private final LayoutInflater mInflater; private final View mView; private String mDescription; private int mImage = 0; private boolean mIsRTL = false; private Typeface mCustomFont; /** * The AboutPage requires a context to perform it's functions. Give it a context associated to an * Activity or a Fragment. To avoid memory leaks, don't pass a * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()} here. * * @param context */ public AboutPage(Context context) { this.mContext = context; this.mInflater = LayoutInflater.from(context); this.mView = mInflater.inflate(R.layout.about_page, null); } /** * Provide a valid path to a font here to use another font for the text inside this AboutPage * * @param path * @return this AboutPage instance for builder pattern support */ public AboutPage setCustomFont(String path) { //TODO: check if file exists mCustomFont = Typeface.createFromAsset(mContext.getAssets(), path); return this; } /** * Convenience method for {@link AboutPage#addEmail(java.lang.String, java.lang.String)} but with * a predefined title string * * @param email the email address to send to * @return this AboutPage instance for builder pattern support */ public AboutPage addEmail(String email) { return addEmail(email, mContext.getString(R.string.about_contact_us)); } /** * Add a predefined Element that opens the users default email client with a new email to the * email address passed as parameter * * @param email the email address to send to * @param title the title string to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addEmail(String email, String title) { Element emailElement = new Element(); emailElement.setTitle(title); emailElement.setIconDrawable(R.drawable.about_icon_email); emailElement.setIconTint(R.color.about_item_icon_color); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("message/rfc822"); intent.putExtra(Intent.EXTRA_EMAIL, new String[]{email}); emailElement.setIntent(intent); addItem(emailElement); return this; } /** * Convenience method for {@link AboutPage#addFacebook(java.lang.String, java.lang.String)} but with * a predefined title string * * @param id the facebook id to display * @return this AboutPage instance for builder pattern support */ public AboutPage addFacebook(String id) { return addFacebook(id, mContext.getString(R.string.about_facebook)); } /** * Add a predefined Element that the opens Facebook app with a deep link to the specified user id * If the Facebook application is not installed this will open a web page instead. * * @param id the id of the Facebook user to display in the Facebook app * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addFacebook(String id, String title) { Element facebookElement = new Element(); facebookElement.setTitle(title); facebookElement.setIconDrawable(R.drawable.about_icon_facebook); facebookElement.setIconTint(R.color.about_facebook_color); facebookElement.setValue(id); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_BROWSABLE); if (AboutPageUtils.isAppInstalled(mContext, "com.facebook.katana")) { intent.setPackage("com.facebook.katana"); int versionCode = 0; try { versionCode = mContext.getPackageManager().getPackageInfo("com.facebook.katana", 0).versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } if (versionCode >= 3002850) { Uri uri = Uri.parse("fb://facewebmodal/f?href=" + "http://m.facebook.com/" + id); intent.setData(uri); } else { Uri uri = Uri.parse("fb://page/" + id); intent.setData(uri); } } else { intent.setData(Uri.parse("http://m.facebook.com/" + id)); } facebookElement.setIntent(intent); addItem(facebookElement); return this; } /** * Convenience method for {@link AboutPage#addTwitter(String, String)} but with * a predefined title string * * @param id the Twitter id to display * @return this AboutPage instance for builder pattern support */ public AboutPage addTwitter(String id) { return addTwitter(id, mContext.getString(R.string.about_twitter)); } /** * Add a predefined Element that the opens the Twitter app with a deep link to the specified user id * If the Twitter application is not installed this will open a web page instead. * * @param id the id of the Twitter user to display in the Twitter app * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addTwitter(String id, String title) { Element twitterElement = new Element(); twitterElement.setTitle(title); twitterElement.setIconDrawable(R.drawable.about_icon_twitter); twitterElement.setIconTint(R.color.about_twitter_color); twitterElement.setValue(id); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_BROWSABLE); if (AboutPageUtils.isAppInstalled(mContext, "com.twitter.android")) { intent.setPackage("com.twitter.android"); intent.setData(Uri.parse(String.format("twitter://user?screen_name=%s", id))); } else { intent.setData(Uri.parse(String.format("http://twitter.com/intent/user?screen_name=%s", id))); } twitterElement.setIntent(intent); addItem(twitterElement); return this; } /** * Convenience method for {@link AboutPage#addPlayStore(String, String)} but with * a predefined title string * * @param id the package id of the app to display * @return this AboutPage instance for builder pattern support */ public AboutPage addPlayStore(String id) { return addPlayStore(id, mContext.getString(R.string.about_play_store)); } /** * Add a predefined Element that the opens the PlayStore app with a deep link to the * specified app application id. * * @param id the package id of the app to display * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addPlayStore(String id, String title) { Element playStoreElement = new Element(); playStoreElement.setTitle(title); playStoreElement.setIconDrawable(R.drawable.about_icon_google_play); playStoreElement.setIconTint(R.color.about_play_store_color); playStoreElement.setValue(id); Uri uri = Uri.parse("market://details?id=" + id); Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri); playStoreElement.setIntent(goToMarket); addItem(playStoreElement); return this; } /** * Convenience method for {@link AboutPage#addYoutube(String, String)} but with * a predefined title string * * @param id the id of the channel to deep link to * @return this AboutPage instance for builder pattern support */ public AboutPage addYoutube(String id) { return addYoutube(id, mContext.getString(R.string.about_youtube)); } /** * Add a predefined Element that the opens the Youtube app with a deep link to the * specified channel id. * <p> * If the Youtube app is not installed this will open the Youtube web page instead. * * @param id the id of the channel to deep link to * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addYoutube(String id, String title) { Element youtubeElement = new Element(); youtubeElement.setTitle(title); youtubeElement.setIconDrawable(R.drawable.about_icon_youtube); youtubeElement.setIconTint(R.color.about_youtube_color); youtubeElement.setValue(id); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse(String.format("http://youtube.com/channel/%s", id))); if (AboutPageUtils.isAppInstalled(mContext, "com.google.android.youtube")) { intent.setPackage("com.google.android.youtube"); } youtubeElement.setIntent(intent); addItem(youtubeElement); return this; } /** * Convenience method for {@link AboutPage#addInstagram(String, String)} (String, String)} but with * a predefined title string * * @param id the id of the instagram user to deep link to * @return this AboutPage instance for builder pattern support */ public AboutPage addInstagram(String id) { return addInstagram(id, mContext.getString(R.string.about_instagram)); } /** * Add a predefined Element that the opens the Instagram app with a deep link to the * specified user id. * <p> * If the Instagram app is not installed this will open the Intagram web page instead. * * @param id the user id to deep link to * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addInstagram(String id, String title) { Element instagramElement = new Element(); instagramElement.setTitle(title); instagramElement.setIconDrawable(R.drawable.about_icon_instagram); instagramElement.setIconTint(R.color.about_instagram_color); instagramElement.setValue(id); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://instagram.com/_u/" + id)); if (AboutPageUtils.isAppInstalled(mContext, "com.instagram.android")) { intent.setPackage("com.instagram.android"); } instagramElement.setIntent(intent); addItem(instagramElement); return this; } /** * Convenience method for {@link AboutPage#addGitHub(String, String)} but with * a predefined title string * * @param id the id of the GitHub user to display * @return this AboutPage instance for builder pattern support */ public AboutPage addGitHub(String id) { return addGitHub(id, mContext.getString(R.string.about_github)); } /** * Add a predefined Element that the opens the a browser and displays the specified GitHub * users profile page. * * @param id the GitHub user to link to * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addGitHub(String id, String title) { Element gitHubElement = new Element(); gitHubElement.setTitle(title); gitHubElement.setIconDrawable(R.drawable.about_icon_github); gitHubElement.setIconTint(R.color.about_github_color); gitHubElement.setValue(id); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_BROWSABLE); intent.setData(Uri.parse(String.format("https://github.com/%s", id))); gitHubElement.setIntent(intent); addItem(gitHubElement); return this; } /** * Convenience method for {@link AboutPage#addWebsite(String, String)} but with * a predefined title string * * @param url the URL to open in a browser * @return this AboutPage instance for builder pattern support */ public AboutPage addWebsite(String url) { return addWebsite(url, mContext.getString(R.string.about_website)); } /** * Add a predefined Element that the opens a browser and loads the specified URL * * @param url the URL to open in a browser * @param title the title to display on this item * @return this AboutPage instance for builder pattern support */ public AboutPage addWebsite(String url, String title) { if (!url.startsWith("http://") && !url.startsWith("https://")) { url = "http://" + url; } Element websiteElement = new Element(); websiteElement.setTitle(title); websiteElement.setIconDrawable(R.drawable.about_icon_link); websiteElement.setIconTint(R.color.about_item_icon_color); websiteElement.setValue(url); Uri uri = Uri.parse(url); Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri); websiteElement.setIntent(browserIntent); addItem(websiteElement); return this; } /** * Add a custom {@link Element} to this AboutPage * * @param element * @return this AboutPage instance for builder pattern support * @see Element */ public AboutPage addItem(Element element) { LinearLayout wrapper = (LinearLayout) mView.findViewById(R.id.about_providers); wrapper.addView(createItem(element)); wrapper.addView(getSeparator(), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mContext.getResources().getDimensionPixelSize(R.dimen.about_separator_height))); return this; } /** * Set the header image to display in this AboutPage * * @param resource the resource id of the image to display * @return this AboutPage instance for builder pattern support */ public AboutPage setImage(@DrawableRes int resource) { this.mImage = resource; return this; } /** * Add a new group that will display a header in this AboutPage * <p> * A header will be displayed in the order it was added. For e.g: * <p> * <code> * new AboutPage(this) * .addItem(firstItem) * .addGroup("Header") * .addItem(secondItem) * .create(); * </code> * <p> * Will display the following * [First item] * [Header] * [Second item] * * @param name the title for this group * @return this AboutPage instance for builder pattern support */ public AboutPage addGroup(String name) { TextView textView = new TextView(mContext); textView.setText(name); TextViewCompat.setTextAppearance(textView, R.style.about_groupTextAppearance); LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); if (mCustomFont != null) { textView.setTypeface(mCustomFont); } int padding = mContext.getResources().getDimensionPixelSize(R.dimen.about_group_text_padding); textView.setPadding(padding, padding, padding, padding); if (mIsRTL) { textView.setGravity(Gravity.END | Gravity.CENTER_VERTICAL); textParams.gravity = Gravity.END | Gravity.CENTER_VERTICAL; } else { textView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); textParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL; } textView.setLayoutParams(textParams); ((LinearLayout) mView.findViewById(R.id.about_providers)).addView(textView); return this; } /** * Turn on the RTL mode. * * @param value * @return this AboutPage instance for builder pattern support */ public AboutPage isRTL(boolean value) { this.mIsRTL = value; return this; } public AboutPage setDescription(String description) { this.mDescription = description; return this; } /** * Create and inflate this AboutPage. After this method is called the AboutPage * cannot be customized any more. * * @return the inflated {@link View} of this AboutPage */ public View create() { TextView description = (TextView) mView.findViewById(R.id.description); ImageView image = (ImageView) mView.findViewById(R.id.image); if (mImage > 0) { image.setImageResource(mImage); } if (!TextUtils.isEmpty(mDescription)) { description.setText(mDescription); } description.setGravity(Gravity.CENTER); if (mCustomFont != null) { description.setTypeface(mCustomFont); } return mView; } private View createItem(final Element element) { LinearLayout wrapper = new LinearLayout(mContext); wrapper.setOrientation(LinearLayout.HORIZONTAL); wrapper.setClickable(true); if (element.getOnClickListener() != null) { wrapper.setOnClickListener(element.getOnClickListener()); } else if (element.getIntent() != null) { wrapper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { mContext.startActivity(element.getIntent()); } catch (Exception e) { } } }); } TypedValue outValue = new TypedValue(); mContext.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); wrapper.setBackgroundResource(outValue.resourceId); int padding = mContext.getResources().getDimensionPixelSize(R.dimen.about_text_padding); wrapper.setPadding(padding, padding, padding, padding); LinearLayout.LayoutParams wrapperParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); wrapper.setLayoutParams(wrapperParams); TextView textView = new TextView(mContext); TextViewCompat.setTextAppearance(textView, R.style.about_elementTextAppearance); LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); textView.setLayoutParams(textParams); if (mCustomFont != null) { textView.setTypeface(mCustomFont); } ImageView iconView = null; if (element.getIconDrawable() != null) { iconView = new ImageView(mContext); int size = mContext.getResources().getDimensionPixelSize(R.dimen.about_icon_size); LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(size, size); iconView.setLayoutParams(iconParams); int iconPadding = mContext.getResources().getDimensionPixelSize(R.dimen.about_icon_padding); iconView.setPadding(iconPadding, 0, iconPadding, 0); if (Build.VERSION.SDK_INT < 21) { Drawable drawable = VectorDrawableCompat.create(iconView.getResources(), element.getIconDrawable(), iconView.getContext().getTheme()); iconView.setImageDrawable(drawable); } else { iconView.setImageResource(element.getIconDrawable()); } Drawable wrappedDrawable = DrawableCompat.wrap(iconView.getDrawable()); wrappedDrawable = wrappedDrawable.mutate(); if (element.getAutoApplyIconTint()) { int currentNightMode = mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; if (currentNightMode != Configuration.UI_MODE_NIGHT_YES) { if (element.getIconTint() != null) { DrawableCompat.setTint(wrappedDrawable, ContextCompat.getColor(mContext, element.getIconTint())); } else { DrawableCompat.setTint(wrappedDrawable, ContextCompat.getColor(mContext, R.color.about_item_icon_color)); } } else if (element.getIconNightTint() != null) { DrawableCompat.setTint(wrappedDrawable, ContextCompat.getColor(mContext, element.getIconNightTint())); } else { DrawableCompat.setTint(wrappedDrawable, AboutPageUtils.getThemeAccentColor(mContext)); } } } else { int iconPadding = mContext.getResources().getDimensionPixelSize(R.dimen.about_icon_padding); textView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding); } textView.setText(element.getTitle()); if (mIsRTL) { final int gravity = element.getGravity() != null ? element.getGravity() : Gravity.END; wrapper.setGravity(gravity | Gravity.CENTER_VERTICAL); //noinspection ResourceType textParams.gravity = gravity | Gravity.CENTER_VERTICAL; wrapper.addView(textView); if (element.getIconDrawable() != null) { wrapper.addView(iconView); } } else { final int gravity = element.getGravity() != null ? element.getGravity() : Gravity.START; wrapper.setGravity(gravity | Gravity.CENTER_VERTICAL); //noinspection ResourceType textParams.gravity = gravity | Gravity.CENTER_VERTICAL; if (element.getIconDrawable() != null) { wrapper.addView(iconView); } wrapper.addView(textView); } return wrapper; } private View getSeparator() { return mInflater.inflate(R.layout.about_page_separator, null); } }