From c51cca9fd3b1476db21e3878f8cc4b01166851af Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 13 Jan 2025 10:05:00 +0100 Subject: [PATCH] MOBILE-4724 ux: Change confirm message when leaving page --- scripts/langindex.json | 5 ++- .../blog/pages/edit-entry/edit-entry.ts | 3 +- .../calendar/pages/edit-event/edit-event.ts | 2 +- .../edit-feedback-modal.ts | 4 +- .../components/submission/submission.ts | 2 +- src/addons/mod/assign/pages/edit/edit.ts | 2 +- src/addons/mod/data/pages/edit/edit.ts | 2 +- src/addons/mod/feedback/pages/form/form.ts | 2 +- .../mod/forum/pages/discussion/discussion.ts | 2 +- .../pages/new-discussion/new-discussion.ts | 2 +- src/addons/mod/glossary/pages/edit/edit.ts | 2 +- .../mod/h5pactivity/pages/index/index.ts | 3 +- src/addons/mod/lesson/pages/player/player.ts | 2 +- src/addons/mod/wiki/pages/edit/edit.ts | 2 +- .../workshop/pages/assessment/assessment.ts | 2 +- .../pages/edit-submission/edit-submission.ts | 2 +- .../workshop/pages/submission/submission.ts | 2 +- .../components/capture-media/capture-media.ts | 4 +- .../features/login/tests/behat/logout.feature | 14 +++--- src/core/lang.json | 5 ++- src/core/services/overlays/alerts.ts | 44 +++++++------------ .../tests/behat/navigation_deeplinks.feature | 5 ++- 22 files changed, 53 insertions(+), 60 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 9e6a56dc5..66eb70568 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1561,9 +1561,9 @@ "core.completion-alt-manual-n-override": "completion", "core.completion-alt-manual-y": "completion", "core.completion-alt-manual-y-override": "completion", - "core.confirmcanceledit": "local_moodlemobileapp", "core.confirmdeletefile": "repository", - "core.confirmleaveunknownchanges": "local_moodlemobileapp", + "core.confirmleavepagedescription": "local_moodlemobileapp", + "core.confirmleavepagetitle": "local_moodlemobileapp", "core.confirmloss": "local_moodlemobileapp", "core.confirmopeninbrowser": "local_moodlemobileapp", "core.confirmremoveselectedfile": "local_moodlemobileapp", @@ -2091,6 +2091,7 @@ "core.lastmodified": "moodle", "core.lastsync": "local_moodlemobileapp", "core.layoutgrid": "workshopform_rubric", + "core.leave": "local_moodlemobileapp", "core.list": "moodle", "core.listsep": "langconfig", "core.loading": "moodle", diff --git a/src/addons/blog/pages/edit-entry/edit-entry.ts b/src/addons/blog/pages/edit-entry/edit-entry.ts index 778667479..c1018222a 100644 --- a/src/addons/blog/pages/edit-entry/edit-entry.ts +++ b/src/addons/blog/pages/edit-entry/edit-entry.ts @@ -41,7 +41,6 @@ import { CoreNetwork } from '@services/network'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSync } from '@services/sync'; import { CoreWSError } from '@classes/errors/wserror'; -import { Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { CoreForms } from '@singletons/form'; import { CoreFileEntry } from '@services/file-helper'; @@ -412,7 +411,7 @@ export default class AddonBlogEditEntryPage implements CanLeave, OnInit, OnDestr if ((!this.entry && this.hasDataChangedForNewEntry) || (this.entry && this.hasDataChangedForEdit)) { // Modified, confirm user wants to go back. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId()); diff --git a/src/addons/calendar/pages/edit-event/edit-event.ts b/src/addons/calendar/pages/edit-event/edit-event.ts index 4aeee891f..f1a5d3bbb 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.ts +++ b/src/addons/calendar/pages/edit-event/edit-event.ts @@ -593,7 +593,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { async canLeave(): Promise { if (AddonCalendarHelper.hasEventDataChanged(this.form.value, this.originalData)) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } CoreForms.triggerFormCancelledEvent(this.formElement, this.currentSite.getId()); diff --git a/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts b/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts index 361259fc7..5bc1dc7de 100644 --- a/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts +++ b/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts @@ -16,7 +16,7 @@ import { Component, Input, ViewChild, ElementRef } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreFormFields, CoreForms } from '@singletons/form'; import { CorePromiseUtils } from '@singletons/promise-utils'; -import { ModalController, Translate } from '@singletons'; +import { ModalController } from '@singletons'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '../../services/assign'; import { AddonModAssignFeedbackDelegate } from '../../services/feedback-delegate'; import { CoreSharedModule } from '@/core/shared.module'; @@ -50,7 +50,7 @@ export class AddonModAssignEditFeedbackModalComponent { async closeModal(): Promise { const changed = await this.hasDataChanged(); if (changed) { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId()); diff --git a/src/addons/mod/assign/components/submission/submission.ts b/src/addons/mod/assign/components/submission/submission.ts index ba0d03cf4..d0d7c9a96 100644 --- a/src/addons/mod/assign/components/submission/submission.ts +++ b/src/addons/mod/assign/components/submission/submission.ts @@ -296,7 +296,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can if (modified) { // Modified, confirm user wants to go back. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); await this.discardDrafts(); } diff --git a/src/addons/mod/assign/pages/edit/edit.ts b/src/addons/mod/assign/pages/edit/edit.ts index 645d2c4ff..c2b917f99 100644 --- a/src/addons/mod/assign/pages/edit/edit.ts +++ b/src/addons/mod/assign/pages/edit/edit.ts @@ -125,7 +125,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy, CanLeave { // Check if data has changed. const changed = await this.hasDataChanged(); if (changed) { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } // Nothing has changed or user confirmed to leave. Clear temporary data from plugins. diff --git a/src/addons/mod/data/pages/edit/edit.ts b/src/addons/mod/data/pages/edit/edit.ts index dea968bde..d03763942 100644 --- a/src/addons/mod/data/pages/edit/edit.ts +++ b/src/addons/mod/data/pages/edit/edit.ts @@ -156,7 +156,7 @@ export class AddonModDataEditPage implements OnInit { if (changed) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } // Delete the local files from the tmp folder. diff --git a/src/addons/mod/feedback/pages/form/form.ts b/src/addons/mod/feedback/pages/form/form.ts index 935a1b3ae..e176ee5d1 100644 --- a/src/addons/mod/feedback/pages/form/form.ts +++ b/src/addons/mod/feedback/pages/form/form.ts @@ -160,7 +160,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave { if (this.items && !this.completed && this.originalData) { // Form submitted. Check if there is any change. if (!CoreObject.basicLeftCompare(responses, this.originalData, 3)) { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } } } diff --git a/src/addons/mod/forum/pages/discussion/discussion.ts b/src/addons/mod/forum/pages/discussion/discussion.ts index 9ba5e03ae..3e89ed320 100644 --- a/src/addons/mod/forum/pages/discussion/discussion.ts +++ b/src/addons/mod/forum/pages/discussion/discussion.ts @@ -303,7 +303,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes async canLeave(): Promise { if (AddonModForumHelper.hasPostDataChanged(this.formData, this.originalData)) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } // Delete the local files from the tmp folder. diff --git a/src/addons/mod/forum/pages/new-discussion/new-discussion.ts b/src/addons/mod/forum/pages/new-discussion/new-discussion.ts index 6a53b218e..20e5bbbaf 100644 --- a/src/addons/mod/forum/pages/new-discussion/new-discussion.ts +++ b/src/addons/mod/forum/pages/new-discussion/new-discussion.ts @@ -662,7 +662,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea if (AddonModForumHelper.hasPostDataChanged(this.newDiscussion, this.originalData)) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } // Delete the local files from the tmp folder. diff --git a/src/addons/mod/glossary/pages/edit/edit.ts b/src/addons/mod/glossary/pages/edit/edit.ts index 0c4800d8c..65be7888b 100644 --- a/src/addons/mod/glossary/pages/edit/edit.ts +++ b/src/addons/mod/glossary/pages/edit/edit.ts @@ -187,7 +187,7 @@ export class AddonModGlossaryEditPage implements OnInit, CanLeave { if (this.hasDataChanged()) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } // Delete the local files from the tmp folder. diff --git a/src/addons/mod/h5pactivity/pages/index/index.ts b/src/addons/mod/h5pactivity/pages/index/index.ts index b6a100c89..9a3c16934 100644 --- a/src/addons/mod/h5pactivity/pages/index/index.ts +++ b/src/addons/mod/h5pactivity/pages/index/index.ts @@ -16,7 +16,6 @@ import { Component, OnDestroy, ViewChild } from '@angular/core'; import { CoreCourseModuleMainActivityPage } from '@features/course/classes/main-activity-page'; import { CanLeave } from '@guards/can-leave'; -import { Translate } from '@singletons'; import { AddonModH5PActivityIndexComponent } from '../../components/index'; import { CoreAlerts } from '@services/overlays/alerts'; @@ -45,7 +44,7 @@ export class AddonModH5PActivityIndexPage extends CoreCourseModuleMainActivityPa if (!this.canLeaveSafely) { try { - await CoreAlerts.confirm(Translate.instant('core.confirmleaveunknownchanges')); + await CoreAlerts.confirmLeaveWithChanges(); return true; } catch { diff --git a/src/addons/mod/lesson/pages/player/player.ts b/src/addons/mod/lesson/pages/player/player.ts index 6ed71931e..7d64ce768 100644 --- a/src/addons/mod/lesson/pages/player/player.ts +++ b/src/addons/mod/lesson/pages/player/player.ts @@ -173,7 +173,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { if (this.question && !this.eolData && !this.processData && this.originalData) { // Question shown. Check if there is any change. if (!CoreObject.basicLeftCompare(this.questionForm.getRawValue(), this.originalData, 3)) { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } } diff --git a/src/addons/mod/wiki/pages/edit/edit.ts b/src/addons/mod/wiki/pages/edit/edit.ts index ba130fc5d..481b42484 100644 --- a/src/addons/mod/wiki/pages/edit/edit.ts +++ b/src/addons/mod/wiki/pages/edit/edit.ts @@ -337,7 +337,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave { // Check if data has changed. if (this.hasDataChanged()) { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId()); diff --git a/src/addons/mod/workshop/pages/assessment/assessment.ts b/src/addons/mod/workshop/pages/assessment/assessment.ts index 98f55d960..4e7fe8954 100644 --- a/src/addons/mod/workshop/pages/assessment/assessment.ts +++ b/src/addons/mod/workshop/pages/assessment/assessment.ts @@ -172,7 +172,7 @@ export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy, CanLea } // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); CoreForms.triggerFormCancelledEvent(this.formElement, this.siteId); diff --git a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts index 0c88f0567..ec851b200 100644 --- a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts +++ b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts @@ -147,7 +147,7 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy, Ca // Check if data has changed. if (this.hasDataChanged()) { // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } if (this.submission?.attachmentfiles) { diff --git a/src/addons/mod/workshop/pages/submission/submission.ts b/src/addons/mod/workshop/pages/submission/submission.ts index 6d36c33a3..36c334c89 100644 --- a/src/addons/mod/workshop/pages/submission/submission.ts +++ b/src/addons/mod/workshop/pages/submission/submission.ts @@ -184,7 +184,7 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy, CanLea } // Show confirmation if some data has been modified. - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); CoreForms.triggerFormCancelledEvent(this.formElement, this.siteId); diff --git a/src/core/features/emulator/components/capture-media/capture-media.ts b/src/core/features/emulator/components/capture-media/capture-media.ts index d16c4f24c..fdc9c7cc5 100644 --- a/src/core/features/emulator/components/capture-media/capture-media.ts +++ b/src/core/features/emulator/components/capture-media/capture-media.ts @@ -18,7 +18,7 @@ import { MediaFile } from '@awesome-cordova-plugins/media-capture/ngx'; import { CoreFile, CoreFileProvider } from '@services/file'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreTimeUtils } from '@services/utils/time'; -import { ModalController, Translate } from '@singletons'; +import { ModalController } from '@singletons'; import { CoreError } from '@classes/errors/error'; import { CoreCaptureError } from '@classes/errors/captureerror'; import { CoreCanceledError } from '@classes/errors/cancelederror'; @@ -235,7 +235,7 @@ export class CoreEmulatorCaptureMediaComponent implements OnInit, OnDestroy { async cancel(): Promise { if (this.hasCaptured) { try { - await CoreAlerts.confirm(Translate.instant('core.confirmcanceledit')); + await CoreAlerts.confirmLeaveWithChanges(); } catch { // Canceled. return; diff --git a/src/core/features/login/tests/behat/logout.feature b/src/core/features/login/tests/behat/logout.feature index 15b1ebb73..07aaa06c2 100755 --- a/src/core/features/login/tests/behat/logout.feature +++ b/src/core/features/login/tests/behat/logout.feature @@ -87,12 +87,13 @@ Feature: Test different cases of logout and switch account | Message | An awesome message | And I press the user menu button in the app And I press "Log out" in the app - Then I should find "Are you sure you want to leave this page?" in the app + Then I should find "Leave page?" in the app + And I should find "Unsaved changes will be lost." in the app # Check that the app continues working fine if the user cancels the logout. When I press "Cancel" in the app And I press "Forum topic 1" in the app - And I press "OK" in the app + And I press "Leave" in the app Then I should find "Forum message 1" in the app When I press "Forum topic 2" in the app @@ -105,7 +106,7 @@ Feature: Test different cases of logout and switch account | Message | An awesome message | And I press the user menu button in the app And I press "Log out" in the app - And I press "OK" in the app + And I press "Leave" in the app And I wait the app to restart Then the header should be "Accounts" in the app @@ -135,12 +136,13 @@ Feature: Test different cases of logout and switch account And I press the user menu button in the app And I press "Switch account" in the app And I press "pau student2" in the app - Then I should find "Are you sure you want to leave this page?" in the app + Then I should find "Leave page?" in the app + And I should find "Unsaved changes will be lost." in the app # Check that the app continues working fine if the user cancels the switch account. When I press "Cancel" in the app And I press "Forum topic 1" in the app - And I press "OK" in the app + And I press "Leave" in the app Then I should find "Forum message 1" in the app When I press "Forum topic 2" in the app @@ -154,7 +156,7 @@ Feature: Test different cases of logout and switch account And I press the user menu button in the app And I press "Switch account" in the app And I press "pau student2" in the app - And I press "OK" in the app + And I press "Leave" in the app And I wait the app to restart And I press the user menu button in the app Then I should find "pau student2" in the app diff --git a/src/core/lang.json b/src/core/lang.json index a4a3981d3..c0857841d 100644 --- a/src/core/lang.json +++ b/src/core/lang.json @@ -48,9 +48,9 @@ "completion-alt-manual-n-override": "Not completed: {{$a.modname}} (set by {{$a.overrideuser}}). Select to mark as complete.", "completion-alt-manual-y": "Completed: {{$a}}. Select to mark as not complete.", "completion-alt-manual-y-override": "Completed: {{$a.modname}} (set by {{$a.overrideuser}}). Select to mark as not complete.", - "confirmcanceledit": "Are you sure you want to leave this page? All changes will be lost.", "confirmdeletefile": "Are you sure you want to delete this file?", - "confirmleaveunknownchanges": "Are you sure you want to leave this page? If you have unsaved changes they will be lost.", + "confirmleavepagedescription": "Unsaved changes will be lost.", + "confirmleavepagetitle": "Leave page?", "confirmloss": "Are you sure? All changes will be lost.", "confirmopeninbrowser": "Do you want to open it in a web browser?", "confirmremoveselectedfile": "This will permanently delete '{{filename}}'. You can't undo this.", @@ -168,6 +168,7 @@ "lastmodified": "Last modified", "lastsync": "Last synchronisation", "layoutgrid": "Grid", + "leave": "Leave", "list": "List", "listsep": ",", "loading": "Loading", diff --git a/src/core/services/overlays/alerts.ts b/src/core/services/overlays/alerts.ts index 9223a357a..4407cc342 100644 --- a/src/core/services/overlays/alerts.ts +++ b/src/core/services/overlays/alerts.ts @@ -70,7 +70,7 @@ export class CoreAlertsService { */ confirm(message: string, options: CoreAlertsConfirmOptions = {}): Promise { return new Promise((resolve, reject): void => { - const { okText, cancelText, ...alertOptions } = options; + const { okText, cancelText, isDestructive, ...alertOptions } = options; const buttons = [ { text: cancelText || Translate.instant('core.cancel'), @@ -81,6 +81,7 @@ export class CoreAlertsService { }, { text: okText || Translate.instant('core.ok'), + role: isDestructive ? 'destructive' : undefined, handler: (data: T) => { resolve(data); }, @@ -111,34 +112,22 @@ export class CoreAlertsService { async confirmDelete(message: string, options: Omit = {}): Promise { message = await CoreLang.filterMultilang(message); - const alertOptions: AlertOptions = { + await this.confirm(message, { ...options, - message, - }; + okText: Translate.instant('core.delete'), + isDestructive: true, + }); + } - return new Promise((resolve, reject): void => { - alertOptions.buttons = [ - { - text: Translate.instant('core.cancel'), - role: 'cancel', - handler: () => { - reject(new CoreCanceledError()); - }, - }, - { - text: Translate.instant('core.delete'), - role: 'destructive', - handler: () => { - resolve(); - }, - }, - ]; - - if (!alertOptions.header) { - alertOptions.cssClass = (alertOptions.cssClass || '') + ' core-nohead'; - } - - this.show(alertOptions); + /** + * Show a confirmation modal to confirm leaving a page with unsaves changes. + * + * @returns Promise resolved if the user confirms and rejected with a canceled error if he cancels. + */ + async confirmLeaveWithChanges(): Promise { + await this.confirm(Translate.instant('core.confirmleavepagedescription'), { + header: Translate.instant('core.confirmleavepagetitle'), + okText: Translate.instant('core.leave'), }); } @@ -504,6 +493,7 @@ export const CoreAlerts = makeSingleton(CoreAlertsService); export type CoreAlertsConfirmOptions = Omit & { okText?: string; // Text of the OK button. By default, 'OK'. cancelText?: string; // Text of the Cancel button. By default, 'Cancel'. + isDestructive?: boolean; // Whether confirming is destructive (will remove data), so the button will have a danger color. }; /** diff --git a/src/core/tests/behat/navigation_deeplinks.feature b/src/core/tests/behat/navigation_deeplinks.feature index 7f858d53b..ed387b757 100644 --- a/src/core/tests/behat/navigation_deeplinks.feature +++ b/src/core/tests/behat/navigation_deeplinks.feature @@ -155,7 +155,8 @@ Feature: It navigates properly using deep links. Then I should find "This link belongs to another site" in the app When I press "OK" in the app - Then I should find "Are you sure you want to leave this page?" in the app + Then I should find "Leave page?" in the app + And I should find "Unsaved changes will be lost." in the app When I press "Cancel" in the app Then I should not find "Forum message" in the app @@ -164,7 +165,7 @@ Feature: It navigates properly using deep links. | discussion | user | | Forum topic | student2 | And I press "OK" in the app - And I press "OK" in the app + And I press "Leave" in the app And I wait the app to restart Then I should find "Forum topic" in the app And I should find "Forum message" in the app