MOBILE-2319 notes: PR fixes

main
Albert Gasset 2018-03-21 15:50:05 +01:00
parent a6ea996778
commit a0c57f46c0
7 changed files with 40 additions and 130 deletions

View File

@ -22,11 +22,7 @@ import { AddonNotesUserHandler } from './providers/user-handler';
import { AddonNotesComponentsModule } from './components/components.module'; import { AddonNotesComponentsModule } from './components/components.module';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreCronDelegate } from '@providers/cron'; import { CoreCronDelegate } from '@providers/cron';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreUserDelegate } from '@core/user/providers/user-delegate'; import { CoreUserDelegate } from '@core/user/providers/user-delegate';
import { CoreUserProvider } from '@core/user/providers/user';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -45,23 +41,11 @@ import { CoreUserProvider } from '@core/user/providers/user';
}) })
export class AddonNotesModule { export class AddonNotesModule {
constructor(courseOptionsDelegate: CoreCourseOptionsDelegate, courseOptionHandler: AddonNotesCourseOptionHandler, constructor(courseOptionsDelegate: CoreCourseOptionsDelegate, courseOptionHandler: AddonNotesCourseOptionHandler,
userDelegate: CoreUserDelegate, userHandler: AddonNotesUserHandler, cronDelegate: CoreCronDelegate, userDelegate: CoreUserDelegate, userHandler: AddonNotesUserHandler,
syncHandler: AddonNotesSyncCronHandler, eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) { cronDelegate: CoreCronDelegate, syncHandler: AddonNotesSyncCronHandler) {
// Register handlers. // Register handlers.
courseOptionsDelegate.registerHandler(courseOptionHandler); courseOptionsDelegate.registerHandler(courseOptionHandler);
userDelegate.registerHandler(userHandler); userDelegate.registerHandler(userHandler);
cronDelegate.register(syncHandler); cronDelegate.register(syncHandler);
eventsProvider.on(CoreEventsProvider.LOGOUT, () => {
courseOptionHandler.clearCoursesNavCache();
}, sitesProvider.getCurrentSiteId());
eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED, () => {
courseOptionHandler.clearCoursesNavCache();
}, sitesProvider.getCurrentSiteId());
eventsProvider.on(CoreUserProvider.PROFILE_REFRESHED, () => {
userHandler.clearAddNoteCache();
}, sitesProvider.getCurrentSiteId());
} }
} }

View File

@ -21,7 +21,7 @@
<ion-item> <ion-item>
<ion-textarea placeholder="{{ 'addon.notes.note' | translate }}" rows="5" [(ngModel)]="text" name="text" required="required"></ion-textarea> <ion-textarea placeholder="{{ 'addon.notes.note' | translate }}" rows="5" [(ngModel)]="text" name="text" required="required"></ion-textarea>
</ion-item> </ion-item>
<button ion-button full margin-vertical type="submit" [disabled]="processing || text.length < 2"> <button ion-button block margin-vertical type="submit" [disabled]="processing || text.length < 2">
{{ 'addon.notes.addnewnote' | translate }} {{ 'addon.notes.addnewnote' | translate }}
</button> </button>
</form> </form>

View File

@ -17,9 +17,10 @@
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="notesLoaded" class="core-loading-center"> <core-loading [hideUntil]="notesLoaded" class="core-loading-center">
<p class="core-warning-card" *ngIf="hasOffline"> <div class="core-warning-card" icon-start *ngIf="hasOffline">
<ion-icon name="alert" color="warning" padding-right></ion-icon> {{ 'core.thereisdatatosync' | translate:{$a: 'addon.notes.notes' | translate | lowercase } }} <ion-icon name="warning"></ion-icon>
</p> {{ 'core.thereisdatatosync' | translate:{$a: 'addon.notes.notes' | translate | lowercase } }}
</div>
<core-empty-box *ngIf="notes && notes.length == 0" icon="list" [message]="'addon.notes.nonotes' | translate"></core-empty-box> <core-empty-box *ngIf="notes && notes.length == 0" icon="list" [message]="'addon.notes.nonotes' | translate"></core-empty-box>

View File

@ -76,10 +76,11 @@ export class AddonNotesListPage implements OnDestroy {
} }
/** /**
* Fetch notes * Fetch notes.
*
* @param {boolean} sync When to resync notes. * @param {boolean} sync When to resync notes.
* @param {boolean} [showErrors] When to display errors or not. * @param {boolean} [showErrors] When to display errors or not.
* @return {Promise<any>} Promise with the notes, * @return {Promise<any>} Promise with the notes.
*/ */
private fetchNotes(sync: boolean, showErrors?: boolean): Promise<any> { private fetchNotes(sync: boolean, showErrors?: boolean): Promise<any> {
const promise = sync ? this.syncNotes(showErrors) : Promise.resolve(); const promise = sync ? this.syncNotes(showErrors) : Promise.resolve();
@ -90,7 +91,7 @@ export class AddonNotesListPage implements OnDestroy {
return this.notesProvider.getNotes(this.courseId).then((notes) => { return this.notesProvider.getNotes(this.courseId).then((notes) => {
notes = notes[this.type + 'notes'] || []; notes = notes[this.type + 'notes'] || [];
this.hasOffline = this.notesProvider.hasOfflineNote(notes); this.hasOffline = notes.some((note) => note.offline);
return this.notesProvider.getNotesUserData(notes, this.courseId).then((notes) => { return this.notesProvider.getNotesUserData(notes, this.courseId).then((notes) => {
this.notes = notes; this.notes = notes;
@ -101,7 +102,7 @@ export class AddonNotesListPage implements OnDestroy {
}).finally(() => { }).finally(() => {
this.notesLoaded = true; this.notesLoaded = true;
this.refreshIcon = 'refresh'; this.refreshIcon = 'refresh';
this.syncIcon = 'loop'; this.syncIcon = 'sync';
}); });
} }
@ -124,7 +125,7 @@ export class AddonNotesListPage implements OnDestroy {
} }
/** /**
* Tries to syncrhonize course notes. * Tries to synchronize course notes.
* *
* @param {boolean} showErrors Whether to display errors or not. * @param {boolean} showErrors Whether to display errors or not.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.

View File

@ -25,24 +25,16 @@ import { AddonNotesTypesComponent } from '../components/types/types';
export class AddonNotesCourseOptionHandler implements CoreCourseOptionsHandler { export class AddonNotesCourseOptionHandler implements CoreCourseOptionsHandler {
name = 'AddonNotes'; name = 'AddonNotes';
priority = 200; priority = 200;
protected coursesNavEnabledCache = {};
constructor(private notesProvider: AddonNotesProvider) { constructor(private notesProvider: AddonNotesProvider) {
} }
/**
* Clear courses nav cache.
*/
clearCoursesNavCache(): void {
this.coursesNavEnabledCache = {};
}
/** /**
* Whether or not the handler is enabled on a site level. * Whether or not the handler is enabled on a site level.
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level. * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
*/ */
isEnabled(): boolean | Promise<boolean> { isEnabled(): boolean | Promise<boolean> {
return this.notesProvider.isPluginViewNotesEnabled(); return this.notesProvider.isPluginEnabled();
} }
/** /**
@ -63,15 +55,7 @@ export class AddonNotesCourseOptionHandler implements CoreCourseOptionsHandler {
return navOptions.notes; return navOptions.notes;
} }
if (typeof this.coursesNavEnabledCache[courseId] != 'undefined') { return this.notesProvider.isPluginViewNotesEnabledForCourse(courseId);
return this.coursesNavEnabledCache[courseId];
}
return this.notesProvider.isPluginViewNotesEnabledForCourse(courseId).then((enabled) => {
this.coursesNavEnabledCache[courseId] = enabled;
return enabled;
});
} }
/** /**

View File

@ -32,7 +32,7 @@ export class AddonNotesProvider {
protected logger; protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider,
private utilsProvider: CoreUtilsProvider, private translate: TranslateService, private userProvider: CoreUserProvider, private utils: CoreUtilsProvider, private translate: TranslateService, private userProvider: CoreUserProvider,
private notesOffline: AddonNotesOfflineProvider) { private notesOffline: AddonNotesOfflineProvider) {
this.logger = logger.getInstance('AddonNotesProvider'); this.logger = logger.getInstance('AddonNotesProvider');
} }
@ -65,14 +65,14 @@ export class AddonNotesProvider {
// Send note to server. // Send note to server.
return this.addNoteOnline(userId, courseId, publishState, noteText, siteId).then(() => { return this.addNoteOnline(userId, courseId, publishState, noteText, siteId).then(() => {
return true; return true;
}).catch((data) => { }).catch((error) => {
if (data.wserror) { if (this.utils.isWebServiceError(error)) {
// It's a WebService error, the user cannot add the note so don't store it. // It's a WebService error, the user cannot send the message so don't store it.
return Promise.reject(data.error); return Promise.reject(error);
} else { }
// Error sending note, store it to retry later. // Error sending note, store it to retry later.
return storeOffline(); return storeOffline();
}
}); });
} }
@ -84,9 +84,7 @@ export class AddonNotesProvider {
* @param {string} publishState Personal, Site or Course. * @param {string} publishState Personal, Site or Course.
* @param {string} noteText The note text. * @param {string} noteText The note text.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when added, rejected otherwise. Reject param is an object with: * @return {Promise<any>} Promise resolved when added, rejected otherwise.
* - error: The error message.
* - wserror: True if it's an error returned by the WebService, false otherwise.
*/ */
addNoteOnline(userId: number, courseId: number, publishState: string, noteText: string, siteId?: string): Promise<any> { addNoteOnline(userId: number, courseId: number, publishState: string, noteText: string, siteId?: string): Promise<any> {
const notes = [ const notes = [
@ -99,18 +97,10 @@ export class AddonNotesProvider {
} }
]; ];
return this.addNotesOnline(notes, siteId).catch((error) => { return this.addNotesOnline(notes, siteId).then((response) => {
return Promise.reject({
error: error,
wserror: this.utilsProvider.isWebServiceError(error)
});
}).then((response) => {
if (response && response[0] && response[0].noteid === -1) { if (response && response[0] && response[0].noteid === -1) {
// There was an error, and it should be translated already. // There was an error, and it should be translated already.
return Promise.reject({ return Promise.reject(this.utils.createFakeWSError(response[0].errormessage));
error: response[0].errormessage,
wserror: true
});
} }
// A note was added, invalidate the course notes. // A note was added, invalidate the course notes.
@ -143,7 +133,7 @@ export class AddonNotesProvider {
} }
/** /**
* Returns whether or not the add note plugin is enabled for a certain site. * Returns whether or not the notes plugin is enabled for a certain site.
* *
* This method is called quite often and thus should only perform a quick * This method is called quite often and thus should only perform a quick
* check, we should not be calling WS from here. * check, we should not be calling WS from here.
@ -151,15 +141,9 @@ export class AddonNotesProvider {
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise. * @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise.
*/ */
isPluginAddNoteEnabled(siteId?: string): Promise<boolean> { isPluginEnabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
if (!site.canUseAdvancedFeature('enablenotes')) { return site.canUseAdvancedFeature('enablenotes');
return false;
} else if (!site.wsAvailable('core_notes_create_notes')) {
return false;
}
return true;
}); });
} }
@ -188,33 +172,7 @@ export class AddonNotesProvider {
/* Use .read to cache data and be able to check it in offline. This means that, if a user loses the capabilities /* Use .read to cache data and be able to check it in offline. This means that, if a user loses the capabilities
to add notes, he'll still see the option in the app. */ to add notes, he'll still see the option in the app. */
return site.read('core_notes_create_notes', data).then(() => { return this.utils.promiseWorks(site.read('core_notes_create_notes', data));
// User can add notes.
return true;
}).catch(() => {
return false;
});
});
}
/**
* Returns whether or not the read notes plugin is enabled for the current site.
*
* This method is called quite often and thus should only perform a quick
* check, we should not be calling WS from here.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise.
*/
isPluginViewNotesEnabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
if (!site.canUseAdvancedFeature('enablenotes')) {
return false;
} else if (!site.wsAvailable('core_notes_get_course_notes')) {
return false;
}
return true;
}); });
} }
@ -226,11 +184,7 @@ export class AddonNotesProvider {
* @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise. * @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false or rejected otherwise.
*/ */
isPluginViewNotesEnabledForCourse(courseId: number, siteId?: string): Promise<boolean> { isPluginViewNotesEnabledForCourse(courseId: number, siteId?: string): Promise<boolean> {
return this.getNotes(courseId, false, true, siteId).then(() => { return this.utils.promiseWorks(this.getNotes(courseId, false, true, siteId));
return true;
}).catch(() => {
return false;
});
} }
/** /**
@ -314,26 +268,6 @@ export class AddonNotesProvider {
}); });
} }
/**
* Given a list of notes, check if any of them is an offline note.
*
* @param {any[]} notes List of notes.
* @return {boolean} True if at least 1 note is offline, false otherwise.
*/
hasOfflineNote(notes: any[]): boolean {
if (!notes || !notes.length) {
return false;
}
for (let i = 0, len = notes.length; i < len; i++) {
if (notes[i].offline) {
return true;
}
}
return false;
}
/** /**
* Invalidate get notes WS call. * Invalidate get notes WS call.
* *

View File

@ -14,6 +14,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ModalController } from 'ionic-angular'; import { ModalController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate'; import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { AddonNotesProvider } from './notes'; import { AddonNotesProvider } from './notes';
@ -29,7 +31,11 @@ export class AddonNotesUserHandler implements CoreUserProfileHandler {
addNoteEnabledCache = {}; addNoteEnabledCache = {};
constructor(private modalCtrl: ModalController, private sitesProvider: CoreSitesProvider, constructor(private modalCtrl: ModalController, private sitesProvider: CoreSitesProvider,
private notesProvider: AddonNotesProvider) { private notesProvider: AddonNotesProvider, eventsProvider: CoreEventsProvider) {
eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearAddNoteCache.bind(this));
eventsProvider.on(CoreUserProvider.PROFILE_REFRESHED, (data) => {
this.clearAddNoteCache(data.courseId);
});
} }
/** /**
@ -38,7 +44,7 @@ export class AddonNotesUserHandler implements CoreUserProfileHandler {
* *
* @param {number} [courseId] Course ID. * @param {number} [courseId] Course ID.
*/ */
clearAddNoteCache(courseId?: number): void { private clearAddNoteCache(courseId?: number): void {
if (courseId) { if (courseId) {
delete this.addNoteEnabledCache[courseId]; delete this.addNoteEnabledCache[courseId];
} else { } else {
@ -51,7 +57,7 @@ export class AddonNotesUserHandler implements CoreUserProfileHandler {
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level. * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
*/ */
isEnabled(): boolean | Promise<boolean> { isEnabled(): boolean | Promise<boolean> {
return this.notesProvider.isPluginAddNoteEnabled(); return this.notesProvider.isPluginEnabled();
} }
/** /**