package com.instructure.canvasapi.model; import android.content.Context; import android.os.Parcel; import com.google.gson.annotations.SerializedName; import com.instructure.canvasapi.R; import com.instructure.canvasapi.utilities.APIHelpers; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; /** * Created by Joshua Dutton on 10/22/13. * * Copyright (c) 2014 Instructure. All rights reserved. */ public class StreamItem extends CanvasModel<StreamItem> { public enum Type { DISCUSSION_TOPIC, SUBMISSION, ANNOUNCEMENT, CONVERSATION, MESSAGE, CONFERENCE, COLLABORATION, COLLECTION_ITEM, UNKNOWN, NOT_SET; public static boolean isDiscussionTopic(StreamItem streamItem) {return streamItem.getType() == DISCUSSION_TOPIC;} public static boolean isSubmission(StreamItem streamItem) {return streamItem.getType() == SUBMISSION;} public static boolean isAnnouncement(StreamItem streamItem) {return streamItem.getType() == ANNOUNCEMENT;} public static boolean isConversation(StreamItem streamItem) {return streamItem.getType() == CONVERSATION;} public static boolean isMessage(StreamItem streamItem) {return streamItem.getType() == MESSAGE;} public static boolean isConference(StreamItem streamItem) {return streamItem.getType() == CONFERENCE;} public static boolean isCollaboration(StreamItem streamItem) {return streamItem.getType() == COLLABORATION;} public static boolean isCollectionItem(StreamItem streamItem) {return streamItem.getType() == COLLECTION_ITEM;} public static boolean isUnknown(StreamItem streamItem) {return streamItem.getType() == UNKNOWN;} public static boolean isNotSet(StreamItem streamItem) {return streamItem.getType() == NOT_SET;} } // general info returned by the API private String updated_at; private long id; private String title; private String message; private String type; private String context_type; private boolean read_state; private String url; private String html_url; private long course_id = -1; private long group_id = -1; private long assignment_id = -1; // message type, which is not a conversation, but stream notifications private long message_id; private String notification_category; // conversation private long conversation_id; @SerializedName("private") private boolean isPrivate; private int participant_count; // discussionTopic or announcement private long discussion_topic_id = -1; private long announcement_id; private int total_root_discussion_entries; private boolean require_initial_post; private boolean user_has_posted; private List<DiscussionEntry> root_discussion_entries = new ArrayList<DiscussionEntry>(); // submission private int attempt; private String body; private String grade; private boolean grade_matches_current_submission; private String graded_at; private long grader_id; private double score = -1.0; private String submission_type; private String submitted_at; private String workflow_state; private boolean late; private String preview_url; private List<SubmissionComment> submission_comments = new ArrayList<SubmissionComment>(); private CanvasContext canvasContext; private Assignment assignment; private long user_id; private User user; // helper fields private Type enumType = Type.NOT_SET; private CanvasContext.Type canvasContextType = CanvasContext.Type.USER; private boolean hasSetContextType = false; private Date updatedAtDate; private Date gradedAtDate; private Date submittedAtDate; private Conversation conversation; private boolean isChecked; /////////////////////////////////////////////////////////////////////////// // Required Overrides /////////////////////////////////////////////////////////////////////////// // We want opposite of natural sorting order of date since we want the newest one to come first @Override public Date getComparisonDate() { return getUpdatedAtDate(); } @Override public String getComparisonString() { return title; } /////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////// public Date getUpdatedAtDate() { if (updatedAtDate == null) { updatedAtDate = APIHelpers.stringToDate(updated_at); } return updatedAtDate; } public long getId() { return id; } public String getTitle(Context context) { if (title == null && getType() == Type.CONVERSATION) { title = context.getString(R.string.Message); } return title; } public String getMessage(Context context) { if (message == null) { message = createMessage(context); } return message; } public Type getType() { if (enumType == Type.NOT_SET) { enumType = typeFromString(type); } return enumType; } public CanvasContext.Type getContextType() { if (!hasSetContextType) { if (context_type != null && (context_type.toLowerCase().equals("course") || course_id > 0)) { canvasContextType = CanvasContext.Type.COURSE; } else if (context_type != null && (context_type.toLowerCase().equals("group") || group_id > 0)){ canvasContextType = CanvasContext.Type.GROUP; } hasSetContextType = true; } return canvasContextType; } public boolean isReadState() { return read_state; } //helper method to show that the stream item has been read without having to reload all the data. //this method does not get the data from the server, so make sure item is actually read. public void setReadState(boolean readState) { read_state = readState; } public String getUrl() { return url; } public String getHtmlUrl() { return html_url; } public long getCourseId() { if (getContextType() == CanvasContext.Type.COURSE && course_id == -1) { course_id = parseCourseId(); } return course_id; } public long getGroupId() { if (getContextType() == CanvasContext.Type.GROUP && group_id == -1) { group_id = parseGroupId(); } return group_id; } public long getAssignmentId() { if (getContextType() == CanvasContext.Type.COURSE && assignment_id == -1) { assignment_id = parseAssignmentId(); } return assignment_id; } public long getMessageId() { return message_id; } public String getNotificationCategory() { return notification_category; } public long getConversationId() { return conversation_id; } public boolean isPrivate() { return isPrivate; } public int getParticipantCount() { return participant_count; } public long getDiscussionTopicId() { if (discussion_topic_id == -1) { return announcement_id; } return discussion_topic_id; } public int getTotalRootDiscussionEntries() { return total_root_discussion_entries; } public boolean requiresInitialPost() { return require_initial_post; } public boolean userHasPosted() { return user_has_posted; } public List<DiscussionEntry> getRootDiscussionEntries() { return root_discussion_entries; } public int getAttempt() { return attempt; } public String getBody() { return body; } public String getGrade() { return grade; } public boolean gradeMatchesCurrentSubmission() { return grade_matches_current_submission; } public Date getGradedAt() { if (gradedAtDate == null) { gradedAtDate = APIHelpers.stringToDate(graded_at); } return gradedAtDate; } public long getGraderId() { return grader_id; } public double getScore() { return score; } public String getSubmissionType() { return submission_type; } public Date getSubmittedAt() { if (submittedAtDate == null) { submittedAtDate = APIHelpers.stringToDate(submitted_at); } return submittedAtDate; } public String getWorkflowState() { return workflow_state; } public boolean isLate() { return late; } public String getPreviewUrl() { return preview_url; } public List<SubmissionComment> getSubmissionComments() { return submission_comments; } public CanvasContext getCanvasContext() { return canvasContext; } public Assignment getAssignment() { return assignment; } public long getUser_id() { return user_id; } public User getUser() { return user; } public Conversation getConversation() { return conversation; } public boolean isChecked() { return isChecked; } public void setChecked(boolean isChecked) { this.isChecked = isChecked; } /////////////////////////////////////////////////////////////////////////// // Helpers /////////////////////////////////////////////////////////////////////////// private Type typeFromString(String type) { if(type.toLowerCase().equals("conversation")) { return Type.CONVERSATION; } else if(type.toLowerCase().equals("submission")) { return Type.SUBMISSION; } else if(type.toLowerCase().equals("discussiontopic")) { return Type.DISCUSSION_TOPIC; } else if (type.toLowerCase().equals("announcement")){ return Type.ANNOUNCEMENT; } else if(type.toLowerCase().equals("message")) { return Type.MESSAGE; } else if(type.toLowerCase().equals("conference")) { return Type.CONFERENCE; } else if(type.toLowerCase().equals("webconference")) { return Type.CONFERENCE; } else if(type.toLowerCase().equals("collaboration")) { return Type.COLLABORATION; } else if(type.toLowerCase().equals("collectionitem")) { return Type.COLLECTION_ITEM; } return Type.UNKNOWN; } public void setConversation(Context context, Conversation conversation, long myUserId, String monologueDefault) { if(APIHelpers.paramIsNull(context, conversation,monologueDefault)){ return; } this.conversation = conversation; title = conversation.getMessageTitle(myUserId,monologueDefault); message = createMessage(context); } public void setCanvasContextFromMap(Map<Long, Course> courseMap, Map<Long, Group> groupMap) { if (getContextType() == CanvasContext.Type.COURSE) { canvasContext = courseMap.get(getCourseId()); } else { canvasContext = groupMap.get(getGroupId()); } } private String createMessage(Context context) { switch (getType()) { case CONVERSATION: if (conversation == null) { return context.getString(R.string.Loading); } else if (conversation.getLastMessagePreview() == null) { return ""; } return conversation.getLastMessagePreview(); case SUBMISSION: //get comments from assignment String comment = null; if (submission_comments.size()> 0) { comment = submission_comments.get(submission_comments.size() - 1).getComment(); } //set it to the last comment if it's not null if(comment != null && !comment.equals("null") && score != -1.0) { return (":" + score + " " + comment); } else if((comment == null || comment.equals("null")) && score != -1.0){ return (":" + score); } else if(comment != null && !comment.equals("null") && score == -1.0) { return (comment); } break; case DISCUSSION_TOPIC : //if it's a discussionTopic, get the last entry for the message. if (root_discussion_entries.size() > 0) { return root_discussion_entries.get(root_discussion_entries.size() - 1).getMessage(context.getString(R.string.Deleted)); } break; default: break; } if (message == null) { return ""; } return message; } private long parseAssignmentId() { //get the assignment from the url if(html_url.length() > 0 && !html_url.equals("null")) { String searchFor = "assignments/"; int start = html_url.indexOf(searchFor); if (start == -1) { return 0; } start += searchFor.length(); int end = html_url.indexOf("/", start); //in some urls the assignmentID might be the last thing so there wouldn't be a final / if(end == -1) { end = html_url.length(); } String assignmentId = html_url.substring(start,end); return Long.parseLong(assignmentId); } return 0; } private long parseCourseId() { if(html_url.length() > 0 && !html_url.equals("null")) { String searchFor = "courses/"; int start = html_url.indexOf(searchFor); if (start == -1) { return 0; } start += searchFor.length(); int end = html_url.indexOf("/", start); String courseIdString = html_url.substring(start,end); return Long.parseLong(courseIdString); } return 0; } private long parseGroupId() { if(html_url.length() > 0 && !html_url.equals("null")) { String searchFor = "groups/"; int start = html_url.indexOf(searchFor); if (start == -1) { return 0; } start += searchFor.length(); int end = html_url.indexOf("/", start); String groupIdString = html_url.substring(start,end); return Long.parseLong(groupIdString); } return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.updated_at); dest.writeLong(this.id); dest.writeString(this.title); dest.writeString(this.message); dest.writeString(this.type); dest.writeString(this.context_type); dest.writeByte(read_state ? (byte) 1 : (byte) 0); dest.writeString(this.url); dest.writeString(this.html_url); dest.writeLong(this.course_id); dest.writeLong(this.group_id); dest.writeLong(this.assignment_id); dest.writeLong(this.message_id); dest.writeString(this.notification_category); dest.writeLong(this.conversation_id); dest.writeByte(isPrivate ? (byte) 1 : (byte) 0); dest.writeInt(this.participant_count); dest.writeLong(this.discussion_topic_id); dest.writeLong(this.announcement_id); dest.writeInt(this.total_root_discussion_entries); dest.writeByte(require_initial_post ? (byte) 1 : (byte) 0); dest.writeByte(user_has_posted ? (byte) 1 : (byte) 0); dest.writeList(this.root_discussion_entries); dest.writeInt(this.attempt); dest.writeString(this.body); dest.writeString(this.grade); dest.writeByte(grade_matches_current_submission ? (byte) 1 : (byte) 0); dest.writeString(this.graded_at); dest.writeLong(this.grader_id); dest.writeDouble(this.score); dest.writeString(this.submission_type); dest.writeString(this.submitted_at); dest.writeString(this.workflow_state); dest.writeByte(late ? (byte) 1 : (byte) 0); dest.writeString(this.preview_url); dest.writeList(this.submission_comments); dest.writeParcelable(this.canvasContext, 0); dest.writeParcelable(this.assignment, flags); dest.writeLong(this.user_id); dest.writeParcelable(this.user, 0); dest.writeInt(this.enumType == null ? -1 : this.enumType.ordinal()); dest.writeInt(this.canvasContextType == null ? -1 : this.canvasContextType.ordinal()); dest.writeByte(hasSetContextType ? (byte) 1 : (byte) 0); dest.writeLong(updatedAtDate != null ? updatedAtDate.getTime() : -1); dest.writeLong(gradedAtDate != null ? gradedAtDate.getTime() : -1); dest.writeLong(submittedAtDate != null ? submittedAtDate.getTime() : -1); dest.writeParcelable(this.conversation, flags); dest.writeByte(isChecked ? (byte) 1 : (byte) 0); } public StreamItem() { } private StreamItem(Parcel in) { this.updated_at = in.readString(); this.id = in.readLong(); this.title = in.readString(); this.message = in.readString(); this.type = in.readString(); this.context_type = in.readString(); this.read_state = in.readByte() != 0; this.url = in.readString(); this.html_url = in.readString(); this.course_id = in.readLong(); this.group_id = in.readLong(); this.assignment_id = in.readLong(); this.message_id = in.readLong(); this.notification_category = in.readString(); this.conversation_id = in.readLong(); this.isPrivate = in.readByte() != 0; this.participant_count = in.readInt(); this.discussion_topic_id = in.readLong(); this.announcement_id = in.readLong(); this.total_root_discussion_entries = in.readInt(); this.require_initial_post = in.readByte() != 0; this.user_has_posted = in.readByte() != 0; in.readList(this.root_discussion_entries, DiscussionEntry.class.getClassLoader()); this.attempt = in.readInt(); this.body = in.readString(); this.grade = in.readString(); this.grade_matches_current_submission = in.readByte() != 0; this.graded_at = in.readString(); this.grader_id = in.readLong(); this.score = in.readDouble(); this.submission_type = in.readString(); this.submitted_at = in.readString(); this.workflow_state = in.readString(); this.late = in.readByte() != 0; this.preview_url = in.readString(); in.readList(this.submission_comments, SubmissionComment.class.getClassLoader()); this.canvasContext = in.readParcelable(CanvasContext.class.getClassLoader()); this.assignment = in.readParcelable(Assignment.class.getClassLoader()); this.user_id = in.readLong(); this.user = in.readParcelable(User.class.getClassLoader()); int tmpEnumType = in.readInt(); this.enumType = tmpEnumType == -1 ? null : Type.values()[tmpEnumType]; int tmpCanvasContextType = in.readInt(); this.canvasContextType = tmpCanvasContextType == -1 ? null : CanvasContext.Type.values()[tmpCanvasContextType]; this.hasSetContextType = in.readByte() != 0; long tmpUpdatedAtDate = in.readLong(); this.updatedAtDate = tmpUpdatedAtDate == -1 ? null : new Date(tmpUpdatedAtDate); long tmpGradedAtDate = in.readLong(); this.gradedAtDate = tmpGradedAtDate == -1 ? null : new Date(tmpGradedAtDate); long tmpSubmittedAtDate = in.readLong(); this.submittedAtDate = tmpSubmittedAtDate == -1 ? null : new Date(tmpSubmittedAtDate); this.conversation = in.readParcelable(Conversation.class.getClassLoader()); this.isChecked = in.readByte() != 0; } public static Creator<StreamItem> CREATOR = new Creator<StreamItem>() { public StreamItem createFromParcel(Parcel source) { return new StreamItem(source); } public StreamItem[] newArray(int size) { return new StreamItem[size]; } }; }