diff --git a/scripts/langindex.json b/scripts/langindex.json index 22b33e825..3993e76f7 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -214,6 +214,9 @@ "addon.messages.unabletomessage": "message", "addon.messages.unblockuser": "message", "addon.messages.unblockuserconfirm": "message", + "addon.messages.useentertosend": "message", + "addon.messages.useentertosenddescdesktop": "local_moodlemobileapp", + "addon.messages.useentertosenddescmac": "local_moodlemobileapp", "addon.messages.userwouldliketocontactyou": "message", "addon.messages.warningconversationmessagenotsent": "local_moodlemobileapp", "addon.messages.warningmessagenotsent": "local_moodlemobileapp", @@ -602,6 +605,7 @@ "addon.mod_lti.modulenameplural": "lti", "addon.mod_page.errorwhileloadingthepage": "local_moodlemobileapp", "addon.mod_page.modulenameplural": "page", + "addon.mod_quiz.answercolon": "qtype_numerical", "addon.mod_quiz.attemptfirst": "quiz", "addon.mod_quiz.attemptlast": "quiz", "addon.mod_quiz.attemptnumber": "quiz", @@ -1246,6 +1250,7 @@ "core.courses.enrolme": "local_moodlemobileapp", "core.courses.errorloadcategories": "local_moodlemobileapp", "core.courses.errorloadcourses": "local_moodlemobileapp", + "core.courses.errorloadplugins": "local_moodlemobileapp", "core.courses.errorsearching": "local_moodlemobileapp", "core.courses.errorselfenrol": "local_moodlemobileapp", "core.courses.filtermycourses": "local_moodlemobileapp", diff --git a/src/addon/messages/lang/en.json b/src/addon/messages/lang/en.json index 2ec162f66..75419bf5b 100644 --- a/src/addon/messages/lang/en.json +++ b/src/addon/messages/lang/en.json @@ -66,6 +66,9 @@ "unabletomessage": "You are unable to message this user", "unblockuser": "Unblock user", "unblockuserconfirm": "Are you sure you want to unblock {{$a}}?", + "useentertosend": "Use enter to send", + "useentertosenddescdesktop": "If disabled, you can use Ctrl+Enter to send the message.", + "useentertosenddescmac": "If disabled, you can use Cmd+Enter to send the message.", "userwouldliketocontactyou": "{{$a}} would like to contact you", "warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}", "warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}", diff --git a/src/addon/messages/pages/settings/settings.html b/src/addon/messages/pages/settings/settings.html index 4048bb8f6..0172888d9 100644 --- a/src/addon/messages/pages/settings/settings.html +++ b/src/addon/messages/pages/settings/settings.html @@ -32,6 +32,7 @@ </ion-list> </ion-card> + <!-- Notifications. --> <ng-container *ngIf="preferences"> <div *ngFor="let component of preferences.components"> <ion-card list *ngFor="let notification of component.notifications"> @@ -90,5 +91,20 @@ </ion-card> </div> </ng-container> + + <!-- General settings. --> + <ion-card> + <ion-list text-wrap> + <ion-item-divider>{{ 'core.settings.general' | translate }}</ion-item-divider> + <ion-item text-wrap> + <ion-label> + <h2>{{ 'addon.messages.useentertosend' | translate }}</h2> + <p *ngIf="isDesktop && !isMac">{{ 'addon.messages.useentertosenddescdesktop' | translate }}</p> + <p *ngIf="isDesktop && isMac">{{ 'addon.messages.useentertosenddescmac' | translate }}</p> + </ion-label> + <ion-toggle [(ngModel)]="sendOnEnter" (ngModelChange)="sendOnEnterChanged()"></ion-toggle> + </ion-item> + </ion-list> + </ion-card> </core-loading> </ion-content> diff --git a/src/addon/messages/pages/settings/settings.ts b/src/addon/messages/pages/settings/settings.ts index 7b524ff3c..d7e30cd01 100644 --- a/src/addon/messages/pages/settings/settings.ts +++ b/src/addon/messages/pages/settings/settings.ts @@ -16,8 +16,12 @@ import { Component, OnDestroy } from '@angular/core'; import { IonicPage } from 'ionic-angular'; import { AddonMessagesProvider } from '../../providers/messages'; import { CoreUserProvider } from '@core/user/providers/user'; -import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreAppProvider } from '@providers/app'; +import { CoreConfigProvider } from '@providers/config'; +import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreConstants } from '@core/constants'; /** * Page that displays the messages settings page. @@ -39,16 +43,27 @@ export class AddonMessagesSettingsPage implements OnDestroy { courseMemberValue = AddonMessagesProvider.MESSAGE_PRIVACY_COURSEMEMBER; siteValue = AddonMessagesProvider.MESSAGE_PRIVACY_SITE; groupMessagingEnabled: boolean; + sendOnEnter: boolean; + isDesktop: boolean; + isMac: boolean; protected previousContactableValue: number | boolean; constructor(private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, - private userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider) { + private userProvider: CoreUserProvider, private sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider, + private configProvider: CoreConfigProvider, private eventsProvider: CoreEventsProvider) { const currentSite = sitesProvider.getCurrentSite(); this.advancedContactable = currentSite && currentSite.isVersionGreaterEqualThan('3.6'); this.allowSiteMessaging = currentSite && currentSite.canUseAdvancedFeature('messagingallusers'); this.groupMessagingEnabled = this.messagesProvider.isGroupMessagingEnabled(); + + this.configProvider.get(CoreConstants.SETTINGS_SEND_ON_ENTER, !appProvider.isMobile()).then((sendOnEnter) => { + this.sendOnEnter = !!sendOnEnter; + }); + + this.isDesktop = !appProvider.isMobile(); + this.isMac = appProvider.isMac(); } /** @@ -233,6 +248,15 @@ export class AddonMessagesSettingsPage implements OnDestroy { }); } + sendOnEnterChanged(): void { + // Save the value. + this.configProvider.set(CoreConstants.SETTINGS_SEND_ON_ENTER, this.sendOnEnter ? 1 : 0); + + // Notify the app. + this.eventsProvider.trigger(CoreEventsProvider.SEND_ON_ENTER_CHANGED, {sendOnEnter: !!this.sendOnEnter}, + this.sitesProvider.getCurrentSiteId()); + } + /** * Page destroyed. */ diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 47566d043..048521fcd 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -214,6 +214,9 @@ "addon.messages.unabletomessage": "You are unable to message this user", "addon.messages.unblockuser": "Unblock user", "addon.messages.unblockuserconfirm": "Are you sure you want to unblock {{$a}}?", + "addon.messages.useentertosend": "Use enter to send", + "addon.messages.useentertosenddescdesktop": "If disabled, you can use Ctrl+Enter to send the message.", + "addon.messages.useentertosenddescmac": "If disabled, you can use Cmd+Enter to send the message.", "addon.messages.userwouldliketocontactyou": "{{$a}} would like to contact you", "addon.messages.warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}", "addon.messages.warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}", diff --git a/src/components/send-message-form/core-send-message-form.html b/src/components/send-message-form/core-send-message-form.html index aea20f503..f02a7ee2c 100644 --- a/src/components/send-message-form/core-send-message-form.html +++ b/src/components/send-message-form/core-send-message-form.html @@ -1,5 +1,5 @@ <form> - <textarea class="core-send-message-input" [core-auto-focus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows [(ngModel)]="message" name="message" (onResize)="textareaResized()"></textarea> + <textarea class="core-send-message-input" [core-auto-focus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows [(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)" (keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')"></textarea> <ion-buttons end> <button ion-button icon-only clear="true" type="submit" [disabled]="!message" [attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)"> <ion-icon name="send" color="dark"></ion-icon> diff --git a/src/components/send-message-form/send-message-form.ts b/src/components/send-message-form/send-message-form.ts index bac82624d..ae7a25ff9 100644 --- a/src/components/send-message-form/send-message-form.ts +++ b/src/components/send-message-form/send-message-form.ts @@ -13,8 +13,13 @@ // limitations under the License. import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; +import { CoreAppProvider } from '@providers/app'; +import { CoreConfigProvider } from '@providers/config'; +import { CoreEventsProvider } from '@providers/events'; +import { CoreSitesProvider } from '@providers/sites'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreTextUtilsProvider } from '@providers/utils/text'; +import { CoreConstants } from '@core/constants'; /** * Component to display a "send message form". @@ -37,9 +42,21 @@ export class CoreSendMessageFormComponent implements OnInit { @Output() onSubmit: EventEmitter<string>; // Send data when submitting the message form. @Output() onResize: EventEmitter<void>; // Emit when resizing the textarea. - constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider) { + protected sendOnEnter: boolean; + + constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider, configProvider: CoreConfigProvider, + eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider) { + this.onSubmit = new EventEmitter(); this.onResize = new EventEmitter(); + + configProvider.get(CoreConstants.SETTINGS_SEND_ON_ENTER, !this.appProvider.isMobile()).then((sendOnEnter) => { + this.sendOnEnter = !!sendOnEnter; + }); + + eventsProvider.on(CoreEventsProvider.SEND_ON_ENTER_CHANGED, (newValue) => { + this.sendOnEnter = newValue; + }, sitesProvider.getCurrentSiteId()); } ngOnInit(): void { @@ -74,4 +91,22 @@ export class CoreSendMessageFormComponent implements OnInit { textareaResized(): void { this.onResize.emit(); } + + /** + * Enter key clicked. + * + * @param {Event} e Event. + * @param {string} other The name of the other key that was clicked, undefined if no other key. + */ + enterClicked(e: Event, other: string): void { + if (this.sendOnEnter && !other) { + // Enter clicked, send the message. + this.submitForm(e); + } else if (!this.sendOnEnter && !this.appProvider.isMobile()) { + if ((this.appProvider.isMac() && other == 'meta') || (!this.appProvider.isMac() && other == 'control')) { + // Cmd+Enter or Ctrl+Enter, send message. + this.submitForm(e); + } + } + } } diff --git a/src/core/constants.ts b/src/core/constants.ts index 79e131672..2fc8bfc79 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -32,6 +32,7 @@ export class CoreConstants { static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi'; static SETTINGS_DEBUG_DISPLAY = 'CoreSettingsDebugDisplay'; static SETTINGS_REPORT_IN_BACKGROUND = 'CoreSettingsReportInBackground'; // @deprecated since 3.5.0 + static SETTINGS_SEND_ON_ENTER = 'CoreSettingsSendOnEnter'; // WS constants. static WS_TIMEOUT = 30000; diff --git a/src/providers/events.ts b/src/providers/events.ts index 55def12a0..fca9550ed 100644 --- a/src/providers/events.ts +++ b/src/providers/events.ts @@ -58,6 +58,7 @@ export class CoreEventsProvider { static CORE_LOADING_CHANGED = 'core_loading_changed'; static ORIENTATION_CHANGE = 'orientation_change'; static LOAD_PAGE_MAIN_MENU = 'load_page_main_menu'; + static SEND_ON_ENTER_CHANGED = 'send_on_enter_changed'; protected logger; protected observables: { [s: string]: Subject<any> } = {};