From 4eed98d58dbdf14a3366749cf1d8ff22887e32ef Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 7 Dec 2021 09:55:13 -0500 Subject: [PATCH] feat(mail): delay or disable automatic mark message as read Fixes #1585 --- SoObjects/SOGo/SOGoDefaults.plist | 1 + SoObjects/SOGo/SOGoUserDefaults.h | 4 ++ SoObjects/SOGo/SOGoUserDefaults.m | 12 +++++ UI/MailerUI/UIxMailView.m | 9 +++- .../English.lproj/Localizable.strings | 4 ++ UI/PreferencesUI/UIxJSONPreferences.m | 3 ++ UI/Templates/MailerUI/UIxMailViewTemplate.wox | 6 +++ UI/Templates/PreferencesUI/UIxPreferences.wox | 22 ++++++-- UI/WebServerResources/img/mark_email_read.svg | 1 + .../img/mark_email_unread.svg | 1 + .../js/Mailer/Message.service.js | 54 ++++++++++++++++--- .../js/Mailer/MessageController.js | 3 ++ .../js/Preferences/Preferences.service.js | 16 ++++++ .../js/Preferences/PreferencesController.js | 5 ++ 14 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 UI/WebServerResources/img/mark_email_read.svg create mode 100644 UI/WebServerResources/img/mark_email_unread.svg diff --git a/SoObjects/SOGo/SOGoDefaults.plist b/SoObjects/SOGo/SOGoDefaults.plist index fc7e95e21..3163dd3b6 100644 --- a/SoObjects/SOGo/SOGoDefaults.plist +++ b/SoObjects/SOGo/SOGoDefaults.plist @@ -119,6 +119,7 @@ SOGoMailDisplayRemoteInlineImages = "never"; SOGoMailCertificateEnabled = YES; + SOGoMailAutoMarkAsReadDelay = "0"; SOGoMailAutoSave = "5"; SOGoCalendarShouldDisplayWeekend = YES; diff --git a/SoObjects/SOGo/SOGoUserDefaults.h b/SoObjects/SOGo/SOGoUserDefaults.h index 62b9d9009..11131f8c1 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.h +++ b/SoObjects/SOGo/SOGoUserDefaults.h @@ -148,6 +148,10 @@ extern NSString *SOGoWeekStartFirstFullWeek; - (void) setMailDisplayRemoteInlineImages: (NSString *) newValue; - (NSString *) mailDisplayRemoteInlineImages; + +- (void) setMailAutoMarkAsReadDelay: (int) newValue; +- (int) mailAutoMarkAsReadDelay; + - (void) setMailAutoSave: (NSString *) newValue; - (NSString *) mailAutoSave; diff --git a/SoObjects/SOGo/SOGoUserDefaults.m b/SoObjects/SOGo/SOGoUserDefaults.m index edfdbd2cf..0f8ecb22e 100644 --- a/SoObjects/SOGo/SOGoUserDefaults.m +++ b/SoObjects/SOGo/SOGoUserDefaults.m @@ -18,10 +18,12 @@ * Boston, MA 02111-1307, USA. */ +#import #import #import #import +#import #import #import #import @@ -618,6 +620,16 @@ NSString *SOGoWeekStartFirstFullWeek = @"FirstFullWeek"; return [self stringForKey: @"SOGoMailDisplayRemoteInlineImages"]; } +- (void) setMailAutoMarkAsReadDelay: (int) newValue +{ + [self setInteger: newValue forKey: @"SOGoMailAutoMarkAsReadDelay"]; +} + +- (int) mailAutoMarkAsReadDelay +{ + return [self integerForKey: @"SOGoMailAutoMarkAsReadDelay"]; +} + - (void) setMailAutoSave: (NSString *) newValue { [self setObject: newValue forKey: @"SOGoMailAutoSave"]; diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m index 85b652e0e..54ed8ef34 100644 --- a/UI/MailerUI/UIxMailView.m +++ b/UI/MailerUI/UIxMailView.m @@ -272,11 +272,13 @@ static NSString *mailETag = nil; NSMutableDictionary *data; NSArray *addresses; SOGoMailObject *co; + SOGoUserDefaults *ud; UIxEnvelopeAddressFormatter *addressFormatter; UIxMailRenderingContext *mctx; id viewer, renderedPart; co = [self clientObject]; + ud = [[context activeUser] userDefaults]; addressFormatter = [context mailEnvelopeAddressFormatter]; mctx = [[UIxMailRenderingContext alloc] initWithViewer: self context: context]; @@ -349,8 +351,11 @@ static NSString *mailETag = nil; if ((addresses = [addressFormatter dictionariesForArray: [co replyToEnvelopeAddresses]])) [data setObject: addresses forKey: @"reply-to"]; - // Mark message as read - [co addFlags: @"seen"]; + if ([ud mailAutoMarkAsReadDelay] == 0) + // Mark message as read + [co addFlags: @"seen"]; + + [data setObject: [NSNumber numberWithBool: [co read]] forKey: @"isRead"]; response = [self responseWithStatus: 200 andJSONRepresentation: data]; diff --git a/UI/PreferencesUI/English.lproj/Localizable.strings b/UI/PreferencesUI/English.lproj/Localizable.strings index 7880db460..0c01c5955 100644 --- a/UI/PreferencesUI/English.lproj/Localizable.strings +++ b/UI/PreferencesUI/English.lproj/Localizable.strings @@ -201,6 +201,10 @@ "displayremoteinlineimages_always" = "Always"; "Auto save every" = "Auto save every"; "minutes" = "minutes"; +"Automatically mark messages as read" = "Automatically mark messages as read"; +"Immediately on display" = "Immediately on display"; +"After displaying for" = "After displaying for"; +"seconds" = "seconds"; /* Contact */ "Personal Address Book" = "Personal Address Book"; diff --git a/UI/PreferencesUI/UIxJSONPreferences.m b/UI/PreferencesUI/UIxJSONPreferences.m index 602c5a6bd..517c609cf 100644 --- a/UI/PreferencesUI/UIxJSONPreferences.m +++ b/UI/PreferencesUI/UIxJSONPreferences.m @@ -342,6 +342,9 @@ static SoProduct *preferencesProduct = nil; if (![[defaults source] objectForKey: @"SOGoMailDisplayRemoteInlineImages"]) [[defaults source] setObject: [defaults mailDisplayRemoteInlineImages] forKey: @"SOGoMailDisplayRemoteInlineImages"]; + if ([[defaults source] objectForKey: @"SOGoMailAutoMarkAsReadDelay"] == nil) + [[defaults source] setObject: [NSNumber numberWithInt: [defaults mailAutoMarkAsReadDelay]] forKey: @"SOGoMailAutoMarkAsReadDelay"]; + if (![[defaults source] objectForKey: @"SOGoMailAutoSave"]) [[defaults source] setObject: [defaults mailAutoSave] forKey: @"SOGoMailAutoSave"]; diff --git a/UI/Templates/MailerUI/UIxMailViewTemplate.wox b/UI/Templates/MailerUI/UIxMailViewTemplate.wox index 5d69b0ba3..41281015d 100644 --- a/UI/Templates/MailerUI/UIxMailViewTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailViewTemplate.wox @@ -35,6 +35,12 @@ {{ viewer.message.isflagged ? 'star' : 'star_border' }} + + + + +
+ + + + + + + + + + +
diff --git a/UI/WebServerResources/img/mark_email_read.svg b/UI/WebServerResources/img/mark_email_read.svg new file mode 100644 index 000000000..c0ca62eba --- /dev/null +++ b/UI/WebServerResources/img/mark_email_read.svg @@ -0,0 +1 @@ + diff --git a/UI/WebServerResources/img/mark_email_unread.svg b/UI/WebServerResources/img/mark_email_unread.svg new file mode 100644 index 000000000..4d76873cf --- /dev/null +++ b/UI/WebServerResources/img/mark_email_unread.svg @@ -0,0 +1 @@ + diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js index c51a30858..8745940b4 100644 --- a/UI/WebServerResources/js/Mailer/Message.service.js +++ b/UI/WebServerResources/js/Mailer/Message.service.js @@ -132,6 +132,7 @@ _this.flags.splice(i, 1,'_' + flag); } }); + this.isread = !!this.isread; }; /** @@ -540,6 +541,31 @@ return Message.$$resource.post(this.$mailbox.$id(), 'addOrRemoveLabel', data); }; + /** + * @function toggleRead + * @memberof Message.prototype + * @desc Toggle message unseen status + * @returns a promise of the HTTP operation + */ + Message.prototype.toggleRead = function() { + var _this = this; + + if (this.isread) + return Message.$$resource.fetch(this.$absolutePath(), 'markMessageUnread').then(function() { + Message.$timeout(function() { + _this.isread = false; + _this.$mailbox.unseenCount++; + }); + }); + else + return Message.$$resource.fetch(this.$absolutePath(), 'markMessageRead').then(function() { + Message.$timeout(function() { + _this.isread = true; + _this.$mailbox.unseenCount--; + }); + }); + }; + /** * @function $imipAction * @memberof Message.prototype @@ -664,13 +690,16 @@ var _this = this, futureMessageData; if (options && options.useCache && this.$futureMessageData) { + // The message has already been fetched. if (!this.isread) { - Message.$$resource.fetch(this.$absolutePath(), 'markMessageRead').then(function() { - Message.$timeout(function() { - _this.isread = true; - _this.$mailbox.unseenCount--; - }); - }); + if (Message.$Preferences.defaults.SOGoMailAutoMarkAsReadDelay > -1) + // Automatically mark message as read + _this.$markAsReadPromise = Message.$timeout(function() { + Message.$$resource.fetch(_this.$absolutePath(), 'markMessageRead').then(function() { + _this.isread = true; + _this.$mailbox.unseenCount--; + }); + }, Message.$Preferences.defaults.SOGoMailAutoMarkAsReadDelay * 1000); } return this; } @@ -865,7 +894,18 @@ // Resolve and expose the promise this.$futureMessageData = futureMessageData.then(function(data) { // Calling $timeout will force Angular to refresh the view - if (_this.isread === 0) { + if (!data.isRead) { + if (Message.$Preferences.defaults.SOGoMailAutoMarkAsReadDelay > -1) + // Automatically mark message as read + _this.$markAsReadPromise = Message.$timeout(function() { + Message.$$resource.fetch(_this.$absolutePath(), 'markMessageRead').then(function() { + _this.isread = true; + _this.$mailbox.unseenCount--; + }); + }, Message.$Preferences.defaults.SOGoMailAutoMarkAsReadDelay * 1000); + } + else if (!_this.isread) { + // Message as already been marked read on the server _this.isread = true; _this.$mailbox.unseenCount--; } diff --git a/UI/WebServerResources/js/Mailer/MessageController.js b/UI/WebServerResources/js/Mailer/MessageController.js index 05cb3be96..bf41f4fb4 100644 --- a/UI/WebServerResources/js/Mailer/MessageController.js +++ b/UI/WebServerResources/js/Mailer/MessageController.js @@ -98,6 +98,9 @@ _.forEach(hotkeys, function(key) { sgHotkeys.deregisterHotkey(key); }); + // Cancel automatic mark as read + if (vm.message.$markAsReadPromise) + vm.service.$timeout.cancel(vm.message.$markAsReadPromise); }); }; // $onInit diff --git a/UI/WebServerResources/js/Preferences/Preferences.service.js b/UI/WebServerResources/js/Preferences/Preferences.service.js index 4dfc36c5f..b87ecda81 100644 --- a/UI/WebServerResources/js/Preferences/Preferences.service.js +++ b/UI/WebServerResources/js/Preferences/Preferences.service.js @@ -53,6 +53,13 @@ if (data.SOGoRememberLastModule) data.SOGoLoginModule = "Last"; + data.SOGoMailAutoMarkAsReadDelay = parseInt(data.SOGoMailAutoMarkAsReadDelay) || 0; + data.SOGoMailAutoMarkAsReadEnabled = (data.SOGoMailAutoMarkAsReadDelay >= 0); + if (data.SOGoMailAutoMarkAsReadDelay > 0) + data.SOGoMailAutoMarkAsReadMode = 'delay'; + else + data.SOGoMailAutoMarkAsReadMode = 'immediate'; + // Mail editor autosave is a number of minutes or 0 if disabled data.SOGoMailAutoSave = parseInt(data.SOGoMailAutoSave) || 0; @@ -724,6 +731,15 @@ // Don't push locale definition delete preferences.defaults.locale; + if (preferences.defaults.SOGoMailAutoMarkAsReadEnabled) { + if (preferences.defaults.SOGoMailAutoMarkAsReadMode == 'immediate') + preferences.defaults.SOGoMailAutoMarkAsReadDelay = 0; + } else { + preferences.defaults.SOGoMailAutoMarkAsReadDelay = -1; + } + delete preferences.defaults.SOGoMailAutoMarkAsReadEnabled; + delete preferences.defaults.SOGoMailAutoMarkAsReadMode; + // Merge back mail labels keys and values preferences.defaults.SOGoMailLabelsColors = {}; _.forEach(preferences.defaults.SOGoMailLabelsColorsKeys, function(key, i) { diff --git a/UI/WebServerResources/js/Preferences/PreferencesController.js b/UI/WebServerResources/js/Preferences/PreferencesController.js index cb8edb143..81f2e0b41 100644 --- a/UI/WebServerResources/js/Preferences/PreferencesController.js +++ b/UI/WebServerResources/js/Preferences/PreferencesController.js @@ -25,6 +25,7 @@ $mdConstant.KEY_CODE.COMMA, $mdConstant.KEY_CODE.SEMICOLON ]; + this.mailAutoMarkAsReadDelay = Preferences.defaults.SOGoMailAutoMarkAsReadEnabled ? Preferences.defaults.SOGoMailAutoMarkAsReadDelay : 5; // Set alternate avatar in User service if (Preferences.defaults.SOGoAlternateAvatar) @@ -107,6 +108,10 @@ form.$setDirty(); }; + this.onMailAutoMarkAsReadDelay = function() { + this.preferences.defaults.SOGoMailAutoMarkAsReadDelay = this.mailAutoMarkAsReadDelay; + }; + this.addMailAccount = function(ev, form) { var account, index;