Merge pull request #1758 from dpalou/MOBILE-2807

MOBILE-2807 message: Add setting to configure send
main
Juan Leyva 2019-02-08 14:01:15 +01:00 committed by GitHub
commit bccf9ca576
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 92 additions and 4 deletions

View File

@ -214,6 +214,9 @@
"addon.messages.unabletomessage": "message", "addon.messages.unabletomessage": "message",
"addon.messages.unblockuser": "message", "addon.messages.unblockuser": "message",
"addon.messages.unblockuserconfirm": "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.userwouldliketocontactyou": "message",
"addon.messages.warningconversationmessagenotsent": "local_moodlemobileapp", "addon.messages.warningconversationmessagenotsent": "local_moodlemobileapp",
"addon.messages.warningmessagenotsent": "local_moodlemobileapp", "addon.messages.warningmessagenotsent": "local_moodlemobileapp",
@ -602,6 +605,7 @@
"addon.mod_lti.modulenameplural": "lti", "addon.mod_lti.modulenameplural": "lti",
"addon.mod_page.errorwhileloadingthepage": "local_moodlemobileapp", "addon.mod_page.errorwhileloadingthepage": "local_moodlemobileapp",
"addon.mod_page.modulenameplural": "page", "addon.mod_page.modulenameplural": "page",
"addon.mod_quiz.answercolon": "qtype_numerical",
"addon.mod_quiz.attemptfirst": "quiz", "addon.mod_quiz.attemptfirst": "quiz",
"addon.mod_quiz.attemptlast": "quiz", "addon.mod_quiz.attemptlast": "quiz",
"addon.mod_quiz.attemptnumber": "quiz", "addon.mod_quiz.attemptnumber": "quiz",
@ -1246,6 +1250,7 @@
"core.courses.enrolme": "local_moodlemobileapp", "core.courses.enrolme": "local_moodlemobileapp",
"core.courses.errorloadcategories": "local_moodlemobileapp", "core.courses.errorloadcategories": "local_moodlemobileapp",
"core.courses.errorloadcourses": "local_moodlemobileapp", "core.courses.errorloadcourses": "local_moodlemobileapp",
"core.courses.errorloadplugins": "local_moodlemobileapp",
"core.courses.errorsearching": "local_moodlemobileapp", "core.courses.errorsearching": "local_moodlemobileapp",
"core.courses.errorselfenrol": "local_moodlemobileapp", "core.courses.errorselfenrol": "local_moodlemobileapp",
"core.courses.filtermycourses": "local_moodlemobileapp", "core.courses.filtermycourses": "local_moodlemobileapp",

View File

@ -66,6 +66,9 @@
"unabletomessage": "You are unable to message this user", "unabletomessage": "You are unable to message this user",
"unblockuser": "Unblock user", "unblockuser": "Unblock user",
"unblockuserconfirm": "Are you sure you want to unblock {{$a}}?", "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", "userwouldliketocontactyou": "{{$a}} would like to contact you",
"warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}", "warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}",
"warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}", "warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}",

View File

@ -32,6 +32,7 @@
</ion-list> </ion-list>
</ion-card> </ion-card>
<!-- Notifications. -->
<ng-container *ngIf="preferences"> <ng-container *ngIf="preferences">
<div *ngFor="let component of preferences.components"> <div *ngFor="let component of preferences.components">
<ion-card list *ngFor="let notification of component.notifications"> <ion-card list *ngFor="let notification of component.notifications">
@ -90,5 +91,20 @@
</ion-card> </ion-card>
</div> </div>
</ng-container> </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> </core-loading>
</ion-content> </ion-content>

View File

@ -16,8 +16,12 @@ import { Component, OnDestroy } from '@angular/core';
import { IonicPage } from 'ionic-angular'; import { IonicPage } from 'ionic-angular';
import { AddonMessagesProvider } from '../../providers/messages'; import { AddonMessagesProvider } from '../../providers/messages';
import { CoreUserProvider } from '@core/user/providers/user'; 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 { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreConstants } from '@core/constants';
/** /**
* Page that displays the messages settings page. * Page that displays the messages settings page.
@ -39,16 +43,27 @@ export class AddonMessagesSettingsPage implements OnDestroy {
courseMemberValue = AddonMessagesProvider.MESSAGE_PRIVACY_COURSEMEMBER; courseMemberValue = AddonMessagesProvider.MESSAGE_PRIVACY_COURSEMEMBER;
siteValue = AddonMessagesProvider.MESSAGE_PRIVACY_SITE; siteValue = AddonMessagesProvider.MESSAGE_PRIVACY_SITE;
groupMessagingEnabled: boolean; groupMessagingEnabled: boolean;
sendOnEnter: boolean;
isDesktop: boolean;
isMac: boolean;
protected previousContactableValue: number | boolean; protected previousContactableValue: number | boolean;
constructor(private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, 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(); const currentSite = sitesProvider.getCurrentSite();
this.advancedContactable = currentSite && currentSite.isVersionGreaterEqualThan('3.6'); this.advancedContactable = currentSite && currentSite.isVersionGreaterEqualThan('3.6');
this.allowSiteMessaging = currentSite && currentSite.canUseAdvancedFeature('messagingallusers'); this.allowSiteMessaging = currentSite && currentSite.canUseAdvancedFeature('messagingallusers');
this.groupMessagingEnabled = this.messagesProvider.isGroupMessagingEnabled(); 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. * Page destroyed.
*/ */

View File

@ -214,6 +214,9 @@
"addon.messages.unabletomessage": "You are unable to message this user", "addon.messages.unabletomessage": "You are unable to message this user",
"addon.messages.unblockuser": "Unblock user", "addon.messages.unblockuser": "Unblock user",
"addon.messages.unblockuserconfirm": "Are you sure you want to unblock {{$a}}?", "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.userwouldliketocontactyou": "{{$a}} would like to contact you",
"addon.messages.warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}", "addon.messages.warningconversationmessagenotsent": "Couldn't send message(s) to conversation {{conversation}}. {{error}}",
"addon.messages.warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}", "addon.messages.warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}",

View File

@ -1,5 +1,5 @@
<form> <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> <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)"> <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> <ion-icon name="send" color="dark"></ion-icon>

View File

@ -13,8 +13,13 @@
// limitations under the License. // limitations under the License.
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; 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 { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreConstants } from '@core/constants';
/** /**
* Component to display a "send message form". * 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() onSubmit: EventEmitter<string>; // Send data when submitting the message form.
@Output() onResize: EventEmitter<void>; // Emit when resizing the textarea. @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.onSubmit = new EventEmitter();
this.onResize = 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 { ngOnInit(): void {
@ -74,4 +91,22 @@ export class CoreSendMessageFormComponent implements OnInit {
textareaResized(): void { textareaResized(): void {
this.onResize.emit(); 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);
}
}
}
} }

View File

@ -32,6 +32,7 @@ export class CoreConstants {
static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi'; static SETTINGS_SYNC_ONLY_ON_WIFI = 'CoreSettingsSyncOnlyOnWifi';
static SETTINGS_DEBUG_DISPLAY = 'CoreSettingsDebugDisplay'; static SETTINGS_DEBUG_DISPLAY = 'CoreSettingsDebugDisplay';
static SETTINGS_REPORT_IN_BACKGROUND = 'CoreSettingsReportInBackground'; // @deprecated since 3.5.0 static SETTINGS_REPORT_IN_BACKGROUND = 'CoreSettingsReportInBackground'; // @deprecated since 3.5.0
static SETTINGS_SEND_ON_ENTER = 'CoreSettingsSendOnEnter';
// WS constants. // WS constants.
static WS_TIMEOUT = 30000; static WS_TIMEOUT = 30000;

View File

@ -58,6 +58,7 @@ export class CoreEventsProvider {
static CORE_LOADING_CHANGED = 'core_loading_changed'; static CORE_LOADING_CHANGED = 'core_loading_changed';
static ORIENTATION_CHANGE = 'orientation_change'; static ORIENTATION_CHANGE = 'orientation_change';
static LOAD_PAGE_MAIN_MENU = 'load_page_main_menu'; static LOAD_PAGE_MAIN_MENU = 'load_page_main_menu';
static SEND_ON_ENTER_CHANGED = 'send_on_enter_changed';
protected logger; protected logger;
protected observables: { [s: string]: Subject<any> } = {}; protected observables: { [s: string]: Subject<any> } = {};