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

Commit 63b6b497 authored by cketti's avatar cketti
Browse files

Early version of message threading

Missing:
- UI support for threading when polling
- code to upgrade existing installations
- UI elements to switch from/to threaded display mode
- threading of messages with same subject
parent e66dd3d5
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -45,14 +45,32 @@
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/chip_wrapper"
        android:layout_below="@+id/subject"
        android:layout_toLeftOf="@+id/thread_count"
        android:layout_marginLeft="1dip"
        android:layout_marginBottom="3dip"
        android:layout_marginRight="16dip"
        android:layout_alignParentRight="true"
        android:layout_marginRight="3dip"
        android:bufferType="spannable"
        android:singleLine="false"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="?android:attr/textColorPrimary" />

    <TextView
        android:id="@+id/thread_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="6dip"
        android:layout_marginRight="12dip"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/subject"
        android:gravity="center_vertical|center_horizontal"
        android:paddingLeft="4dip"
        android:paddingRight="4dip"
        android:paddingTop="2dip"
        android:paddingBottom="2dip"
        android:background="#50000000"
        android:focusable="false" />


    <TextView
        android:id="@+id/date"
        android:layout_width="wrap_content"
@@ -65,7 +83,4 @@
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="?android:attr/textColorSecondary" />




</RelativeLayout>
+8 −0
Original line number Diff line number Diff line
@@ -748,4 +748,12 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme

        return true;
    }

    @Override
    public void showThread(Account account, String folderName, long threadRootId) {
        MessageListFragment fragment = MessageListFragment.newInstance(account, folderName,
                threadRootId);

        addMessageListFragment(fragment);
    }
}
+18 −7
Original line number Diff line number Diff line
@@ -517,13 +517,16 @@ public class MessagingController implements Runnable {
     * @param account
     * @param folder
     * @param listener
     * @param threaded
     * @param threadId
     * @throws MessagingException
     */
    public void listLocalMessages(final Account account, final String folder, final MessagingListener listener) {
    public void listLocalMessages(final Account account, final String folder,
            final MessagingListener listener, final boolean threaded, final long threadId) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                listLocalMessagesSynchronous(account, folder, listener);
                listLocalMessagesSynchronous(account, folder, listener, threaded, threadId);
            }
        });
    }
@@ -535,9 +538,12 @@ public class MessagingController implements Runnable {
     * @param account
     * @param folder
     * @param listener
     * @param threaded
     * @param threadId
     * @throws MessagingException
     */
    public void listLocalMessagesSynchronous(final Account account, final String folder, final MessagingListener listener) {
    public void listLocalMessagesSynchronous(final Account account, final String folder,
            final MessagingListener listener, boolean threaded, long threadId) {

        for (MessagingListener l : getListeners(listener)) {
            l.listLocalMessagesStarted(account, folder);
@@ -588,10 +594,15 @@ public class MessagingController implements Runnable {
            //Purging followed by getting requires 2 DB queries.
            //TODO: Fix getMessages to allow auto-pruning at visible limit?
            localFolder.purgeToVisibleLimit(null);
            localFolder.getMessages(
                retrievalListener,
                false // Skip deleted messages
            );

            if (threadId != -1) {
                localFolder.getMessagesInThread(threadId, retrievalListener);
            } else if (threaded) {
                localFolder.getThreadedMessages(retrievalListener);
            } else {
                localFolder.getMessages(retrievalListener, false);
            }

            if (K9.DEBUG)
                Log.v(K9.LOG_TAG, "Got ack that callbackRunner finished");

+40 −2
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Store;
import com.fsck.k9.mail.store.LocalStore;
import com.fsck.k9.mail.store.LocalStore.LocalFolder;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;

@@ -94,6 +95,19 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
        return fragment;
    }

    public static MessageListFragment newInstance(Account account, String folderName,
            long threadRootId) {
        MessageListFragment fragment = new MessageListFragment();

        Bundle args = new Bundle();
        args.putString(ARG_ACCOUNT, account.getUuid());
        args.putString(ARG_FOLDER, folderName);
        args.putLong(ARG_THREAD_ID, threadRootId);
        fragment.setArguments(args);

        return fragment;
    }

    public static MessageListFragment newInstance(String title, String[] accountUuids,
            String[] folderNames, String queryString, Flag[] flags,
            Flag[] forbiddenFlags, boolean integrate) {
@@ -290,6 +304,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
    private static final String ARG_ACCOUNT_UUIDS = "accountUuids";
    private static final String ARG_FOLDER_NAMES = "folderNames";
    private static final String ARG_TITLE = "title";
    private static final String ARG_THREAD_ID = "thread_id";

    private static final String STATE_LIST_POSITION = "listPosition";

@@ -389,6 +404,11 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick

    private DateFormat mTimeFormat;

    //TODO: make this a setting
    private boolean mThreadViewEnabled = true;

    private long mThreadId;


    /**
     * This class is used to run operations that modify UI elements in the UI thread.
@@ -667,6 +687,10 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
        final MessageInfoHolder message = (MessageInfoHolder) parent.getItemAtPosition(position);
        if (mSelectedCount > 0) {
            toggleMessageSelect(message);
        } else if (((LocalMessage) message.message).getThreadCount() > 1) {
            Folder folder = message.message.getFolder();
            long rootId = ((LocalMessage) message.message).getRootId();
            mFragmentListener.showThread(folder.getAccount(), folder.getName(), rootId);
        } else {
            onOpenMessage(message);
        }
@@ -730,6 +754,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
        mRemoteSearch = args.getBoolean(ARG_REMOTE_SEARCH, false);
        mSearchAccount = args.getString(ARG_SEARCH_ACCOUNT);
        mSearchFolder = args.getString(ARG_SEARCH_FOLDER);
        mThreadId = args.getLong(ARG_THREAD_ID, -1);

        String accountUuid = args.getString(ARG_ACCOUNT);

@@ -892,7 +917,8 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
                //TODO: Support flag based search
                mRemoteSearchFuture = mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener);
            } else if (mFolderName != null) {
                mController.listLocalMessages(mAccount, mFolderName,  mAdapter.mListener);
                mController.listLocalMessages(mAccount, mFolderName,  mAdapter.mListener, mThreadViewEnabled, mThreadId);

                // Hide the archive button if we don't have an archive folder.
                if (!mAccount.hasArchiveFolder()) {
//                    mBatchArchiveButton.setVisibility(View.GONE);
@@ -914,7 +940,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
                    @Override
                    public void run() {
                        if (mFolderName != null) {
                            mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener);
                            mController.listLocalMessagesSynchronous(mAccount, mFolderName,  mAdapter.mListener, mThreadViewEnabled, mThreadId);
                        } else if (mQueryString != null) {
                            mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
                        }
@@ -1929,6 +1955,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick

                holder.preview.setLines(mPreviewLines);
                holder.preview.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageListPreview());
                holder.threadCount = (TextView) view.findViewById(R.id.thread_count);

                view.setTag(holder);
            }
@@ -2029,6 +2056,15 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
                subject = message.message.getSubject();
            }

            int threadCount = ((LocalMessage) message.message).getThreadCount();
            if (threadCount > 1) {
                holder.threadCount.setText(Integer.toString(threadCount));
                holder.threadCount.setVisibility(View.VISIBLE);
            } else {
                holder.threadCount.setVisibility(View.GONE);
            }


            // We'll get badge support soon --jrv
//            if (holder.badge != null) {
//                String email = message.counterpartyAddress;
@@ -2133,6 +2169,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
        public TextView date;
        public View chip;
        public int position = -1;
        public TextView threadCount;

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -2902,6 +2939,7 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick

    public interface MessageListFragmentListener {
        void setMessageListProgress(int level);
        void showThread(Account account, String folderName, long rootId);
        void remoteSearch(String searchAccount, String searchFolder, String queryString);
        void showMoreFromSameSender(String senderAddress);
        void onResendMessage(Message message);
+42 −0
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -666,4 +668,44 @@ public class Utility {
            return false;
        }
    }

    private static final Pattern MESSAGE_ID = Pattern.compile("<" +
            "(?:" +
                "[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+" +
                "(?:\\.[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+)*" +
                "|" +
                "\"(?:[^\\\\\"]|\\\\.)*\"" +
            ")" +
            "@" +
            "(?:" +
                "[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+" +
                "(?:\\.[a-zA-Z0-9!#$%&'*+\\-/=?^_`{|}~]+)*" +
                "|" +
                "\\[(?:[^\\\\\\]]|\\\\.)*\\]" +
            ")" +
            ">");

    public static List<String> extractMessageIds(final String text) {
        List<String> messageIds = new ArrayList<String>();
        Matcher matcher = MESSAGE_ID.matcher(text);

        int start = 0;
        while (matcher.find(start)) {
            String messageId = text.substring(matcher.start(), matcher.end());
            messageIds.add(messageId);
            start = matcher.end();
        }

        return messageIds;
    }

    public static String extractMessageId(final String text) {
        Matcher matcher = MESSAGE_ID.matcher(text);

        if (matcher.find()) {
            return text.substring(matcher.start(), matcher.end());
        }

        return null;
    }
}
Loading