Idea for contacts screen route

This commit is contained in:
the-djmaze 2024-02-11 03:43:44 +01:00
parent a25d35d6df
commit fc141fe29b
10 changed files with 197 additions and 9 deletions

View file

@ -48,6 +48,7 @@ import { IdentityModel } from 'Model/Identity';
import { LoginUserScreen } from 'Screen/User/Login'; import { LoginUserScreen } from 'Screen/User/Login';
import { MailBoxUserScreen } from 'Screen/User/MailBox'; import { MailBoxUserScreen } from 'Screen/User/MailBox';
import { ContactsUserScreen } from 'Screen/User/Contacts';
import { SettingsUserScreen } from 'Screen/User/Settings'; import { SettingsUserScreen } from 'Screen/User/Settings';
import { startScreens, showScreenPopup, arePopupsVisible } from 'Knoin/Knoin'; import { startScreens, showScreenPopup, arePopupsVisible } from 'Knoin/Knoin';
@ -211,6 +212,7 @@ export class AppUser extends AbstractApp {
if (value) { if (value) {
startScreens([ startScreens([
MailBoxUserScreen, MailBoxUserScreen,
ContactsUserScreen,
SettingsUserScreen SettingsUserScreen
]); ]);

View file

@ -9,6 +9,7 @@ ScopeMessageList = 'MessageList',
ScopeFolderList = 'FolderList', ScopeFolderList = 'FolderList',
ScopeMessageView = 'MessageView', ScopeMessageView = 'MessageView',
ScopeSettings = 'Settings', ScopeSettings = 'Settings',
ScopeContacts = 'Contacts',
/** /**
* @enum {number} * @enum {number}

View file

@ -0,0 +1,33 @@
import { ScopeContacts } from 'Common/Enums';
import { i18n } from 'Common/Translator';
import { AppUserStore } from 'Stores/User/App';
import { SystemDropDownUserView } from 'View/User/SystemDropDown';
import { AddressBooks } from 'View/User/Contacts/AddressBooks';
import { ContactsList } from 'View/User/Contacts/ContactsList';
import { ContactView } from 'View/User/Contacts/ContactView';
import { AbstractScreen } from 'Knoin/AbstractScreen';
export class ContactsUserScreen extends AbstractScreen {
constructor() {
super('contacts', [
SystemDropDownUserView,
AddressBooks,
ContactsList,
ContactView
]);
}
onShow() {
this.setTitle();
AppUserStore.focusedState('none');
AppUserStore.focusedState(ScopeContacts);
}
setTitle() {
rl.setTitle(i18n('GLOBAL/CONTACTS'));
}
}

View file

@ -39,7 +39,7 @@ export class MailBoxUserScreen extends AbstractScreen {
/** /**
* @returns {void} * @returns {void}
*/ */
updateWindowTitle() { setTitle() {
const count = Settings.app('listPermanentFiltered') ? 0 : FolderUserStore.foldersInboxUnreadCount(), const count = Settings.app('listPermanentFiltered') ? 0 : FolderUserStore.foldersInboxUnreadCount(),
email = AccountUserStore.email(); email = AccountUserStore.email();
@ -55,7 +55,7 @@ export class MailBoxUserScreen extends AbstractScreen {
* @returns {void} * @returns {void}
*/ */
onShow() { onShow() {
this.updateWindowTitle(); this.setTitle();
AppUserStore.focusedState('none'); AppUserStore.focusedState('none');
AppUserStore.focusedState(ScopeMessageList); AppUserStore.focusedState(ScopeMessageList);
} }
@ -99,7 +99,7 @@ export class MailBoxUserScreen extends AbstractScreen {
email === item?.email && item?.count(e.detail) email === item?.email && item?.count(e.detail)
); );
*/ */
this.updateWindowTitle(); this.setTitle();
}); });
} }

View file

@ -66,11 +66,11 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
} }
onShow() { onShow() {
this.setSettingsTitle(); this.setTitle();
keyScope(ScopeSettings); keyScope(ScopeSettings);
} }
setSettingsTitle() { setTitle() {
const sEmail = AccountUserStore.email(); const sEmail = AccountUserStore.email();
rl.setTitle((sEmail ? sEmail + ' - ' : '') + this.sSettingsTitle); rl.setTitle((sEmail ? sEmail + ' - ' : '') + this.sSettingsTitle);
} }

View file

@ -19,6 +19,7 @@ AppUserStore.focusedState.subscribe(value => {
arePopupsVisible() || keyScope(value); arePopupsVisible() || keyScope(value);
ThemeStore.isMobile() && leftPanelDisabled('FolderList' !== value); ThemeStore.isMobile() && leftPanelDisabled('FolderList' !== value);
} }
elementById('V-Mail'+name).classList.toggle('focused', name === value); let el = elementById('V-Mail'+name);
el && el.classList.toggle('focused', name === value);
}); });
}); });

View file

@ -21,9 +21,10 @@ import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { AskPopupView } from 'View/Popup/Ask'; import { AskPopupView } from 'View/Popup/Ask';
import { ScopeContacts } from 'Common/Enums';
const const
CONTACTS_PER_PAGE = 50, CONTACTS_PER_PAGE = 50;
ScopeContacts = 'Contacts';
let let
bOpenCompose = false, bOpenCompose = false,
@ -342,7 +343,7 @@ export class ContactsPopupView extends AbstractViewPopup {
this.search(''); this.search('');
this.contactsCount(0); this.contactsCount(0);
ContactUserStore([]); // ContactUserStore([]);
bOpenCompose && showMessageComposer(); bOpenCompose && showMessageComposer();
} }

View file

@ -0,0 +1,7 @@
import { AbstractViewLeft } from 'Knoin/AbstractViews';
export class AddressBooks extends AbstractViewLeft {
constructor() {
super();
}
}

View file

@ -0,0 +1,47 @@
import { AbstractViewRight } from 'Knoin/AbstractViews';
import { addObservablesTo } from 'External/ko';
import { decorateKoCommands } from 'Knoin/Knoin';
import Remote from 'Remote/User/Fetch';
import { getNotification } from 'Common/Translator';
export class ContactView extends AbstractViewRight {
constructor() {
super();
addObservablesTo(this, {
contact: null
});
this.saveCommand = this.saveCommand.bind(this);
decorateKoCommands(this, {
saveCommand: self => !self.isBusy()
});
}
saveCommand() {
this.saveContact(this.contact());
}
saveContact(contact) {
const data = contact.toJSON();
if (data.jCard != JSON.stringify(contact.jCard)) {
this.isSaving(true);
Remote.request('ContactSave',
(iError, oData) => {
if (iError) {
alert(oData?.ErrorMessage || getNotification(iError));
} else if (oData.Result.ResultID) {
if (contact.id()) {
contact.id(oData.Result.ResultID);
contact.jCard = JSON.parse(data.jCard);
} else {
this.reloadContactList(); // TODO: remove when e-contact-foreach is dynamic
}
}
this.isSaving(false);
}, data
);
}
}
}

View file

@ -0,0 +1,96 @@
import { AbstractViewRight } from 'Knoin/AbstractViews';
import { addObservablesTo, addComputablesTo } from 'External/ko';
import { computedPaginatorHelper } from 'Common/UtilsUser';
import { Selector } from 'Common/Selector';
import { SettingsUserStore } from 'Stores/User/Settings';
import { ContactUserStore } from 'Stores/User/Contact';
import { decorateKoCommands } from 'Knoin/Knoin';
const
CONTACTS_PER_PAGE = 50;
export class ContactsList extends AbstractViewRight {
constructor() {
super();
addObservablesTo(this, {
search: '',
contactsCount: 0,
selectorContact: null,
importButton: null,
contactsPage: 1,
isSaving: false,
contact: null
});
addComputablesTo(this, {
checkAll: {
read: () => ContactUserStore.hasChecked(),
write: (value) => {
value = !!value;
ContactUserStore.forEach(contact => contact.checked(value));
}
}
});
this.contacts = ContactUserStore;
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
this.selector = new Selector(
ContactUserStore,
this.selectorContact,
null,
'.e-contact-item',
'.e-contact-item .checkboxItem'
);
this.selector.on('ItemSelect', contact => this.populateViewContact(contact));
this.selector.on('ItemGetUid', contact => contact ? contact.id() : '');
addComputablesTo(this, {
contactsPaginator: computedPaginatorHelper(
this.contactsPage,
() => Math.max(1, Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE))
),
contactsCheckedOrSelected: () => {
const checked = ContactUserStore.filter(item => item.checked()),
selected = this.selectorContact();
return checked.length ? checked : (selected ? [selected] : []);
},
contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode(),
isIncompleteChecked: () => {
const c = ContactUserStore.listChecked().length;
return c && ContactUserStore().length > c;
},
isBusy: () => ContactUserStore.syncing() | ContactUserStore.importing() | ContactUserStore.loading()
| this.isSaving()
});
this.search.subscribe(() => this.reloadContactList());
decorateKoCommands(this, {
deleteCommand: self => !self.isBusy() && 0 < self.contactsCheckedOrSelected().length,
newMessageCommand: self => !self.isBusy() && 0 < self.contactsCheckedOrSelected().length,
syncCommand: self => !self.isBusy()
});
}
clearSearch() {
this.search('');
}
}