Browse Source

Implement deleting all messages of a chat (#329)

Fixes #50.
Silly 8 years ago
parent
commit
9f1332e10b

+ 3 - 1
public/i18n/de.json

@@ -151,7 +151,9 @@
         "UNKNOWN_MESSAGE_TYPE": "Unbekannter Nachrichtentyp",
         "NICKNAME": "Nickname",
         "THREEMA_WORK_CONTACT": "Threema Work Nutzer",
-        "THREEMA_BLOCKED_RECEIVER": "blockiert"
+        "THREEMA_BLOCKED_RECEIVER": "blockiert",
+        "DELETE_THREAD": "Chat löschen",
+        "DELETE_THREAD_MESSAGE": "{count, plural, one {Möchten Sie wirklich diesen Chat löschen? Die Nachrichten können nicht wiederhergestellt werden.} other {Möchten Sie wirklich # Chats löschen? Die Nachrichten können nicht wiederhergestellt werden.}}"
     },
     "messageTypes": {
         "AUDIO_MESSAGE": "Sprachnachricht",

+ 3 - 1
public/i18n/en.json

@@ -152,7 +152,9 @@
         "UNKNOWN_MESSAGE_TYPE": "Unknown message type",
         "NICKNAME": "Nickname",
         "THREEMA_WORK_CONTACT": "Threema Work user",
-        "THREEMA_BLOCKED_RECEIVER": "blocked"
+        "THREEMA_BLOCKED_RECEIVER": "blocked",
+        "DELETE_THREAD": "Delete chat",
+        "DELETE_THREAD_MESSAGE": "{count, plural, one {Do you really want to delete this chat? You will not be able to recover the messages.} other {Do you really want to delete # chat(s)? You will not be able to recover the messages.}}"
     },
     "messageTypes": {
         "AUDIO_MESSAGE": "Audio Message",

+ 35 - 0
src/controller_model/contact.ts

@@ -111,6 +111,41 @@ export class ContactControllerModel implements threema.ControllerModel {
             );
     }
 
+    public canClean(): boolean {
+        return this.canView();
+    }
+
+    public clean(ev: any): any {
+        let confirm = this.$mdDialog.confirm()
+            .title(this.$translate.instant('messenger.DELETE_THREAD'))
+            .textContent(this.$translate.instant('messenger.DELETE_THREAD_MESSAGE', {count: 1}))
+            .targetEvent(ev)
+            .ok(this.$translate.instant('common.YES'))
+            .cancel(this.$translate.instant('common.NO'));
+
+        this.$mdDialog.show(confirm).then(() => {
+            this.reallyClean();
+        }, () => {
+            this.$log.debug('clean canceled');
+        });
+    }
+
+    private reallyClean(): any {
+        if (!this.canClean()) {
+            this.$log.error('not allowed to clean this contact');
+            return;
+        }
+
+        this.isLoading = true;
+        this.webClientService.cleanReceiverConversation(this.contact)
+            .then(() => {
+                this.isLoading = false;
+            })
+            .catch(() => {
+                this.isLoading = false;
+            });
+    }
+
     public save(): Promise<threema.ContactReceiver> {
         switch (this.getMode()) {
             case ControllerModelMode.EDIT:

+ 35 - 0
src/controller_model/distributionList.ts

@@ -95,6 +95,41 @@ export class DistributionListControllerModel implements threema.ControllerModel
         return true;
     }
 
+    public canClean(): boolean {
+        return true;
+    }
+
+    public clean(ev: any): any {
+        let confirm = this.$mdDialog.confirm()
+            .title(this.$translate.instant('messenger.DELETE_THREAD'))
+            .textContent(this.$translate.instant('messenger.DELETE_THREAD_MESSAGE', {count: 1}))
+            .targetEvent(ev)
+            .ok(this.$translate.instant('common.YES'))
+            .cancel(this.$translate.instant('common.CANCEL'));
+
+        this.$mdDialog.show(confirm).then(() => {
+            this.reallyClean();
+        }, () => {
+            this.$log.debug('clean canceled');
+        });
+    }
+
+    private reallyClean(): any {
+        if (!this.canClean()) {
+            this.$log.error('not allowed to clean this contact');
+            return;
+        }
+
+        this.isLoading = true;
+        this.webClientService.cleanReceiverConversation(this.distributionList)
+            .then(() => {
+                this.isLoading = false;
+            })
+            .catch(() => {
+                this.isLoading = false;
+            });
+    }
+
     public delete(ev): void {
 
         let confirm = this.$mdDialog.confirm()

+ 35 - 0
src/controller_model/group.ts

@@ -110,6 +110,41 @@ export class GroupControllerModel implements threema.ControllerModel {
             );
     }
 
+    public canClean(): boolean {
+        return this.canView();
+    }
+
+    public clean(ev: any): any {
+        let confirm = this.$mdDialog.confirm()
+            .title(this.$translate.instant('messenger.DELETE_THREAD'))
+            .textContent(this.$translate.instant('messenger.DELETE_THREAD_MESSAGE', {count: 1}))
+            .targetEvent(ev)
+            .ok(this.$translate.instant('common.YES'))
+            .cancel(this.$translate.instant('common.CANCEL'));
+
+        this.$mdDialog.show(confirm).then(() => {
+            this.reallyClean();
+        }, () => {
+            this.$log.debug('clean canceled');
+        });
+    }
+
+    private reallyClean(): any {
+        if (!this.canClean()) {
+            this.$log.error('not allowed to clean this contact');
+            return;
+        }
+
+        this.isLoading = true;
+        this.webClientService.cleanReceiverConversation(this.group)
+            .then(() => {
+                this.isLoading = false;
+            })
+            .catch(() => {
+                this.isLoading = false;
+            });
+    }
+
     public leave(ev): void {
         let confirm = this.$mdDialog.confirm()
             .title(this.$translate.instant('messenger.GROUP_LEAVE'))

+ 11 - 0
src/partials/messenger.receiver/contact.html

@@ -39,6 +39,17 @@
 			</dl>
 		</md-card-content>
 	</md-card>
+
+	<md-card>
+		<md-card-content>
+			<section layout="row" layout-sm="column" layout-align="center center" layout-wrap>
+				<md-button ng-disabled="!ctrl.controllerModel.canClean()" class="md-raised" ng-click="ctrl.controllerModel.clean($event)">
+					<span translate>messenger.DELETE_THREAD</span>
+				</md-button>
+			</section>
+		</md-card-content>
+	</md-card>
+
 	<!-- system contact list card -->
 	<md-card ng-if="ctrl.hasSystemEmails || ctrl.hasSystemPhones">
 		<md-card-title>

+ 4 - 1
src/partials/messenger.receiver/distributionList.html

@@ -19,6 +19,9 @@
 
 	<md-card>
 		<md-card-content>
+				<md-button ng-disabled="!ctrl.controllerModel.canClean()" class="md-raised" ng-click="ctrl.controllerModel.clean($event)">
+					<span translate>messenger.DELETE_THREAD</span>
+				</md-button>
 			<section layout="row" layout-sm="column" layout-align="center center" layout-wrap>
 				<md-button ng-disabled="!ctrl.receiver.access.canDelete" class="md-raised md-warn" ng-click="ctrl.controllerModel.delete()">
 					<span translate>messenger.DISTRIBUTION_LIST_DELETE</span>
@@ -26,4 +29,4 @@
 			</section>
 		</md-card-content>
 	</md-card>
-</div>
+</div>

+ 3 - 0
src/partials/messenger.receiver/group.html

@@ -51,6 +51,9 @@
 				<md-button ng-disabled="!ctrl.receiver.access.canSync" class="md-raised" ng-click="ctrl.controllerModel.sync($event)">
 					<span translate>messenger.GROUP_SYNC</span>
 				</md-button>
+				<md-button ng-disabled="!ctrl.controllerModel.canClean()" class="md-raised" ng-click="ctrl.controllerModel.clean($event)">
+					<span translate>messenger.DELETE_THREAD</span>
+				</md-button>
 				<md-button ng-disabled="!ctrl.receiver.access.canLeave" class="md-raised " ng-click="ctrl.controllerModel.leave($event)">
 					<span translate>messenger.GROUP_LEAVE</span>
 				</md-button>

+ 1 - 1
src/partials/messenger.ts

@@ -904,7 +904,7 @@ class MessengerController {
                             if ($state.params.type === receiver.type
                                 && $state.params.id === receiver.id) {
                                 // conversation or sub form is open, redirect to home!
-                                this.$state.go('messenger.home', null, {location: 'replace'});
+                                $state.go('messenger.home', null, {location: 'replace'});
                             }
                         }
                         break;

+ 28 - 7
src/services/webclient.ts

@@ -96,6 +96,7 @@ export class WebClientService {
     private static SUB_TYPE_ALERT = 'alert';
     private static SUB_TYPE_GROUP_SYNC = 'groupSync';
     private static SUB_TYPE_BATTERY_STATUS = 'batteryStatus';
+    private static SUB_TYPE_CLEAN_RECEIVER_CONVERSATION = 'cleanReceiverConversation';
     private static ARGUMENT_MODE = 'mode';
     private static ARGUMENT_MODE_REFRESH = 'refresh';
     private static ARGUMENT_MODE_NEW = 'new';
@@ -1032,7 +1033,8 @@ export class WebClientService {
     public ackMessage(receiver, message: threema.Message, acknowledged: boolean = true): void {
         // Ignore empty text messages
         // TODO check into a util class
-        if (message === undefined
+        if (message === null
+            || message === undefined
             || message.isOutbox) {
             return;
         }
@@ -1051,7 +1053,7 @@ export class WebClientService {
      */
     public deleteMessage(receiver, message: threema.Message): void {
         // Ignore empty text messages
-        if (message === undefined) {
+        if (message === null || message === undefined) {
             return;
         }
 
@@ -1156,7 +1158,7 @@ export class WebClientService {
     }
 
     public leaveGroup(group: threema.GroupReceiver): Promise<any> {
-        if (group === undefined || !group.access.canLeave) {
+        if (group === null || group === undefined || !group.access.canLeave) {
             return new Promise((resolve, reject) => reject('not allowed'));
         }
 
@@ -1170,7 +1172,7 @@ export class WebClientService {
     }
 
     public deleteGroup(group: threema.GroupReceiver): Promise<any> {
-        if (group === undefined || !group.access.canDelete) {
+        if (group === null || group === undefined || !group.access.canDelete) {
             return new Promise<any> (
                 (resolve, reject) => {
                     reject('not allowed');
@@ -1187,7 +1189,7 @@ export class WebClientService {
     }
 
     public syncGroup(group: threema.GroupReceiver): Promise<any> {
-        if (group === undefined || !group.access.canSync) {
+        if (group === null || group === undefined || !group.access.canSync) {
             return new Promise<any> (
                 (resolve, reject) => {
                     reject('not allowed');
@@ -1224,7 +1226,7 @@ export class WebClientService {
     }
 
     public deleteDistributionList(distributionList: threema.DistributionListReceiver): Promise<any> {
-        if (distributionList === undefined || !distributionList.access.canDelete) {
+        if (distributionList === null || distributionList === undefined || !distributionList.access.canDelete) {
             return new Promise((resolve, reject) => reject('not allowed'));
         }
 
@@ -1235,6 +1237,24 @@ export class WebClientService {
         return this._sendDeletePromise(WebClientService.SUB_TYPE_DISTRIBUTION_LIST, args);
     }
 
+    /**
+     * Remove all messages of a receiver
+     * @param {threema.Receiver} receiver
+     * @returns {Promise<any>}
+     */
+    public cleanReceiverConversation(receiver: threema.Receiver): Promise<any> {
+        if (receiver === null || receiver === undefined) {
+            return new Promise((resolve, reject) => reject('invalid receiver'));
+        }
+
+        let args = {
+            [WebClientService.ARGUMENT_RECEIVER_TYPE]: receiver.type,
+            [WebClientService.ARGUMENT_RECEIVER_ID]: receiver.id,
+        };
+
+        return this._sendDeletePromise(WebClientService.SUB_TYPE_CLEAN_RECEIVER_CONVERSATION, args);
+    }
+
     /**
      * Return whether the specified contact is currently typing.
      *
@@ -1654,7 +1674,8 @@ export class WebClientService {
                 break;
             case WebClientService.ARGUMENT_MODE_REMOVED:
                 this.conversations.remove(data);
-
+                // Remove all cached messages
+                this.messages.clearReceiverMessages((data as threema.Receiver));
                 this.receiverListener.forEach((listener: threema.ReceiverListener) => {
                     this.$log.debug('call on removed listener');
                     listener.onRemoved(data);

+ 2 - 0
src/threema.d.ts

@@ -420,9 +420,11 @@ declare namespace threema {
         subject: string;
         isLoading: boolean;
         save(): any;
+        clean(ev: any): any;
         isValid(): boolean;
         canView(): boolean;
         canEdit(): boolean;
+        canClean(): boolean;
         getMode(): number;
         setOnRemoved(callback: any): void;
     }