Merge pull request #3629 from alfonso-salces/MOBILE-4248

Mobile 4248
main
Dani Palou 2023-04-25 10:49:18 +02:00 committed by GitHub
commit 882cbb6473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 156 additions and 13 deletions

View File

@ -524,6 +524,7 @@
"addon.mod_choice.savemychoice": "choice",
"addon.mod_choice.userchoosethisoption": "choice",
"addon.mod_choice.yourselection": "choice",
"addon.mod_data.actions": "data",
"addon.mod_data.addentries": "data",
"addon.mod_data.advancedsearch": "data",
"addon.mod_data.alttext": "data",
@ -567,6 +568,7 @@
"addon.mod_data.search": "data",
"addon.mod_data.searchbytagsnotsupported": "local_moodlemobileapp",
"addon.mod_data.selectedrequired": "data",
"addon.mod_data.showmore": "data",
"addon.mod_data.single": "data",
"addon.mod_data.tagarea_data_records": "data",
"addon.mod_data.timeadded": "data",

View File

@ -23,12 +23,15 @@ import {
AddonModDataAction,
AddonModDataData,
AddonModDataEntry,
AddonModDataGetDataAccessInformationWSResponse,
AddonModDataProvider,
AddonModDataTemplateMode,
} from '../../services/data';
import { AddonModDataHelper } from '../../services/data-helper';
import { AddonModDataOffline } from '../../services/data-offline';
import { AddonModDataModuleHandlerService } from '../../services/handlers/module';
import { CoreDomUtils } from '@services/utils/dom';
import { AddonModDataActionsMenuComponent, AddonModDataActionsMenuItem } from '../actionsmenu/actionsmenu';
/**
* Component that displays a database action.
@ -39,6 +42,7 @@ import { AddonModDataModuleHandlerService } from '../../services/handlers/module
})
export class AddonModDataActionComponent implements OnInit {
@Input() access?: AddonModDataGetDataAccessInformationWSResponse; // Access info.
@Input() mode!: AddonModDataTemplateMode; // The render mode.
@Input() action!: AddonModDataAction; // The field to render.
@Input() entry!: AddonModDataEntry; // The value of the field.
@ -139,4 +143,66 @@ export class AddonModDataActionComponent implements OnInit {
CoreEvents.trigger(AddonModDataProvider.ENTRY_CHANGED, { dataId: dataId, entryId: entryId }, this.siteId);
}
/**
* Open actions menu popover.
*/
async actionsMenu(): Promise<void> {
const items: AddonModDataActionsMenuItem[] = [];
if (this.entry.canmanageentry) {
items.push(
this.entry.deleted
? {
action: () => this.undoDelete(),
text: 'core.restore',
icon: 'fas-rotate-left',
}
: {
action: () => this.deleteEntry(),
text: 'core.delete',
icon: 'fas-trash',
},
);
if (!this.entry.deleted) {
items.unshift({
action: () => this.editEntry(),
text: 'core.edit',
icon: 'fas-pen',
});
}
}
if (this.database.approval && this.access?.canapprove && !this.entry.deleted) {
items.push(
!this.entry.approved
? {
action: () => this.approveEntry(),
text: 'addon.mod_data.approve',
icon: 'fas-thumbs-up',
}
: {
action: () => this.disapproveEntry(),
text: 'addon.mod_data.disapprove',
icon: 'far-thumbs-down',
},
);
}
if (this.mode === AddonModDataTemplateMode.LIST) {
items.unshift({
action: () => this.viewEntry(),
text: 'addon.mod_data.showmore',
icon: 'fas-magnifying-glass-plus',
});
}
await CoreDomUtils.openPopover({
component: AddonModDataActionsMenuComponent,
componentProps: { items },
showBackdrop: true,
id: 'actionsmenu-popover',
});
}
}

View File

@ -1,4 +1,10 @@
<ion-button size="small" *ngIf="action == 'more'" fill="clear" (click)="viewEntry()" [attr.aria-label]="'addon.mod_data.more' | translate">
<ion-button size="small" *ngIf="action == 'actionsmenu'" fill="clear" (click)="actionsMenu()"
[attr.aria-label]="'addon.mod_data.actions' | translate">
<ion-icon name="fas-ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>
<ion-button size="small" *ngIf="action == 'more'" fill="clear" (click)="viewEntry()"
[attr.aria-label]="'addon.mod_data.showmore' | translate">
<ion-icon name="fas-magnifying-glass-plus" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>

View File

@ -0,0 +1,9 @@
<ion-list>
<ion-item button class="ion-text-wrap" (click)="onItemClick(item)" *ngFor="let item of items" detail="false"
[attr.aria-label]="item.text | translate">
<ion-label>
<p class="item-heading">{{ item.text | translate }}</p>
</ion-label>
<ion-icon [name]="item.icon" slot="end" aria-hidden="true"></ion-icon>
</ion-item>
</ion-list>

View File

@ -0,0 +1,45 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input } from '@angular/core';
import { PopoverController } from '@singletons';
/**
* Component that displays the actionsmenu.
*/
@Component({
selector: 'addon-mod-data-actionsmenu',
templateUrl: 'actionsmenu.html',
})
export class AddonModDataActionsMenuComponent {
@Input() items: AddonModDataActionsMenuItem[] = [];
/**
* Execute item action and dismiss the popover.
*
* @param item item from which the action will be executed.
*/
async onItemClick(item: AddonModDataActionsMenuItem): Promise<void> {
item.action();
await PopoverController.dismiss();
}
}
export interface AddonModDataActionsMenuItem {
text: string;
icon: string;
action: () => void;
};

View File

@ -18,11 +18,13 @@ import { CoreCourseComponentsModule } from '@features/course/components/componen
import { AddonModDataIndexComponent } from './index';
import { AddonModDataSearchComponent } from './search/search';
import { CoreCompileHtmlComponentModule } from '@features/compile/components/compile-html/compile-html.module';
import { AddonModDataActionsMenuComponent } from './actionsmenu/actionsmenu';
@NgModule({
declarations: [
AddonModDataIndexComponent,
AddonModDataSearchComponent,
AddonModDataActionsMenuComponent,
],
imports: [
CoreSharedModule,
@ -32,6 +34,7 @@ import { CoreCompileHtmlComponentModule } from '@features/compile/components/com
exports: [
AddonModDataIndexComponent,
AddonModDataSearchComponent,
AddonModDataActionsMenuComponent,
],
})
export class AddonModDataComponentsModule {}

View File

@ -95,6 +95,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
database: AddonModDataData;
title: string;
group: number;
access: AddonModDataGetDataAccessInformationWSResponse | undefined;
gotoEntry: (entryId: number) => void;
};
@ -348,7 +349,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
this.entries.forEach((entry, index) => {
entriesById[entry.id] = entry;
const actions = AddonModDataHelper.getActions(this.database!, this.access!, entry);
const actions = AddonModDataHelper.getActions(this.database!, this.access!, entry, AddonModDataTemplateMode.LIST);
const options: AddonModDatDisplayFieldsOptions = {};
if (!this.search.searching) {
options.offset = this.search.page * AddonModDataProvider.PER_PAGE + index - numOfflineEntries;
@ -375,6 +376,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
database: this.database!,
title: this.module.name,
group: this.selectedGroup,
access: this.access,
gotoEntry: (entryId) => this.gotoEntry(entryId),
};
} else if (!this.search.searching) {

View File

@ -1,4 +1,5 @@
{
"actions": "Actions menu",
"addentries": "Add entries",
"advancedsearch": "Advanced search",
"alttext": "Alternative text",
@ -42,6 +43,7 @@
"search": "Search",
"searchbytagsnotsupported": "Sorry, searching by tags is not supported by the app.",
"selectedrequired": "All selected required",
"showmore": "Show more",
"single": "View single",
"tagarea_data_records": "Data records",
"timeadded": "Time added",

View File

@ -86,6 +86,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
database: AddonModDataData;
title: string;
group: number;
access: AddonModDataGetDataAccessInformationWSResponse | undefined;
};
ratingInfo?: CoreRatingInfo;
@ -187,7 +188,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
this.selectedGroup = CoreGroups.validateGroupId(this.selectedGroup, this.groupInfo);
const actions = AddonModDataHelper.getActions(this.database, this.access, this.entry!);
const actions = AddonModDataHelper.getActions(this.database, this.access, this.entry!, AddonModDataTemplateMode.SHOW);
const template = AddonModDataHelper.getTemplate(this.database, AddonModDataTemplateType.SINGLE, this.fieldsArray);
this.entryHtml = AddonModDataHelper.displayShowFields(
@ -215,6 +216,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
database: this.database,
title: this.title,
group: this.selectedGroup,
access: this.access,
};
if (this.logAfterFetch) {

View File

@ -234,7 +234,7 @@ export class AddonModDataHelperProvider {
render = Translate.instant('addon.mod_data.' + (entry.approved ? 'approved' : 'notapproved'));
} else {
render = `<addon-mod-data-action action="${action}" [entry]="entries[${entry.id}]" mode="${mode}" ` +
'[database]="database" [title]="title" ' +
'[database]="database" [access]="access" [title]="title" ' +
(options.offset !== undefined ? `[offset]="${options.offset}" ` : '') +
(options.sortBy !== undefined ? `[sortBy]="${options.sortBy}" ` : '') +
(options.sortDirection !== undefined ? `sortDirection="${options.sortDirection}" ` : '') +
@ -407,6 +407,7 @@ export class AddonModDataHelperProvider {
database: AddonModDataData,
accessInfo: AddonModDataGetDataAccessInformationWSResponse,
entry: AddonModDataEntry,
mode: AddonModDataTemplateMode,
): Record<AddonModDataAction, boolean> {
return {
add: false, // Not directly used on entries.
@ -426,6 +427,10 @@ export class AddonModDataHelperProvider {
approvalstatus: database.approval,
comments: database.comments,
actionsmenu: entry.canmanageentry
|| (database.approval && accessInfo.canapprove && !entry.deleted)
|| mode === AddonModDataTemplateMode.LIST,
// Unsupported actions.
delcheck: false,
export: false,
@ -497,7 +502,7 @@ export class AddonModDataHelperProvider {
html.push(
'<tr class="lastrow">',
'<td class="controls template-field cell c0 lastcol" style="" colspan="2">',
'##edit## ##more## ##delete## ##approve## ##disapprove## ##export##',
'##actionsmenu## ##edit## ##more## ##delete## ##approve## ##disapprove## ##export##',
'</td>',
'</tr>',
);
@ -505,7 +510,7 @@ export class AddonModDataHelperProvider {
html.push(
'<tr class="lastrow">',
'<td class="controls template-field cell c0 lastcol" style="" colspan="2">',
'##edit## ##delete## ##approve## ##disapprove## ##export##',
'##actionsmenu## ##edit## ##delete## ##approve## ##disapprove## ##export##',
'</td>',
'</tr>',
);

View File

@ -62,6 +62,7 @@ export enum AddonModDataAction {
APPROVALSTATUS = 'approvalstatus',
DELCHECK = 'delcheck', // Unused.
EXPORT = 'export', // Unused.
ACTIONSMENU = 'actionsmenu',
}
export enum AddonModDataTemplateType {

View File

@ -52,7 +52,7 @@ Feature: Users can manage entries in database activities
| URL | https://moodlecloud.com/ |
| Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
And I press "More" near "Moodle community site" in the app
And I press "Show more" near "Moodle community site" in the app
Then I should find "Moodle community site" in the app
And I should be able to press "Previous" in the app
But I should not be able to press "Next" in the app
@ -81,7 +81,7 @@ Feature: Users can manage entries in database activities
When I press "Web links" near "General" in the app
Then "Edit" "link" should not exist
And "Delete" "link" should not exist
And I press "More" in the app
And I press "Show more" in the app
And "Edit" "link" should not exist
And "Delete" "link" should not exist
@ -122,7 +122,7 @@ Feature: Users can manage entries in database activities
And I press "Save" near "Web links" in the app
# Edit the entry from single view.
When I press "More" in the app
When I press "Show more" in the app
And I press "Edit" in the app
And I set the following fields to these values in the app:
| URL | https://moodlecloud.com/ |
@ -184,7 +184,7 @@ Feature: Users can manage entries in database activities
And I should not find "Moodle Cloud" in the app
# Edit the entry from single view.
When I press "More" in the app
When I press "Show more" in the app
And I should find "https://telegram.org/" in the app
And I should find "Telegram" in the app
And I press "Edit" in the app

View File

@ -32,7 +32,7 @@ Feature: Test basic usage of comments in app
And I press "Add entries" in the app
And I set the field "Test field name" to "Test" in the app
And I press "Save" in the app
And I press "More" in the app
And I press "Show more" in the app
And I press "Comments (0)" in the app
And I set the field "Add a comment..." to "comment test teacher" in the app
And I press "Send" in the app
@ -44,7 +44,7 @@ Feature: Test basic usage of comments in app
# Create and delete comments as a student
Given I entered the data activity "Data" on course "Course 1" as "student1" in the app
And I press "More" in the app
And I press "Show more" in the app
And I press "Comments (1)" in the app
And I set the field "Add a comment..." to "comment test student" in the app
And I press "Send" in the app
@ -69,7 +69,7 @@ Feature: Test basic usage of comments in app
And I press "Add entries" in the app
And I set the field "Test field name" to "Test" in the app
And I press "Save" in the app
And I press "More" in the app
And I press "Show more" in the app
And I press "Comments (0)" in the app
And I switch network connection to offline
And I set the field "Add a comment..." to "comment test" in the app