Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class Message : RealmObject, Snoozable {
@InternalModelProperties
set
var mentions = realmListOf<String>()
@SerialName("reminder")
var reminder: ReminderMessageInfo? = null
@SerialName("reminder_action")
var reminderAction: String? = null
Comment thread
Elouan1411 marked this conversation as resolved.
//endregion

//region Local data (Transient)
Expand Down Expand Up @@ -301,6 +305,14 @@ class Message : RealmObject, Snoozable {

fun isOrphan(): Boolean = threads.isEmpty() && threadsDuplicatedIn.isEmpty()

fun extractFromNames(): List<String> {
return from.map { it.name.ifBlank { it.email } }
}

fun extractRecipientNames(): List<String> {
return allRecipients.map { it.name.ifBlank { it.email } }
}

// Be careful when using this method because some folders might contain messages from other folders than itself. This
// operation should only happen in very specific situations like computing the shortUid of a Message from its uid.
private fun String.toShortUid(): Int = substringBefore('@').toInt()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Infomaniak Mail - Android
* Copyright (C) 2026 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@file:UseSerializers(RealmInstantSerializer::class)

package com.infomaniak.mail.data.models.message

import com.infomaniak.mail.data.api.RealmInstantSerializer
import io.realm.kotlin.types.EmbeddedRealmObject
import io.realm.kotlin.types.RealmInstant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers

@Serializable
class ReminderMessageInfo : EmbeddedRealmObject {
// API returns date and uuid for an already sent email, and only returns a delta for a scheduled email
@SerialName("date")
var date: RealmInstant? = null
@SerialName("uuid")
var uuid: String? = null
@SerialName("delta")
var delta: Int? = null

companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class Thread : RealmObject, Snoozable {
var hasAttachable: Boolean = false
@Transient
var hasUnseenMentions: Boolean = false
@Transient
var hasReminders: Boolean = false
// Has been moved (archived, spammed, deleted, moved) but API call hasn't been done yet.
// It's only used to locally filter the Threads' list.
@Transient
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/infomaniak/mail/MatomoMail.kt
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,13 @@ object MatomoMail : Matomo {
ReplaceSubjectConfirm("replaceSubjectConfirm"),
ReplaceSubjectDialog("replaceSubjectDialog"),
Reply("reply"),
FollowUp("followUp"),
ReplyAll("replyAll"),
ReplyMaybe("replyMaybe"),
ReplyNo("replyNo"),
ReplyYes("replyYes"),
ReprogramSchedule("reprogramSchedule"),
ReprogramReminder("reprogramReminder"),
RequestPassword("requestPassword"),
Restore("restore"),
RestoreEmails("restoreEmails"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import com.infomaniak.mail.data.models.message.EmojiReactionAuthor
import com.infomaniak.mail.data.models.message.EmojiReactionState
import com.infomaniak.mail.data.models.message.Headers
import com.infomaniak.mail.data.models.message.Message
import com.infomaniak.mail.data.models.message.ReminderMessageInfo
import com.infomaniak.mail.data.models.message.SubBody
import com.infomaniak.mail.data.models.signature.Signature
import com.infomaniak.mail.data.models.thread.Thread
Expand Down Expand Up @@ -237,6 +238,7 @@ object RealmDatabase {
Folder::class,
Thread::class,
Message::class,
ReminderMessageInfo::class,
ReminderDraftInfo::class,
Headers::class,
Draft::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.infomaniak.mail.data.models.message.Message.Companion.parseMessagesId
import com.infomaniak.mail.data.models.thread.Thread
import com.infomaniak.mail.data.models.thread.computeReactionsPerMessageId
import com.infomaniak.mail.data.models.thread.overrideWith
import com.infomaniak.mail.utils.ThreadListUtils.hasReminders
import com.infomaniak.mail.utils.ThreadListUtils.hasUnseenMentions
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
Expand Down Expand Up @@ -82,6 +83,7 @@ object ThreadRecomputations {
isForwarded = false
hasAttachable = false
hasUnseenMentions = false
hasReminders = false
numberOfScheduledDrafts = 0
snoozeState = null
snoozeEndDate = null
Expand All @@ -100,6 +102,7 @@ object ThreadRecomputations {
}

hasUnseenMentions = hasUnseenMentions(aliases?.toList() ?: emptyList(), allMessages)
hasReminders = hasReminders(allMessages)

displayDate = lastMessage.displayDate
internalDate = lastMessage.internalDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import com.infomaniak.mail.R
import com.infomaniak.mail.data.LocalSettings
import com.infomaniak.mail.data.LocalSettings.ThreadDensity
import com.infomaniak.mail.data.cache.RealmDatabase
import com.infomaniak.mail.data.models.FeatureFlag
import com.infomaniak.mail.data.models.FolderRole
import com.infomaniak.mail.data.models.SwipeAction
import com.infomaniak.mail.data.models.correspondent.MergedContact
Expand Down Expand Up @@ -320,6 +321,8 @@ class ThreadListAdapter @Inject constructor(
iconMention.isVisible = hasUnseenMentions
iconCalendar.isGone = true // TODO: See with API when we should display this icon
iconFavorite.isVisible = isFavorite
iconReminder.isVisible = hasReminders &&
callbacks?.getFeatureFlags?.invoke()?.contains(FeatureFlag.RESPONSE_REQUIRED) == true

val messagesCount = getDisplayedMessages(callbacks?.getFeatureFlags?.invoke(), localSettings).count()
threadCountText.text = "$messagesCount"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class MessageAlertView @JvmOverloads constructor(

private val action1LoadingTimer = Utils.createRefreshTimer(onTimerFinish = { binding.action1.showProgress() })
private val action2LoadingTimer = Utils.createRefreshTimer(onTimerFinish = { binding.action2.showProgress() })
private val action3LoadingTimer = Utils.createRefreshTimer(onTimerFinish = { binding.action3.showProgress() })

init {
attrs?.getAttributes(context, R.styleable.MessageAlertView) {
Expand All @@ -63,7 +64,12 @@ class MessageAlertView @JvmOverloads constructor(
text = getString(R.styleable.MessageAlertView_action2)
isVisible = hasAction2
}
divider.isVisible = hasAction2

val hasAction3 = hasValue(R.styleable.MessageAlertView_action3)
action3.apply {
text = getString(R.styleable.MessageAlertView_action3)
isVisible = hasAction3
}
}
}
}
Expand All @@ -72,6 +78,7 @@ class MessageAlertView @JvmOverloads constructor(
super.setEnabled(isEnabled)
action1.isEnabled = isEnabled
action2.isEnabled = isEnabled
action3.isEnabled = isEnabled
}

fun setDescription(text: String) {
Expand Down Expand Up @@ -116,6 +123,23 @@ class MessageAlertView @JvmOverloads constructor(
}
}

fun onAction3(listener: OnClickListener) {
binding.action3.setOnClickListener(listener)
}

fun showAction3Progress() {
binding.action3.isEnabled = false
action3LoadingTimer.start()
}

fun hideAction3Progress(@StringRes text: Int) {
action3LoadingTimer.cancel()
binding.action3.apply {
hideProgressCatching(text)
isEnabled = true
}
}

fun setActionsVisibility(shouldDisplayAction: Boolean) {
binding.actionsLayout.isVisible = shouldDisplayAction
val margin = if (shouldDisplayAction) RCore.dimen.marginStandardMedium else RCore.dimen.marginStandardSmall
Expand Down
Loading
Loading