implemented block restore on messages and topics

This commit is contained in:
balzack 2024-12-24 08:31:36 -08:00
parent 9e23a2689d
commit 421963956b
9 changed files with 188 additions and 32 deletions

View File

@ -52,6 +52,7 @@ export const en = {
subject: 'Subject',
noContacts: 'No Contacts',
noTopics: 'No Topics',
noMessages: 'No Messages',
noConnected: 'No Connected Contacts',
subjectOptional: 'Subject (optional)',
members: 'Members',
@ -363,6 +364,7 @@ export const fr = {
subject: 'Sujet',
noContacts: 'Pas de Contacts',
noTopics: 'Pas de Sujets',
noMessages: 'Pas de Messages',
noConnected: 'Pas de Contacts Connecter',
subjectOptional: 'Sujet (optionnel)',
members: 'Membres',
@ -637,8 +639,9 @@ export const sp = {
newTopic: 'Nuevo tema',
subject: 'Tema',
noContacts: 'Sin contactos',
noTopics: 'Sin temas',
noContacts: 'Sin Contactos',
noTopics: 'Sin Temas',
noMessages: 'Sin Mensajes',
noConnected: 'Ningún contacto conectado',
subjectOptional: 'Tema (opcional)',
members: 'Miembros',
@ -912,8 +915,9 @@ export const pt = {
newTopic: 'Novo tópico',
subject: 'Assunto',
noContacts: 'Sem contatos',
noTopics: 'Sem tópicos',
noContacts: 'Sem Contatos',
noTopics: 'Sem Tópicos',
noMessages: 'Sem Mensagem',
noConnected: 'Nenhum contato conectado',
subjectOptional: 'Assunto (opcional)',
members: 'Membros',
@ -1189,6 +1193,7 @@ export const de = {
subject: 'Betreff',
noContacts: 'Keine Kontakte',
noTopics: 'Keine Themen',
noMessages: 'Keine Nachrichten',
noConnected: 'Keine verbundenen Kontakte',
subjectOptional: 'Betreff (optional)',
members: 'Mitglieder',
@ -1464,6 +1469,7 @@ export const ru = {
subject: 'Тема',
noContacts: 'Нет контактов',
noTopics: 'Нет тем',
noMessages: 'Нет сообщений',
noConnected: 'Нет подключенных контактов',
subjectOptional: 'Тема (необязательно)',
members: 'Участники',

View File

@ -280,7 +280,7 @@
}
.empty {
width: 600px;
width: 400px;
height: 128px;
display: flex;
align-items: center;
@ -295,7 +295,7 @@
}
}
.blocked {
width: 600px;
width: 400px;
min-height: 128px;
max-height: 256px;
border: 1px solid var(--mantine-color-text-7);
@ -312,6 +312,10 @@
padding-bottom: 8px;
border-bottom: 1px solid var(--mantine-color-text-8);
&:hover {
background: var(--mantine-color-surface-2);
}
.blockedValue {
flex-grow: 1;
font-size: 14px;

View File

@ -45,7 +45,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
const [mfaOpened, { open: mfaOpen, close: mfaClose }] = useDisclosure(false)
const [sealOpened, { open: sealOpen, close: sealClose }] = useDisclosure(false)
const [blockedContactOpened, { open: blockedContactOpen, close: blockedContactClose }] = useDisclosure(false)
const [blockedTopicOpened, { open: blockedTopicOpen, close: blockedTopicClose }] = useDisclosure(false)
const [blockedChannelOpened, { open: blockedChannelOpen, close: blockedChannelClose }] = useDisclosure(false)
const [blockedMessageOpened, { open: blockedMessageOpen, close: blockedMessageClose }] = useDisclosure(false)
const [savingLogin, setSavingLogin] = useState(false)
const [savingDetails, setSavingDetails] = useState(false)
@ -66,19 +66,62 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
blockedContactOpen();
}
const unblockCard = async (cardId: string) => {
const unblockCard = async (blocked: {cardId: string, timestamp: number}) => {
try {
await actions.unblockCard(cardId);
await actions.unblockCard(blocked.cardId);
} catch (err) {
console.log(err);
showError();
}
}
const blockedCards = state.blockedCards.map(blocked => (
<div className={classes.blockedItem}>
<Text className={classes.blockedValue}>CardID: { blocked.cardId }</Text>
<ActionIcon variant="subtle" size="md" onClick={()=>unblockCard(blocked.cardId)}><IconRestore /></ActionIcon>
const blockedCards = state.blockedCards.map((blocked, index) => (
<div key={index} className={classes.blockedItem}>
<Text className={classes.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<ActionIcon variant="subtle" size="md" onClick={()=>unblockCard(blocked)}><IconRestore /></ActionIcon>
</div>
));
const showBlockedChannels = async () => {
await actions.loadBlockedChannels();
blockedChannelOpen();
}
const unblockChannel = async (blocked: {cardId: string | null, channelId: string, timestamp: number}) => {
try {
await actions.unblockChannel(blocked.cardId, blocked.channelId);
} catch (err) {
console.log(err);
showError();
}
}
const blockedChannels = state.blockedChannels.map((blocked, index) => (
<div key={index} className={classes.blockedItem}>
<Text className={classes.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<ActionIcon variant="subtle" size="md" onClick={()=>unblockChannel(blocked)}><IconRestore /></ActionIcon>
</div>
));
const showBlockedMessages = async () => {
await actions.loadBlockedMessages();
blockedMessageOpen();
}
const unblockMessage = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
try {
await actions.unblockMessage(blocked.cardId, blocked.channelId, blocked.topicId);
} catch (err) {
console.log(err);
showError();
}
}
const blockedMessages = state.blockedMessages.map((blocked, index) => (
<div key={index} className={classes.blockedItem}>
<Text className={classes.blockedValue}> { actions.getTimestamp(blocked.timestamp) }</Text>
<ActionIcon variant="subtle" size="md" onClick={()=>unblockMessage(blocked)}><IconRestore /></ActionIcon>
</div>
));
@ -461,13 +504,13 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
</div>
<Text className={classes.entryLabel}>{state.strings.blockedContacts}</Text>
</div>
<div className={classes.entry} onClick={blockedTopicOpen}>
<div className={classes.entry} onClick={showBlockedChannels}>
<div className={classes.entryIcon}>
<IconFolderCancel />
</div>
<Text className={classes.entryLabel}>{state.strings.blockedTopics}</Text>
</div>
<div className={classes.entry} onClick={blockedMessageOpen}>
<div className={classes.entry} onClick={showBlockedMessages}>
<div className={classes.entryIcon}>
<IconMessage2Cancel />
</div>
@ -845,11 +888,39 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
</Button>
</div>
</Modal>
<Modal title={state.strings.blockedTopics} opened={blockedTopicOpened} onClose={blockedTopicClose} overlayProps={{ backgroundOpacity: 0.55, blur: 3 }} centered>
<div className={classes.blocked}></div>
<Modal title={state.strings.blockedTopics} opened={blockedChannelOpened} onClose={blockedChannelClose} overlayProps={{ backgroundOpacity: 0.55, blur: 3 }} centered>
{ blockedChannels.length > 0 && (
<div className={classes.blocked}>
{ blockedChannels }
</div>
)}
{ blockedChannels.length === 0 && (
<div className={classes.empty}>
<Text className={classes.emptyLabel}>{ state.strings.noTopics }</Text>
</div>
)}
<div className={classes.controls}>
<Button variant="default" onClick={blockedChannelClose}>
{state.strings.close}
</Button>
</div>
</Modal>
<Modal title={state.strings.blockedMessages} opened={blockedMessageOpened} onClose={blockedMessageClose} overlayProps={{ backgroundOpacity: 0.55, blur: 3 }} centered>
<div className={classes.blocked}></div>
{ blockedMessages.length > 0 && (
<div className={classes.blocked}>
{ blockedMessages }
</div>
)}
{ blockedMessages.length === 0 && (
<div className={classes.empty}>
<Text className={classes.emptyLabel}>{ state.strings.noMessages }</Text>
</div>
)}
<div className={classes.controls}>
<Button variant="default" onClick={blockedMessageClose}>
{state.strings.close}
</Button>
</div>
</Modal>
</>
)

View File

@ -50,7 +50,9 @@ export function useSettings() {
sealConfirm: '',
sealDelete: '',
secretCopied: false,
blockedCards: [] as {cardId: string}[],
blockedCards: [] as {cardId: string, timestamp: number}[],
blockedChannels: [] as {cardId: string | null, channelId: string, timestamp: number}[],
blockedMessages: [] as {cardId: string | null, channelId: string, topicId: string, timestamp: number}[],
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -113,6 +115,30 @@ export function useSettings() {
}, [display.state])
const actions = {
loadBlockedMessages: async () => {
const settings = app.state.session.getSettings();
const blockedMessages = await settings.getBlockedTopics();
updateState({ blockedMessages });
},
unblockMessage: async (cardId: string | null, channelId: string, topicId: string) => {
const content = app.state.session.getContent();
await content.clearBlockedChannelTopic(cardId, channelId, topicId);
const blockedMessages = state.blockedMessages.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId || blocked.topicId != topicId));
updateState({ blockedMessages });
},
loadBlockedChannels: async () => {
console.log("LOAD BLOCKED");
const settings = app.state.session.getSettings();
const blockedChannels = await settings.getBlockedChannels();
console.log("LOADED: ", blockedChannels);
updateState({ blockedChannels });
},
unblockChannel: async (cardId: string | null, channelId: string) => {
const content = app.state.session.getContent();
await content.setBlockedChannel(cardId, channelId, false);
const blockedChannels = state.blockedChannels.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId));
updateState({ blockedChannels });
},
loadBlockedCards: async () => {
const settings = app.state.session.getSettings();
const blockedCards = await settings.getBlockedCards();
@ -314,6 +340,35 @@ export function useSettings() {
const data = dataUrl.split(',')[1]
await identity.setProfileImage(data)
},
getTimestamp: (created: number) => {
const now = Math.floor((new Date()).getTime() / 1000)
const date = new Date(created * 1000);
const offset = now - created;
if(offset < 43200) {
if (state.timeFormat === '12h') {
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
}
else {
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
}
}
else if (offset < 31449600) {
if (state.dateFormat === 'mm/dd') {
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
}
else {
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
}
}
else {
if (state.dateFormat === 'mm/dd') {
return date.toLocaleDateString("en-US");
}
else {
return date.toLocaleDateString("en-GB");
}
}
}
}
return { state, actions }

View File

@ -44,9 +44,9 @@ export interface Settings {
updateSeal(password: string): Promise<void>;
forgetSeal(): Promise<void>;
getBlockedCards(): Promise<{cardId: string}[]>;
getBlockedChannels(): Promise<{cardId: string | null, channelId: string}[]>;
getBlockedTopicis(): Promise<{cardId: string | null, channelId: string, topicId: string}[]>;
getBlockedCards(): Promise<{cardId: string, timestamp: number}[]>;
getBlockedChannels(): Promise<{cardId: string | null, channelId: string, timestamp: number}[]>;
getBlockedTopicis(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]>;
addConfigListener(ev: (config: Config) => void): void;
removeConfigListener(ev: (config: Config) => void): void;

View File

@ -199,7 +199,8 @@ export class ContactModule implements Contact {
this.blockedCard.add(cardId);
entry.card = this.setCard(cardId, entry.item);
this.emitCards();
await this.store.setMarker(this.guid, 'blocked_card', cardId, JSON.stringify({cardId}));
const timestamp = Math.floor(Date.now() / 1000);
await this.store.setMarker(this.guid, 'blocked_card', cardId, JSON.stringify({cardId, timestamp}));
}
private async clearCardBlocked(cardId: string) {
@ -231,7 +232,8 @@ export class ContactModule implements Contact {
this.blockedCardChannel.add(id);
channelEntry.channel = this.setChannel(cardId, channelId, channelEntry.item);
this.emitChannels(cardId);
await this.store.setMarker(this.guid, 'blocked_card_channel', id, JSON.stringify({ cardId, channelId }));
const timestamp = Math.floor(Date.now() / 1000);
await this.store.setMarker(this.guid, 'blocked_card_channel', id, JSON.stringify({ cardId, channelId, timestamp }));
}
private async clearChannelBlocked(cardId: string, channelId: string) {
@ -871,6 +873,7 @@ export class ContactModule implements Contact {
}
public async clearBlockedChannelTopic(cardId: string, channelId: string, topicId: string) {
const { guid } = this;
const id = `${cardId}:${channelId}:${topicId}`
await this.store.clearMarker(guid, 'blocked_topic', id);
if (this.focus) {

View File

@ -822,7 +822,8 @@ export class FocusModule implements Focus {
this.blocked.add(id);
entry.topic = this.setTopic(topicId, entry.item);
this.emitTopics();
await this.store.setMarker(guid, 'blocked_topic', id, JSON.stringify({ cardId, channelId, topicId }));
const timestamp = Math.floor(Date.now() / 1000);
await this.store.setMarker(guid, 'blocked_topic', id, JSON.stringify({ cardId, channelId, topicId, timestamp }));
}
}

View File

@ -280,7 +280,7 @@ export class SettingsModule implements Settings {
await setAccountLogin(node, secure, token, username, password);
}
public async getBlockedCards(): Promise<{cardId: string}[]> {
public async getBlockedCards(): Promise<{cardId: string, timestamp: number}[]> {
const { guid } = this;
const blockedContacts = await this.store.getMarkers(guid, 'blocked_card');
return blockedContacts.map(marker => {
@ -292,13 +292,28 @@ export class SettingsModule implements Settings {
});
}
public async getBlockedChannels(): Promise<{cardId: string | null, channelId: string}[]> {
const blockedChannels = await this.store.getMarkers(guid, 'blocked_card_channel');
return [];
public async getBlockedChannels(): Promise<{cardId: string | null, channelId: string, timestamp: number}[]> {
const { guid } = this;
const blockedChannels = await this.store.getMarkers(guid, 'blocked_channel');
const blockedCardChannels = await this.store.getMarkers(guid, 'blocked_card_channel');
return blockedChannels.concat(blockedCardChannels).map(marker => {
try {
return JSON.parse(marker.value);
} catch (err) {
return {};
}
});
}
public async getBlockedTopics(): Promise<{cardId: string | null, channelId: string, topicId: string}[]> {
public async getBlockedTopics(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]> {
const { guid } = this;
const blockedTopics = await this.store.getMarkers(guid, 'blocked_topic');
return [];
return blockedTopics.map(marker => {
try {
return JSON.parse(marker.value);
} catch (err) {
return {};
}
});
}
}

View File

@ -509,7 +509,8 @@ export class StreamModule {
this.blocked.add(channelId);
entry.channel = this.setChannel(channelId, entry.item);
this.emitChannels();
await this.store.setMarker(this.guid, 'blocked_channel', channelId, JSON.stringify({ cardId: null, channelId }));
const timestamp = Math.floor(Date.now() / 1000);
await this.store.setMarker(this.guid, 'blocked_channel', channelId, JSON.stringify({ cardId: null, channelId, timestamp }));
}
private async clearChannelBlocked(channelId: string) {