diff --git a/ElectronClient/app/gui/MainScreen.jsx b/ElectronClient/app/gui/MainScreen.jsx
index e83f48baa81..a98b2689ce4 100644
--- a/ElectronClient/app/gui/MainScreen.jsx
+++ b/ElectronClient/app/gui/MainScreen.jsx
@@ -16,6 +16,7 @@ const { _ } = require('lib/locale.js');
const layoutUtils = require('lib/layout-utils.js');
const { bridge } = require('electron').remote.require('./bridge');
const eventManager = require('../eventManager');
+const { NoteCountUtils } = require('lib/note-count-utils.js');
class MainScreenComponent extends React.Component {
@@ -90,6 +91,7 @@ class MainScreenComponent extends React.Component {
let folder = null;
try {
folder = await Folder.save({ title: answer }, { userSideValidation: true });
+ await NoteCountUtils.refreshNotesCount();
} catch (error) {
bridge().showErrorMessageBox(error.message);
}
diff --git a/ElectronClient/app/gui/NoteList.jsx b/ElectronClient/app/gui/NoteList.jsx
index 93611b733ee..65dc80857a1 100644
--- a/ElectronClient/app/gui/NoteList.jsx
+++ b/ElectronClient/app/gui/NoteList.jsx
@@ -13,7 +13,7 @@ const InteropService = require('lib/services/InteropService');
const InteropServiceHelper = require('../InteropServiceHelper.js');
const Search = require('lib/models/Search');
const Mark = require('mark.js/dist/mark.min.js');
-
+const { NoteCountUtils } = require('lib/note-count-utils.js');
class NoteListComponent extends React.Component {
style() {
@@ -126,8 +126,22 @@ class NoteListComponent extends React.Component {
menu.append(new MenuItem({label: _('Delete'), click: async () => {
const ok = bridge().showConfirmMessageBox(noteIds.length > 1 ? _('Delete notes?') : _('Delete note?'));
- if (!ok) return;
- await Note.batchDelete(noteIds);
+ if (!ok) return;
+ await Note.batchDelete(noteIds);
+ if(this.props.notesParentType === 'Tag' || this.props.notesParentType === 'Search'){
+ await NoteCountUtils.refreshNotesCount();
+ } else if(this.props.notesParentType === 'Folder'){
+ let tempProps = Object.assign({},this.props);
+ let notesCount = [];
+ for(let key in tempProps.notesCount){
+ notesCount[key] = tempProps.notesCount[key];
+ }
+ notesCount[this.props.selectedFolderId] = +notesCount[this.props.selectedFolderId] - noteIds.length;
+ this.props.dispatch({
+ type:'FOLDER_COUNT_UPDATE_ALL',
+ notesCount: notesCount
+ })
+ }
}}));
menu.popup(bridge().window());
@@ -281,7 +295,9 @@ const mapStateToProps = (state) => {
theme: state.settings.theme,
notesParentType: state.notesParentType,
searches: state.searches,
- selectedSearchId: state.selectedSearchId,
+ selectedSearchId: state.selectedSearchId,
+ selectedFolderId: state.selectedFolderId,
+ notesCount: state.notesCount
};
};
diff --git a/ElectronClient/app/gui/SideBar.jsx b/ElectronClient/app/gui/SideBar.jsx
index 127166ec0a6..5de8bb0cff6 100644
--- a/ElectronClient/app/gui/SideBar.jsx
+++ b/ElectronClient/app/gui/SideBar.jsx
@@ -22,7 +22,7 @@ class SideBarComponent extends React.Component {
this.onFolderDragStart_ = (event) => {
const folderId = event.currentTarget.getAttribute('folderid');
if (!folderId) return;
-
+
event.dataTransfer.setDragImage(new Image(), 1, 1);
event.dataTransfer.clearData();
event.dataTransfer.setData('text/x-jop-folder-ids', JSON.stringify([folderId]));
@@ -250,7 +250,7 @@ class SideBarComponent extends React.Component {
);
}
- if (itemType === BaseModel.TYPE_TAG) {
+ if (itemType === BaseModel.TYPE_TAG) {
menu.append(
new MenuItem({
label: _('Rename'),
@@ -313,10 +313,15 @@ class SideBarComponent extends React.Component {
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-plus-square' : 'fa-minus-square';
const expandIcon =
const expandLink = hasChildren ? {expandIcon} : {expandIcon}
-
+ let count = '0';
+ if (this.props.notesCount[folder.id] !== 'undefined'
+ && this.props.notesCount[folder.id] !== undefined) {
+ count = this.props.notesCount[folder.id];
+ }
return (
+
);
@@ -485,6 +490,7 @@ const mapStateToProps = state => {
locale: state.settings.locale,
theme: state.settings.theme,
collapsedFolderIds: state.collapsedFolderIds,
+ notesCount: state.notesCount
};
};
diff --git a/ReactNativeClient/lib/BaseApplication.js b/ReactNativeClient/lib/BaseApplication.js
index b5b22e94c70..8aa1f0d1c39 100644
--- a/ReactNativeClient/lib/BaseApplication.js
+++ b/ReactNativeClient/lib/BaseApplication.js
@@ -3,6 +3,7 @@ const { reducer, defaultState, stateUtils } = require('lib/reducer.js');
const { JoplinDatabase } = require('lib/joplin-database.js');
const { Database } = require('lib/database.js');
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
+const { NoteCountUtils } = require('lib/note-count-utils.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
@@ -35,6 +36,7 @@ const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseService = require('lib/services/BaseService');
+
SyncTargetRegistry.addClass(SyncTargetFilesystem);
SyncTargetRegistry.addClass(SyncTargetOneDrive);
SyncTargetRegistry.addClass(SyncTargetOneDriveDev);
@@ -356,6 +358,7 @@ class BaseApplication {
this.store_ = createStore(this.reducer, applyMiddleware(this.generalMiddlewareFn()));
BaseModel.dispatch = this.store().dispatch;
FoldersScreenUtils.dispatch = this.store().dispatch;
+ NoteCountUtils.dispatch = this.store().dispatch;
reg.dispatch = this.store().dispatch;
BaseSyncTarget.dispatch = this.store().dispatch;
DecryptionWorker.instance().dispatch = this.store().dispatch;
diff --git a/ReactNativeClient/lib/folders-screen-utils.js b/ReactNativeClient/lib/folders-screen-utils.js
index 1a6971da471..f73e2ffdf75 100644
--- a/ReactNativeClient/lib/folders-screen-utils.js
+++ b/ReactNativeClient/lib/folders-screen-utils.js
@@ -3,11 +3,18 @@ const Folder = require('lib/models/Folder.js');
class FoldersScreenUtils {
static async refreshFolders() {
- let initialFolders = await Folder.all({ includeConflictFolder: true });
-
+ let initialFolders = await Folder.all({ includeConflictFolder: true });
+ let allFolderCountData = await Folder.allFolderNoteCount();
+ let notesCount = [];
+ for (let n = 0; n < allFolderCountData.length; n++) {
+ let mFolder = allFolderCountData[n];
+ let searchedFolder = allFolderCountData.find(folder => folder.parent_id === mFolder.id);
+ notesCount[mFolder.id] = (searchedFolder != undefined && searchedFolder != 'undefined') ? searchedFolder.total : 0;
+ }
this.dispatch({
type: 'FOLDER_UPDATE_ALL',
items: initialFolders,
+ notesCount: notesCount
});
}
diff --git a/ReactNativeClient/lib/models/Folder.js b/ReactNativeClient/lib/models/Folder.js
index 4d24e9405dc..775e19295d7 100644
--- a/ReactNativeClient/lib/models/Folder.js
+++ b/ReactNativeClient/lib/models/Folder.js
@@ -65,7 +65,12 @@ class Folder extends BaseItem {
static async noteCount(parentId) {
let r = await this.db().selectOne('SELECT count(*) as total FROM notes WHERE is_conflict = 0 AND parent_id = ?', [parentId]);
return r ? r.total : 0;
- }
+ }
+
+ static async allFolderNoteCount() {
+ let rows = await this.db().selectAll('SELECT count(*) as total, parent_id FROM notes WHERE is_conflict = 0 GROUP BY parent_id', []);
+ return rows;
+ }
static markNotesAsConflict(parentId) {
let query = Database.updateQuery('notes', { is_conflict: 1 }, { parent_id: parentId });
diff --git a/ReactNativeClient/lib/note-count-utils.js b/ReactNativeClient/lib/note-count-utils.js
new file mode 100644
index 00000000000..2b8ed164e23
--- /dev/null
+++ b/ReactNativeClient/lib/note-count-utils.js
@@ -0,0 +1,22 @@
+const Folder = require('lib/models/Folder.js');
+
+class NoteCountUtils {
+ static async refreshNotesCount() {
+
+ let allFolderCountData = await Folder.allFolderNoteCount();
+ let notesCount = [];
+ for (let n = 0; n < allFolderCountData.length; n++) {
+ let mFolder = allFolderCountData[n];
+ let searchedFolder = allFolderCountData.find(folder => folder.parent_id === mFolder.id);
+ notesCount[mFolder.id] = (searchedFolder != undefined && searchedFolder != 'undefined') ? searchedFolder.total : 0;
+ }
+ this.dispatch({
+ type: 'FOLDER_COUNT_UPDATE_ALL',
+ notesCount: notesCount
+ });
+ }
+}
+
+module.exports = {
+ NoteCountUtils
+};
\ No newline at end of file
diff --git a/ReactNativeClient/lib/reducer.js b/ReactNativeClient/lib/reducer.js
index e3c40679020..3ca8b1907b9 100644
--- a/ReactNativeClient/lib/reducer.js
+++ b/ReactNativeClient/lib/reducer.js
@@ -1,7 +1,7 @@
const Note = require('lib/models/Note.js');
const Folder = require('lib/models/Folder.js');
const ArrayUtils = require('lib/ArrayUtils.js');
-
+const { NoteCountUtils } = require('lib/note-count-utils.js');
const defaultState = {
notes: [],
notesSource: '',
@@ -31,11 +31,12 @@ const defaultState = {
startState: 'idle',
port: null,
},
+ notesCount: [],
};
const stateUtils = {};
-stateUtils.notesOrder = function(stateSettings) {
+stateUtils.notesOrder = function (stateSettings) {
return [{
by: stateSettings['notes.sortOrder.field'],
dir: stateSettings['notes.sortOrder.reverse'] ? 'DESC' : 'ASC',
@@ -294,7 +295,7 @@ const reducer = (state = defaultState, action) => {
const modNote = action.note;
- const noteIsInFolder = function(note, folderId) {
+ const noteIsInFolder = function (note, folderId) {
if (note.is_conflict) return folderId === Folder.conflictFolderId();
if (!('parent_id' in modNote) || note.parent_id == folderId) return true;
return false;
@@ -343,6 +344,7 @@ const reducer = (state = defaultState, action) => {
if (noteFolderHasChanged) {
newState.selectedNoteIds = newNotes.length ? [newNotes[0].id] : [];
}
+ NoteCountUtils.refreshNotesCount();
break;
case 'NOTE_DELETE':
@@ -359,6 +361,7 @@ const reducer = (state = defaultState, action) => {
newState = Object.assign({}, state);
newState.folders = action.items;
+ newState.notesCount = action.notesCount;
break;
case 'FOLDER_SET_COLLAPSED':
@@ -500,7 +503,7 @@ const reducer = (state = defaultState, action) => {
case 'SEARCH_DELETE':
newState = handleItemDelete(state, action);
- break;
+ break;
case 'SEARCH_SELECT':
@@ -538,8 +541,12 @@ const reducer = (state = defaultState, action) => {
if ('startState' in action) clipperServer.startState = action.startState;
if ('port' in action) clipperServer.port = action.port;
newState.clipperServer = clipperServer;
- break;
+ break;
+ case 'FOLDER_COUNT_UPDATE_ALL':
+ newState = Object.assign({}, state);
+ newState.notesCount = action.notesCount;
+ break;
}
} catch (error) {
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);