Skip to content

refactor: Implement trailing content management for schedule options and bottom sheets - #2990

Open
Elouan1411 wants to merge 6 commits into
draft-send-optionsfrom
trailing-content
Open

refactor: Implement trailing content management for schedule options and bottom sheets#2990
Elouan1411 wants to merge 6 commits into
draft-send-optionsfrom
trailing-content

Conversation

@Elouan1411

@Elouan1411 Elouan1411 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@Elouan1411 Elouan1411 changed the title refactor: Implement trailing content management for schedule options … refactor: Implement trailing content management for schedule options and bottom sheets Jul 22, 2026
@Elouan1411
Elouan1411 requested a review from Copilot July 22, 2026 13:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Refactors trailing-content handling across schedule options, settings rows, and bottom sheets.

Changes:

  • Extracts shared KSuite chip and trailing-content management.
  • Adds plan-specific chips to custom scheduling and reminder options.
  • Updates last-schedule-option visibility handling.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
DraftSendOptionsFragment.kt Integrates trailing content and custom reminder handling.
MailActionsBottomSheetDialog.kt Updates the extracted trailing-content import.
KSuiteChipManager.kt Adds reusable chip management and trailing-content types.
ActionItemView.kt Delegates chip rendering to the shared manager.
ItemSettingView.kt Supports chips and chevrons as trailing content.
SimpleSchedulePickerBottomSheet.kt Configures plan-specific custom-option content.
ScheduleOptionsHelper.kt Coordinates trailing content and option visibility.
Comments suppressed due to low confidence (1)

app/src/main/java/com/infomaniak/mail/ui/newMessage/sendOptions/DraftSendOptionsFragment.kt:271

  • onViewCreated() calls this with false immediately after ScheduleOptionsHelper computes whether the last option is eligible. That sets the child to GONE; a later call with true then evaluates true && false, so the last schedule option can never reappear. Hide only the wrapper and preserve the child's helper-computed visibility.
        lastScheduleOption.isVisible = isVisible && lastScheduleOption.isVisible

@Elouan1411
Elouan1411 force-pushed the trailing-content branch 4 times, most recently from d7c3db2 to 6083e12 Compare July 28, 2026 09:25
(firstItem as? ActionItemView)?.setDividerVisibility(shouldDisplayDivider)
}

protected open fun setupCustomScheduleOptionTrailing(kSuite: KSuite?) {

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.

Why did you put that as protected open?

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.

Also you don't need the kSuite parameter as you can directly use currentKSuite

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Why did you put that as protected open?

I forgot to remove it, it's no longer useful

chevron.isGone = mustBlock
}

fun setMyKSuiteChipVisibility(isVisible: Boolean) {

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.

This is never used ?


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

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.

No need to create a hasCip variable here as you only use it here.

import com.infomaniak.core.ksuite.ksuitepro.views.EvolveChipView
import com.infomaniak.core.ksuite.myksuite.ui.views.MyKSuitePlusChipView

class KSuiteChipManager(private val container: ViewGroup) {

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.

Don't pass a view like that as a val. It could leak. If you want the context, you could just pass it as a parameter:

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

    fun displayChipFor(container: ViewGroup, trailingContent: TrailingContent): Boolean {
...

and the by lazy is not necessary as you always use those variables.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks 🙏

(firstItem as? ActionItemView)?.setDividerVisibility(shouldDisplayDivider)
}

protected open fun setupCustomScheduleOptionTrailing(kSuite: KSuite?) {

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.

Also you don't need the kSuite parameter as you can directly use currentKSuite

Comment on lines +88 to +93
binding.customScheduleOption.trailingContent = when (kSuite) {
KSuite.Perso.Free -> TrailingContent.KSuitePersoChip
KSuite.Pro.Free, KSuite.StarterPack -> TrailingContent.KSuiteProChip
else -> TrailingContent.Chevron
}
}

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.

This could probably by factorized by a View extension function

Comment on lines +31 to +44
fun displayChipFor(trailingContent: TrailingContent): Boolean {
container.removeView(kSuitePersoChipView)
container.removeView(kSuiteProChipView)

return 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 -> container.addView(kSuitePersoChipView).let { true }
TrailingContent.KSuiteProChip -> container.addView(kSuiteProChipView).let { true }
else -> false
}
}
}

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.

Here's my suggestion :

Suggested change
fun displayChipFor(trailingContent: TrailingContent): Boolean {
container.removeView(kSuitePersoChipView)
container.removeView(kSuiteProChipView)
return 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 -> container.addView(kSuitePersoChipView).let { true }
TrailingContent.KSuiteProChip -> container.addView(kSuiteProChipView).let { true }
else -> false
}
}
}
fun displayChipFor(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
}

@tevincent @Elouan1411 ?

}

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

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.

I'm don't think this should be kept in this class because it's not only related to kSuite chips

Or the class should be renamed and used more generally

Comment on lines +346 to +347
private fun onCustomDelayReminderClicked() =
executeIfAuthorized(MatomoName.ReminderCustomDelta.value) { showCustomDelayReminderDatePicker() }

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.

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

ScheduleOptionUtils.getAvailableScheduleOptions(currentlyScheduledEpochMillis).forEach { scheduleOption ->
scheduleOptions.addView(createScheduleOptionItem(scheduleOption))
}

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

@Elouan1411
Elouan1411 force-pushed the trailing-content branch 2 times, most recently from 478c028 to c5058ec Compare July 29, 2026 14:16
@Elouan1411
Elouan1411 force-pushed the trailing-content branch 2 times, most recently from 41a8670 to 784c3f3 Compare July 31, 2026 11:44
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants