diff --git a/README.md b/README.md index 4759ed7..7ff6383 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ | ๐Ÿ—๏ธ ้›ถ็Ÿฅ่ฏ†ๆœๅŠกๅ™จ | ๆœๅŠกๅ™จๅชๅญ˜ๅ‚จๅฏ†ๆ–‡๏ผŒ็ง้’ฅไป…ๅœจ่ฎพๅค‡ๆœฌๅœฐ๏ผˆๅ››ๅฑ‚ๆŒไน…ๅŒ–๏ผ‰ | | ๐Ÿ“น ่ง†้ข‘/่ฏญ้Ÿณ้€š่ฏ | WebRTC P2P๏ผˆ1:1๏ผ‰+ Mesh๏ผˆๅคšไบบ๏ผ‰๏ผŒCloudflare TURN ็ฉฟ้€ | | ๐Ÿ‘ฅ ็พค่Š | ๆœ€ๅคš 2000 ไบบ็พค็ป„๏ผŒ็บฏๆ–‡ๆœฌๆถˆๆฏ๏ผˆๆ— ๅŠ ๅฏ†๏ผ‰๏ผŒๅ…ๆ‰“ๆ‰ฐๆจกๅผ๏ผŒๆˆๅ‘˜็ฎก็† | +| โฑ๏ธ ๆถˆๆฏ่‡ชๅŠจๅˆ ้™ค | 5 ๆกฃๅฏ้€‰๏ผˆๆฐธไธ/1ๅคฉ/3ๅคฉ/1ๅ‘จ/1ๆœˆ๏ผ‰๏ผŒ็ง่ŠๅŒๆ–นๅ‡ๅฏ่ฎพ็ฝฎ๏ผŒ็พค่Š็พคไธปไธ“ๅฑž | | ๐Ÿ”” ๆถˆๆฏๆŽจ้€ | Web Push (VAPID) + OneSignal ๅŒ้€š้“๏ผŒ็ฆป็บฟไนŸ่ƒฝๆ”ถๅˆฐ้€š็Ÿฅ | | ๐ŸŒ ๅคš่ฏญ่จ€ | ไธญๆ–‡ใ€่‹ฑๆ–‡ใ€ๆ—ฅ่ฏญใ€้Ÿฉ่ฏญใ€ๆณ•่ฏญ๏ผˆ่‡ชๅŠจๆฃ€ๆต‹ + ๆ‰‹ๅŠจๅˆ‡ๆข๏ผ‰ | | ๐Ÿ“ฑ iOS ๆฐธไน…ๅ…็ญพ | PWA H5 โ†’ Safariใ€ŒๆทปๅŠ ๅˆฐไธปๅฑๅน•ใ€๏ผŒๆ— ้œ€ไผไธš่ฏไนฆ | diff --git a/README_EN.md b/README_EN.md index 862df5e..59c8246 100644 --- a/README_EN.md +++ b/README_EN.md @@ -16,6 +16,7 @@ A WeChat-style end-to-end encrypted instant messaging app with stateless ECDH + | ๐Ÿ—‘๏ธ Zero-Knowledge Server | Server stores only ciphertext; private keys never leave the device | | ๐Ÿ“น Video & Voice Calls | WebRTC P2P (1:1) + Mesh (group), Cloudflare TURN for NAT traversal | | ๐Ÿ‘ฅ Group Chat | Up to 2000 members, plain-text messages (no encryption), Do Not Disturb mode, member management | +| โฑ๏ธ Auto-Delete Messages | 5 tiers (never / 1 day / 3 days / 1 week / 1 month), settable by either party in DMs, owner-only in groups | | ๐Ÿ”” Push Notifications | Web Push (VAPID) + OneSignal dual-channel โ€” reach users even when offline | | ๐ŸŒ Multi-Language | Chinese, English, Japanese, Korean, French โ€” auto-detect + manual switch | | ๐Ÿ“ฑ iOS โ€” No Enterprise Cert | PWA via Safari "Add to Home Screen", works permanently without Apple signing | diff --git a/client/src/api.js b/client/src/api.js index b5e1f09..0f1aee9 100644 --- a/client/src/api.js +++ b/client/src/api.js @@ -65,6 +65,8 @@ export const api = { leaveGroup: id => req('DELETE', `/api/groups/${id}/members/me`), disbandGroup: id => req('DELETE', `/api/groups/${id}`), muteGroup: (id, muted) => req('PATCH', `/api/groups/${id}/mute`, { muted }), + setAutoDelete: (friendId, val) => req('PATCH', `/api/friends/${friendId}/auto-delete`, { auto_delete: val }), + setGroupAutoDelete: (groupId, val) => req('PATCH', `/api/groups/${groupId}/auto-delete`, { auto_delete: val }), // Messages privateHistory: pid => req('GET', `/api/messages/private/${pid}`), diff --git a/client/src/app.js b/client/src/app.js index 322d66b..c09a30e 100644 --- a/client/src/app.js +++ b/client/src/app.js @@ -282,6 +282,17 @@ function setupGlobalSocketHandlers() { } }); + // โ”€โ”€ Auto-delete setting changed by other party โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + onEvent('auto_delete_changed', ({ chat_id, chat_type, auto_delete }) => { + if (chat_type === 'private') { + const contact = state.contacts.find(c => c.id === chat_id); + if (contact) contact.auto_delete = auto_delete; + } else { + const group = (state.groupsList || []).find(g => g.id === chat_id); + if (group) group.auto_delete = auto_delete; + } + }); + // โ”€โ”€ Session Revoked (device kicked by another session) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ onEvent('session_revoked', () => { clearToken(); diff --git a/client/src/i18n.js b/client/src/i18n.js index e2c10ce..817ac52 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -184,6 +184,14 @@ const TRANSLATIONS = { muteGroup: 'ๆถˆๆฏๅ…ๆ‰“ๆ‰ฐ', muteEnabled: 'ๅทฒๅผ€ๅฏๅ…ๆ‰“ๆ‰ฐ', muteDisabled: 'ๅทฒๅ…ณ้—ญๅ…ๆ‰“ๆ‰ฐ', + autoDeleteTitle: '่‡ชๅŠจๅˆ ้™คๆถˆๆฏ', + autoDeleteNever: 'ๆฐธไธๅˆ ้™ค', + autoDelete1d: '1 ๅคฉๅŽ', + autoDelete3d: '3 ๅคฉๅŽ', + autoDelete7d: '1 ๅ‘จๅŽ', + autoDelete30d: '1 ไธชๆœˆๅŽ', + autoDeleteUpdated: '่‡ชๅŠจๅˆ ้™คๅทฒๆ›ดๆ–ฐ', + autoDeleteOwnerOnly: 'ๅชๆœ‰็พคไธปๅฏไปฅ่ฎพ็ฝฎ', }, en: { @@ -358,6 +366,14 @@ const TRANSLATIONS = { muteGroup: 'Mute Notifications', muteEnabled: 'Notifications muted', muteDisabled: 'Notifications unmuted', + autoDeleteTitle: 'Auto-Delete Messages', + autoDeleteNever: 'Never', + autoDelete1d: 'After 1 Day', + autoDelete3d: 'After 3 Days', + autoDelete7d: 'After 1 Week', + autoDelete30d: 'After 1 Month', + autoDeleteUpdated: 'Auto-delete updated', + autoDeleteOwnerOnly: 'Only owner can set', }, ja: { @@ -532,6 +548,14 @@ const TRANSLATIONS = { muteGroup: '้€š็ŸฅใƒŸใƒฅใƒผใƒˆ', muteEnabled: '้€š็Ÿฅใ‚’ใƒŸใƒฅใƒผใƒˆใ—ใพใ—ใŸ', muteDisabled: '้€š็ŸฅใฎใƒŸใƒฅใƒผใƒˆใ‚’่งฃ้™คใ—ใพใ—ใŸ', + autoDeleteTitle: 'ใƒกใƒƒใ‚ปใƒผใ‚ธ่‡ชๅŠจๅ‰Š้™ค', + autoDeleteNever: 'ๅ‰Š้™คใ—ใชใ„', + autoDelete1d: '1ๆ—ฅๅพŒ', + autoDelete3d: '3ๆ—ฅๅพŒ', + autoDelete7d: '1้€ฑ้–“ๅพŒ', + autoDelete30d: '1ใ‹ๆœˆๅพŒ', + autoDeleteUpdated: '่‡ชๅŠจๅ‰Š้™คใŒๆ›ดๆ–ฐใ•ใ‚Œใพใ—ใŸ', + autoDeleteOwnerOnly: 'ใ‚ชใƒผใƒŠใƒผใฎใฟ่จญๅฎšๅฏ', }, ko: { @@ -706,6 +730,14 @@ const TRANSLATIONS = { muteGroup: '์•Œ๋ฆผ ์Œ์†Œ๊ฑฐ', muteEnabled: '์•Œ๋ฆผ์ด ์Œ์†Œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค', muteDisabled: '์•Œ๋ฆผ ์Œ์†Œ๊ฑฐ๊ฐ€ ํ•ด์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค', + autoDeleteTitle: '๋ฉ”์‹œ์ง€ ์ž๋™ ์‚ญ์ œ', + autoDeleteNever: '์‚ญ์ œ ์•ˆ ํ•จ', + autoDelete1d: '1์ผ ํ›„', + autoDelete3d: '3์ผ ํ›„', + autoDelete7d: '1์ฃผ์ผ ํ›„', + autoDelete30d: '1๊ฐœ์›” ํ›„', + autoDeleteUpdated: '์ž๋™ ์‚ญ์ œ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค', + autoDeleteOwnerOnly: '๊ทธ๋ฃน์žฅ๋งŒ ์„ค์ • ๊ฐ€๋Šฅ', }, fr: { @@ -880,6 +912,14 @@ const TRANSLATIONS = { muteGroup: 'Mettre en sourdine', muteEnabled: 'Notifications dรฉsactivรฉes', muteDisabled: 'Notifications rรฉactivรฉes', + autoDeleteTitle: 'Suppression auto des messages', + autoDeleteNever: 'Jamais', + autoDelete1d: 'Aprรจs 1 jour', + autoDelete3d: 'Aprรจs 3 jours', + autoDelete7d: 'Aprรจs 1 semaine', + autoDelete30d: 'Aprรจs 1 mois', + autoDeleteUpdated: 'Suppression auto mise ร  jour', + autoDeleteOwnerOnly: 'Seul le propriรฉtaire peut dรฉfinir', }, }; diff --git a/client/src/pages/chat.js b/client/src/pages/chat.js index 0f43368..e7a012f 100644 --- a/client/src/pages/chat.js +++ b/client/src/pages/chat.js @@ -32,6 +32,12 @@ export async function renderChat(root, chat) { ` : ''} + ${chat.type === 'private' ? ` + ` : ''}