Loading app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +33 −59 Original line number Diff line number Diff line Loading @@ -640,7 +640,7 @@ public class MessagingController { if (commandException != null && !syncListener.syncFailed) { String rootMessage = getRootCauseMessage(commandException); Timber.e("Root cause failure in %s:%s was '%s'", account, folderServerId, rootMessage); updateFolderStatus(account, folderServerId, rootMessage); updateFolderStatus(account, folderId, rootMessage); listener.synchronizeMailboxFailed(account, folderId, rootMessage); } } Loading @@ -655,14 +655,9 @@ public class MessagingController { SYNC_FLAGS); } private void updateFolderStatus(Account account, String folderServerId, String status) { try { LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderServerId); localFolder.setStatus(status); } catch (MessagingException e) { Timber.w(e, "Couldn't update folder status for folder %s", folderServerId); } private void updateFolderStatus(Account account, long folderId, String status) { MessageStore messageStore = messageStoreManager.getMessageStore(account); messageStore.setStatus(folderId, status); } public void handleAuthenticationFailure(Account account, boolean incoming) { Loading Loading @@ -1238,51 +1233,37 @@ public class MessagingController { ); } private void loadMessageRemoteSynchronous(Account account, long folderId, String uid, private void loadMessageRemoteSynchronous(Account account, long folderId, String messageServerId, MessagingListener listener, boolean loadPartialFromSearch) { try { LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderId); localFolder.open(); String folderServerId = localFolder.getServerId(); if (messageServerId.startsWith(K9.LOCAL_UID_PREFIX)) { throw new IllegalArgumentException("Must not be called with a local UID"); } LocalMessage message = localFolder.getMessage(uid); MessageStore messageStore = messageStoreManager.getMessageStore(account); String folderServerId = messageStore.getFolderServerId(folderId); if (folderServerId == null) { throw new IllegalStateException("Folder not found (ID: " + folderId + ")"); } if (uid.startsWith(K9.LOCAL_UID_PREFIX)) { Timber.w("Message has local UID so cannot download fully."); // ASH move toast android.widget.Toast.makeText(context, "Message has local UID so cannot download fully", android.widget.Toast.LENGTH_LONG).show(); // TODO: Using X_DOWNLOADED_FULL is wrong because it's only a partial message. But // one we can't download completely. Maybe add a new flag; X_PARTIAL_MESSAGE ? message.setFlag(Flag.X_DOWNLOADED_FULL, true); message.setFlag(Flag.X_DOWNLOADED_PARTIAL, false); } else { Backend backend = getBackend(account); if (loadPartialFromSearch) { SyncConfig syncConfig = createSyncConfig(account); backend.downloadMessage(syncConfig, folderServerId, uid); backend.downloadMessage(syncConfig, folderServerId, messageServerId); } else { backend.downloadCompleteMessage(folderServerId, uid); backend.downloadCompleteMessage(folderServerId, messageServerId); } message = localFolder.getMessage(uid); if (!loadPartialFromSearch) { message.setFlag(Flag.X_DOWNLOADED_FULL, true); } } // now that we have the full message, refresh the headers for (MessagingListener l : getListeners(listener)) { l.loadMessageRemoteFinished(account, folderId, uid); l.loadMessageRemoteFinished(account, folderId, messageServerId); } } catch (Exception e) { for (MessagingListener l : getListeners(listener)) { l.loadMessageRemoteFailed(account, folderId, uid, e); l.loadMessageRemoteFailed(account, folderId, messageServerId, e); } notifyUserIfCertificateProblem(account, e, true); Timber.e(e, "Error while loading remote message"); } Loading Loading @@ -1933,26 +1914,19 @@ public class MessagingController { }); } public void deleteDraft(final Account account, long id) { try { public void deleteDraft(Account account, long messageId) { Long folderId = account.getDraftsFolderId(); if (folderId == null) { Timber.w("No Drafts folder configured. Can't delete draft."); return; } LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderId); localFolder.open(); String uid = localFolder.getMessageUidById(id); if (uid != null) { MessageReference messageReference = new MessageReference(account.getUuid(), folderId, uid); MessageStore messageStore = messageStoreManager.getMessageStore(account); String messageServerId = messageStore.getMessageServerId(messageId); MessageReference messageReference = new MessageReference(account.getUuid(), folderId, messageServerId); deleteMessage(messageReference); } } catch (MessagingException me) { Timber.e(me, "Error deleting draft"); } } public void deleteThreads(final List<MessageReference> messages) { actOnMessagesGroupedByAccountAndFolder(messages, (account, messageFolder, accountMessages) -> { Loading app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java +0 −9 Original line number Diff line number Diff line Loading @@ -117,10 +117,6 @@ public class LocalFolder { return lastChecked; } public String getStatus() { return status; } public long getDatabaseId() { return databaseId; } Loading Loading @@ -297,11 +293,6 @@ public class LocalFolder { } } public void setStatus(final String status) throws MessagingException { this.status = status; updateFolderColumn("status", status); } private void updateFolderColumn(final String column, final Object value) throws MessagingException { this.localStore.getDatabase().execute(false, new DbCallback<Void>() { @Override Loading app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt +40 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import android.view.animation.AnimationUtils import android.widget.ProgressBar import android.widget.Toast import androidx.appcompat.app.ActionBar import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.Toolbar import androidx.drawerlayout.widget.DrawerLayout Loading Loading @@ -100,6 +101,9 @@ open class MessageList : private lateinit var actionBar: ActionBar private lateinit var searchView: SearchView private var initialSearchViewQuery: String? = null private var initialSearchViewIconified: Boolean = true private var drawer: K9Drawer? = null private var openFolderTransaction: FragmentTransaction? = null private var progressBar: ProgressBar? = null Loading Loading @@ -573,6 +577,8 @@ open class MessageList : outState.putSerializable(STATE_DISPLAY_MODE, displayMode) outState.putBoolean(STATE_MESSAGE_VIEW_ONLY, messageViewOnly) outState.putBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED, messageListWasDisplayed) outState.putBoolean(STATE_SEARCH_VIEW_ICONIFIED, searchView.isIconified) outState.putString(STATE_SEARCH_VIEW_QUERY, searchView.query?.toString()) } public override fun onRestoreInstanceState(savedInstanceState: Bundle) { Loading @@ -580,6 +586,8 @@ open class MessageList : messageViewOnly = savedInstanceState.getBoolean(STATE_MESSAGE_VIEW_ONLY) messageListWasDisplayed = savedInstanceState.getBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED) initialSearchViewIconified = savedInstanceState.getBoolean(STATE_SEARCH_VIEW_ICONIFIED) initialSearchViewQuery = savedInstanceState.getString(STATE_SEARCH_VIEW_QUERY) } private fun initializeActionBar() { Loading Loading @@ -708,7 +716,7 @@ open class MessageList : showMessageList() } } else if (this::searchView.isInitialized && !searchView.isIconified) { searchView.isIconified = true collapseSearchView() } else { if (isDrawerEnabled && account != null && supportFragmentManager.backStackEntryCount == 0) { if (K9.isShowUnifiedInbox) { Loading Loading @@ -918,6 +926,7 @@ open class MessageList : if (drawer!!.isOpen) { drawer!!.close() } else { collapseSearchView() drawer!!.open() } } else { Loading @@ -935,16 +944,28 @@ open class MessageList : override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.message_list_option, menu) // setup search view val searchItem = menu.findItem(R.id.search) initializeSearchMenuItem(searchItem) return true } private fun initializeSearchMenuItem(searchItem: MenuItem) { // Reuse existing SearchView if available if (::searchView.isInitialized) { searchItem.actionView = searchView return } searchView = searchItem.actionView as SearchView searchView.maxWidth = Int.MAX_VALUE searchView.queryHint = resources.getString(R.string.search_action) val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager val searchManager = getSystemService(SEARCH_SERVICE) as SearchManager searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName)) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { messageListFragment?.onSearchRequested(query) collapseSearchView() return true } Loading @@ -953,7 +974,13 @@ open class MessageList : } }) return true searchView.isIconified = initialSearchViewIconified searchView.setQuery(initialSearchViewQuery, false) } private fun collapseSearchView() { searchView.setQuery(null, false) searchView.isIconified = true } fun setActionBarTitle(title: String, subtitle: String? = null) { Loading Loading @@ -1000,6 +1027,8 @@ open class MessageList : showMessageView() } } collapseSearchView() } override fun onForward(messageReference: MessageReference, decryptionResultForReply: Parcelable?) { Loading Loading @@ -1082,6 +1111,11 @@ open class MessageList : return true } override fun startSupportActionMode(callback: ActionMode.Callback): ActionMode? { collapseSearchView() return super.startSupportActionMode(callback) } override fun showThread(account: Account, threadRootId: Long) { showMessageViewPlaceHolder() Loading Loading @@ -1391,6 +1425,8 @@ open class MessageList : private const val STATE_DISPLAY_MODE = "displayMode" private const val STATE_MESSAGE_VIEW_ONLY = "messageViewOnly" private const val STATE_MESSAGE_LIST_WAS_DISPLAYED = "messageListWasDisplayed" private const val STATE_SEARCH_VIEW_ICONIFIED = "searchViewIconified" private const val STATE_SEARCH_VIEW_QUERY = "searchViewQuery" private const val FIRST_FRAGMENT_TRANSACTION = "first" private const val FRAGMENT_TAG_MESSAGE_VIEW_CONTAINER = "MessageViewContainerFragment" Loading app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt +2 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import android.widget.AdapterView.OnItemLongClickListener import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.core.os.bundleOf import androidx.fragment.app.Fragment Loading Loading @@ -1534,8 +1533,7 @@ class MessageListFragment : } private fun startAndPrepareActionMode() { val activity = requireActivity() as AppCompatActivity actionMode = activity.startSupportActionMode(actionModeCallback) actionMode = fragmentListener.startSupportActionMode(actionModeCallback) actionMode?.invalidate() } Loading Loading @@ -2003,6 +2001,7 @@ class MessageListFragment : fun setMessageListTitle(title: String, subtitle: String?) fun onCompose(account: Account?) fun startSearch(query: String, account: Account?, folderId: Long?): Boolean fun startSupportActionMode(callback: ActionMode.Callback): ActionMode? fun goBack() fun onFolderNotFoundError() Loading Loading
app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +33 −59 Original line number Diff line number Diff line Loading @@ -640,7 +640,7 @@ public class MessagingController { if (commandException != null && !syncListener.syncFailed) { String rootMessage = getRootCauseMessage(commandException); Timber.e("Root cause failure in %s:%s was '%s'", account, folderServerId, rootMessage); updateFolderStatus(account, folderServerId, rootMessage); updateFolderStatus(account, folderId, rootMessage); listener.synchronizeMailboxFailed(account, folderId, rootMessage); } } Loading @@ -655,14 +655,9 @@ public class MessagingController { SYNC_FLAGS); } private void updateFolderStatus(Account account, String folderServerId, String status) { try { LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderServerId); localFolder.setStatus(status); } catch (MessagingException e) { Timber.w(e, "Couldn't update folder status for folder %s", folderServerId); } private void updateFolderStatus(Account account, long folderId, String status) { MessageStore messageStore = messageStoreManager.getMessageStore(account); messageStore.setStatus(folderId, status); } public void handleAuthenticationFailure(Account account, boolean incoming) { Loading Loading @@ -1238,51 +1233,37 @@ public class MessagingController { ); } private void loadMessageRemoteSynchronous(Account account, long folderId, String uid, private void loadMessageRemoteSynchronous(Account account, long folderId, String messageServerId, MessagingListener listener, boolean loadPartialFromSearch) { try { LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderId); localFolder.open(); String folderServerId = localFolder.getServerId(); if (messageServerId.startsWith(K9.LOCAL_UID_PREFIX)) { throw new IllegalArgumentException("Must not be called with a local UID"); } LocalMessage message = localFolder.getMessage(uid); MessageStore messageStore = messageStoreManager.getMessageStore(account); String folderServerId = messageStore.getFolderServerId(folderId); if (folderServerId == null) { throw new IllegalStateException("Folder not found (ID: " + folderId + ")"); } if (uid.startsWith(K9.LOCAL_UID_PREFIX)) { Timber.w("Message has local UID so cannot download fully."); // ASH move toast android.widget.Toast.makeText(context, "Message has local UID so cannot download fully", android.widget.Toast.LENGTH_LONG).show(); // TODO: Using X_DOWNLOADED_FULL is wrong because it's only a partial message. But // one we can't download completely. Maybe add a new flag; X_PARTIAL_MESSAGE ? message.setFlag(Flag.X_DOWNLOADED_FULL, true); message.setFlag(Flag.X_DOWNLOADED_PARTIAL, false); } else { Backend backend = getBackend(account); if (loadPartialFromSearch) { SyncConfig syncConfig = createSyncConfig(account); backend.downloadMessage(syncConfig, folderServerId, uid); backend.downloadMessage(syncConfig, folderServerId, messageServerId); } else { backend.downloadCompleteMessage(folderServerId, uid); backend.downloadCompleteMessage(folderServerId, messageServerId); } message = localFolder.getMessage(uid); if (!loadPartialFromSearch) { message.setFlag(Flag.X_DOWNLOADED_FULL, true); } } // now that we have the full message, refresh the headers for (MessagingListener l : getListeners(listener)) { l.loadMessageRemoteFinished(account, folderId, uid); l.loadMessageRemoteFinished(account, folderId, messageServerId); } } catch (Exception e) { for (MessagingListener l : getListeners(listener)) { l.loadMessageRemoteFailed(account, folderId, uid, e); l.loadMessageRemoteFailed(account, folderId, messageServerId, e); } notifyUserIfCertificateProblem(account, e, true); Timber.e(e, "Error while loading remote message"); } Loading Loading @@ -1933,26 +1914,19 @@ public class MessagingController { }); } public void deleteDraft(final Account account, long id) { try { public void deleteDraft(Account account, long messageId) { Long folderId = account.getDraftsFolderId(); if (folderId == null) { Timber.w("No Drafts folder configured. Can't delete draft."); return; } LocalStore localStore = localStoreProvider.getInstance(account); LocalFolder localFolder = localStore.getFolder(folderId); localFolder.open(); String uid = localFolder.getMessageUidById(id); if (uid != null) { MessageReference messageReference = new MessageReference(account.getUuid(), folderId, uid); MessageStore messageStore = messageStoreManager.getMessageStore(account); String messageServerId = messageStore.getMessageServerId(messageId); MessageReference messageReference = new MessageReference(account.getUuid(), folderId, messageServerId); deleteMessage(messageReference); } } catch (MessagingException me) { Timber.e(me, "Error deleting draft"); } } public void deleteThreads(final List<MessageReference> messages) { actOnMessagesGroupedByAccountAndFolder(messages, (account, messageFolder, accountMessages) -> { Loading
app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java +0 −9 Original line number Diff line number Diff line Loading @@ -117,10 +117,6 @@ public class LocalFolder { return lastChecked; } public String getStatus() { return status; } public long getDatabaseId() { return databaseId; } Loading Loading @@ -297,11 +293,6 @@ public class LocalFolder { } } public void setStatus(final String status) throws MessagingException { this.status = status; updateFolderColumn("status", status); } private void updateFolderColumn(final String column, final Object value) throws MessagingException { this.localStore.getDatabase().execute(false, new DbCallback<Void>() { @Override Loading
app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt +40 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ import android.view.animation.AnimationUtils import android.widget.ProgressBar import android.widget.Toast import androidx.appcompat.app.ActionBar import androidx.appcompat.view.ActionMode import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.Toolbar import androidx.drawerlayout.widget.DrawerLayout Loading Loading @@ -100,6 +101,9 @@ open class MessageList : private lateinit var actionBar: ActionBar private lateinit var searchView: SearchView private var initialSearchViewQuery: String? = null private var initialSearchViewIconified: Boolean = true private var drawer: K9Drawer? = null private var openFolderTransaction: FragmentTransaction? = null private var progressBar: ProgressBar? = null Loading Loading @@ -573,6 +577,8 @@ open class MessageList : outState.putSerializable(STATE_DISPLAY_MODE, displayMode) outState.putBoolean(STATE_MESSAGE_VIEW_ONLY, messageViewOnly) outState.putBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED, messageListWasDisplayed) outState.putBoolean(STATE_SEARCH_VIEW_ICONIFIED, searchView.isIconified) outState.putString(STATE_SEARCH_VIEW_QUERY, searchView.query?.toString()) } public override fun onRestoreInstanceState(savedInstanceState: Bundle) { Loading @@ -580,6 +586,8 @@ open class MessageList : messageViewOnly = savedInstanceState.getBoolean(STATE_MESSAGE_VIEW_ONLY) messageListWasDisplayed = savedInstanceState.getBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED) initialSearchViewIconified = savedInstanceState.getBoolean(STATE_SEARCH_VIEW_ICONIFIED) initialSearchViewQuery = savedInstanceState.getString(STATE_SEARCH_VIEW_QUERY) } private fun initializeActionBar() { Loading Loading @@ -708,7 +716,7 @@ open class MessageList : showMessageList() } } else if (this::searchView.isInitialized && !searchView.isIconified) { searchView.isIconified = true collapseSearchView() } else { if (isDrawerEnabled && account != null && supportFragmentManager.backStackEntryCount == 0) { if (K9.isShowUnifiedInbox) { Loading Loading @@ -918,6 +926,7 @@ open class MessageList : if (drawer!!.isOpen) { drawer!!.close() } else { collapseSearchView() drawer!!.open() } } else { Loading @@ -935,16 +944,28 @@ open class MessageList : override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.message_list_option, menu) // setup search view val searchItem = menu.findItem(R.id.search) initializeSearchMenuItem(searchItem) return true } private fun initializeSearchMenuItem(searchItem: MenuItem) { // Reuse existing SearchView if available if (::searchView.isInitialized) { searchItem.actionView = searchView return } searchView = searchItem.actionView as SearchView searchView.maxWidth = Int.MAX_VALUE searchView.queryHint = resources.getString(R.string.search_action) val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager val searchManager = getSystemService(SEARCH_SERVICE) as SearchManager searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName)) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { messageListFragment?.onSearchRequested(query) collapseSearchView() return true } Loading @@ -953,7 +974,13 @@ open class MessageList : } }) return true searchView.isIconified = initialSearchViewIconified searchView.setQuery(initialSearchViewQuery, false) } private fun collapseSearchView() { searchView.setQuery(null, false) searchView.isIconified = true } fun setActionBarTitle(title: String, subtitle: String? = null) { Loading Loading @@ -1000,6 +1027,8 @@ open class MessageList : showMessageView() } } collapseSearchView() } override fun onForward(messageReference: MessageReference, decryptionResultForReply: Parcelable?) { Loading Loading @@ -1082,6 +1111,11 @@ open class MessageList : return true } override fun startSupportActionMode(callback: ActionMode.Callback): ActionMode? { collapseSearchView() return super.startSupportActionMode(callback) } override fun showThread(account: Account, threadRootId: Long) { showMessageViewPlaceHolder() Loading Loading @@ -1391,6 +1425,8 @@ open class MessageList : private const val STATE_DISPLAY_MODE = "displayMode" private const val STATE_MESSAGE_VIEW_ONLY = "messageViewOnly" private const val STATE_MESSAGE_LIST_WAS_DISPLAYED = "messageListWasDisplayed" private const val STATE_SEARCH_VIEW_ICONIFIED = "searchViewIconified" private const val STATE_SEARCH_VIEW_QUERY = "searchViewQuery" private const val FIRST_FRAGMENT_TRANSACTION = "first" private const val FRAGMENT_TAG_MESSAGE_VIEW_CONTAINER = "MessageViewContainerFragment" Loading
app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt +2 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ import android.widget.AdapterView.OnItemLongClickListener import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode import androidx.core.os.bundleOf import androidx.fragment.app.Fragment Loading Loading @@ -1534,8 +1533,7 @@ class MessageListFragment : } private fun startAndPrepareActionMode() { val activity = requireActivity() as AppCompatActivity actionMode = activity.startSupportActionMode(actionModeCallback) actionMode = fragmentListener.startSupportActionMode(actionModeCallback) actionMode?.invalidate() } Loading Loading @@ -2003,6 +2001,7 @@ class MessageListFragment : fun setMessageListTitle(title: String, subtitle: String?) fun onCompose(account: Account?) fun startSearch(query: String, account: Account?, folderId: Long?): Boolean fun startSupportActionMode(callback: ActionMode.Callback): ActionMode? fun goBack() fun onFolderNotFoundError() Loading