Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/java/com/infomaniak/mail/MatomoMail.kt
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ object MatomoMail : Matomo {
SaveToKDrive("saveToKDrive"),
ScheduleDraft("scheduleDraft"),
ScheduledCustomDate("scheduledCustomDate"),
ReminderCustomDelta("reminderCustomDelta"),
ScheduledDraftsFolder("scheduledDraftsFolder"),
SeeAllAttendees("seeAllAttendees"),
SelectAvatar("selectAvatar"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.infomaniak.core.legacy.utils.safeBinding
import com.infomaniak.core.legacy.utils.setBackNavigationResult
import com.infomaniak.mail.databinding.BottomSheetScheduleOptionsBinding
import com.infomaniak.mail.ui.main.thread.actions.ActionItemView
import com.infomaniak.mail.utils.extensions.setKSuiteTrailingContent
import com.infomaniak.mail.utils.date.DateFormatUtils.dayOfWeekDateWithoutYear
import com.infomaniak.mail.utils.openKSuiteProBottomSheet
import com.infomaniak.mail.utils.openMailPremiumBottomSheet
Expand Down Expand Up @@ -66,7 +67,7 @@ abstract class SimpleSchedulePickerBottomSheet : EdgeToEdgeBottomSheetDialog() {
}
}

protected open fun createScheduleOptionItem(scheduleOption: ScheduleOption): View {
private fun createScheduleOptionItem(scheduleOption: ScheduleOption): View {
return ActionItemView(requireContext()).apply {
setTitle(scheduleOption.titleRes)
setDescription(context.dayOfWeekDateWithoutYear(date = scheduleOption.date()))
Expand All @@ -75,14 +76,18 @@ abstract class SimpleSchedulePickerBottomSheet : EdgeToEdgeBottomSheetDialog() {
}
}

protected open fun bindLastScheduleOptionDescription(description: String) {
private fun bindLastScheduleOptionDescription(description: String) {
binding.lastScheduleOption.setDescription(description)
}

protected open fun setupFirstScheduleOptionDivider(firstItem: View, shouldDisplayDivider: Boolean) {
private fun setupFirstScheduleOptionDivider(firstItem: View, shouldDisplayDivider: Boolean) {
(firstItem as? ActionItemView)?.setDividerVisibility(shouldDisplayDivider)
}

private fun setupCustomScheduleOptionTrailing() {
binding.customScheduleOption.setKSuiteTrailingContent(currentKSuite)
}

protected fun setupScheduleOptions() = with(binding) {
val lastDate = ScheduleOptionUtils.getLastScheduleOptionDate(lastSelectedEpoch, currentlyScheduledEpochMillis)
if (lastDate != null) {
Expand All @@ -103,6 +108,7 @@ abstract class SimpleSchedulePickerBottomSheet : EdgeToEdgeBottomSheetDialog() {
scheduleOptions.children.firstOrNull()?.let { firstItem ->
setupFirstScheduleOptionDivider(firstItem, shouldDisplayDivider)
}
setupCustomScheduleOptionTrailing()
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import com.google.android.material.materialswitch.MaterialSwitch
import com.infomaniak.core.legacy.utils.getAttributes
import com.infomaniak.mail.R
import com.infomaniak.mail.databinding.ViewItemSettingBinding
import com.infomaniak.mail.ui.main.thread.actions.KSuiteChipManager
import com.infomaniak.mail.ui.main.thread.actions.TrailingContent

class ItemSettingView @JvmOverloads constructor(
context: Context,
Expand All @@ -37,8 +39,16 @@ class ItemSettingView @JvmOverloads constructor(

private val binding by lazy { ViewItemSettingBinding.inflate(LayoutInflater.from(context), this, true) }

private val kSuiteChipManager by lazy { KSuiteChipManager(context) }

private var action: Action = Action.NONE

var trailingContent = TrailingContent.None
set(value) {
field = value
setTrailingContentUi(value)
}

var isChecked
get() = binding.toggle.isChecked
set(value) {
Expand Down Expand Up @@ -118,6 +128,19 @@ class ItemSettingView @JvmOverloads constructor(
chevron.isGone = mustBlock
}

private fun setTrailingContentUi(trailingContent: TrailingContent) = with(binding) {
trailingChipContainer.isVisible = kSuiteChipManager.displayChipFor(binding.trailingChipContainer, trailingContent)

when (trailingContent) {
TrailingContent.KSuitePersoChip, TrailingContent.KSuiteProChip -> {
chevron.isGone = true
checkMark.isGone = true
}
TrailingContent.Chevron -> chevron.isVisible = true
else -> Unit
}
}

private enum class Action {
NONE,
CHEVRON,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import androidx.annotation.StyleableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.infomaniak.core.ksuite.ksuitepro.views.EvolveChipView
import com.infomaniak.core.ksuite.myksuite.ui.views.MyKSuitePlusChipView
import com.infomaniak.core.legacy.utils.getAttributes
import com.infomaniak.core.ui.view.extension.setMarginsRelative
import com.infomaniak.core.ui.view.extension.setPaddingRelative
Expand All @@ -46,8 +44,7 @@ class ActionItemView @JvmOverloads constructor(

private val binding by lazy { ItemBottomSheetActionBinding.inflate(LayoutInflater.from(context), this, true) }

private val kSuitePersoChipView by lazy { MyKSuitePlusChipView(context) }
private val kSuiteProChipView by lazy { EvolveChipView(context) }
private val kSuiteChipManager by lazy { KSuiteChipManager(context) }

var trailingContent = TrailingContent.None
set(value) {
Expand Down Expand Up @@ -108,6 +105,10 @@ class ActionItemView @JvmOverloads constructor(

fun setTitle(@StringRes textResourceId: Int) = binding.title.setText(textResourceId)

fun setTitle(text: String) {
binding.title.text = text
}

private fun setTitleColor(color: ColorStateList) = binding.title.setTextColor(color)

fun setDescription(text: String) {
Expand All @@ -121,8 +122,7 @@ class ActionItemView @JvmOverloads constructor(

private fun setTrailingContentUi(trailingContent: TrailingContent) = with(binding) {
trailingContentLayout.isVisible = true
trailingContentLayout.removeView(kSuitePersoChipView)
trailingContentLayout.removeView(kSuiteProChipView)
kSuiteChipManager.displayChipFor(binding.trailingContentLayout, trailingContent)

when (trailingContent) {
TrailingContent.None -> trailingContentLayout.isGone = true
Expand All @@ -134,32 +134,13 @@ class ActionItemView @JvmOverloads constructor(
description.isVisible = true
actionIcon.isGone = true
}
TrailingContent.KSuitePersoChip -> {
// ComposeView are not compatible with view without lifecycles (ex: PopupWindow in RecipientFieldView).
// This is causing a crash so to avoid that, we have to programmatically
// add the Compose view only where it's needed.
trailingContentLayout.addView(kSuitePersoChipView)

actionIcon.isGone = true
description.isGone = true
}
TrailingContent.KSuiteProChip -> {
// ComposeView are not compatible with view without lifecycles (ex: PopupWindow in RecipientFieldView).
// This is causing a crash so to avoid that, we have to programmatically
// add the Compose view only where it's needed.
trailingContentLayout.addView(kSuiteProChipView)

TrailingContent.KSuitePersoChip, TrailingContent.KSuiteProChip -> {
actionIcon.isGone = true
description.isGone = true
}
}
}

/** Keep the entries order, it's used by the attribute (or change also the attributes order in attrs.xml) */
enum class TrailingContent {
None, Chevron, Description, KSuitePersoChip, KSuiteProChip,
}

private fun TypedArray.getDimenOrNull(@StyleableRes index: Int): Int? {
return getDimensionPixelSize(index, NOT_SET).takeIf { it != NOT_SET }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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/>.
*/
package com.infomaniak.mail.ui.main.thread.actions

import android.content.Context
import android.view.ViewGroup
import com.infomaniak.core.ksuite.ksuitepro.views.EvolveChipView
import com.infomaniak.core.ksuite.myksuite.ui.views.BaseMyKSuiteChipView
import com.infomaniak.core.ksuite.myksuite.ui.views.MyKSuitePlusChipView

class KSuiteChipManager(context: Context) {
private val kSuitePersoChipView: BaseMyKSuiteChipView = MyKSuitePlusChipView(context)
private val kSuiteProChipView: EvolveChipView = EvolveChipView(context)

fun displayChipFor(container: ViewGroup, trailingContent: TrailingContent): Boolean {
container.removeView(kSuitePersoChipView)
container.removeView(kSuiteProChipView)
val chipView = when (trailingContent) {
// ComposeView are not compatible with view without lifecycles (ex: PopupWindow in RecipientFieldView).
// This is causing a crash so to avoid that, we have to programmatically
// add the Compose view only where it's needed.
TrailingContent.KSuitePersoChip -> kSuitePersoChipView
TrailingContent.KSuiteProChip -> kSuiteProChipView
else -> null
}
return chipView?.also(container::addView) != null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import com.infomaniak.mail.data.models.extensions.kSuite
import com.infomaniak.mail.databinding.BottomSheetActionsMenuBinding
import com.infomaniak.mail.ui.MainViewModel
import com.infomaniak.mail.ui.main.folder.TwoPaneViewModel
import com.infomaniak.mail.ui.main.thread.actions.ActionItemView.TrailingContent
import com.infomaniak.mail.utils.AccountUtils
import com.infomaniak.mail.utils.openMyKSuiteUpgradeBottomSheet
import kotlinx.coroutines.runBlocking
Expand All @@ -47,7 +46,6 @@ abstract class MailActionsBottomSheetDialog : ActionsBottomSheetDialog() {
abstract val shouldCloseMultiSelection: Boolean
protected abstract val substituteClassName: String


private var onClickListener: OnActionClick = object : OnActionClick {

//region Main actions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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/>.
*/
package com.infomaniak.mail.ui.main.thread.actions

/** Keep the entries order, it's used by the attribute (or change also the attributes order in attrs.xml) */
enum class TrailingContent {
None,
Chevron,
Description,
KSuitePersoChip,
KSuiteProChip,
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.infomaniak.mail.ui.newMessage.ScheduleConfig
import com.infomaniak.mail.utils.date.DateFormatUtils.dayOfWeekDateWithoutYear
import com.infomaniak.mail.utils.date.DateFormatUtils.formatDelayText
import com.infomaniak.mail.utils.extensions.applyContentPaddingStart
import com.infomaniak.mail.utils.extensions.setKSuiteTrailingContent
import com.infomaniak.mail.utils.openKSuiteProBottomSheet
import com.infomaniak.mail.utils.openMailPremiumBottomSheet
import com.infomaniak.mail.utils.openMyKSuiteUpgradeBottomSheet
Expand Down Expand Up @@ -115,13 +116,17 @@ class DraftSendOptionsFragment : Fragment() {
}
}

private fun bindLastScheduleOptionDescription(description: String) = binding.lastScheduleOption.setDescription(description)
private fun setupCustomScheduleOptionTrailing() {
binding.customScheduleOption.setKSuiteTrailingContent(currentKSuite)
}

private fun onLastScheduleOptionClicked() {
newMessageViewModel.setScheduleConfig(lastSelectedEpoch?.let(ScheduleConfig::Scheduled) ?: ScheduleConfig.None)
}

private fun onCustomScheduleOptionClicked() = executeIfAuthorized { showCustomScheduleDatePicker() }
private fun onCustomScheduleOptionClicked() {
executeIfAuthorized(MatomoName.ScheduledCustomDate.value) { showCustomScheduleDatePicker() }
}

private fun setupScheduleOptions() = with(binding) {
val lastDate = ScheduleOptionUtils.getLastScheduleOptionDate(lastSelectedEpoch, currentlyScheduledEpochMillis)
Expand All @@ -140,6 +145,7 @@ class DraftSendOptionsFragment : Fragment() {
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this

customScheduleOption.setOnClickListener { onCustomScheduleOptionClicked() }
setupCustomScheduleOptionTrailing()
}

private fun setupToggles() = with(binding) {
Expand Down Expand Up @@ -176,6 +182,8 @@ class DraftSendOptionsFragment : Fragment() {
days3.setText(resources.getQuantityString(R.plurals.daysBeforeSendingReminder, 3, 3))
days7.setText(resources.getQuantityString(R.plurals.daysBeforeSendingReminder, 7, 7))

customDelayReminder.setKSuiteTrailingContent(currentKSuite)

val paddingStartValue = resources.getDimensionPixelSize(R.dimen.startPaddingWithoutIcon)
(optionsDelays.children + customDelayReminder).forEach { view -> view.applyContentPaddingStart(paddingStartValue) }

Expand All @@ -190,6 +198,8 @@ class DraftSendOptionsFragment : Fragment() {
}
)
}

customDelayReminder.setOnClickListener { onCustomDelayReminderClicked() }
}

private fun setReminderOptionsVisible(isVisible: Boolean) {
Expand Down Expand Up @@ -308,6 +318,10 @@ class DraftSendOptionsFragment : Fragment() {
}
}

private fun onCustomDelayReminderClicked() {
executeIfAuthorized(MatomoName.ReminderCustomDelta.value) { showCustomDelayReminderDatePicker() }
}

private fun resetCustomDelayReminder() = with(binding) {
customDelayReminder.setCheckMark(displayCheckMark = false)
customDelayReminder.removeSubtitle()
Expand Down Expand Up @@ -338,11 +352,8 @@ class DraftSendOptionsFragment : Fragment() {
}
}

private fun executeIfAuthorized(onAuthorized: () -> Unit) {
val kSuite = currentKSuite
val matomoName = MatomoName.ScheduledCustomDate.value

when (kSuite) {
private fun executeIfAuthorized(matomoName: String, onAuthorized: () -> Unit) {
when (val kSuite = currentKSuite) {
KSuite.Perso.Free -> openMyKSuiteUpgradeBottomSheet(matomoName)
KSuite.Pro.Free -> openKSuiteProBottomSheet(kSuite, navigationArgs.isAdmin, matomoName)
KSuite.StarterPack -> openMailPremiumBottomSheet(matomoName)
Expand All @@ -359,4 +370,9 @@ class DraftSendOptionsFragment : Fragment() {
},
)
}

private fun showCustomDelayReminderDatePicker() {
// TODO
}
Comment thread
Elouan1411 marked this conversation as resolved.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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/>.
*/

package com.infomaniak.mail.utils.extensions

import com.infomaniak.core.ksuite.data.KSuite
import com.infomaniak.mail.ui.main.settings.ItemSettingView
import com.infomaniak.mail.ui.main.thread.actions.ActionItemView
import com.infomaniak.mail.ui.main.thread.actions.TrailingContent

fun KSuite?.toTrailingContent(default: TrailingContent = TrailingContent.Chevron): TrailingContent = when (this) {
KSuite.Perso.Free -> TrailingContent.KSuitePersoChip
KSuite.Pro.Free, KSuite.StarterPack -> TrailingContent.KSuiteProChip
else -> default
}

fun ActionItemView.setKSuiteTrailingContent(kSuite: KSuite?, default: TrailingContent = TrailingContent.Chevron) {
trailingContent = kSuite.toTrailingContent(default)
}

fun ItemSettingView.setKSuiteTrailingContent(kSuite: KSuite?, default: TrailingContent = TrailingContent.Chevron) {
trailingContent = kSuite.toTrailingContent(default)
}
Loading