Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53aeb422 authored by cketti's avatar cketti
Browse files

Add functionality for primary reply action in message view

parent b2eb9fbb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
package com.fsck.k9.ui.messageview

fun interface MessageHeaderOnMenuItemClickListener {
    fun onMenuItemClick(itemId: Int)
}
+2 −2
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener;

import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -226,7 +226,7 @@ public class MessageTopView extends LinearLayout {
        mHeaderContainer.setOnFlagListener(listener);
    }

    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
    public void setOnMenuItemClickListener(MessageHeaderOnMenuItemClickListener listener) {
        mHeaderContainer.setOnMenuItemClickListener(listener);
    }

+2 −6
Original line number Diff line number Diff line
@@ -158,9 +158,7 @@ class MessageViewFragment :
            onToggleFlagged()
        }

        messageTopView.setOnMenuItemClickListener { item ->
            onReplyMenuItemClicked(item.itemId)
        }
        messageTopView.setOnMenuItemClickListener(::onReplyMenuItemClicked)

        messageTopView.setOnDownloadButtonClickListener {
            onDownloadButtonClicked()
@@ -381,7 +379,7 @@ class MessageViewFragment :
        messageTopView.setSubject(displaySubject)
    }

    private fun onReplyMenuItemClicked(itemId: Int): Boolean {
    private fun onReplyMenuItemClicked(itemId: Int) {
        when (itemId) {
            R.id.reply -> onReply()
            R.id.reply_all -> onReplyAll()
@@ -390,8 +388,6 @@ class MessageViewFragment :
            R.id.share -> onSendAlternate()
            else -> error("Missing handler for reply menu item $itemId")
        }

        return true
    }

    private fun onDownloadButtonClicked() {
+4 −0
Original line number Diff line number Diff line
package com.fsck.k9.view

import com.fsck.k9.helper.ReplyToParser
import com.fsck.k9.message.ReplyActionStrategy
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
import org.koin.dsl.module

val viewModule = module {
    single { WebViewConfigProvider(themeManager = get()) }
    factory { RelativeDateTimeFormatter(context = get(), clock = get()) }
    factory { ReplyToParser() }
    factory { ReplyActionStrategy(replyRoParser = get()) }
}
+91 −9
Original line number Diff line number Diff line
package com.fsck.k9.view;


import java.util.List;

import android.content.Context;
import android.content.res.ColorStateList;
import android.util.AttributeSet;
@@ -12,9 +14,9 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.FontSizes;
@@ -26,8 +28,12 @@ import com.fsck.k9.helper.MessageHelper;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Message;
import com.fsck.k9.message.ReplyAction;
import com.fsck.k9.message.ReplyActionStrategy;
import com.fsck.k9.message.ReplyActions;
import com.fsck.k9.ui.R;
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter;
import com.fsck.k9.ui.messageview.MessageHeaderOnMenuItemClickListener;
import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar;

@@ -35,6 +41,7 @@ import com.google.android.material.snackbar.Snackbar;
public class MessageHeader extends LinearLayout implements OnClickListener, OnLongClickListener {
    private static final int DEFAULT_SUBJECT_LINES = 3;

    private final ReplyActionStrategy replyActionStrategy = DI.get(ReplyActionStrategy.class);
    private final FontSizes fontSizes = K9.getFontSizes();

    private Chip accountChip;
@@ -46,11 +53,13 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
    private TextView toView;
    private TextView toCountView;
    private TextView dateView;
    private ImageView menuPrimaryActionView;

    private MessageHelper messageHelper;
    private RelativeDateTimeFormatter relativeDateTimeFormatter;

    private OnMenuItemClickListener onMenuItemClickListener;
    private MessageHeaderOnMenuItemClickListener onMenuItemClickListener;
    private ReplyActions replyActions;


    public MessageHeader(Context context, AttributeSet attrs) {
@@ -85,7 +94,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
        subjectView.setOnClickListener(this);
        subjectView.setOnLongClickListener(this);

        View menuPrimaryActionView = findViewById(R.id.menu_primary_action);
        menuPrimaryActionView = findViewById(R.id.menu_primary_action);
        menuPrimaryActionView.setOnClickListener(this);
        menuPrimaryActionView.setOnLongClickListener(this);

@@ -102,17 +111,46 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
        if (id == R.id.subject) {
            toggleSubjectViewMaxLines();
        } else if (id == R.id.menu_primary_action) {
            Snackbar.make(getRootView(), "TODO: Perform primary action", Snackbar.LENGTH_LONG).show();
            performPrimaryReplyAction();
        } else if (id == R.id.menu_overflow) {
            PopupMenu popupMenu = new PopupMenu(getContext(), view);
            popupMenu.setOnMenuItemClickListener(onMenuItemClickListener);
            popupMenu.inflate(R.menu.single_message_options);
            popupMenu.show();
            showOverflowMenu(view);
        } else if (id == R.id.participants_container) {
            Snackbar.make(getRootView(), "TODO: Display details popup", Snackbar.LENGTH_LONG).show();
        }
    }

    private void performPrimaryReplyAction() {
        ReplyAction defaultAction = replyActions.getDefaultAction();
        if (defaultAction == null) {
            return;
        }

        switch (defaultAction) {
            case REPLY: {
                onMenuItemClickListener.onMenuItemClick(R.id.reply);
                break;
            }
            case REPLY_ALL: {
                onMenuItemClickListener.onMenuItemClick(R.id.reply_all);
                break;
            }
            default: {
                throw new IllegalStateException("Unknown reply action: " + defaultAction);
            }
        }
    }

    private void showOverflowMenu(View view) {
        PopupMenu popupMenu = new PopupMenu(getContext(), view);
        popupMenu.setOnMenuItemClickListener(item -> {
            onMenuItemClickListener.onMenuItemClick(item.getItemId());
            return true;
        });
        popupMenu.inflate(R.menu.single_message_options);
        setAdditionalReplyActions(popupMenu);
        popupMenu.show();
    }

    @Override
    public boolean onLongClick(View view) {
        int id = view.getId();
@@ -190,9 +228,53 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
            dateView.setText("");
        }

        setReplyActions(message, account);

        setVisibility(View.VISIBLE);
    }

    private void setReplyActions(Message message, Account account) {
        ReplyActions replyActions = replyActionStrategy.getReplyActions(account, message);
        this.replyActions = replyActions;

        setDefaultReplyAction(replyActions.getDefaultAction());
    }

    private void setDefaultReplyAction(ReplyAction defaultAction) {
        if (defaultAction == null) {
            menuPrimaryActionView.setVisibility(View.GONE);
        } else {
            int replyIconResource = getReplyImageResource(defaultAction);
            menuPrimaryActionView.setImageResource(replyIconResource);
            menuPrimaryActionView.setVisibility(View.VISIBLE);
        }
    }

    @DrawableRes
    private int getReplyImageResource(@NonNull ReplyAction replyAction) {
        switch (replyAction) {
            case REPLY: {
                return R.drawable.ic_reply;
            }
            case REPLY_ALL: {
                return R.drawable.ic_reply_all;
            }
            default: {
                throw new IllegalStateException("Unknown reply action: " + replyAction);
            }
        }
    }

    private void setAdditionalReplyActions(PopupMenu popupMenu) {
        List<ReplyAction> additionalActions = replyActions.getAdditionalActions();
        if (!additionalActions.contains(ReplyAction.REPLY)) {
            popupMenu.getMenu().removeItem(R.id.reply);
        }
        if (!additionalActions.contains(ReplyAction.REPLY_ALL)) {
            popupMenu.getMenu().removeItem(R.id.reply_all);
        }
    }

    public void setSubject(@NonNull String subject) {
        subjectView.setText(subject);
    }
@@ -221,7 +303,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
        cryptoStatusIcon.setColorFilter(color);
    }

    public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
    public void setOnMenuItemClickListener(MessageHeaderOnMenuItemClickListener onMenuItemClickListener) {
        this.onMenuItemClickListener = onMenuItemClickListener;
    }
}
Loading