MOBILE-2995 qr: Add copy to clipboard button in QR text modal

main
Dani Palou 2020-04-29 13:52:07 +02:00
parent d79f48e3fb
commit ec19082f7b
19 changed files with 159 additions and 40 deletions

View File

@ -1387,6 +1387,7 @@
"core.contentlinks.errorredirectothersite": "local_moodlemobileapp",
"core.continue": "moodle",
"core.copiedtoclipboard": "local_moodlemobileapp",
"core.copytoclipboard": "local_moodlemobileapp",
"core.course": "moodle",
"core.course.activitydisabled": "local_moodlemobileapp",
"core.course.activitynotyetviewableremoteaddon": "local_moodlemobileapp",
@ -1754,6 +1755,7 @@
"core.login.mustconfirm": "moodle",
"core.login.newaccount": "moodle",
"core.login.notloggedin": "local_moodlemobileapp",
"core.login.or": "local_moodlemobileapp",
"core.login.password": "moodle",
"core.login.passwordforgotten": "moodle",
"core.login.passwordforgotteninstructions2": "moodle",
@ -1860,6 +1862,7 @@
"core.online": "message",
"core.openfullimage": "local_moodlemobileapp",
"core.openinbrowser": "local_moodlemobileapp",
"core.openmodinbrowser": "local_moodlemobileapp",
"core.othergroups": "group",
"core.pagea": "moodle",
"core.parentlanguage": "langconfig",

View File

@ -133,8 +133,15 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
ev && ev.stopPropagation();
if (this.assign && (this.description || this.assign.introattachments)) {
this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component,
this.module.id, this.assign.introattachments, true, 'module', this.module.id, this.courseId);
this.textUtils.viewText(this.translate.instant('core.description'), this.description, {
component: this.component,
componentId: this.module.id,
files: this.assign.introattachments,
filter: true,
contextLevel: 'module',
instanceId: this.module.id,
courseId: this.courseId,
});
}
}

View File

@ -678,8 +678,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
*/
showAdvancedGrade(): void {
if (this.feedback && this.feedback.advancedgrade) {
this.textUtils.expandText(this.translate.instant('core.grades.grade'), this.feedback.gradefordisplay,
AddonModAssignProvider.COMPONENT, this.moduleId);
this.textUtils.viewText(this.translate.instant('core.grades.grade'), this.feedback.gradefordisplay, {
component: AddonModAssignProvider.COMPONENT,
componentId: this.moduleId,
});
}
}

View File

@ -65,8 +65,14 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb
if (this.text) {
// Open a new state with the text.
this.textUtils.expandText(this.plugin.name, this.text, this.component, this.assign.cmid, undefined, true,
'module', this.assign.cmid, this.assign.course);
this.textUtils.viewText(this.plugin.name, this.text, {
component: this.component,
componentId: this.assign.cmid,
filter: true,
contextLevel: 'module',
instanceId: this.assign.cmid,
courseId: this.assign.course,
});
}
});
} else if (this.edit) {

View File

@ -83,8 +83,14 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS
if (text) {
// Open a new state with the interpolated contents.
this.textUtils.expandText(this.plugin.name, text, this.component, this.assign.cmid, undefined, true,
'module', this.assign.cmid, this.assign.course);
this.textUtils.viewText(this.plugin.name, text, {
component: this.component,
componentId: this.assign.cmid,
filter: true,
contextLevel: 'module',
instanceId: this.assign.cmid,
courseId: this.assign.course,
});
}
});
} else {

View File

@ -1387,6 +1387,7 @@
"core.contentlinks.errorredirectothersite": "The redirect URL cannot point to a different site.",
"core.continue": "Continue",
"core.copiedtoclipboard": "Text copied to clipboard",
"core.copytoclipboard": "Copy to clipboard",
"core.course": "Course",
"core.course.activitydisabled": "Your organisation has disabled this activity in the mobile app.",
"core.course.activitynotyetviewableremoteaddon": "Your organisation installed a plugin that is not yet supported.",

View File

@ -47,7 +47,13 @@ export class CoreNavigationBarComponent {
}
showInfo(): void {
this.textUtils.expandText(this.title, this.info, this.component, this.componentId, [], true, this.contextLevel,
this.contextInstanceId, this.courseId);
this.textUtils.viewText(this.title, this.info, {
component: this.component,
componentId: this.componentId,
filter: true,
contextLevel: this.contextLevel,
instanceId: this.contextInstanceId,
courseId: this.courseId,
});
}
}

View File

@ -265,8 +265,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
* Expand the description.
*/
expandDescription(): void {
this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id,
[], true, 'module', this.module.id, this.courseId);
this.textUtils.viewText(this.translate.instant('core.description'), this.description, {
component: this.component,
componentId: this.module.id,
filter: true,
contextLevel: 'module',
instanceId: this.module.id,
courseId: this.courseId,
});
}
/**

View File

@ -38,7 +38,11 @@ export class CoreCourseUnsupportedModulePage {
* Expand the description.
*/
expandDescription(): void {
this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, undefined, undefined,
[], true, 'module', this.module.id, this.courseId);
this.textUtils.viewText(this.translate.instant('core.description'), this.module.description, {
filter: true,
contextLevel: 'module',
instanceId: this.module.id,
courseId: this.courseId,
});
}
}

View File

@ -317,7 +317,7 @@ export class CoreLoginEmailSignupPage {
* Show authentication instructions.
*/
protected showAuthInstructions(): void {
this.textUtils.expandText(this.translate.instant('core.login.instructions'), this.authInstructions);
this.textUtils.viewText(this.translate.instant('core.login.instructions'), this.authInstructions);
}
/**

View File

@ -192,7 +192,9 @@ export class CoreMainMenuMorePage implements OnDestroy {
});
} else {
// It's not a URL, open it in a modal so the user can see it and copy it.
this.textUtils.expandText(this.translate.instant('core.qrscanner'), text);
this.textUtils.viewText(this.translate.instant('core.qrscanner'), text, {
displayCopyButton: true,
});
}
}
});

View File

@ -709,8 +709,14 @@ export class CoreQuestionHelperProvider {
if (span) {
// There's a hidden feedback, show it when the icon is clicked.
icon.addEventListener('click', (event) => {
this.textUtils.expandText(title, span.innerHTML, component, componentId, [], true, contextLevel,
contextInstanceId, courseId);
this.textUtils.viewText(title, span.innerHTML, {
component: component,
componentId: componentId,
filter: true,
contextLevel: contextLevel,
instanceId: contextInstanceId,
courseId: courseId,
});
});
}
});

View File

@ -146,8 +146,14 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
* Expand the description.
*/
expandDescription(): void {
this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id,
[], true, 'module', this.module.id, this.courseId);
this.textUtils.viewText(this.translate.instant('core.description'), this.description, {
component: this.component,
componentId: this.module.id,
filter: true,
contextLevel: 'module',
instanceId: this.module.id,
courseId: this.courseId,
});
}
/**

View File

@ -16,3 +16,9 @@
<core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="componentId"></core-file>
</ion-card>
</ion-content>
<ion-footer color="light" *ngIf="displayCopyButton">
<button ion-button block color="light" icon-start (click)="copyText()">
<ion-icon name="copy" aria-hidden="true"></ion-icon>
{{ 'core.copytoclipboard' | translate }}
</button>
</ion-footer>

View File

@ -0,0 +1,5 @@
ion-app.app-root page-core-viewer-text {
ion-footer {
padding: 6px;
}
}

View File

@ -15,6 +15,7 @@
import { Component } from '@angular/core';
import { IonicPage, ViewController, NavParams } from 'ionic-angular';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtils } from '@providers/utils/utils';
/**
* Page to render a certain text. If opened as a modal, it will have a button to close the modal.
@ -34,6 +35,7 @@ export class CoreViewerTextPage {
contextLevel: string; // The context level.
instanceId: number; // The instance ID related to the context.
courseId: number; // Course ID the text belongs to. It can be used to improve performance with filters.
displayCopyButton: boolean; // Whether to display a button to copy the contents.
constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) {
this.title = params.get('title');
@ -45,6 +47,7 @@ export class CoreViewerTextPage {
this.contextLevel = params.get('contextLevel');
this.instanceId = params.get('instanceId');
this.courseId = params.get('courseId');
this.displayCopyButton = !!params.get('displayCopyButton');
}
/**
@ -53,4 +56,11 @@ export class CoreViewerTextPage {
closeModal(): void {
this.viewCtrl.dismiss();
}
/**
* Copy the text to clipboard.
*/
copyText(): void {
CoreUtils.instance.copyToClipboard(this.content);
}
}

View File

@ -307,8 +307,14 @@ export class CoreFormatTextDirective implements OnChanges {
// Open a new state with the contents.
const filter = typeof this.filter != 'undefined' ? this.utils.isTrueOrOne(this.filter) : undefined;
this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text,
this.component, this.componentId, undefined, filter, this.contextLevel, this.contextInstanceId, this.courseId);
this.textUtils.viewText(this.fullTitle || this.translate.instant('core.description'), this.text, {
component: this.component,
componentId: this.componentId,
filter: filter,
contextLevel: this.contextLevel,
instanceId: this.contextInstanceId,
courseId: this.courseId,
});
}
}

View File

@ -51,6 +51,7 @@
"contenteditingsynced": "The content you are editing has been synced.",
"continue": "Continue",
"copiedtoclipboard": "Text copied to clipboard",
"copytoclipboard": "Copy to clipboard",
"course": "Course",
"coursedetails": "Course details",
"coursenogroups": "You are not a member of any group of this course.",

View File

@ -441,28 +441,20 @@ export class CoreTextUtilsProvider {
* @param contextLevel The context level.
* @param instanceId The instance ID related to the context.
* @param courseId Course ID the text belongs to. It can be used to improve performance with filters.
* @deprecated since 3.8.3. Please use viewText instead.
*/
expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[],
filter?: boolean, contextLevel?: string, instanceId?: number, courseId?: number): void {
if (text.length > 0) {
const params: any = {
title: title,
content: text,
component: component,
componentId: componentId,
files: files,
filter: filter,
contextLevel: contextLevel,
instanceId: instanceId,
courseId: courseId
};
// Open a modal with the contents.
params.isModal = true;
const modal = this.modalCtrl.create('CoreViewerTextPage', params);
modal.present();
}
return this.viewText(title, text, {
component,
componentId,
files,
filter,
contextLevel,
instanceId,
courseId,
});
}
/**
@ -1133,6 +1125,50 @@ export class CoreTextUtilsProvider {
return _unserialize((data + ''), 0)[2];
}
/**
* Shows a text on a new page.
*
* @param title Title of the new state.
* @param text Content of the text to be expanded.
* @param component Component to link the embedded files to.
* @param componentId An ID to use in conjunction with the component.
* @param files List of files to display along with the text.
* @param filter Whether the text should be filtered.
* @param contextLevel The context level.
* @param instanceId The instance ID related to the context.
* @param courseId Course ID the text belongs to. It can be used to improve performance with filters.
*/
viewText(title: string, text: string, options?: CoreTextUtilsViewTextOptions): void {
if (text.length > 0) {
options = options || {};
const params: any = {
title: title,
content: text,
isModal: true,
};
Object.assign(params, options);
const modal = this.modalCtrl.create('CoreViewerTextPage', params);
modal.present();
}
}
}
/**
* Options for viewText.
*/
export type CoreTextUtilsViewTextOptions = {
component?: string; // Component to link the embedded files to.
componentId?: string | number; // An ID to use in conjunction with the component.
files?: any[]; // List of files to display along with the text.
filter?: boolean; // Whether the text should be filtered.
contextLevel?: string; // The context level.
instanceId?: number; // The instance ID related to the context.
courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters.
displayCopyButton?: boolean; // Whether to display a button to copy the text.
};
export class CoreTextUtils extends makeSingleton(CoreTextUtilsProvider) {}