package cgeo.geocaching.models; import cgeo.geocaching.R; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import java.io.File; /** * Represent an Image along with Title and Description. * Mostly used for representing image in/from logs. */ public class Image implements Parcelable { /** * Static empty image, linked to nothing. */ public static final Image NONE = new Image(Uri.EMPTY, null, null); /** * Helper class for building or manipulating Image references. * * Use #buildUpon() to obtain a builder representing an existing Image. */ public static class Builder { @NonNull private Uri uri; @Nullable private String title; @Nullable private String description; /** * Create a new Image. * */ public Builder() { uri = Uri.EMPTY; title = null; description = null; } /** * Set image url from String. * */ @NonNull public Image build() { return new Image(uri, title, description); } /** * Set image url from String. * * @param url * The image url from String */ @NonNull public Builder setUrl(@NonNull final String url) { if (StringUtils.isEmpty(url)) { uri = Uri.EMPTY; return this; } // Assume uri has a scheme uri = Uri.parse(url); if (uri.isRelative()) { // If not the case treat it as a file uri = Uri.fromFile(new File(url)); } return this; } /** * Set image from Uri. * * @param uri * The image url from Uri */ @NonNull public Builder setUrl(@NonNull final Uri uri) { this.uri = uri; return this; } /** * Set image from File. * * @param file * The image url from File */ @NonNull public Builder setUrl(@NonNull final File file) { uri = Uri.fromFile(file); return this; } /** * Set image from Image. * * @param image * The image url from Image */ @NonNull public Builder setUrl(@NonNull final Image image) { uri = image.uri; return this; } /** * Set image title. * * @param title * The image title */ @NonNull public Builder setTitle(@Nullable final String title) { this.title = title; return this; } /** * Set image description. * * @param description * The image description */ @NonNull public Builder setDescription(@Nullable final String description) { this.description = description; return this; } } @NonNull public final Uri uri; @Nullable public final String title; @Nullable final String description; /** * Create a new Image from Url. * * @param uri * The image uri * @param title * The image title * @param description * The image description */ private Image(@NonNull final Uri uri, @Nullable final String title, @Nullable final String description) { this.uri = uri; this.title = title; this.description = description; } private Image(@NonNull final Parcel in) { uri = in.readParcelable(Uri.class.getClassLoader()); title = in.readString(); description = in.readString(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(final Parcel dest, final int flags) { dest.writeParcelable(uri, 0); dest.writeString(title); dest.writeString(description); } public static final Parcelable.Creator<Image> CREATOR = new Parcelable.Creator<Image>() { @Override public Image createFromParcel(final Parcel in) { return new Image(in); } @Override public Image[] newArray(final int size) { return new Image[size]; } }; /** * Constructs a new builder, copying the attributes from this Image. * * @return * A new Image Builder */ public Builder buildUpon() { return new Builder() .setUrl(uri) .setTitle(title) .setDescription(description); } /** * Get image title. * * @return * the image title */ @Nullable public String getTitle() { return title; } /** * Get image description. * * @return * the image description */ @Nullable public String getDescription() { return description; } /** * Get the image Url. * * @return * the image url */ @NonNull public String getUrl() { if (isEmpty()) { return ""; } return uri.toString(); } /** * Get the image Uri. * * @return * the image uri */ @NonNull public Uri getUri() { return uri; } /** * Get the image filesystem path. * * @return * the image url path */ @NonNull public String getPath() { return isLocalFile() ? uri.getPath() : ""; } /** * Get the image as File. * If file is not local, return Null * * @return * the image File */ @Nullable public File getFile() { if (isLocalFile()) { return new File(uri.getPath()); } return null; } /** * Check if image has a title. * * @return * True if the image has a title */ public boolean hasTitle() { return StringUtils.isNotBlank(title); } /** * Check if the image has a description. * * @return * True if the image has a description */ public boolean hasDescription() { return StringUtils.isNotBlank(description); } /** * Open the image in an external activity. * Do nothing if image url is empty. * * @param fromActivity * The calling activity */ public void openInBrowser(final Activity fromActivity) { if (isEmpty()) { return; } final Intent browserIntent = new Intent(Intent.ACTION_VIEW, uri); try { fromActivity.startActivity(browserIntent); } catch (final ActivityNotFoundException e) { Log.e("Cannot find suitable activity", e); ActivityMixin.showToast(fromActivity, R.string.err_application_no); } } /** * Check if the URL represents a file on the local file system. * * @return <tt>true</tt> if the URL scheme is <tt>file</tt>, <tt>false</tt> otherwise */ public boolean isLocalFile() { return FileUtils.isFileUrl(getUrl()); } /** * Local file name when {@link #isLocalFile()} is <tt>true</tt>. * * @return the local file */ public File localFile() { return FileUtils.urlToFile(uri.toString()); } /** * Check if the image exists locally. * Return False if Image is not local. * Todo: May check if we have a cached Image for remote Uri * * @return * True if image exists on local filesystem */ public boolean existsLocal() { if (!isLocalFile()) { return false; } return new File(getPath()).exists(); } /** * Check if the image Uri is Empty. * * @return * True if Uri is Empty or blank */ public boolean isEmpty() { return uri.equals(Uri.EMPTY) || StringUtils.isBlank(uri.toString()); } /** * Compare two Images. * * @param o * The Object to compare * @return * True if all fields match */ @Override public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final Image image = (Image) o; return uri.equals(image.uri) && StringUtils.equals(title, image.title) && StringUtils.equals(description, image.description); } @Override public int hashCode() { return new HashCodeBuilder().append(uri).append(title).append(description).build(); } }