mirror of
https://github.com/nextcloud/server.git
synced 2026-04-02 07:35:13 -04:00
Port settings to Modal
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
This commit is contained in:
parent
887c9e05de
commit
5c987a0ff4
18 changed files with 429 additions and 237 deletions
|
|
@ -90,6 +90,16 @@ $application->registerRoutes(
|
|||
'url' => '/api/v1/recent/',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'API#setConfig',
|
||||
'url' => '/api/v1/config/{key}',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'API#getConfigs',
|
||||
'url' => '/api/v1/configs',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'API#updateFileSorting',
|
||||
'url' => '/api/v1/sorting',
|
||||
|
|
|
|||
|
|
@ -58,5 +58,6 @@ return array(
|
|||
'OCA\\Files\\Service\\DirectEditingService' => $baseDir . '/../lib/Service/DirectEditingService.php',
|
||||
'OCA\\Files\\Service\\OwnershipTransferService' => $baseDir . '/../lib/Service/OwnershipTransferService.php',
|
||||
'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php',
|
||||
'OCA\\Files\\Service\\UserConfig' => $baseDir . '/../lib/Service/UserConfig.php',
|
||||
'OCA\\Files\\Settings\\PersonalSettings' => $baseDir . '/../lib/Settings/PersonalSettings.php',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class ComposerStaticInitFiles
|
|||
'OCA\\Files\\Service\\DirectEditingService' => __DIR__ . '/..' . '/../lib/Service/DirectEditingService.php',
|
||||
'OCA\\Files\\Service\\OwnershipTransferService' => __DIR__ . '/..' . '/../lib/Service/OwnershipTransferService.php',
|
||||
'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php',
|
||||
'OCA\\Files\\Service\\UserConfig' => __DIR__ . '/..' . '/../lib/Service/UserConfig.php',
|
||||
'OCA\\Files\\Settings\\PersonalSettings' => __DIR__ . '/..' . '/../lib/Settings/PersonalSettings.php',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,11 +56,6 @@
|
|||
var showHidden = $('#showHiddenFiles').val() === "1";
|
||||
this.$showHiddenFiles.prop('checked', showHidden);
|
||||
|
||||
// crop image previews
|
||||
this.$cropImagePreviews = $('input#cropimagepreviewsToggle');
|
||||
var cropImagePreviews = $('#cropImagePreviews').val() === "1";
|
||||
this.$cropImagePreviews.prop('checked', cropImagePreviews);
|
||||
|
||||
// Toggle for grid view
|
||||
this.$showGridView = $('input#showgridview');
|
||||
this.$showGridView.on('change', _.bind(this._onGridviewChange, this));
|
||||
|
|
@ -69,10 +64,7 @@
|
|||
OC.Notification.show(t('files', 'File could not be found'), {type: 'error'});
|
||||
}
|
||||
|
||||
this._filesConfig = new OC.Backbone.Model({
|
||||
showhidden: showHidden,
|
||||
cropimagepreviews: cropImagePreviews,
|
||||
});
|
||||
this._filesConfig = OCP.InitialState.loadState('files', 'config', {})
|
||||
|
||||
var urlParams = OC.Util.History.parseUrlQuery();
|
||||
var fileActions = new OCA.Files.FileActions();
|
||||
|
|
@ -223,8 +215,8 @@
|
|||
* Sets the currently active view
|
||||
* @param viewId view id
|
||||
*/
|
||||
setActiveView: function(viewId, options) {
|
||||
window._nc_event_bus.emit('files:view:changed', { id: viewId })
|
||||
setActiveView: function(viewId) {
|
||||
window._nc_event_bus.emit('files:navigation:changed', { id: viewId })
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -254,57 +246,6 @@
|
|||
$('#app-content').delegate('>div', 'changeDirectory', _.bind(this._onDirectoryChanged, this));
|
||||
$('#app-content').delegate('>div', 'afterChangeDirectory', _.bind(this._onAfterDirectoryChanged, this));
|
||||
$('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this));
|
||||
|
||||
window._nc_event_bus.subscribe('files:view:changed', _.bind(this._onNavigationChanged, this))
|
||||
$('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this));
|
||||
this.$showHiddenFiles.on('change', _.bind(this._onShowHiddenFilesChange, this));
|
||||
this.$cropImagePreviews.on('change', _.bind(this._onCropImagePreviewsChange, this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle showing hidden files according to the settings checkbox
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
_onShowHiddenFilesChange: function() {
|
||||
var show = this.$showHiddenFiles.is(':checked');
|
||||
this._filesConfig.set('showhidden', show);
|
||||
this._debouncedPersistShowHiddenFilesState();
|
||||
},
|
||||
|
||||
/**
|
||||
* Persist show hidden preference on the server
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
_persistShowHiddenFilesState: function() {
|
||||
var show = this._filesConfig.get('showhidden');
|
||||
$.post(OC.generateUrl('/apps/files/api/v1/showhidden'), {
|
||||
show: show
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle cropping image previews according to the settings checkbox
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_onCropImagePreviewsChange: function() {
|
||||
var crop = this.$cropImagePreviews.is(':checked');
|
||||
this._filesConfig.set('cropimagepreviews', crop);
|
||||
this._debouncedPersistCropImagePreviewsState();
|
||||
},
|
||||
|
||||
/**
|
||||
* Persist crop image previews preference on the server
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
_persistCropImagePreviewsState: function() {
|
||||
var crop = this._filesConfig.get('cropimagepreviews');
|
||||
$.post(OC.generateUrl('/apps/files/api/v1/cropimagepreviews'), {
|
||||
crop: crop
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -379,7 +320,7 @@
|
|||
if (lastId !== this.getActiveView()) {
|
||||
this.getCurrentAppContainer().trigger(new $.Event('show'));
|
||||
}
|
||||
this.getCurrentAppContainer().trigger(new $.Event('urlChanged', params));
|
||||
// this.getCurrentAppContainer().trigger(new $.Event('urlChanged', params));
|
||||
window._nc_event_bus.emit('files:navigation:changed')
|
||||
},
|
||||
|
||||
|
|
@ -408,13 +349,18 @@
|
|||
}
|
||||
var currentParams = OC.Util.History.parseUrlQuery();
|
||||
if (currentParams.dir === params.dir && currentParams.view === params.view) {
|
||||
if (currentParams.fileid !== params.fileid) {
|
||||
if (parseInt(currentParams.fileid) !== parseInt(params.fileid)) {
|
||||
// if only fileid changed or was added, replace instead of push
|
||||
console.debug('F2V 1', currentParams.fileid, params.fileid, params);
|
||||
OC.Util.History.replaceState(this._makeUrlParams(params));
|
||||
return
|
||||
}
|
||||
} else {
|
||||
console.debug('F2V 2', params);
|
||||
OC.Util.History.pushState(this._makeUrlParams(params));
|
||||
return
|
||||
}
|
||||
console.debug('F2V 3', params, currentParams);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@
|
|||
_filter: '',
|
||||
|
||||
/**
|
||||
* @type Backbone.Model
|
||||
* @type UserConfig
|
||||
* @see /apps/files/lib/Service/UserConfig.php
|
||||
*/
|
||||
_filesConfig: undefined,
|
||||
|
||||
|
|
@ -252,10 +253,7 @@
|
|||
} else if (!_.isUndefined(OCA.Files) && !_.isUndefined(OCA.Files.App)) {
|
||||
this._filesConfig = OCA.Files.App.getFilesConfig();
|
||||
} else {
|
||||
this._filesConfig = new OC.Backbone.Model({
|
||||
'showhidden': false,
|
||||
'cropimagepreviews': true
|
||||
});
|
||||
this._filesConfig = OCP.InitialState.loadState('files', 'config', {})
|
||||
}
|
||||
|
||||
if (options.dragOptions) {
|
||||
|
|
@ -281,26 +279,30 @@
|
|||
this.$header = $el.find('.filelist-header');
|
||||
this.$footer = $el.find('.filelist-footer');
|
||||
|
||||
if (!_.isUndefined(this._filesConfig)) {
|
||||
this._filesConfig.on('change:showhidden', function() {
|
||||
var showHidden = this.get('showhidden');
|
||||
self.$el.toggleClass('hide-hidden-files', !showHidden);
|
||||
// Legacy mapper for new vue components
|
||||
window._nc_event_bus.subscribe('files:config:updated', ({ key, value }) => {
|
||||
// Replace existing config with new one
|
||||
Object.assign(this._filesConfig, { [key]: value })
|
||||
|
||||
if (key === 'show_hidden') {
|
||||
self.$el.toggleClass('hide-hidden-files', !value);
|
||||
self.updateSelectionSummary();
|
||||
|
||||
if (!showHidden) {
|
||||
// hiding files could make the page too small, need to try rendering next page
|
||||
// hiding files could make the page too small, need to try rendering next page
|
||||
if (!value) {
|
||||
self._onScroll();
|
||||
}
|
||||
});
|
||||
|
||||
this._filesConfig.on('change:cropimagepreviews', function() {
|
||||
}
|
||||
if (key === 'crop_image_previews') {
|
||||
self.reload();
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
this.$el.toggleClass('hide-hidden-files', !this._filesConfig.get('showhidden'));
|
||||
var config = OCP.InitialState.loadState('files', 'config', {})
|
||||
if (config.show_hidden === false) {
|
||||
this.$el.addClass('hide-hidden-files');
|
||||
}
|
||||
|
||||
|
||||
if (_.isUndefined(options.detailsViewEnabled) || options.detailsViewEnabled) {
|
||||
this._detailsView = new OCA.Files.DetailsView();
|
||||
this._detailsView.$el.addClass('disappear');
|
||||
|
|
@ -393,6 +395,7 @@
|
|||
|
||||
this.$fileList.on('change', 'td.selection>.selectCheckBox', _.bind(this._onClickFileCheckbox, this));
|
||||
this.$fileList.on('mouseover', 'td.selection', _.bind(this._onMouseOverCheckbox, this));
|
||||
console.debug('F2V', this.$el);
|
||||
this.$el.on('show', _.bind(this._onShow, this));
|
||||
this.$el.on('urlChanged', _.bind(this._onUrlChanged, this));
|
||||
this.$el.find('.select-all').click(_.bind(this._onClickSelectAll, this));
|
||||
|
|
@ -754,23 +757,22 @@
|
|||
* Event handler when leaving previously hidden state
|
||||
*/
|
||||
_onShow: function(e) {
|
||||
console.debug('F2V', 'onShow', e);
|
||||
OCA.Files.App && OCA.Files.App.updateCurrentFileList(this);
|
||||
if (this.shown) {
|
||||
if (e.itemId === this.id) {
|
||||
this._setCurrentDir('/', false);
|
||||
}
|
||||
// Only reload if we don't navigate to a different directory
|
||||
if (typeof e.dir === 'undefined' || e.dir === this.getCurrentDirectory()) {
|
||||
this.reload();
|
||||
}
|
||||
if (e.itemId === this.id) {
|
||||
this._setCurrentDir('/', false);
|
||||
}
|
||||
// Only reload if we don't navigate to a different directory
|
||||
if (typeof e.dir === 'undefined' || e.dir === this.getCurrentDirectory()) {
|
||||
this.reload();
|
||||
}
|
||||
this.shown = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for when the URL changed
|
||||
*/
|
||||
_onUrlChanged: function(e) {
|
||||
console.debug('F2V', 'onUrlChanged', e);
|
||||
if (e && _.isString(e.dir)) {
|
||||
var currentDir = this.getCurrentDirectory();
|
||||
// this._currentDirectory is NULL when fileList is first initialised
|
||||
|
|
@ -1407,7 +1409,7 @@
|
|||
fileData,
|
||||
newTrs = [],
|
||||
isAllSelected = this.isAllSelected(),
|
||||
showHidden = this._filesConfig.get('showhidden');
|
||||
showHidden = this._filesConfig.show_hidden;
|
||||
|
||||
if (index >= this.files.length) {
|
||||
return false;
|
||||
|
|
@ -2371,7 +2373,7 @@
|
|||
* Images are cropped to a square by default. Append a=1 to the URL
|
||||
* if the user wants to see images with original aspect ratio.
|
||||
*/
|
||||
urlSpec.a = this._filesConfig.get('cropimagepreviews') ? 0 : 1;
|
||||
urlSpec.a = this._filesConfig.crop_image_previews ? 0 : 1;
|
||||
|
||||
if (typeof urlSpec.fileId !== 'undefined') {
|
||||
delete urlSpec.file;
|
||||
|
|
@ -3295,7 +3297,7 @@
|
|||
|
||||
this.$el.find('tfoot').append($tr);
|
||||
|
||||
return new OCA.Files.FileSummary($tr, {config: this._filesConfig});
|
||||
return new OCA.Files.FileSummary($tr, { config: this._filesConfig });
|
||||
},
|
||||
updateEmptyContent: function() {
|
||||
var permissions = this.getDirectoryPermissions();
|
||||
|
|
@ -3443,7 +3445,7 @@
|
|||
var summary = this._selectionSummary.summary;
|
||||
var selection;
|
||||
|
||||
var showHidden = !!this._filesConfig.get('showhidden');
|
||||
var showHidden = !!this._filesConfig.show_hidden;
|
||||
if (summary.totalFiles === 0 && summary.totalDirs === 0) {
|
||||
this.$el.find('.column-name a.name>span:first').text(t('files','Name'));
|
||||
this.$el.find('.column-size a>span:first').text(t('files','Size'));
|
||||
|
|
|
|||
|
|
@ -36,10 +36,12 @@
|
|||
this.$el = $tr;
|
||||
var filesConfig = options.config;
|
||||
if (filesConfig) {
|
||||
this._showHidden = !!filesConfig.get('showhidden');
|
||||
filesConfig.on('change:showhidden', function() {
|
||||
self._showHidden = !!this.get('showhidden');
|
||||
self.update();
|
||||
this._showHidden = !!filesConfig.show_hidden;
|
||||
window._nc_event_bus.subscribe('files:config:updated', ({ key, value }) => {
|
||||
if (key === 'show_hidden') {
|
||||
self._showHidden = !!value;
|
||||
self.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
this.clear();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ use OCA\Files\Listener\LoadSidebarListener;
|
|||
use OCA\Files\Notification\Notifier;
|
||||
use OCA\Files\Search\FilesSearchProvider;
|
||||
use OCA\Files\Service\TagService;
|
||||
use OCA\Files\Service\UserConfig;
|
||||
use OCP\Activity\IManager as IActivityManager;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||
|
|
@ -88,7 +89,8 @@ class Application extends App implements IBootstrap {
|
|||
$c->get(IPreview::class),
|
||||
$c->get(IShareManager::class),
|
||||
$c->get(IConfig::class),
|
||||
$server->getUserFolder()
|
||||
$server->getUserFolder(),
|
||||
$c->get(UserConfig::class),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace OCA\Files\Controller;
|
|||
|
||||
use OC\Files\Node\Node;
|
||||
use OCA\Files\Service\TagService;
|
||||
use OCA\Files\Service\UserConfig;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
|
|
@ -61,18 +62,13 @@ use OCP\Share\IShare;
|
|||
* @package OCA\Files\Controller
|
||||
*/
|
||||
class ApiController extends Controller {
|
||||
/** @var TagService */
|
||||
private $tagService;
|
||||
/** @var IManager * */
|
||||
private $shareManager;
|
||||
/** @var IPreview */
|
||||
private $previewManager;
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
/** @var Folder */
|
||||
private $userFolder;
|
||||
private TagService $tagService;
|
||||
private IManager $shareManager;
|
||||
private IPreview $previewManager;
|
||||
private IUserSession $userSession;
|
||||
private IConfig $config;
|
||||
private Folder $userFolder;
|
||||
private UserConfig $userConfig;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
|
|
@ -91,7 +87,8 @@ class ApiController extends Controller {
|
|||
IPreview $previewManager,
|
||||
IManager $shareManager,
|
||||
IConfig $config,
|
||||
Folder $userFolder) {
|
||||
Folder $userFolder,
|
||||
UserConfig $userConfig) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->userSession = $userSession;
|
||||
$this->tagService = $tagService;
|
||||
|
|
@ -99,6 +96,7 @@ class ApiController extends Controller {
|
|||
$this->shareManager = $shareManager;
|
||||
$this->config = $config;
|
||||
$this->userFolder = $userFolder;
|
||||
$this->userConfig = $userConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -282,17 +280,48 @@ class ApiController extends Controller {
|
|||
return new Response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle default files user config
|
||||
*
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* @param bool $key
|
||||
* @param string|bool $value
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function setConfig(string $key, string|bool $value): JSONResponse {
|
||||
try {
|
||||
$this->userConfig->setConfig($key, $value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new JSONResponse(['message' => 'ok', 'data' => ['key' => $key, 'value' => $value]]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the user config
|
||||
*
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function getConfigs(): JSONResponse {
|
||||
return new JSONResponse(['message' => 'ok', 'data' => $this->userConfig->getConfigs()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle default for showing/hiding hidden files
|
||||
*
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* @param bool $show
|
||||
* @param bool $value
|
||||
* @return Response
|
||||
* @throws \OCP\PreConditionNotMetException
|
||||
*/
|
||||
public function showHiddenFiles(bool $show): Response {
|
||||
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', $show ? '1' : '0');
|
||||
public function showHiddenFiles(bool $value): Response {
|
||||
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', $value ? '1' : '0');
|
||||
return new Response();
|
||||
}
|
||||
|
||||
|
|
@ -301,12 +330,12 @@ class ApiController extends Controller {
|
|||
*
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* @param bool $crop
|
||||
* @param bool $value
|
||||
* @return Response
|
||||
* @throws \OCP\PreConditionNotMetException
|
||||
*/
|
||||
public function cropImagePreviews(bool $crop): Response {
|
||||
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'crop_image_previews', $crop ? '1' : '0');
|
||||
public function cropImagePreviews(bool $value): Response {
|
||||
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'crop_image_previews', $value ? '1' : '0');
|
||||
return new Response();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@
|
|||
namespace OCA\Files\Controller;
|
||||
|
||||
use OCA\Files\Activity\Helper;
|
||||
use OCA\Files\AppInfo\Application;
|
||||
use OCA\Files\Event\LoadAdditionalScriptsEvent;
|
||||
use OCA\Files\Event\LoadSidebar;
|
||||
use OCA\Files\Service\UserConfig;
|
||||
use OCA\Viewer\Event\LoadViewer;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Controller;
|
||||
|
|
@ -65,32 +67,18 @@ use OCP\Share\IManager;
|
|||
* @package OCA\Files\Controller
|
||||
*/
|
||||
class ViewController extends Controller {
|
||||
/** @var string */
|
||||
protected $appName;
|
||||
/** @var IRequest */
|
||||
protected $request;
|
||||
/** @var IURLGenerator */
|
||||
protected $urlGenerator;
|
||||
/** @var IL10N */
|
||||
protected $l10n;
|
||||
/** @var IConfig */
|
||||
protected $config;
|
||||
/** @var IEventDispatcher */
|
||||
protected $eventDispatcher;
|
||||
/** @var IUserSession */
|
||||
protected $userSession;
|
||||
/** @var IAppManager */
|
||||
protected $appManager;
|
||||
/** @var IRootFolder */
|
||||
protected $rootFolder;
|
||||
/** @var Helper */
|
||||
protected $activityHelper;
|
||||
/** @var IInitialState */
|
||||
private $initialState;
|
||||
/** @var ITemplateManager */
|
||||
private $templateManager;
|
||||
/** @var IManager */
|
||||
private $shareManager;
|
||||
private IURLGenerator $urlGenerator;
|
||||
private IL10N $l10n;
|
||||
private IConfig $config;
|
||||
private IEventDispatcher $eventDispatcher;
|
||||
private IUserSession $userSession;
|
||||
private IAppManager $appManager;
|
||||
private IRootFolder $rootFolder;
|
||||
private Helper $activityHelper;
|
||||
private IInitialState $initialState;
|
||||
private ITemplateManager $templateManager;
|
||||
private IManager $shareManager;
|
||||
private UserConfig $userConfig;
|
||||
|
||||
public function __construct(string $appName,
|
||||
IRequest $request,
|
||||
|
|
@ -104,11 +92,10 @@ class ViewController extends Controller {
|
|||
Helper $activityHelper,
|
||||
IInitialState $initialState,
|
||||
ITemplateManager $templateManager,
|
||||
IManager $shareManager
|
||||
IManager $shareManager,
|
||||
UserConfig $userConfig
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->appName = $appName;
|
||||
$this->request = $request;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->l10n = $l10n;
|
||||
$this->config = $config;
|
||||
|
|
@ -120,6 +107,7 @@ class ViewController extends Controller {
|
|||
$this->initialState = $initialState;
|
||||
$this->templateManager = $templateManager;
|
||||
$this->shareManager = $shareManager;
|
||||
$this->userConfig = $userConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -236,7 +224,6 @@ class ViewController extends Controller {
|
|||
'folderPosition' => $sortingValue,
|
||||
'name' => basename($favElement),
|
||||
'icon' => 'folder',
|
||||
'quickaccesselement' => 'true'
|
||||
];
|
||||
|
||||
array_push($favoritesSublistArray, $element);
|
||||
|
|
@ -266,11 +253,10 @@ class ViewController extends Controller {
|
|||
$nav->assign('quota', $storageInfo['quota']);
|
||||
$nav->assign('usage_relative', $storageInfo['relative']);
|
||||
|
||||
$nav->assign('webdav_url', \OCP\Util::linkToRemote('dav/files/' . rawurlencode($userId)));
|
||||
|
||||
$contentItems = [];
|
||||
|
||||
$this->initialState->provideInitialState('navigation', $navItems);
|
||||
$this->initialState->provideInitialState('config', $this->userConfig->getConfigs());
|
||||
|
||||
// render the container content for every navigation item
|
||||
foreach ($navItems as $item) {
|
||||
|
|
@ -328,7 +314,7 @@ class ViewController extends Controller {
|
|||
$params['hiddenFields'] = $event->getHiddenFields();
|
||||
|
||||
$response = new TemplateResponse(
|
||||
$this->appName,
|
||||
Application::APP_ID,
|
||||
'index',
|
||||
$params
|
||||
);
|
||||
|
|
|
|||
142
apps/files/lib/Service/UserConfig.php
Normal file
142
apps/files/lib/Service/UserConfig.php
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
namespace OCA\Files\Service;
|
||||
|
||||
use OCA\Files\AppInfo\Application;
|
||||
use OCP\IConfig;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class UserConfig {
|
||||
const ALLOWED_CONFIGS = [
|
||||
[
|
||||
'key' => 'crop_image_previews',
|
||||
'default' => true,
|
||||
'allowed' => [true, false],
|
||||
],
|
||||
[
|
||||
'key' => 'show_hidden',
|
||||
'default' => false,
|
||||
'allowed' => [true, false],
|
||||
],
|
||||
];
|
||||
|
||||
private IConfig $config;
|
||||
private IUser|null $user;
|
||||
|
||||
public function __construct(IConfig $config, IUserSession $userSession) {
|
||||
$this->config = $config;
|
||||
$this->user = $userSession->getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all allowed user config keys
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAllowedConfigKeys(): array {
|
||||
return array_map(function($config) {
|
||||
return $config['key'];
|
||||
}, self::ALLOWED_CONFIGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of allowed config values for a given key
|
||||
*
|
||||
* @param string $key a valid config key
|
||||
* @return array
|
||||
*/
|
||||
private function getAllowedConfigValues(string $key): array {
|
||||
foreach (self::ALLOWED_CONFIGS as $config) {
|
||||
if ($config['key'] === $key) {
|
||||
return $config['allowed'];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default config value for a given key
|
||||
*
|
||||
* @param string $key a valid config key
|
||||
* @return string|bool
|
||||
*/
|
||||
private function getDefaultConfigValue(string $key): string|bool {
|
||||
foreach (self::ALLOWED_CONFIGS as $config) {
|
||||
if ($config['key'] === $key) {
|
||||
return $config['default'];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a user config
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @throws \Exception
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setConfig($key, $value) {
|
||||
if (!$this->user) {
|
||||
throw new \Exception('No user logged in');
|
||||
}
|
||||
|
||||
if (!in_array($key, $this->getAllowedConfigKeys())) {
|
||||
throw new \InvalidArgumentException('Unknown config key');
|
||||
}
|
||||
|
||||
if (!in_array($value, $this->getAllowedConfigValues($key))) {
|
||||
throw new \InvalidArgumentException('Invalid config value');
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
$value = $value ? '1' : '0';
|
||||
}
|
||||
|
||||
$this->config->setUserValue($this->user->getUID(), Application::APP_ID, $key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user configs array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfigs(): array {
|
||||
if (!$this->user) {
|
||||
throw new \Exception('No user logged in');
|
||||
}
|
||||
|
||||
$userId = $this->user->getUID();
|
||||
$userConfigs = array_map(function(string $key) use ($userId): string|bool {
|
||||
$value = $this->config->getUserValue($userId, Application::APP_ID, $key, $this->getDefaultConfigValue($key));
|
||||
// If the default is expected to be a boolean, we need to cast the value
|
||||
if (is_bool($this->getDefaultConfigValue($key))) {
|
||||
return $value === '1';
|
||||
}
|
||||
return $value;
|
||||
}, $this->getAllowedConfigKeys());
|
||||
|
||||
return array_combine($this->getAllowedConfigKeys(), $userConfigs);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,5 +37,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2019 Gary Kim <gary@garykim.dev>
|
||||
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @author Gary Kim <gary@garykim.dev>
|
||||
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import Settings from './services/Settings'
|
||||
import SettingsView from './views/Settings'
|
||||
import Setting from './models/Setting'
|
||||
|
||||
Vue.prototype.t = t
|
||||
|
||||
// Init Files App Settings Service
|
||||
if (!window.OCA.Files) {
|
||||
window.OCA.Files = {}
|
||||
}
|
||||
Object.assign(window.OCA.Files, { Settings: new Settings() })
|
||||
Object.assign(window.OCA.Files.Settings, { Setting })
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
if (window.TESTING) {
|
||||
return
|
||||
}
|
||||
// Init Vue app
|
||||
// eslint-disable-next-line
|
||||
new Vue({
|
||||
el: '#files-app-settings',
|
||||
render: h => h(SettingsView),
|
||||
})
|
||||
|
||||
const appSettingsHeader = document.getElementById('app-settings-header')
|
||||
if (appSettingsHeader) {
|
||||
appSettingsHeader.addEventListener('click', e => {
|
||||
const opened = e.currentTarget.children[0].classList.contains('opened')
|
||||
OCA.Files.Settings.settings.forEach(e => opened ? e.close() : e.open())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import './files-app-settings.js'
|
||||
import './templates.js'
|
||||
import './legacy/filelistSearch.js'
|
||||
import processLegacyFilesViews from './legacy/navigationMapper.js'
|
||||
|
|
@ -7,15 +6,24 @@ import Vue from 'vue'
|
|||
import NavigationService from './services/Navigation.ts'
|
||||
import NavigationView from './views/Navigation.vue'
|
||||
|
||||
import SettingsService from './services/Settings.js'
|
||||
import SettingsModel from './models/Setting.js'
|
||||
|
||||
import router from './router/router.js'
|
||||
|
||||
// Init Files App Navigation Service
|
||||
const Navigation = new NavigationService()
|
||||
|
||||
// Assign Navigation Service to the global OCP.Files
|
||||
// Init private and public Files namespace
|
||||
window.OCA.Files = window.OCA.Files ?? {}
|
||||
window.OCP.Files = window.OCP.Files ?? {}
|
||||
|
||||
// Init Navigation Service
|
||||
const Navigation = new NavigationService()
|
||||
Object.assign(window.OCP.Files, { Navigation })
|
||||
|
||||
// Init Files App Settings Service
|
||||
const Settings = new SettingsService()
|
||||
Object.assign(window.OCA.Files, { Settings })
|
||||
Object.assign(window.OCA.Files.Settings, { Setting: SettingsModel })
|
||||
|
||||
// Init Navigation View
|
||||
const View = Vue.extend(NavigationView)
|
||||
const FilesNavigationRoot = new View({
|
||||
|
|
|
|||
|
|
@ -44,9 +44,5 @@ export default new Router({
|
|||
name: 'filelist',
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/not-found',
|
||||
name: 'notfound',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -36,6 +36,19 @@
|
|||
:icon="child.iconClass"
|
||||
:title="child.name" />
|
||||
</NcAppNavigationItem>
|
||||
|
||||
<!-- Settings toggle -->
|
||||
<template #footer>
|
||||
<NcAppNavigationItem :pinned="true"
|
||||
:title="t('files', 'Files settings')"
|
||||
@click.prevent.stop="openSettings">
|
||||
<Cog slot="icon" :size="20" />
|
||||
</NcAppNavigationItem>
|
||||
</template>
|
||||
|
||||
<!-- Settings modal-->
|
||||
<SettingsModal :open="settingsOpened"
|
||||
@close="onSettingsClose" />
|
||||
</NcAppNavigation>
|
||||
</template>
|
||||
|
||||
|
|
@ -45,7 +58,9 @@ import { generateUrl } from '@nextcloud/router'
|
|||
import axios from '@nextcloud/axios'
|
||||
import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js'
|
||||
import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js'
|
||||
import Cog from 'vue-material-design-icons/Cog.vue'
|
||||
|
||||
import SettingsModal from './Settings.vue'
|
||||
import Navigation from '../services/Navigation.ts'
|
||||
import logger from '../logger.js'
|
||||
|
||||
|
|
@ -53,8 +68,10 @@ export default {
|
|||
name: 'Navigation',
|
||||
|
||||
components: {
|
||||
Cog,
|
||||
NcAppNavigation,
|
||||
NcAppNavigationItem,
|
||||
SettingsModal,
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -67,7 +84,7 @@ export default {
|
|||
|
||||
data() {
|
||||
return {
|
||||
key: 'value',
|
||||
settingsOpened: false,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -110,7 +127,7 @@ export default {
|
|||
|
||||
watch: {
|
||||
currentView(view, oldView) {
|
||||
logger.debug('View changed', { view })
|
||||
logger.debug('View changed', { id: view.id, view })
|
||||
this.showView(view, oldView)
|
||||
},
|
||||
},
|
||||
|
|
@ -128,21 +145,57 @@ export default {
|
|||
* @param {Navigation} oldView the old active view
|
||||
*/
|
||||
showView(view, oldView) {
|
||||
// Closing any opened sidebar
|
||||
OCA.Files?.Sidebar?.close?.()
|
||||
|
||||
if (view.legacy) {
|
||||
const newAppContent = document.querySelector('#app-content #app-content-' + this.currentView.id + '.viewcontainer')
|
||||
document.querySelectorAll('#app-content .viewcontainer').forEach(el => {
|
||||
el.classList.add('hidden')
|
||||
})
|
||||
document.querySelector('#app-content #app-content-' + this.currentView.id + '.viewcontainer').classList.remove('hidden')
|
||||
newAppContent.classList.remove('hidden')
|
||||
|
||||
// Legacy event
|
||||
console.debug('F2V', jQuery(newAppContent))
|
||||
|
||||
// previousItemId: oldItemId,
|
||||
// dir: itemDir,
|
||||
// view: itemView
|
||||
$(newAppContent).trigger(new $.Event('show', { itemId: view.id, dir: '/' }))
|
||||
$(newAppContent).trigger(new $.Event('urlChanged', { itemId: view.id, dir: '/' }))
|
||||
}
|
||||
|
||||
this.Navigation.setActive(view)
|
||||
emit('files:view:changed', view)
|
||||
emit('files:navigation:changed', view)
|
||||
},
|
||||
|
||||
/**
|
||||
* Expand/collapse a a view with children and permanently
|
||||
* save this setting in the server.
|
||||
*
|
||||
* @param {Navigation} view the view to toggle
|
||||
*/
|
||||
onToggleExpand(view) {
|
||||
// Invert state
|
||||
view.expanded = !view.expanded
|
||||
axios.post(generateUrl(`/apps/files/api/v1/toggleShowFolder/${view.id}`), { show: view.expanded })
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the settings modal and update the settings API entries
|
||||
*/
|
||||
openSettings() {
|
||||
this.settingsOpened = true
|
||||
OCA.Files.Settings.settings.forEach(setting => setting.open())
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the settings modal and update the settings API entries
|
||||
*/
|
||||
onSettingsClose() {
|
||||
this.settingsOpened = false
|
||||
OCA.Files.Settings.settings.forEach(setting => setting.close())
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -20,26 +20,99 @@
|
|||
-
|
||||
-->
|
||||
<template>
|
||||
<div id="files-app-extra-settings">
|
||||
<template v-for="setting in settings">
|
||||
<Setting :key="setting.name" :el="setting.el" />
|
||||
</template>
|
||||
</div>
|
||||
<NcAppSettingsDialog :open="open"
|
||||
:show-navigation="true"
|
||||
:title="t('files', 'Files settings')"
|
||||
@update:open="onClose">
|
||||
<!-- Settings API-->
|
||||
<NcAppSettingsSection id="settings" :title="t('files', 'Files settings')">
|
||||
<NcCheckboxRadioSwitch :checked.sync="show_hidden"
|
||||
@update:checked="setConfig('show_hidden', $event)">
|
||||
{{ t('files', 'Show hidden files') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<NcCheckboxRadioSwitch :checked.sync="crop_image_previews"
|
||||
@update:checked="setConfig('crop_image_previews', $event)">
|
||||
{{ t('files', 'Crop image previews') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
</NcAppSettingsSection>
|
||||
|
||||
<!-- Settings API-->
|
||||
<NcAppSettingsSection id="more-settings" :title="t('files', 'Additional settings')">
|
||||
<template v-for="setting in settings">
|
||||
<Setting :key="setting.name" :el="setting.el" />
|
||||
</template>
|
||||
</NcAppSettingsSection>
|
||||
|
||||
<!-- Webdav URL-->
|
||||
<NcAppSettingsSection id="webdav" :title="t('files', 'Webdav')">
|
||||
<NcInputField type="text" readonly="readonly" :value="webdavUrl" />
|
||||
<em>
|
||||
<a :href="webdavDocs" target="_blank" rel="noreferrer noopener">
|
||||
{{ t('files', 'Use this address to access your Files via WebDAV') }} ↗
|
||||
</a>
|
||||
</em>
|
||||
</NcAppSettingsSection>
|
||||
</NcAppSettingsDialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Setting from '../components/Setting'
|
||||
import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDialog.js'
|
||||
import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
|
||||
import NcInputField from '@nextcloud/vue/dist/Components/NcInputField'
|
||||
import Setting from '../components/Setting.vue'
|
||||
|
||||
import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
const userConfig = loadState('files', 'config')
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
NcAppSettingsDialog,
|
||||
NcAppSettingsSection,
|
||||
NcCheckboxRadioSwitch,
|
||||
NcInputField,
|
||||
Setting,
|
||||
},
|
||||
|
||||
props: {
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
||||
...userConfig,
|
||||
|
||||
// Settings API
|
||||
settings: OCA.Files.Settings.settings,
|
||||
|
||||
// Webdav infos
|
||||
webdavUrl: generateRemoteUrl('dav/files/' + getCurrentUser()?.uid),
|
||||
webdavDocs: 'https://docs.nextcloud.com/server/stable/go.php?to=user-webdav',
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
setConfig(key, value) {
|
||||
emit('files:config:updated', { key, value })
|
||||
axios.post(generateUrl('/apps/files/api/v1/config/' + key), {
|
||||
value,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -24,7 +24,7 @@
|
|||
"@nextcloud/l10n": "^1.6.0",
|
||||
"@nextcloud/logger": "^2.4.0",
|
||||
"@nextcloud/moment": "^1.2.1",
|
||||
"@nextcloud/password-confirmation": "^4.0.2",
|
||||
"@nextcloud/password-confirmation": "^4.0.3",
|
||||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
|
|
@ -4290,9 +4290,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nextcloud/password-confirmation": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-4.0.2.tgz",
|
||||
"integrity": "sha512-5UwPka9hHOOaoevAE9PpPzZYepKJURuogggAp71BrGl8z1mvE8iMckRQ3B7TYwWX5p9pmMtdWtflWIsVA0uvhw==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-4.0.3.tgz",
|
||||
"integrity": "sha512-kS7yREq3F4DiXpmbxVsm9Ezv58+1BT5PPrrZV+VjQtUY69Rjc0xP9X5fbZH+BBT9LXHPypN32qbBuvPpgVZZqA==",
|
||||
"dependencies": {
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/l10n": "^1.6.0",
|
||||
|
|
@ -26826,9 +26826,9 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/password-confirmation": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-4.0.2.tgz",
|
||||
"integrity": "sha512-5UwPka9hHOOaoevAE9PpPzZYepKJURuogggAp71BrGl8z1mvE8iMckRQ3B7TYwWX5p9pmMtdWtflWIsVA0uvhw==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-4.0.3.tgz",
|
||||
"integrity": "sha512-kS7yREq3F4DiXpmbxVsm9Ezv58+1BT5PPrrZV+VjQtUY69Rjc0xP9X5fbZH+BBT9LXHPypN32qbBuvPpgVZZqA==",
|
||||
"requires": {
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/l10n": "^1.6.0",
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
"@nextcloud/l10n": "^1.6.0",
|
||||
"@nextcloud/logger": "^2.4.0",
|
||||
"@nextcloud/moment": "^1.2.1",
|
||||
"@nextcloud/password-confirmation": "^4.0.2",
|
||||
"@nextcloud/password-confirmation": "^4.0.3",
|
||||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue