diff --git a/CHANGELOG.md b/CHANGELOG.md
index 845ba97..161d55a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,18 @@
## [Unreleased]
+## 2.3.0
+### Added
+- fix #82: add an option to keep visible an app in both menus
+- fix #83: add custom categories
+- add auto-reload when settings are saved
+
## 2.2.0
### Added
- fix #84: update icons
- fix #85: use Nextcloud colors by default
### Fixed
-- Fix categories order in large menu
+- fix categories order in large menu
## 2.1.0
### Added
diff --git a/README.md b/README.md
index 2e359f4..62f0ad9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
===============================
Allows you to modify the position of the main menu by creating a panel on the left of the interface or with a big menu on the top.
-You can also define apps that must be displayed in the top menu. Fully customisable.
+You can also add and sort custom categories, define apps that must be displayed in the top menu, etc. Fully customisable.
This application is rather suitable for instances that activate a lot of applications.
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 126024d..e65d4cd 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -26,7 +26,7 @@ If you like this application and if you want to support the development:
* [Donate with liberapay](https://liberapay.com/deblan)
* [Leave a comment](https://apps.nextcloud.com/apps/side_menu#comments)
]]>
- 2.2.0
+ 2.3.0agplSimon VieilleSideMenu
diff --git a/css/admin.css b/css/admin.css
index a15aa64..82c6b31 100644
--- a/css/admin.css
+++ b/css/admin.css
@@ -97,6 +97,10 @@
margin-top: -1px;
}
+#apps-categories-custom-list select {
+ width: 100%;
+}
+
.side-menu-setting-table {
display: table;
@@ -115,7 +119,7 @@
.side-menu-setting-form {
display: table-cell;
- width: 300px;
+ min-width: 300px;
}
.side-menu-setting-label-short {
diff --git a/lib/Controller/JsController.php b/lib/Controller/JsController.php
index 135b1ab..c873826 100644
--- a/lib/Controller/JsController.php
+++ b/lib/Controller/JsController.php
@@ -94,6 +94,7 @@ class JsController extends Controller
protected function getConfig(): array
{
$topMenuApps = $this->config->getAppValueArray('top-menu-apps', '[]');
+ $topSideMenuApps = $this->config->getAppValueArray('top-side-menu-apps', '[]');
$targetBlankApps = $this->config->getAppValueArray('target-blank-apps', '[]');
$useAvatar = $this->config->getAppValueBool('use-avatar', '0');
$isForced = $this->config->getAppValueBool('force', '0');
@@ -103,11 +104,16 @@ class JsController extends Controller
if ($this->user) {
$userTopMenuApps = $this->config->getUserValueArray($this->user, 'top-menu-apps', '[]');
+ $userTopSideMenuApps = $this->config->getUserValueArray($this->user, 'top-side-menu-apps', '[]');
if (!empty($userTopMenuApps) && !$isForced) {
$topMenuApps = $userTopMenuApps;
}
+ if (!empty($userTopSideMenuApps) && !$isForced) {
+ $topSideMenuApps = $userTopSideMenuApps;
+ }
+
$userTargetBlankMode = $this->config->getUserValueInt($this->user, 'target-blank-mode', '1');
$userTargetBlankApps = $this->config->getUserValueArray($this->user, 'target-blank-apps', '[]');
@@ -157,6 +163,7 @@ class JsController extends Controller
'big-menu-hidden-apps' => $this->config->getAppValueArray('big-menu-hidden-apps', '[]'),
'avatar' => $avatar,
'top-menu-apps' => $topMenuApps,
+ 'top-side-menu-apps' => $topSideMenuApps,
'target-blank-apps' => $targetBlankApps,
'settings' => $settings,
'logo' => $this->themingDefaults->getLogo(),
diff --git a/lib/Controller/PersonalSettingController.php b/lib/Controller/PersonalSettingController.php
index 90fb758..bdc9fca 100644
--- a/lib/Controller/PersonalSettingController.php
+++ b/lib/Controller/PersonalSettingController.php
@@ -97,7 +97,7 @@ class PersonalSettingController extends Controller
}
}
- if ('top-menu-apps' === $name) {
+ if (in_array($name, ['top-menu-apps', 'top-side-menu-apps'])) {
$doSave = true;
$data = json_decode($value, true);
diff --git a/lib/Service/AppRepository.php b/lib/Service/AppRepository.php
index 93c8f9c..d91ec75 100644
--- a/lib/Service/AppRepository.php
+++ b/lib/Service/AppRepository.php
@@ -21,10 +21,27 @@ class AppRepository
*/
protected $l10nFactory;
- public function __construct(\OC_App $ocApp, IFactory $l10nFactory)
+ /**
+ * @var ConfigProxy
+ */
+ protected $config;
+
+ /**
+ * @var CategoryRepository
+ */
+ protected $categoryRepository;
+
+ public function __construct(
+ \OC_App $ocApp,
+ IFactory $l10nFactory,
+ ConfigProxy $config,
+ CategoryRepository $categoryRepository
+ )
{
$this->ocApp = $ocApp;
$this->l10nFactory = $l10nFactory;
+ $this->config = $config;
+ $this->categoryRepository = $categoryRepository;
}
/**
@@ -35,6 +52,9 @@ class AppRepository
public function getVisibleApps()
{
$navigation = $this->ocApp->getNavigation();
+ $appCategoriesCustom = $this->config->getAppValueArray('apps-categories-custom', '[]');
+ $categoriesCustom = $this->config->getAppValueArray('categories-custom', '[]');
+ $categories = $this->categoryRepository->getOrderedCategories();
$apps = $this->ocApp->listAllApps();
$visibleApps = [];
@@ -74,6 +94,12 @@ class AppRepository
}
}
+ foreach ($visibleApps as $id => $app) {
+ if (isset($appCategoriesCustom[$id], $categories[$appCategoriesCustom[$id]])) {
+ $visibleApps[$id]['category'] = [$appCategoriesCustom[$id]];
+ }
+ }
+
usort($visibleApps, function ($a, $b) {
return ($a['name'] < $b['name']) ? -1 : 1;
});
diff --git a/lib/Service/CategoryRepository.php b/lib/Service/CategoryRepository.php
index 3e67e63..7559854 100644
--- a/lib/Service/CategoryRepository.php
+++ b/lib/Service/CategoryRepository.php
@@ -5,6 +5,7 @@ namespace OCA\SideMenu\Service;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OCA\SideMenu\AppInfo\Application;
use OCP\IConfig;
+use OCP\IUserSession;
use OCP\L10N\IFactory;
/**
@@ -34,16 +35,23 @@ class CategoryRepository
*/
protected $iConfig;
+ /**
+ * @var IUserSession
+ */
+ protected $userSession;
+
public function __construct(
CategoryFetcher $categoryFetcher,
ConfigProxy $config,
IConfig $iConfig,
- IFactory $l10nFactory
+ IFactory $l10nFactory,
+ IUserSession $userSession
) {
$this->categoryFetcher = $categoryFetcher;
$this->l10nFactory = $l10nFactory;
$this->config = $config;
$this->iConfig = $iConfig;
+ $this->userSession = $userSession;
}
/**
@@ -56,8 +64,8 @@ class CategoryRepository
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$type = $this->config->getAppValue('categories-order-type', 'default');
$order = $this->config->getAppValueArray('categories-order', '[]');
-
$categoriesLabels = $this->config->getAppValueArray('cache-categories', '[]');
+ $customCategories = $this->config->getAppValueArray('categories-custom', '[]');
if (empty($categoriesLabels)) {
$categoriesLabels = $this->categoryFetcher->get();
@@ -74,6 +82,18 @@ class CategoryRepository
$categoriesLabels['external_links'] = $this->l10nFactory->get('external')->t('External sites');
$categoriesLabels['other'] = '';
+ $user = $this->userSession->getUser();
+
+ if ($user) {
+ $lang = $this->iConfig->getUserValue($user->getUid(), 'core', 'lang');
+ } else {
+ $lang = 'en';
+ }
+
+ foreach ($customCategories as $category) {
+ $categoriesLabels[$category['id']] = $category[$lang] ?? $category['en'];
+ }
+
asort($categoriesLabels);
if ('custom' === $type) {
diff --git a/lib/Service/LangRepository.php b/lib/Service/LangRepository.php
new file mode 100644
index 0000000..c998a7e
--- /dev/null
+++ b/lib/Service/LangRepository.php
@@ -0,0 +1,43 @@
+
+ */
+class LangRepository
+{
+ /**
+ * @var IDBConnection
+ */
+ protected $db;
+
+ public function __construct(IDBConnection $db)
+ {
+ $this->db = $db;
+ }
+
+ public function getUsedLangs(): array
+ {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select($qb->createFunction('DISTINCT configvalue'))
+ ->where('configkey="lang" and appid="core" and configvalue<>"en"')
+ ->from('preferences')
+ ;
+
+ $stmt = $qb->execute();
+
+ $langs = ['en'];
+
+ foreach ($stmt->fetchAll() as $result) {
+ $langs[] = $result['configvalue'];
+ }
+
+ return $langs;
+ }
+}
diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php
index e7a2bab..d0a532b 100644
--- a/lib/Settings/Admin.php
+++ b/lib/Settings/Admin.php
@@ -28,6 +28,7 @@ use OCP\ILogger;
use OCP\Settings\ISettings;
use OCA\Theming\ThemingDefaults;
use OCA\SideMenu\Service\Color;
+use OCA\SideMenu\Service\LangRepository;
class Admin implements ISettings
{
@@ -66,6 +67,11 @@ class Admin implements ISettings
*/
protected $color;
+ /**
+ * @var LangRepository
+ */
+ protected $langRepository;
+
public function __construct(
IL10N $l,
ILogger $logger,
@@ -73,7 +79,8 @@ class Admin implements ISettings
AppRepository $appRepository,
CategoryRepository $categoryRepository,
ThemingDefaults $theming,
- Color $color
+ Color $color,
+ LangRepository $langRepository
) {
$this->l = $l;
$this->logger = $logger;
@@ -82,6 +89,7 @@ class Admin implements ISettings
$this->categoryRepository = $categoryRepository;
$this->theming = $theming;
$this->color = $color;
+ $this->langRepository = $langRepository;
}
/**
@@ -139,11 +147,15 @@ class Admin implements ISettings
'force' => $this->config->getAppValue('force', '0'),
'target-blank-apps' => $this->config->getAppValueArray('target-blank-apps', '[]'),
'top-menu-apps' => $this->config->getAppValueArray('top-menu-apps', '[]'),
+ 'top-side-menu-apps' => $this->config->getAppValueArray('top-side-menu-apps', '[]'),
'default-enabled' => $this->config->getAppValue('default-enabled', '1'),
+ 'apps' => $this->appRepository->getVisibleApps(),
+ 'apps-categories-custom' => $this->config->getAppValueArray('apps-categories-custom', '[]'),
'categories-order-type' => $this->config->getAppValue('categories-order-type', 'default'),
'categories-order' => $this->config->getAppValueArray('categories-order', '[]'),
- 'apps' => $this->appRepository->getVisibleApps(),
+ 'categories-custom' => $this->config->getAppValueArray('categories-custom', '[]'),
'categories' => $this->categoryRepository->getOrderedCategories(),
+ 'langs' => $this->langRepository->getUsedLangs(),
];
return new TemplateResponse(Application::APP_ID, 'settings/admin-form', $parameters, '');
diff --git a/lib/Settings/Personal.php b/lib/Settings/Personal.php
index 2b34bb2..9ac24c7 100644
--- a/lib/Settings/Personal.php
+++ b/lib/Settings/Personal.php
@@ -78,6 +78,7 @@ class Personal implements ISettings
$this->config->getAppValue('default-enabled', '1')
),
'top-menu-apps' => $this->config->getUserValueArray($user, 'top-menu-apps', '[]'),
+ 'top-side-menu-apps' => $this->config->getUserValueArray($user, 'top-side-menu-apps', '[]'),
'target-blank-mode' => $this->config->getUserValue($user, 'target-blank-mode', '1'),
'target-blank-apps' => $this->config->getUserValueArray($user, 'target-blank-apps', '[]'),
'apps' => $this->appRepository->getVisibleApps(),
diff --git a/package.json b/package.json
index e87767d..f38078f 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@nextcloud/axios": "^1.8.0",
- "@nextcloud/vue": "^1.4.0",
+ "@nextcloud/vue": "^1.5.0",
"axios": "^0.24.0",
"trim": "0.0.1",
"vue": "^2.6.11"
diff --git a/src/AdminCategoriesCustom.vue b/src/AdminCategoriesCustom.vue
new file mode 100644
index 0000000..909580d
--- /dev/null
+++ b/src/AdminCategoriesCustom.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/admin.js b/src/admin.js
index 2d63eca..b7b5982 100644
--- a/src/admin.js
+++ b/src/admin.js
@@ -15,6 +15,12 @@
* along with this program. If not, see .
*/
+import AdminCategoriesCustom from './AdminCategoriesCustom.vue'
+import Vue from 'vue'
+
+Vue.prototype.OC = window.OC
+Vue.prototype.OCA = window.OCA
+
let elements = []
const selector = '#side-menu-message'
@@ -80,10 +86,11 @@ const saveSettings = (key) => {
t('side_menu', (key + 1) + '/' + size)
)
- if (key < size) {
+ if (key < size - 1) {
saveSettings(key + 1)
} else {
- OC.msg.finishedSuccess(selector, t('side_menu', 'Saved'))
+ OC.msg.finishedSuccess(selector, t('side_menu', 'Saved! Page is reloading...'))
+ location.reload()
}
},
error: () => {
@@ -108,7 +115,29 @@ const elementToggler = (element) => {
element.style.display = display
}
+const updateAppsCategoriesCustom = () => {
+ let values = {}
+
+ for (let item of document.querySelectorAll('.apps-categories-custom')) {
+ let app = item.getAttribute('data-app')
+ let value = item.value
+
+ if (value) {
+ values[app] = value
+ }
+ }
+
+ document.querySelector('#apps-categories-custom').value = JSON.stringify(values)
+}
+
document.addEventListener('DOMContentLoaded', () => {
+ if (document.querySelector('#side-menu-categories-custom')) {
+ const View = Vue.extend(AdminCategoriesCustom)
+ const adminCategoriesCustom = new View({})
+
+ adminCategoriesCustom.$mount('#side-menu-categories-custom')
+ }
+
elements = document.querySelectorAll('.side-menu-setting')
document.querySelector('#side-menu-save').addEventListener('click', (event) => {
@@ -134,6 +163,12 @@ document.addEventListener('DOMContentLoaded', () => {
})
}
+ for (let item of document.querySelectorAll('.apps-categories-custom')) {
+ item.addEventListener('change', (event) => {
+ updateAppsCategoriesCustom()
+ })
+ }
+
for (let item of document.querySelectorAll('.side-menu-setting-live')) {
item.addEventListener('change', (event) => {
const target = event.target
@@ -196,6 +231,7 @@ document.addEventListener('DOMContentLoaded', () => {
let value = []
for (let item of document.querySelectorAll('#categories-list .side-menu-setting-list-item')) {
+ console.log(item.getAttribute('data-id'))
value.push(item.getAttribute('data-id'))
}
diff --git a/src/l10n/fixtures/cs.yaml b/src/l10n/fixtures/cs.yaml
index 215c0e3..11fc4b1 100644
--- a/src/l10n/fixtures/cs.yaml
+++ b/src/l10n/fixtures/cs.yaml
@@ -77,3 +77,8 @@
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Tyto parametry jsou použity v případě, že je zapnutý (Breeze) tmavý motiv vzhledu."
"Dark mode colors": "Barvy tmavého režimu"
"With categories": "S kategoriemi"
+"Custom categories": "Vlastní kategorie"
+"Customize application categories": "Personnaliser les catégories des applications"
+"Customize application categories": "Přizpůsobte kategorie aplikací"
+"Apps only visible in the top menu": "Aplikace jsou viditelné pouze v horní nabídce "
+"Apps visible in the top and side menus": "Aplikace viditelné v horní a boční nabídce"
diff --git a/src/l10n/fixtures/de.yaml b/src/l10n/fixtures/de.yaml
index 5d8353a..eb30f55 100644
--- a/src/l10n/fixtures/de.yaml
+++ b/src/l10n/fixtures/de.yaml
@@ -77,3 +77,7 @@
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Diese Optionen werden auf Dark Theme oder Breeze Dark Theme angewendet."
"Dark mode colors": "Farben für den dunklen Modus"
"With categories": "Mit Kategorien"
+"Custom categories": "Benutzerdefinierte Kategorien"
+"Customize application categories": "Anwendungskategorien anpassen"
+"Apps only visible in the top menu": "Apps nur im oberen Menü sichtbar "
+"Apps visible in the top and side menus": "Apps im oberen und seitlichen Menü sichtbar"
diff --git a/src/l10n/fixtures/fr.yaml b/src/l10n/fixtures/fr.yaml
index 56b286e..9b6a6c0 100644
--- a/src/l10n/fixtures/fr.yaml
+++ b/src/l10n/fixtures/fr.yaml
@@ -77,3 +77,7 @@
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "Ces paramètres sont utilisés lorsque le thème sombre ou le thème Breeze Dark sont activés."
"Dark mode colors": "Couleurs du mode sombre"
"With categories": "Avec les catégories"
+"Custom categories": "Catégories personnalisées"
+"Customize application categories": "Personnaliser les catégories des applications"
+"Apps only visible in the top menu": "Applications visibles uniquement dans le menu supérieur"
+"Apps visible in the top and side menus": "Applications visibles dans le menus supérieur et latéral"
diff --git a/src/l10n/fixtures/zh_CN.yaml b/src/l10n/fixtures/zh_CN.yaml
index 969583d..294157a 100644
--- a/src/l10n/fixtures/zh_CN.yaml
+++ b/src/l10n/fixtures/zh_CN.yaml
@@ -77,3 +77,7 @@
"This parameters are used when Dark theme or Breeze Dark Theme are enabled.": "此参数将应用于暗黑主题激活时。"
"Dark mode colors": "暗黑模式颜色"
"With categories": "有类别"
+"Custom categories": "自定义类别"
+"Customize application categories": "自定义应用程序类别"
+"Apps only visible in the top menu": "应用程序仅在顶部菜单中可见"
+"Apps visible in the top and side menus": "顶部和侧边菜单中可见的应用程序"
diff --git a/templates/js/_topMenuApps.js b/templates/js/_topMenuApps.js
index 043eb58..85ed332 100644
--- a/templates/js/_topMenuApps.js
+++ b/templates/js/_topMenuApps.js
@@ -52,7 +52,7 @@ const updateTopMenu = function() {
continue
}
- if (topMenuApps.indexOf(dataId) === -1) {
+ if (topMenuApps.indexOf(dataId) === -1 && topSideMenuApps.indexOf(dataId) === -1) {
app.classList.add('hidden')
app.classList.add('app-hidden')
} else {
diff --git a/templates/js/script.php b/templates/js/script.php
index 8f22477..e133d10 100644
--- a/templates/js/script.php
+++ b/templates/js/script.php
@@ -186,8 +186,9 @@ if ($_['always-displayed']) {
nextcloud.parentNode.insertBefore(sideMenuOpener, nextcloud.nextSibling)
-
- const topMenuApps =
+
+ const topMenuApps =
+ const topSideMenuApps =
diff --git a/templates/settings/admin-form.php b/templates/settings/admin-form.php
index 9b53d7d..1aa2d94 100644
--- a/templates/settings/admin-form.php
+++ b/templates/settings/admin-form.php
@@ -497,7 +497,6 @@ $choicesSizes = [
t('Not compatible with touch screens.')); ?>
@@ -731,7 +730,7 @@ $choicesSizes = [
- t('Apps that not must be moved in the side menu')); ?>
+ t('Apps only visible in the top menu')); ?>