MOBILE-1486 user: Add online status to the user profile

main
Pau Ferrer Ocaña 2018-11-16 14:41:26 +01:00
parent 5e4e4fc75f
commit dbf3c85f73
34 changed files with 78 additions and 67 deletions

View File

@ -28,7 +28,7 @@
<h3 margin-horizontal *ngIf="competencies && competencies.statistics.competencycount > 0">{{ 'addon.competency.competencies' | translate }}</h3> <h3 margin-horizontal *ngIf="competencies && competencies.statistics.competencycount > 0">{{ 'addon.competency.competencies' | translate }}</h3>
<ion-card *ngIf="user"> <ion-card *ngIf="user">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -10,7 +10,7 @@
<core-loading [hideUntil]="competencyLoaded"> <core-loading [hideUntil]="competencyLoaded">
<ion-card *ngIf="user"> <ion-card *ngIf="user">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -73,7 +73,7 @@
</p> </p>
<ion-card *ngFor="let evidence of competency.evidence"> <ion-card *ngFor="let evidence of competency.evidence">
<a ion-item text-wrap *ngIf="evidence.actionuser" (click)="openUserProfile(evidence.actionuser.id)"> <a ion-item text-wrap *ngIf="evidence.actionuser" (click)="openUserProfile(evidence.actionuser.id)">
<ion-avatar class="user-avatar" [user]="evidence.actionuser" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="evidence.actionuser" item-start></ion-avatar>
<h2>{{ evidence.actionuser.fullname }}</h2> <h2>{{ evidence.actionuser.fullname }}</h2>
<p>{{ evidence.timemodified | coreToLocaleString }}</p> <p>{{ evidence.timemodified | coreToLocaleString }}</p>
</a> </a>

View File

@ -10,7 +10,7 @@
<core-loading [hideUntil]="planLoaded"> <core-loading [hideUntil]="planLoaded">
<ion-card *ngIf="user"> <ion-card *ngIf="user">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -19,7 +19,7 @@
<ng-container *ngFor="let contact of contacts[contactType]"> <ng-container *ngFor="let contact of contacts[contactType]">
<!-- Don't show deleted users --> <!-- Don't show deleted users -->
<a ion-item text-wrap *ngIf="contact.profileimageurl || contact.profileimageurlsmall" [title]="contact.fullname" (click)="gotoDiscussion(contact.id)" [class.core-split-item-selected]="contact.id == discussionUserId" detail-none> <a ion-item text-wrap *ngIf="contact.profileimageurl || contact.profileimageurlsmall" [title]="contact.fullname" (click)="gotoDiscussion(contact.id)" [class.core-split-item-selected]="contact.id == discussionUserId" detail-none>
<ion-avatar class="user-avatar" [user]="contact" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="contact" item-start></ion-avatar>
<h2><core-format-text [text]="contact.fullname"></core-format-text></h2> <h2><core-format-text [text]="contact.fullname"></core-format-text></h2>
</a> </a>
</ng-container> </ng-container>

View File

@ -17,7 +17,7 @@
<ion-note item-end>{{ search.results.length }}</ion-note> <ion-note item-end>{{ search.results.length }}</ion-note>
</ion-item-divider> </ion-item-divider>
<a ion-item text-wrap *ngFor="let result of search.results" [title]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)" [class.core-split-item-selected]="result.userid == discussionUserId" detail-none> <a ion-item text-wrap *ngFor="let result of search.results" [title]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)" [class.core-split-item-selected]="result.userid == discussionUserId" detail-none>
<ion-avatar class="user-avatar" [user]="result" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="result" item-start></ion-avatar>
<h2><core-format-text [text]="result.fullname"></core-format-text></h2> <h2><core-format-text [text]="result.fullname"></core-format-text></h2>
<p><core-format-text clean="true" singleLine="true" [text]="result.lastmessage"></core-format-text></p> <p><core-format-text clean="true" singleLine="true" [text]="result.lastmessage"></core-format-text></p>
</a> </a>
@ -25,7 +25,7 @@
<ion-list *ngIf="!search.showResults" no-margin> <ion-list *ngIf="!search.showResults" no-margin>
<a ion-item text-wrap *ngFor="let discussion of discussions" [title]="discussion.fullname" (click)="gotoDiscussion(discussion.message.user)" [class.core-split-item-selected]="discussion.message.user == discussionUserId" detail-none> <a ion-item text-wrap *ngFor="let discussion of discussions" [title]="discussion.fullname" (click)="gotoDiscussion(discussion.message.user)" [class.core-split-item-selected]="discussion.message.user == discussionUserId" detail-none>
<ion-avatar class="user-avatar" [user]="discussion" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="discussion" item-start></ion-avatar>
<h2> <h2>
<core-format-text [text]="discussion.fullname"></core-format-text> <core-format-text [text]="discussion.fullname"></core-format-text>
<ion-note *ngIf="discussion.message.timecreated > 0 || discussion.unread"> <ion-note *ngIf="discussion.message.timecreated > 0 || discussion.unread">

View File

@ -2,7 +2,7 @@
<!-- User and status of the submission. --> <!-- User and status of the submission. -->
<a ion-item text-wrap *ngIf="!blindMarking && user" (click)="openUserProfile(submitId)" [title]="user.fullname"> <a ion-item text-wrap *ngIf="!blindMarking && user" (click)="openUserProfile(submitId)" [title]="user.fullname">
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>
<ng-container *ngTemplateOutlet="submissionStatus"></ng-container> <ng-container *ngTemplateOutlet="submissionStatus"></ng-container>
</a> </a>
@ -111,7 +111,7 @@
<h2>{{ 'addon.mod_assign.userswhoneedtosubmit' | translate: {$a: ''} }}</h2> <h2>{{ 'addon.mod_assign.userswhoneedtosubmit' | translate: {$a: ''} }}</h2>
<div *ngFor="let user of membersToSubmit"> <div *ngFor="let user of membersToSubmit">
<a ion-item text-wrap *ngIf="user.fullname" (click)="openUserProfile(user.id)" [title]="user.fullname"> <a ion-item text-wrap *ngIf="user.fullname" (click)="openUserProfile(user.id)" [title]="user.fullname">
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>
</a> </a>
<ion-item text-wrap *ngIf="!user.fullname"> <ion-item text-wrap *ngIf="!user.fullname">
@ -209,7 +209,7 @@
<!-- Data about the grader (teacher who graded). --> <!-- Data about the grader (teacher who graded). -->
<a ion-item text-wrap *ngIf="grader" (click)="openUserProfile(grader.id)" [title]="grader.fullname" detail-push> <a ion-item text-wrap *ngIf="grader" (click)="openUserProfile(grader.id)" [title]="grader.fullname" detail-push>
<ion-avatar class="user-avatar" [user]="grader" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="grader" item-start></ion-avatar>
<h2>{{ 'addon.mod_assign.gradedby' | translate }}</h2> <h2>{{ 'addon.mod_assign.gradedby' | translate }}</h2>
<h2>{{ grader.fullname }}</h2> <h2>{{ grader.fullname }}</h2>
<p *ngIf="feedback.gradeddate">{{ feedback.gradeddate * 1000 | coreFormatDate:"dfmediumdate" }}</p> <p *ngIf="feedback.gradeddate">{{ feedback.gradeddate * 1000 | coreFormatDate:"dfmediumdate" }}</p>

View File

@ -18,7 +18,7 @@
<!-- List of submissions. --> <!-- List of submissions. -->
<ng-container *ngFor="let submission of submissions"> <ng-container *ngFor="let submission of submissions">
<a ion-item text-wrap (click)="loadSubmission(submission)" [class.core-split-item-selected]="submission.id == selectedSubmissionId"> <a ion-item text-wrap (click)="loadSubmission(submission)" [class.core-split-item-selected]="submission.id == selectedSubmissionId">
<ion-avatar class="user-avatar" [user]="submission" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="submission" item-start></ion-avatar>
<h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2> <h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2>
<h2 *ngIf="!submission.userfullname">{{ 'addon.mod_assign.hiddenuser' | translate }}{{submission.blindid}}</h2> <h2 *ngIf="!submission.userfullname">{{ 'addon.mod_assign.hiddenuser' | translate }}{{submission.blindid}}</h2>
<p *ngIf="assign.teamsubmission"> <p *ngIf="assign.teamsubmission">

View File

@ -38,7 +38,7 @@
</div> </div>
<ion-item text-wrap *ngIf="!message.system && message.message.substr(0, 4) != 'beep'" class="addon-mod-chat-message"> <ion-item text-wrap *ngIf="!message.system && message.message.substr(0, 4) != 'beep'" class="addon-mod-chat-message">
<ion-avatar class="user-avatar" [user]="message" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="message" item-start></ion-avatar>
<h2> <h2>
<p float-end>{{ message.timestamp * 1000 | coreFormatDate:"dftimedate" }}</p> <p float-end>{{ message.timestamp * 1000 | coreFormatDate:"dftimedate" }}</p>
<core-format-text [text]="message.userfullname"></core-format-text> <core-format-text [text]="message.userfullname"></core-format-text>

View File

@ -11,7 +11,7 @@
<ion-content> <ion-content>
<core-loading [hideUntil]="usersLoaded"> <core-loading [hideUntil]="usersLoaded">
<ion-item text-wrap *ngFor="let user of users" [class.addon-mod-chat-user]="currentUserId != user.id && isOnline"> <ion-item text-wrap *ngFor="let user of users" [class.addon-mod-chat-user]="currentUserId != user.id && isOnline">
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
<ng-container *ngIf="currentUserId != user.id && isOnline"> <ng-container *ngIf="currentUserId != user.id && isOnline">
<button ion-button clear icon-left (click)="talkTo(user)"> <button ion-button clear icon-left (click)="talkTo(user)">

View File

@ -82,7 +82,7 @@
<p>{{ 'addon.mod_choice.numberofuser' | translate }}: {{ result.numberofuser }} ({{ 'core.percentagenumber' | translate: {$a: result.percentageamount} }})</p> <p>{{ 'addon.mod_choice.numberofuser' | translate }}: {{ result.numberofuser }} ({{ 'core.percentagenumber' | translate: {$a: result.percentageamount} }})</p>
</ion-item-divider> </ion-item-divider>
<a ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseid" [userId]="user.userid" [title]="user.fullname" text-wrap> <a ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseid" [userId]="user.userid" [title]="user.fullname" text-wrap>
<ion-avatar class="user-avatar" [user]="user" item-start [courseId]="courseid"></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start [courseId]="courseid"></ion-avatar>
<p>{{user.fullname}}</p> <p>{{user.fullname}}</p>
</a> </a>
</ion-item-group> </ion-item-group>

View File

@ -7,7 +7,7 @@
<core-loading [hideUntil]="feedbackLoaded"> <core-loading [hideUntil]="feedbackLoaded">
<ion-list no-margin> <ion-list no-margin>
<a *ngIf="attempt.fullname" ion-item text-wrap core-user-link [userId]="attempt.userid" [attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid" [title]="attempt.fullname"> <a *ngIf="attempt.fullname" ion-item text-wrap core-user-link [userId]="attempt.userid" [attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid" [title]="attempt.fullname">
<ion-avatar class="user-avatar" [user]="attempt" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="attempt" item-start></ion-avatar>
<h2>{{attempt.fullname}}</h2> <h2>{{attempt.fullname}}</h2>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate:"LLL"}}</p> <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate:"LLL"}}</p>
</a> </a>

View File

@ -21,7 +21,7 @@
</ion-item-divider> </ion-item-divider>
<ng-container *ngIf="total > 0"> <ng-container *ngIf="total > 0">
<ion-item *ngFor="let user of users" text-wrap> <ion-item *ngFor="let user of users" text-wrap>
<ion-avatar class="user-avatar" [user]="user" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
<p> <p>
<ion-badge color="success" *ngIf="user.started"> <ion-badge color="success" *ngIf="user.started">

View File

@ -22,7 +22,7 @@
{{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.total } }} {{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.total } }}
</ion-item-divider> </ion-item-divider>
<a *ngFor="let attempt of responses.attempts" ion-item text-wrap (click)="gotoAttempt(attempt)" [class.core-split-item-selected]="attempt.id == attemptId"> <a *ngFor="let attempt of responses.attempts" ion-item text-wrap (click)="gotoAttempt(attempt)" [class.core-split-item-selected]="attempt.id == attemptId">
<ion-avatar class="user-avatar" [user]="attempt" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="attempt" item-start></ion-avatar>
<h2><core-format-text [text]="attempt.fullname"></core-format-text></h2> <h2><core-format-text [text]="attempt.fullname"></core-format-text></h2>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate: "LLL"}}</p> <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate: "LLL"}}</p>
</a> </a>

View File

@ -27,7 +27,7 @@
<ng-container *ngIf="forum && discussions.length > 0"> <ng-container *ngIf="forum && discussions.length > 0">
<ion-card *ngFor="let discussion of offlineDiscussions" (click)="openNewDiscussion(discussion.timecreated)" [class.addon-forum-discussion-selected]="discussion.timecreated == -selectedDiscussion"> <ion-card *ngFor="let discussion of offlineDiscussions" (click)="openNewDiscussion(discussion.timecreated)" [class.addon-forum-discussion-selected]="discussion.timecreated == -selectedDiscussion">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="discussion" item-start [courseId]="courseId"></ion-avatar> <ion-avatar core-user-avatar [user]="discussion" item-start [courseId]="courseId"></ion-avatar>
<h2><core-format-text [text]="discussion.subject"></core-format-text></h2> <h2><core-format-text [text]="discussion.subject"></core-format-text></h2>
<p *ngIf="discussion.userfullname"> <p *ngIf="discussion.userfullname">
<ion-note float-end padding-left><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</ion-note> <ion-note float-end padding-left><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</ion-note>
@ -43,7 +43,7 @@
</ion-card> </ion-card>
<ion-card *ngFor="let discussion of discussions" (click)="openDiscussion(discussion)" [class.addon-forum-discussion-selected]="discussion.discussion == selectedDiscussion"> <ion-card *ngFor="let discussion of discussions" (click)="openDiscussion(discussion)" [class.addon-forum-discussion-selected]="discussion.discussion == selectedDiscussion">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="discussion" item-start [courseId]="courseId"></ion-avatar> <ion-avatar core-user-avatar [user]="discussion" item-start [courseId]="courseId"></ion-avatar>
<h2><core-icon name="fa-map-pin" *ngIf="discussion.pinned"></core-icon> <core-format-text [text]="discussion.subject"></core-format-text></h2> <h2><core-icon name="fa-map-pin" *ngIf="discussion.pinned"></core-icon> <core-format-text [text]="discussion.subject"></core-format-text></h2>
<p> <p>
<ion-note float-end padding-left text-end> <ion-note float-end padding-left text-end>

View File

@ -1,6 +1,6 @@
<ion-card-header text-wrap no-padding > <ion-card-header text-wrap no-padding >
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="post" item-start (click)="openUserProfile(post.userid)"></ion-avatar> <ion-avatar core-user-avatar [user]="post" item-start (click)="openUserProfile(post.userid)"></ion-avatar>
<h2><span [class.core-bold]="post.parent == 0"><core-format-text [text]="post.subject"></core-format-text></span></h2> <h2><span [class.core-bold]="post.parent == 0"><core-format-text [text]="post.subject"></core-format-text></span></h2>
<p> <p>
<ion-note float-end padding-left *ngIf="!post.modified"><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</ion-note> <ion-note float-end padding-left *ngIf="!post.modified"><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</ion-note>

View File

@ -11,7 +11,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<ng-container *ngIf="entry"> <ng-container *ngIf="entry">
<ion-item text-wrap *ngIf="showAuthor"> <ion-item text-wrap *ngIf="showAuthor">
<ion-avatar class="user-avatar" [user]="entry" (click)="openUserProfile(post.userid)" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="entry" (click)="openUserProfile(post.userid)" item-start></ion-avatar>
<h2><core-format-text [text]="entry.concept"></core-format-text></h2> <h2><core-format-text [text]="entry.concept"></core-format-text></h2>
<ion-note item-end *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note> <ion-note item-end *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note>
<p><core-format-text [text]="entry.userfullname"></core-format-text></p> <p><core-format-text [text]="entry.userfullname"></core-format-text></p>

View File

@ -233,7 +233,7 @@
</ion-card-header> </ion-card-header>
<a ion-item text-wrap *ngFor="let student of overview.students" [navPush]="'AddonModLessonUserRetakePage'" [navParams]="{courseId: courseId, lessonId: lesson.id, userId: student.id}"> <a ion-item text-wrap *ngFor="let student of overview.students" [navPush]="'AddonModLessonUserRetakePage'" [navParams]="{courseId: courseId, lessonId: lesson.id, userId: student.id}">
<ion-avatar class="user-avatar" [user]="student" item-start [userId]="student.id" [courseId]="courseId"></ion-avatar> <ion-avatar core-user-avatar [user]="student" item-start [userId]="student.id" [courseId]="courseId"></ion-avatar>
<h2>{{ student.fullname }}</h2> <h2>{{ student.fullname }}</h2>
<core-progress-bar [progress]="student.bestgrade"></core-progress-bar> <core-progress-bar [progress]="student.bestgrade"></core-progress-bar>
</a> </a>

View File

@ -12,7 +12,7 @@
<ion-list *ngIf="student"> <ion-list *ngIf="student">
<!-- Student data. --> <!-- Student data. -->
<a ion-item text-wrap core-user-link [userId]="student.id" [courseId]="courseId" [title]="student.fullname"> <a ion-item text-wrap core-user-link [userId]="student.id" [courseId]="courseId" [title]="student.fullname">
<ion-avatar class="user-avatar" [user]="student" item-start [userId]="student.id" [courseId]="courseId"></ion-avatar> <ion-avatar core-user-avatar [user]="student" item-start [userId]="student.id" [courseId]="courseId"></ion-avatar>
<h2>{{student.fullname}}</h2> <h2>{{student.fullname}}</h2>
<core-progress-bar [progress]="student.bestgrade"></core-progress-bar> <core-progress-bar [progress]="student.bestgrade"></core-progress-bar>
</a> </a>

View File

@ -1,6 +1,6 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<a ion-item *ngIf="summary" text-wrap [attr.detail-none]="canViewAssessment && !canSelfAssess? null : true" (click)="gotoAssessment()"> <a ion-item *ngIf="summary" text-wrap [attr.detail-none]="canViewAssessment && !canSelfAssess? null : true" (click)="gotoAssessment()">
<ion-avatar class="user-avatar" [user]="profile" item-start [courseId]="courseId" [userId]="profile && profile.id"></ion-avatar> <ion-avatar core-user-avatar [user]="profile" item-start [courseId]="courseId" [userId]="profile && profile.id"></ion-avatar>
<h2 *ngIf="profile && profile.fullname">{{profile.fullname}}</h2> <h2 *ngIf="profile && profile.fullname">{{profile.fullname}}</h2>
<p *ngIf="showGrade(assessment.grade)"> <p *ngIf="showGrade(assessment.grade)">

View File

@ -1,7 +1,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<div *ngIf="!summary"> <div *ngIf="!summary">
<ion-list-header text-wrap> <ion-list-header text-wrap>
<ion-avatar class="user-avatar" [user]="profile" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="profile" item-start></ion-avatar>
<h2>{{submission.title}}</h2> <h2>{{submission.title}}</h2>
<p *ngIf="profile && profile.fullname">{{profile.fullname}}</p> <p *ngIf="profile && profile.fullname">{{profile.fullname}}</p>
<p *ngIf="showGrade(submission.submissiongrade)" [class.addon-has-overriden-grade]="showGrade(submission.submissiongradeover)"> <p *ngIf="showGrade(submission.submissiongrade)" [class.addon-has-overriden-grade]="showGrade(submission.submissiongradeover)">
@ -32,7 +32,7 @@
<core-local-file *ngIf="attachment.name" [file]="attachment"></core-local-file> <core-local-file *ngIf="attachment.name" [file]="attachment"></core-local-file>
</ion-item> </ion-item>
<ion-item text-wrap *ngIf="viewDetails && submission.feedbackauthor"> <ion-item text-wrap *ngIf="viewDetails && submission.feedbackauthor">
<ion-avatar class="user-avatar" [user]="evaluateByProfile" item-start [courseId]="courseId" [userId]="evaluateByProfile.id"></ion-avatar> <ion-avatar core-user-avatar [user]="evaluateByProfile" item-start [courseId]="courseId" [userId]="evaluateByProfile.id"></ion-avatar>
<h2 *ngIf="evaluateByProfile && evaluateByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateByProfile.fullname} }}</h2> <h2 *ngIf="evaluateByProfile && evaluateByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateByProfile.fullname} }}</h2>
<core-format-text [text]="submission.feedbackauthor"></core-format-text> <core-format-text [text]="submission.feedbackauthor"></core-format-text>
@ -46,7 +46,7 @@
</div> </div>
<a ion-item text-wrap *ngIf="summary" [attr.detail-none]="submission.timemodified ? null : true" (click)="gotoSubmission()"> <a ion-item text-wrap *ngIf="summary" [attr.detail-none]="submission.timemodified ? null : true" (click)="gotoSubmission()">
<ion-avatar class="user-avatar" [user]="profile" item-start [courseId]="courseId" [userId]="profile && profile.id"></ion-avatar> <ion-avatar core-user-avatar [user]="profile" item-start [courseId]="courseId" [userId]="profile && profile.id"></ion-avatar>
<h2>{{submission.title}}</h2> <h2>{{submission.title}}</h2>
<p *ngIf="profile && profile.fullname">{{profile.fullname}}</p> <p *ngIf="profile && profile.fullname">{{profile.fullname}}</p>

View File

@ -15,7 +15,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="profile" item-start [courseId]="courseId" [userId]="profile.id"></ion-avatar> <ion-avatar *ngIf="profile" core-user-avatar [user]="profile" item-start [courseId]="courseId" [userId]="profile.id"></ion-avatar>
<h2 *ngIf="profile && profile.fullname">{{profile.fullname}}</h2> <h2 *ngIf="profile && profile.fullname">{{profile.fullname}}</h2>
@ -65,7 +65,7 @@
</form> </form>
<ion-list *ngIf="!evaluating && evaluate && evaluate.text"> <ion-list *ngIf="!evaluating && evaluate && evaluate.text">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="evaluateGradingByProfile" item-start [courseId]="courseId" [userId]="evaluateGradingByProfile.id"></ion-avatar> <ion-avatar core-user-avatar *ngIf="evaluateGradingByProfile" [user]="evaluateGradingByProfile" item-start [courseId]="courseId" [userId]="evaluateGradingByProfile.id"></ion-avatar>
<h2 *ngIf="evaluateGradingByProfile && evaluateGradingByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateGradingByProfile.fullname} }}</h2> <h2 *ngIf="evaluateGradingByProfile && evaluateGradingByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateGradingByProfile.fullname} }}</h2>
<core-format-text [text]="evaluate.text"></core-format-text> <core-format-text [text]="evaluate.text"></core-format-text>
</ion-item> </ion-item>

View File

@ -36,7 +36,7 @@
<ion-list *ngIf="!canAddFeedback && evaluate && evaluate.text"> <ion-list *ngIf="!canAddFeedback && evaluate && evaluate.text">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="evaluateByProfile" item-start [courseId]="courseId" [userId]="evaluateByProfile.id"></ion-avatar> <ion-avatar core-user-avatar *ngIf="evaluateByProfile" [user]="evaluateByProfile" item-start [courseId]="courseId" [userId]="evaluateByProfile.id"></ion-avatar>
<h2 *ngIf="evaluateByProfile && evaluateByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateByProfile.fullname} }}</h2> <h2 *ngIf="evaluateByProfile && evaluateByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateByProfile.fullname} }}</h2>
<core-format-text [text]="evaluate.text"></core-format-text> <core-format-text [text]="evaluate.text"></core-format-text>
</ion-item> </ion-item>
@ -95,7 +95,7 @@
<ion-list *ngIf="assessmentId && !access.assessingallowed && assessment.feedbackreviewer"> <ion-list *ngIf="assessmentId && !access.assessingallowed && assessment.feedbackreviewer">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="evaluateGradingByProfile" item-start [courseId]="courseId" [userId]="evaluateGradingByProfile.id"></ion-avatar> <ion-avatar core-user-avatar *ngIf="evaluateGradingByProfile" [user]="evaluateGradingByProfile" item-start [courseId]="courseId" [userId]="evaluateGradingByProfile.id"></ion-avatar>
<h2 *ngIf="evaluateGradingByProfile && evaluateGradingByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateGradingByProfile.fullname} }}</h2> <h2 *ngIf="evaluateGradingByProfile && evaluateGradingByProfile.fullname">{{ 'addon.mod_workshop.feedbackby' | translate : {$a: evaluateGradingByProfile.fullname} }}</h2>
<core-format-text [text]="assessment.feedbackreviewer"></core-format-text> <core-format-text [text]="assessment.feedbackreviewer"></core-format-text>
</ion-item> </ion-item>

View File

@ -27,7 +27,7 @@
<ion-list *ngIf="notes && notes.length > 0"> <ion-list *ngIf="notes && notes.length > 0">
<ion-card *ngFor="let note of notes"> <ion-card *ngFor="let note of notes">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="note" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="note" item-start></ion-avatar>
<h2>{{note.userfullname}}</h2> <h2>{{note.userfullname}}</h2>
<p *ngIf="!note.offline" item-end>{{note.lastmodified | coreDateDayOrTime}}</p> <p *ngIf="!note.offline" item-end>{{note.lastmodified | coreDateDayOrTime}}</p>
<p *ngIf="note.offline" item-end><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</p> <p *ngIf="note.offline" item-end><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</p>

View File

@ -19,7 +19,7 @@
</div> </div>
<ion-card *ngFor="let notification of notifications"> <ion-card *ngFor="let notification of notifications">
<ion-item> <ion-item>
<ion-avatar class="user-avatar" [user]="notification" item-start [profileUrl]="notification.profileimageurlfrom" [fullname]="notification.userfromfullname" [userId]="notification.useridfrom" [courseId]="notification.courseid"></ion-avatar> <ion-avatar core-user-avatar [user]="notification" item-start [profileUrl]="notification.profileimageurlfrom" [fullname]="notification.userfromfullname" [userId]="notification.useridfrom"></ion-avatar>
<h2>{{notification.userfromfullname}}</h2> <h2>{{notification.userfromfullname}}</h2>
<div item-end *ngIf="!notification.timeread"><core-icon name="fa-circle" color="primary"></core-icon></div> <div item-end *ngIf="!notification.timeread"><core-icon name="fa-circle" color="primary"></core-icon></div>
<p>{{notification.timecreated | coreDateDayOrTime}}</p> <p>{{notification.timecreated | coreDateDayOrTime}}</p>

View File

@ -173,6 +173,7 @@ ion-app.app-root {
border-radius : 50%; border-radius : 50%;
padding: 4px; padding: 4px;
border: 1px solid #ddd; border: 1px solid #ddd;
background-color: white;
&.avatar-full { &.avatar-full {
border-radius: 2%; border-radius: 2%;

View File

@ -1,2 +1,3 @@
<img src="{{profileUrl}}" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation" [siteId]="siteId || null" (click)="gotoProfile($event)"> <img src="{{profileUrl}}" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation" [siteId]="siteId || null" (click)="gotoProfile($event)">
<span *ngIf="isOnline()" class="contact-status online"></span> <span *ngIf="checkOnline && isOnline()" class="contact-status online"></span>
<ng-content></ng-content>

View File

@ -1,4 +1,4 @@
ion-avatar.user-avatar { ion-avatar[core-user-avatar] {
position: relative; position: relative;
.contact-status { .contact-status {

View File

@ -19,21 +19,24 @@ import { CoreSitesProvider } from '@providers/sites';
/** /**
* Component to display a "user avatar". * Component to display a "user avatar".
* *
* Example: <core-user-avatar [user]="participant"></core-user-avatar> * Example: <ion-avatar core-user-avatar [user]="participant"></ion-avatar>
*/ */
@Component({ @Component({
selector: 'ion-avatar.user-avatar', selector: 'ion-avatar[core-user-avatar]',
templateUrl: 'core-user-avatar.html' templateUrl: 'core-user-avatar.html'
}) })
export class CoreUserAvatarComponent implements OnInit, OnChanges { export class CoreUserAvatarComponent implements OnInit, OnChanges {
@Input() user: any; @Input() user: any;
// The following params will override the ones in user object. // The following params will override the ones in user object.
@Input() profileUrl?: string; @Input() profileUrl?: string;
@Input() protected linkProfile = true; // Avoid linking to the profile if wanted.
@Input() fullname?: string; @Input() fullname?: string;
@Input() protected userId?: number; // If provided or found it will be used to link the image to the profile. @Input() protected userId?: number; // If provided or found it will be used to link the image to the profile.
@Input() protected courseId?: number; @Input() protected courseId?: number;
@Input() checkOnline = false; // If want to check and show online status.
// Variable to check if we consider this user online or not. // Variable to check if we consider this user online or not.
// @TODO: Use setting when available (see MDL-63972) so we can use site setting.
protected timetoshowusers = 300000; // Miliseconds default. protected timetoshowusers = 300000; // Miliseconds default.
protected myUser = false; protected myUser = false;
protected currentUserId: number; protected currentUserId: number;
@ -46,20 +49,7 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges {
* Component being initialized. * Component being initialized.
*/ */
ngOnInit(): void { ngOnInit(): void {
console.error(this.user);
this.setFields(); this.setFields();
// @TODO: This setting is not currently available so we are always using the default setting.
/*if (!this.myUser) {
let minutes = 5;
this.sitesProvider.getCurrentSite().getConfig('block_online_users_timetosee').then((timetosee) => {
minutes = timetosee || minutes;
}).catch(() => {
// Ignore errors.
}).finally(() => {
this.timetoshowusers = minutes * 60000;
});
}*/
} }
/** /**
@ -76,16 +66,18 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges {
* Set fields from user. * Set fields from user.
*/ */
protected setFields(): void { protected setFields(): void {
this.profileUrl = this.profileUrl || this.user.profileimageurl || this.user.userprofileimageurl || if (this.user) {
this.user.userpictureurl || this.user.profileimageurlsmall; this.profileUrl = this.profileUrl || this.user.profileimageurl || this.user.userprofileimageurl ||
this.user.userpictureurl || this.user.profileimageurlsmall;
this.fullname = this.fullname || this.user.fullname || this.user.userfullname; this.fullname = this.fullname || this.user.fullname || this.user.userfullname;
this.userId = this.userId || this.user.userid; this.userId = this.userId || this.user.userid;
this.courseId = this.courseId || this.user.courseid; this.courseId = this.courseId || this.user.courseid;
// If not available we cannot ensure the avatar is from the current user. // If not available we cannot ensure the avatar is from the current user.
this.myUser = this.userId && this.userId == this.currentUserId; this.myUser = this.userId && this.userId == this.currentUserId;
}
} }
/** /**
@ -104,7 +96,7 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges {
*/ */
gotoProfile(event: any): void { gotoProfile(event: any): void {
// If the event prevented default action, do nothing. // If the event prevented default action, do nothing.
if (!event.defaultPrevented && this.userId) { if (this.linkProfile && this.userId) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.navCtrl.push('CoreUserProfilePage', { userId: this.userId, courseId: this.courseId }); this.navCtrl.push('CoreUserProfilePage', { userId: this.userId, courseId: this.courseId });

View File

@ -12,7 +12,7 @@
<ion-card *ngFor="let comment of comments"> <ion-card *ngFor="let comment of comments">
<ion-item text-wrap> <ion-item text-wrap>
<ion-avatar class="user-avatar" [user]="comment" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="comment" item-start></ion-avatar>
<h2>{{ comment.fullname }}</h2> <h2>{{ comment.fullname }}</h2>
<p>{{ comment.time }}</p> <p>{{ comment.time }}</p>
</ion-item> </ion-item>

View File

@ -27,7 +27,7 @@
<ng-container text-wrap *ngIf="course.contacts && course.contacts.length"> <ng-container text-wrap *ngIf="course.contacts && course.contacts.length">
<ion-item-divider color="light">{{ 'core.teachers' | translate }}</ion-item-divider> <ion-item-divider color="light">{{ 'core.teachers' | translate }}</ion-item-divider>
<a ion-item text-wrap *ngFor="let contact of course.contacts" core-user-link [userId]="contact.id" [courseId]="isEnrolled ? course.id : null" [attr.aria-label]="'core.viewprofile' | translate"> <a ion-item text-wrap *ngFor="let contact of course.contacts" core-user-link [userId]="contact.id" [courseId]="isEnrolled ? course.id : null" [attr.aria-label]="'core.viewprofile' | translate">
<ion-avatar class="user-avatar" [user]="contact" item-start [userId]="contact.id" [courseId]="isEnrolled ? course.id : null"></ion-avatar> <ion-avatar core-user-avatar [user]="contact" item-start [userId]="contact.id" [courseId]="isEnrolled ? course.id : null"></ion-avatar>
<h2>{{contact.fullname}}</h2> <h2>{{contact.fullname}}</h2>
</a> </a>
<ion-item-divider color="light"></ion-item-divider> <ion-item-divider color="light"></ion-item-divider>

View File

@ -6,7 +6,7 @@
<ion-content> <ion-content>
<ion-list> <ion-list>
<a ion-item core-user-link [userId]="siteInfo.userid"> <a ion-item core-user-link [userId]="siteInfo.userid">
<ion-avatar class="user-avatar" [user]="siteInfo" item-start></ion-avatar> <ion-avatar core-user-avatar [user]="siteInfo" item-start></ion-avatar>
<p>{{siteInfo.fullname}}</p> <p>{{siteInfo.fullname}}</p>
</a> </a>
<ion-item-divider color="light"></ion-item-divider> <ion-item-divider color="light"></ion-item-divider>

View File

@ -9,7 +9,7 @@
<ion-list *ngIf="participants && participants.length > 0" no-margin> <ion-list *ngIf="participants && participants.length > 0" no-margin>
<a ion-item text-wrap *ngFor="let participant of participants" [title]="participant.fullname" (click)="gotoParticipant(participant.id)" [class.core-split-item-selected]="participant.id == participantId"> <a ion-item text-wrap *ngFor="let participant of participants" [title]="participant.fullname" (click)="gotoParticipant(participant.id)" [class.core-split-item-selected]="participant.id == participantId">
<ion-avatar class="user-avatar" [user]="participant" item-start [userId]="participant.id"></ion-avatar> <ion-avatar core-user-avatar [user]="participant" item-start [userId]="participant.id" [checkOnline]="true"></ion-avatar>
<h2><core-format-text [text]="participant.fullname"></core-format-text></h2> <h2><core-format-text [text]="participant.fullname"></core-format-text></h2>
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p> <p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p>
</a> </a>

View File

@ -10,10 +10,9 @@
<core-loading [hideUntil]="userLoaded"> <core-loading [hideUntil]="userLoaded">
<ion-list *ngIf="user && !isDeleted"> <ion-list *ngIf="user && !isDeleted">
<ion-item text-center> <ion-item text-center>
<div class="item-avatar-center"> <ion-avatar class="user-avatar item-avatar-center" [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true">
<img class="avatar" [src]="user.profileimageurl" core-external-content alt="{{ 'core.pictureof' | translate:{$a: user.fullname} }}" role="presentation" onError="this.src='assets/img/user-avatar.png'">
<ion-icon name="create" class="core-icon-foreground" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"></ion-icon> <ion-icon name="create" class="core-icon-foreground" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"></ion-icon>
</div> </ion-avatar>
<h2><core-format-text [text]="user.fullname"></core-format-text></h2> <h2><core-format-text [text]="user.fullname"></core-format-text></h2>
<p><core-format-text *ngIf="user.address" [text]="user.address"></core-format-text></p> <p><core-format-text *ngIf="user.address" [text]="user.address"></core-format-text></p>
<p *ngIf="user.roles" text-wrap> <p *ngIf="user.roles" text-wrap>

View File

@ -1,9 +1,27 @@
ion-app.app-root page-core-user-profile { ion-app.app-root page-core-user-profile {
.core-icon-foreground { .core-icon-foreground {
position: relative; position: absolute;
@include position(null, null, 30px, 60px); @include position(null, 0, 0, null);
font-size: 24px; font-size: 24px;
line-height: 30px;
text-align: center;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: white;
} }
.user-avatar.item-avatar-center {
display: inline-block;
img {
margin: 0;
}
.contact-status {
width: 24px;
height: 24px;
}
}
.core-user-communication-handlers { .core-user-communication-handlers {
background: $list-background-color; background: $list-background-color;
border-bottom: 1px solid $list-border-color; border-bottom: 1px solid $list-border-color;