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' ? `
+ ` : ''}