This commit is contained in:
the-djmaze 2023-05-30 16:02:41 +02:00
parent 1f8fddd3f4
commit 26fb2cf9fb
6 changed files with 56 additions and 35 deletions

View file

@ -113,14 +113,12 @@ export class MessageModel extends AbstractModel {
// rfc8621 // rfc8621
id: '', id: '',
// threadId: '', // threadId: ''
hasUnseenSubMessage: false,
hasFlaggedSubMessage: false
}); });
this.attachments = ko.observableArray(new AttachmentCollectionModel); this.attachments = ko.observableArray(new AttachmentCollectionModel);
this.threads = ko.observableArray(); this.threads = ko.observableArray();
this.threadUnseen = ko.observableArray();
this.unsubsribeLinks = ko.observableArray(); this.unsubsribeLinks = ko.observableArray();
this.flags = ko.observableArray(); this.flags = ko.observableArray();
@ -128,6 +126,7 @@ export class MessageModel extends AbstractModel {
attachmentIconClass: () => attachmentIconClass: () =>
this.encrypted() ? 'icon-lock' : FileInfo.getAttachmentsIconClass(this.attachments()), this.encrypted() ? 'icon-lock' : FileInfo.getAttachmentsIconClass(this.attachments()),
threadsLen: () => rl.app.messageList.threadUid() ? 0 : this.threads().length, threadsLen: () => rl.app.messageList.threadUid() ? 0 : this.threads().length,
threadUnseenLen: () => rl.app.messageList.threadUid() ? 0 : this.threadUnseen().length,
isUnseen: () => !this.flags().includes('\\seen'), isUnseen: () => !this.flags().includes('\\seen'),
isFlagged: () => this.flags().includes('\\flagged'), isFlagged: () => this.flags().includes('\\flagged'),
@ -238,9 +237,7 @@ export class MessageModel extends AbstractModel {
focused: this.focused(), focused: this.focused(),
priorityHigh: this.priority() === 1, priorityHigh: this.priority() === 1,
withAttachments: !!this.attachments().length, withAttachments: !!this.attachments().length,
// hasChildrenMessage: 1 < this.threadsLen(), // hasChildrenMessage: 1 < this.threadsLen()
hasUnseenSubMessage: this.hasUnseenSubMessage(),
hasFlaggedSubMessage: this.hasFlaggedSubMessage()
}, (key, value) => value && classes.push(key)); }, (key, value) => value && classes.push(key));
flags && this.flags().forEach(value => classes.push('msgflag-'+value)); flags && this.flags().forEach(value => classes.push('msgflag-'+value));
return classes.join(' '); return classes.join(' ');

View file

@ -289,16 +289,6 @@
margin-right: 0.25em; margin-right: 0.25em;
} }
&.hasUnseenSubMessage {
background-color: rgba(255, 255, 64, 0.15);
border-left-color: lighten(orange, 30%);
border-right-color: lighten(orange, 30%) !important;
&.focused {
border-left-color: darken(orange, 10%);
border-right-color: darken(orange, 10%) !important;
}
}
&.unseen { &.unseen {
background-color: rgba(255, 255, 64, 0.15); background-color: rgba(255, 255, 64, 0.15);
border-left-color: orange; border-left-color: orange;
@ -312,6 +302,9 @@
border-right-color: darken(orange, 10%) !important; border-right-color: darken(orange, 10%) !important;
} }
} }
[data-unseen] {
background-color: rgba(255, 255, 64, 0.15);
}
&.checked { &.checked {
border-left-color: lighten(#398CF2, 10%); border-left-color: lighten(#398CF2, 10%);

View file

@ -446,7 +446,8 @@ class MailClient
* @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Net\Exceptions\*
* @throws \MailSo\Imap\Exceptions\* * @throws \MailSo\Imap\Exceptions\*
*/ */
protected function MessageListByRequestIndexOrUids(MessageCollection $oMessageCollection, SequenceSet $oRange, array &$aAllThreads = []) : void protected function MessageListByRequestIndexOrUids(MessageCollection $oMessageCollection, SequenceSet $oRange,
array &$aAllThreads = [], array &$aUnseenUIDs = []) : void
{ {
if (\count($oRange)) { if (\count($oRange)) {
$aFetchIterator = $this->oImapClient->FetchIterate(array( $aFetchIterator = $this->oImapClient->FetchIterate(array(
@ -472,6 +473,7 @@ class MailClient
foreach ($aAllThreads as $aMap) { foreach ($aAllThreads as $aMap) {
if (\in_array($iUid, $aMap)) { if (\in_array($iUid, $aMap)) {
$oMessage->SetThreads($aMap); $oMessage->SetThreads($aMap);
$oMessage->SetThreadUnseen(\array_values(\array_intersect($aUnseenUIDs, $aMap)));
break; break;
} }
} }
@ -490,7 +492,7 @@ class MailClient
* @throws \MailSo\Imap\Exceptions\* * @throws \MailSo\Imap\Exceptions\*
*/ */
private function GetUids(MessageListParams $oParams, string $sSearch, private function GetUids(MessageListParams $oParams, string $sSearch,
string $sFolderHash, bool $bUseSort = false) : array FolderInformation $oInfo, bool $bUseSort = false) : array
{ {
$oCacher = $oParams->oCacher; $oCacher = $oParams->oCacher;
$sFolderName = $oParams->sFolderName; $sFolderName = $oParams->sFolderName;
@ -562,7 +564,7 @@ class MailClient
if (!empty($sSerialized)) { if (!empty($sSerialized)) {
$aSerialized = \json_decode($sSerialized, true); $aSerialized = \json_decode($sSerialized, true);
if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) && if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
$sFolderHash === $aSerialized['FolderHash'] && $oInfo->etag === $aSerialized['FolderHash'] &&
\is_array($aSerialized['Uids']) \is_array($aSerialized['Uids'])
) { ) {
$this->logWrite('Get Serialized '.($bReturnUid?'UIDS':'IDS').' from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']'); $this->logWrite('Get Serialized '.($bReturnUid?'UIDS':'IDS').' from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
@ -594,7 +596,7 @@ class MailClient
if ($bUseCacheAfterSearch) { if ($bUseCacheAfterSearch) {
$oCacher->Set($sSerializedHash, \json_encode(array( $oCacher->Set($sSerializedHash, \json_encode(array(
'FolderHash' => $sFolderHash, 'FolderHash' => $oInfo->etag,
'Uids' => $aResultUids 'Uids' => $aResultUids
))); )));
@ -604,6 +606,23 @@ class MailClient
return $aResultUids; return $aResultUids;
} }
public function MessageListUnseen(MessageListParams $oParams, FolderInformation $oInfo) : array
{
$oUnseenParams = new MessageListParams;
$oUnseenParams->sFolderName = $oParams->sFolderName;
// $oUnseenParams->sSearch = $oParams->sSearch;
// $oUnseenParams->sSort = $oParams->sSort;
$oUnseenParams->oCacher = $oParams->oCacher;
$oUnseenParams->bUseSort = false; // $oParams->bUseSort
$oUnseenParams->bUseThreads = false; // $oParams->bUseThreads;
$oUnseenParams->bHideDeleted = $oParams->bHideDeleted;
// $oUnseenParams->iOffset = $oParams->iOffset;
// $oUnseenParams->iLimit = $oParams->iLimit;
// $oUnseenParams->iPrevUidNext = $oParams->iPrevUidNext;
// $oUnseenParams->iThreadUid = $oParams->iThreadUid;
return $this->GetUids($oUnseenParams, 'unseen', $oInfo);
}
/** /**
* Runs SORT/SEARCH when $sSearch is provided * Runs SORT/SEARCH when $sSearch is provided
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
@ -646,6 +665,7 @@ class MailClient
if ($oInfo->MESSAGES) { if ($oInfo->MESSAGES) {
$bUseSort = $oParams->bUseSort || $oParams->sSort; $bUseSort = $oParams->bUseSort || $oParams->sSort;
$aAllThreads = []; $aAllThreads = [];
$aUnseenUIDs = [];
$aUids = []; $aUids = [];
$message_list_limit = $this->oImapClient->Settings->message_list_limit; $message_list_limit = $this->oImapClient->Settings->message_list_limit;
@ -657,7 +677,7 @@ class MailClient
$this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')'); $this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')');
if (\strlen($sSearch)) { if (\strlen($sSearch)) {
// Don't use SORT for speed // Don't use SORT for speed
$aUids = $this->GetUids($oParams, $sSearch, $oInfo->etag/*, $bUseSort*/); $aUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/);
} else { } else {
$bUseSort = $this->oImapClient->hasCapability('SORT'); $bUseSort = $this->oImapClient->hasCapability('SORT');
if (2 > $oInfo->MESSAGES) { if (2 > $oInfo->MESSAGES) {
@ -667,7 +687,7 @@ class MailClient
$end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit)); $end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit));
$start = \max(1, $end - ($oParams->iLimit * 3) + 1); $start = \max(1, $end - ($oParams->iLimit * 3) + 1);
$oParams->oSequenceSet = new SequenceSet(\range($end, $start), false); $oParams->oSequenceSet = new SequenceSet(\range($end, $start), false);
$aRequestIndexes = $this->GetUids($oParams, '', $oInfo->etag, $bUseSort); $aRequestIndexes = $this->GetUids($oParams, '', $oInfo, $bUseSort);
// Attempt to get the correct $oParams->iLimit slice // Attempt to get the correct $oParams->iLimit slice
$aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit); $aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit);
} else { } else {
@ -681,7 +701,7 @@ class MailClient
} else { } else {
$aUids = ($bUseThreads && $oParams->iThreadUid) $aUids = ($bUseThreads && $oParams->iThreadUid)
? [$oParams->iThreadUid] ? [$oParams->iThreadUid]
: $this->GetUids($oParams, '', $oInfo->etag, $bUseSort); : $this->GetUids($oParams, '', $oInfo, $bUseSort);
if ($bUseThreads) { if ($bUseThreads) {
$aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher); $aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher);
@ -706,11 +726,13 @@ class MailClient
$threadedUids = \array_merge($threadedUids, $aMap); $threadedUids = \array_merge($threadedUids, $aMap);
} }
$aUids = \array_diff($aUids, $threadedUids); $aUids = \array_diff($aUids, $threadedUids);
// Get all unseen
$aUnseenUIDs = $this->MessageListUnseen($oParams, $oInfo);
} }
} }
if ($aUids && \strlen($sSearch)) { if ($aUids && \strlen($sSearch)) {
$aSearchedUids = $this->GetUids($oParams, $sSearch, $oInfo->etag/*, $bUseSort*/); $aSearchedUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/);
if ($bUseThreads && !$oParams->iThreadUid) { if ($bUseThreads && !$oParams->iThreadUid) {
$matchingThreadUids = []; $matchingThreadUids = [];
foreach ($aAllThreads as $aMap) { foreach ($aAllThreads as $aMap) {
@ -732,7 +754,7 @@ class MailClient
if (\count($aUids)) { if (\count($aUids)) {
$oMessageCollection->totalEmails = \count($aUids); $oMessageCollection->totalEmails = \count($aUids);
$aUids = \array_slice($aUids, $oParams->iOffset, $oParams->iLimit); $aUids = \array_slice($aUids, $oParams->iOffset, $oParams->iLimit);
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aUids), $aAllThreads); $this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aUids), $aAllThreads, $aUnseenUIDs);
} }
} else { } else {
$this->logWrite('No messages in '.$oMessageCollection->FolderName); $this->logWrite('No messages in '.$oMessageCollection->FolderName);

View file

@ -69,7 +69,8 @@ class Message implements \JsonSerializable
// $aFlags = [], // $aFlags = [],
$aFlagsLowerCase = [], $aFlagsLowerCase = [],
$UnsubsribeLinks = [], $UnsubsribeLinks = [],
$aThreads = []; $aThreadUIDs = [],
$aThreadUnseenUIDs = [];
private ?array $DraftInfo = null; private ?array $DraftInfo = null;
private ?array $pgpSigned = null; private ?array $pgpSigned = null;
@ -117,9 +118,14 @@ class Message implements \JsonSerializable
$this->SpamScore = \intval(\max(0, \min(100, $value))); $this->SpamScore = \intval(\max(0, \min(100, $value)));
} }
public function SetThreads(array $aThreads) public function SetThreads(array $aThreadUIDs)
{ {
$this->aThreads = $aThreads; $this->aThreadUIDs = $aThreadUIDs;
}
public function SetThreadUnseen(array $aUnseenUIDs)
{
$this->aThreadUnseenUIDs = $aUnseenUIDs;
} }
public static function fromFetchResponse(string $sFolder, \MailSo\Imap\FetchResponse $oFetchResponse, ?\MailSo\Imap\BodyStructure $oBodyStructure = null) : self public static function fromFetchResponse(string $sFolder, \MailSo\Imap\FetchResponse $oFetchResponse, ?\MailSo\Imap\BodyStructure $oBodyStructure = null) : self
@ -456,7 +462,7 @@ class Message implements \JsonSerializable
$this->sFolder, $this->sFolder,
$this->Uid, $this->Uid,
\implode(',', $this->getFlags()), \implode(',', $this->getFlags()),
// \implode(',', $this->aThreads), // \implode(',', $this->aThreadUIDs),
$sClientHash $sClientHash
])); ]));
} }
@ -576,8 +582,11 @@ class Message implements \JsonSerializable
$result['pgpEncrypted'] = $this->pgpEncrypted; $result['pgpEncrypted'] = $this->pgpEncrypted;
} }
if ($this->aThreads) { if ($this->aThreadUIDs) {
$result['threads'] = $this->aThreads; $result['threads'] = $this->aThreadUIDs;
}
if ($this->aThreadUnseenUIDs) {
$result['threadUnseen'] = $this->aThreadUnseenUIDs;
} }
return $result; return $result;

View file

@ -27,8 +27,8 @@ class MessageListParams
$bHideDeleted = true; $bHideDeleted = true;
protected int protected int
$iOffset, $iOffset = 0,
$iLimit, $iLimit = 0,
$iPrevUidNext = 0, // used to check for new messages $iPrevUidNext = 0, // used to check for new messages
$iThreadUid = 0; $iThreadUid = 0;

View file

@ -139,7 +139,7 @@
<div class="flagParent fontastic"></div> <div class="flagParent fontastic"></div>
<div class="senderParent actionHandle" data-bind="attr: {'title': senderClearEmailsString}, text: senderEmailsString"></div> <div class="senderParent actionHandle" data-bind="attr: {'title': senderClearEmailsString}, text: senderEmailsString"></div>
<div class="subjectParent actionHandle" data-bind="text: subject"></div> <div class="subjectParent actionHandle" data-bind="text: subject"></div>
<div class="threads-len" data-bind="visible: 1 < threadsLen(), text: threadsLen"></div> <div class="threads-len" data-bind="visible: 1 < threadsLen(), text: threadsLen, attr: {'data-unseen': threadUnseenLen() || null}"></div>
<div class="attachmentParent actionHandle"> <div class="attachmentParent actionHandle">
<i data-bind="css: attachmentIconClass"></i> <i data-bind="css: attachmentIconClass"></i>
</div> </div>