diff --git a/public/admin/tool/mobile/classes/api.php b/public/admin/tool/mobile/classes/api.php index 11ef7715246..26f431211b6 100644 --- a/public/admin/tool/mobile/classes/api.php +++ b/public/admin/tool/mobile/classes/api.php @@ -324,13 +324,16 @@ class api { $settings->tool_mobile_disabledfeatures = get_config('tool_mobile', 'disabledfeatures'); $settings->tool_mobile_filetypeexclusionlist = get_config('tool_mobile', 'filetypeexclusionlist'); $custommenuitems = get_config('tool_mobile', 'custommenuitems'); + $customusermenuitems = get_config('tool_mobile', 'customusermenuitems'); // If filtering of the primary custom menu is enabled, apply only the string filters. if (!empty($CFG->navfilter && !empty($CFG->stringfilters))) { // Apply filters that are enabled for Content and Headings. $filtermanager = \filter_manager::instance(); $custommenuitems = $filtermanager->filter_string($custommenuitems, \context_system::instance()); + $customusermenuitems = $filtermanager->filter_string($customusermenuitems, \context_system::instance()); } $settings->tool_mobile_custommenuitems = $custommenuitems; + $settings->tool_mobile_customusermenuitems = $customusermenuitems; $settings->tool_mobile_apppolicy = get_config('tool_mobile', 'apppolicy'); // This setting could be not set in some edge cases such as bad upgrade. $mintimereq = get_config('tool_mobile', 'autologinmintimebetweenreq'); diff --git a/public/admin/tool/mobile/classes/output/subscription.php b/public/admin/tool/mobile/classes/output/subscription.php index 572a91ac400..cf31dc3c2e5 100644 --- a/public/admin/tool/mobile/classes/output/subscription.php +++ b/public/admin/tool/mobile/classes/output/subscription.php @@ -121,12 +121,25 @@ class subscription implements \renderable, \templatable { $custommenuitems = explode("\n", $els); // Get unique custom menu urls. $custommenuitems = array_flip( - array_map(function($val) { + array_map(function ($val) { return explode('|', $val)[1]; }, $custommenuitems) ); } - $feature['status'] = count($custommenuitems); + + $customusermenuitems = []; + $els = rtrim($ms->customusermenuitems, "\n"); + if (!empty($els)) { + $customusermenuitems = explode("\n", $els); + // Get unique custom menu urls. + $customusermenuitems = array_flip( + array_map(function ($val) { + return explode('|', $val)[1]; + }, $customusermenuitems) + ); + } + + $feature['status'] = count($custommenuitems) + count($customusermenuitems); break; // Check language strings. case 'customlanguagestrings': diff --git a/public/admin/tool/mobile/lang/en/tool_mobile.php b/public/admin/tool/mobile/lang/en/tool_mobile.php index 06ca328f080..19dd8c6f9f8 100644 --- a/public/admin/tool/mobile/lang/en/tool_mobile.php +++ b/public/admin/tool/mobile/lang/en/tool_mobile.php @@ -45,8 +45,8 @@ $string['configmobilecssurl'] = 'A CSS file to customise your mobile app interfa $string['customlangstrings'] = 'Custom language strings'; $string['customlangstrings_desc'] = 'Words and phrases displayed in the app can be customised here. Enter each custom language string on a new line with format: string identifier, custom language string and language code, separated by pipe characters. For example:
-mm.user.student|Learner|en
-mm.user.student|Aprendiz|es
+core.user.student|Learner|en
+core.user.student|Aprendiz|es
 
For a complete list of string identifiers, see the documentation.'; $string['custommenuitems'] = 'Custom menu items'; @@ -56,6 +56,20 @@ Link-opening methods are: app (for linking to an activity supported by the app), When items are missing a translation for a given language, they will use other languages as fallback unless "_only" is appended to the language code. +For example: +
+App help|https://someurl.xyz/help|inappbrowser
+My grades|https://someurl.xyz/local/mygrades/index.php|embedded|en
+Mis calificaciones|https://someurl.xyz/local/mygrades/index.php|embedded|es
+You will only see this in English|https://someurl.xyz/english|browser|en_only
+
'; +$string['customusermenuitems'] = 'Custom user menu items'; +$string['customusermenuitems_desc'] = 'Additional items can be added to the app\'s user menu by specifying them here. Enter each custom user menu item on a new line with format: item text, link URL, link-opening method and language code (optional, for displaying the item to users of the specified language only), separated by pipe characters. + +Link-opening methods are: app (for linking to an activity supported by the app), inappbrowser (for opening a link in a browser without leaving the app), browser (for opening the link in the device default browser outside the app) and embedded (for displaying the link in an iframe in a new page in the app). + +When items are missing a translation for a given language, they will use other languages as fallback unless "_only" is appended to the language code. + For example:
 App help|https://someurl.xyz/help|inappbrowser
diff --git a/public/admin/tool/mobile/settings.php b/public/admin/tool/mobile/settings.php
index 8055b2f3c18..e0ce32ede18 100644
--- a/public/admin/tool/mobile/settings.php
+++ b/public/admin/tool/mobile/settings.php
@@ -230,9 +230,25 @@ if ($hassiteconfig) {
                 new lang_string('disabledfeatures', 'tool_mobile'),
                 new lang_string('disabledfeatures_desc', 'tool_mobile'), array(), $options));
 
-    $temp->add(new admin_setting_configtextarea('tool_mobile/custommenuitems',
-                new lang_string('custommenuitems', 'tool_mobile'),
-                new lang_string('custommenuitems_desc', 'tool_mobile'), '', PARAM_RAW, '50', '10'));
+    $temp->add(new admin_setting_configtextarea(
+        'tool_mobile/custommenuitems',
+        new lang_string('custommenuitems', 'tool_mobile'),
+        new lang_string('custommenuitems_desc', 'tool_mobile'),
+        '',
+        PARAM_RAW,
+        '50',
+        '10',
+    ));
+
+    $temp->add(new admin_setting_configtextarea(
+        'tool_mobile/customusermenuitems',
+        new lang_string('customusermenuitems', 'tool_mobile'),
+        new lang_string('customusermenuitems_desc', 'tool_mobile'),
+        '',
+        PARAM_RAW,
+        '50',
+        '10',
+    ));
 
     // File type exclusionlist.
     $choices = [];
diff --git a/public/admin/tool/mobile/tests/externallib_test.php b/public/admin/tool/mobile/tests/externallib_test.php
index e260a4af8e6..483aeb23671 100644
--- a/public/admin/tool/mobile/tests/externallib_test.php
+++ b/public/admin/tool/mobile/tests/externallib_test.php
@@ -194,38 +194,39 @@ final class externallib_test extends \core_external\tests\externallib_testcase {
 
         // Test default values.
         $context = \context_system::instance();
-        $expected = array(
-            array('name' => 'fullname', 'value' => $SITE->fullname),
-            array('name' => 'shortname', 'value' => $SITE->shortname),
-            array('name' => 'summary', 'value' => $sitesummary),
-            array('name' => 'summaryformat', 'value' => $summaryformat),
-            array('name' => 'frontpage', 'value' => $CFG->frontpage),
-            array('name' => 'frontpageloggedin', 'value' => $CFG->frontpageloggedin),
-            array('name' => 'maxcategorydepth', 'value' => $CFG->maxcategorydepth),
-            array('name' => 'frontpagecourselimit', 'value' => $CFG->frontpagecourselimit),
-            array('name' => 'numsections', 'value' => course_get_format($SITE)->get_last_section_number()),
-            array('name' => 'newsitems', 'value' => $SITE->newsitems),
-            array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage),
-            array('name' => 'sitepolicy', 'value' => $mysitepolicy),
-            array('name' => 'sitepolicyhandler', 'value' => ''),
-            array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages),
-            array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)),
-            array('name' => 'tool_mobile_forcelogout', 'value' => 0),
-            array('name' => 'tool_mobile_customlangstrings', 'value' => ''),
-            array('name' => 'tool_mobile_disabledfeatures', 'value' => ''),
-            array('name' => 'tool_mobile_filetypeexclusionlist', 'value' => ''),
-            array('name' => 'tool_mobile_custommenuitems', 'value' => ''),
-            array('name' => 'tool_mobile_apppolicy', 'value' => ''),
-            array('name' => 'tool_mobile_autologinmintimebetweenreq', 'value' => 6 * MINSECS),
-            array('name' => 'tool_mobile_autologout', 'value' => get_config('tool_mobile', 'autologout')),
-            array('name' => 'tool_mobile_autologouttime', 'value' => get_config('tool_mobile', 'autologouttime')),
-            array('name' => 'calendartype', 'value' => $CFG->calendartype),
-            array('name' => 'calendar_site_timeformat', 'value' => $CFG->calendar_site_timeformat),
-            array('name' => 'calendar_startwday', 'value' => $CFG->calendar_startwday),
-            array('name' => 'calendar_adminseesall', 'value' => $CFG->calendar_adminseesall),
-            array('name' => 'calendar_lookahead', 'value' => $CFG->calendar_lookahead),
-            array('name' => 'calendar_maxevents', 'value' => $CFG->calendar_maxevents),
-        );
+        $expected = [
+            [ 'name' => 'fullname', 'value' => $SITE->fullname ],
+            [ 'name' => 'shortname', 'value' => $SITE->shortname ],
+            [ 'name' => 'summary', 'value' => $sitesummary ],
+            [ 'name' => 'summaryformat', 'value' => $summaryformat ],
+            [ 'name' => 'frontpage', 'value' => $CFG->frontpage ],
+            [ 'name' => 'frontpageloggedin', 'value' => $CFG->frontpageloggedin ],
+            [ 'name' => 'maxcategorydepth', 'value' => $CFG->maxcategorydepth ],
+            [ 'name' => 'frontpagecourselimit', 'value' => $CFG->frontpagecourselimit ],
+            [ 'name' => 'numsections', 'value' => course_get_format($SITE)->get_last_section_number() ],
+            [ 'name' => 'newsitems', 'value' => $SITE->newsitems ],
+            [ 'name' => 'commentsperpage', 'value' => $CFG->commentsperpage ],
+            [ 'name' => 'sitepolicy', 'value' => $mysitepolicy ],
+            [ 'name' => 'sitepolicyhandler', 'value' => '' ],
+            [ 'name' => 'disableuserimages', 'value' => $CFG->disableuserimages ],
+            [ 'name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false) ],
+            [ 'name' => 'tool_mobile_forcelogout', 'value' => 0 ],
+            [ 'name' => 'tool_mobile_customlangstrings', 'value' => '' ],
+            [ 'name' => 'tool_mobile_disabledfeatures', 'value' => '' ],
+            [ 'name' => 'tool_mobile_filetypeexclusionlist', 'value' => '' ],
+            [ 'name' => 'tool_mobile_custommenuitems', 'value' => '' ],
+            [ 'name' => 'tool_mobile_customusermenuitems', 'value' => '' ],
+            [ 'name' => 'tool_mobile_apppolicy', 'value' => '' ],
+            [ 'name' => 'tool_mobile_autologinmintimebetweenreq', 'value' => 6 * MINSECS ],
+            [ 'name' => 'tool_mobile_autologout', 'value' => get_config('tool_mobile', 'autologout') ],
+            [ 'name' => 'tool_mobile_autologouttime', 'value' => get_config('tool_mobile', 'autologouttime') ],
+            [ 'name' => 'calendartype', 'value' => $CFG->calendartype ],
+            [ 'name' => 'calendar_site_timeformat', 'value' => $CFG->calendar_site_timeformat ],
+            [ 'name' => 'calendar_startwday', 'value' => $CFG->calendar_startwday ],
+            [ 'name' => 'calendar_adminseesall', 'value' => $CFG->calendar_adminseesall ],
+            [ 'name' => 'calendar_lookahead', 'value' => $CFG->calendar_lookahead ],
+            [ 'name' => 'calendar_maxevents', 'value' => $CFG->calendar_maxevents ],
+        ];
         $colornumbers = range(1, 10);
         foreach ($colornumbers as $number) {
             $expected[] = [
diff --git a/public/admin/tool/mobile/version.php b/public/admin/tool/mobile/version.php
index b8330efa391..aa53d539583 100644
--- a/public/admin/tool/mobile/version.php
+++ b/public/admin/tool/mobile/version.php
@@ -23,7 +23,7 @@
  */
 
 defined('MOODLE_INTERNAL') || die();
-$plugin->version   = 2025100600; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version   = 2025102200; // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires  = 2025092600; // Requires this Moodle version.
 $plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
 $plugin->dependencies = [