Merge pull request #4709 from basilgello/restore-clear-local-folder
Restore per-folder clear local messages
This commit is contained in:
commit
f62818b5ef
7 changed files with 134 additions and 17 deletions
|
@ -2235,20 +2235,17 @@ public class MessagingController {
|
|||
});
|
||||
}
|
||||
|
||||
public void clearFolder(final Account account, final String folderServerId, final MessagingListener listener) {
|
||||
putBackground("clearFolder", listener, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
clearFolderSynchronous(account, folderServerId, listener);
|
||||
}
|
||||
});
|
||||
public void clearFolder(Account account, long folderId) {
|
||||
putBackground("clearFolder", null, () ->
|
||||
clearFolderSynchronous(account, folderId)
|
||||
);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void clearFolderSynchronous(Account account, String folderServerId, MessagingListener listener) {
|
||||
protected void clearFolderSynchronous(Account account, long folderId) {
|
||||
LocalFolder localFolder = null;
|
||||
try {
|
||||
localFolder = localStoreProvider.getInstance(account).getFolder(folderServerId);
|
||||
localFolder = localStoreProvider.getInstance(account).getFolder(folderId);
|
||||
localFolder.open();
|
||||
localFolder.clearAllMessages();
|
||||
} catch (UnavailableStorageException e) {
|
||||
|
|
|
@ -73,6 +73,7 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MessagingControllerTest extends K9RobolectricTest {
|
||||
private static final long FOLDER_ID = 23;
|
||||
private static final String FOLDER_NAME = "Folder";
|
||||
private static final String SENT_FOLDER_NAME = "Sent";
|
||||
private static final int MAXIMUM_SMALL_MESSAGE_SIZE = 1000;
|
||||
|
@ -158,21 +159,21 @@ public class MessagingControllerTest extends K9RobolectricTest {
|
|||
|
||||
@Test
|
||||
public void clearFolderSynchronous_shouldOpenFolderForWriting() throws MessagingException {
|
||||
controller.clearFolderSynchronous(account, FOLDER_NAME, listener);
|
||||
controller.clearFolderSynchronous(account, FOLDER_ID);
|
||||
|
||||
verify(localFolder).open();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearFolderSynchronous_shouldClearAllMessagesInTheFolder() throws MessagingException {
|
||||
controller.clearFolderSynchronous(account, FOLDER_NAME, listener);
|
||||
controller.clearFolderSynchronous(account, FOLDER_ID);
|
||||
|
||||
verify(localFolder).clearAllMessages();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearFolderSynchronous_shouldCloseTheFolder() throws MessagingException {
|
||||
controller.clearFolderSynchronous(account, FOLDER_NAME, listener);
|
||||
controller.clearFolderSynchronous(account, FOLDER_ID);
|
||||
|
||||
verify(localFolder, atLeastOnce()).close();
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
|
|||
public void clearFolderSynchronous_whenStorageUnavailable_shouldThrowUnavailableAccountException() throws MessagingException {
|
||||
doThrow(new UnavailableStorageException("Test")).when(localFolder).open();
|
||||
|
||||
controller.clearFolderSynchronous(account, FOLDER_NAME, listener);
|
||||
controller.clearFolderSynchronous(account, FOLDER_ID);
|
||||
}
|
||||
|
||||
@Test()
|
||||
|
@ -189,7 +190,7 @@ public class MessagingControllerTest extends K9RobolectricTest {
|
|||
doThrow(new RuntimeException("Test")).when(localFolder).open();
|
||||
|
||||
try {
|
||||
controller.clearFolderSynchronous(account, FOLDER_NAME, listener);
|
||||
controller.clearFolderSynchronous(account, FOLDER_ID);
|
||||
} catch (Exception ignored){
|
||||
}
|
||||
|
||||
|
@ -486,6 +487,8 @@ public class MessagingControllerTest extends K9RobolectricTest {
|
|||
|
||||
private void configureLocalStore() throws MessagingException {
|
||||
when(localStore.getFolder(FOLDER_NAME)).thenReturn(localFolder);
|
||||
when(localStore.getFolder(FOLDER_ID)).thenReturn(localFolder);
|
||||
when(localFolder.getDatabaseId()).thenReturn(FOLDER_ID);
|
||||
when(localFolder.getServerId()).thenReturn(FOLDER_NAME);
|
||||
when(localStore.getPersonalNamespaces(false)).thenReturn(Collections.singletonList(localFolder));
|
||||
when(localStoreProvider.getInstance(account)).thenReturn(localStore);
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package com.fsck.k9.ui.managefolders
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.Preference
|
||||
import com.fsck.k9.fragment.ConfirmationDialogFragment
|
||||
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
|
||||
import com.fsck.k9.ui.R
|
||||
import com.fsck.k9.ui.folders.FolderNameFormatter
|
||||
import com.fsck.k9.ui.observeNotNull
|
||||
|
@ -12,10 +17,15 @@ import org.koin.android.ext.android.inject
|
|||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
class FolderSettingsFragment : PreferenceFragmentCompat() {
|
||||
class FolderSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFragmentListener {
|
||||
private val viewModel: FolderSettingsViewModel by viewModel()
|
||||
private val folderNameFormatter: FolderNameFormatter by inject { parametersOf(requireActivity()) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
// Set empty preferences resource while data is being loaded
|
||||
setPreferencesFromResource(R.xml.empty_preferences, null)
|
||||
|
@ -35,6 +45,26 @@ class FolderSettingsFragment : PreferenceFragmentCompat() {
|
|||
is FolderSettingsData -> initPreferences(folderSettingsResult)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.getActionEvents().observeNotNull(this) { handleActionEvents(it) }
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.folder_settings_option, menu)
|
||||
|
||||
val clearFolderItem = menu.findItem(R.id.clear_local_folder)
|
||||
clearFolderItem.isVisible = viewModel.showClearFolderInMenu
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.clear_local_folder -> {
|
||||
viewModel.showClearFolderConfirmationDialog()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateBack() {
|
||||
|
@ -46,6 +76,11 @@ class FolderSettingsFragment : PreferenceFragmentCompat() {
|
|||
setPreferencesFromResource(R.xml.folder_settings_preferences, null)
|
||||
|
||||
setCategoryTitle(folderSettings)
|
||||
updateMenu()
|
||||
}
|
||||
|
||||
private fun updateMenu() {
|
||||
requireActivity().invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
private fun setCategoryTitle(folderSettings: FolderSettingsData) {
|
||||
|
@ -53,10 +88,44 @@ class FolderSettingsFragment : PreferenceFragmentCompat() {
|
|||
findPreference<Preference>(PREFERENCE_TOP_CATEGORY)!!.title = folderDisplayName
|
||||
}
|
||||
|
||||
private fun handleActionEvents(action: Action) {
|
||||
when (action) {
|
||||
is Action.ShowClearFolderConfirmationDialog -> showClearFolderConfirmationDialog()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showClearFolderConfirmationDialog() {
|
||||
val dialogFragment = ConfirmationDialogFragment.newInstance(
|
||||
DIALOG_CLEAR_FOLDER,
|
||||
getString(R.string.dialog_confirm_clear_local_folder_title),
|
||||
getString(R.string.dialog_confirm_clear_local_folder_message),
|
||||
getString(R.string.dialog_confirm_clear_local_folder_action),
|
||||
getString(R.string.cancel_action)
|
||||
)
|
||||
dialogFragment.setTargetFragment(this, REQUEST_CLEAR_FOLDER)
|
||||
dialogFragment.show(requireFragmentManager(), TAG_CLEAR_FOLDER_CONFIRMATION)
|
||||
}
|
||||
|
||||
override fun doPositiveClick(dialogId: Int) {
|
||||
when (dialogId) {
|
||||
DIALOG_CLEAR_FOLDER -> {
|
||||
viewModel.onClearFolderConfirmation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun doNegativeClick(dialogId: Int) = Unit
|
||||
|
||||
override fun dialogCancelled(dialogId: Int) = Unit
|
||||
|
||||
companion object {
|
||||
const val EXTRA_ACCOUNT = "account"
|
||||
const val EXTRA_FOLDER_ID = "folderId"
|
||||
|
||||
private const val DIALOG_CLEAR_FOLDER = 1
|
||||
private const val REQUEST_CLEAR_FOLDER = 1
|
||||
private const val TAG_CLEAR_FOLDER_CONFIRMATION = "clear_folder_confirmation"
|
||||
|
||||
private const val PREFERENCE_TOP_CATEGORY = "folder_settings"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.activity.FolderInfoHolder
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import com.fsck.k9.helper.SingleLiveEvent
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderDetails
|
||||
import com.fsck.k9.mailstore.FolderRepository
|
||||
|
@ -15,12 +17,22 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
private const val NO_FOLDER_ID = 0L
|
||||
|
||||
class FolderSettingsViewModel(
|
||||
private val preferences: Preferences,
|
||||
private val folderRepositoryManager: FolderRepositoryManager
|
||||
private val folderRepositoryManager: FolderRepositoryManager,
|
||||
private val messagingController: MessagingController
|
||||
) : ViewModel() {
|
||||
private val actionLiveData = SingleLiveEvent<Action>()
|
||||
private var folderSettingsLiveData: LiveData<FolderSettingsResult>? = null
|
||||
|
||||
private lateinit var account: Account
|
||||
private var folderId: Long = NO_FOLDER_ID
|
||||
|
||||
val showClearFolderInMenu: Boolean
|
||||
get() = this::account.isInitialized && folderId != NO_FOLDER_ID
|
||||
|
||||
fun getFolderSettingsLiveData(accountUuid: String, folderId: Long): LiveData<FolderSettingsResult> {
|
||||
return folderSettingsLiveData ?: createFolderSettingsLiveData(accountUuid, folderId).also {
|
||||
folderSettingsLiveData = it
|
||||
|
@ -41,6 +53,9 @@ class FolderSettingsViewModel(
|
|||
return@liveData
|
||||
}
|
||||
|
||||
this@FolderSettingsViewModel.account = account
|
||||
this@FolderSettingsViewModel.folderId = folderId
|
||||
|
||||
val folderSettingsData = FolderSettingsData(
|
||||
folder = createFolderObject(account, folderDetails.folder),
|
||||
dataStore = FolderSettingsDataStore(folderRepository, folderDetails)
|
||||
|
@ -70,8 +85,26 @@ class FolderSettingsViewModel(
|
|||
type = folderType
|
||||
)
|
||||
}
|
||||
|
||||
fun showClearFolderConfirmationDialog() {
|
||||
sendActionEvent(Action.ShowClearFolderConfirmationDialog)
|
||||
}
|
||||
|
||||
fun onClearFolderConfirmation() {
|
||||
messagingController.clearFolder(account, folderId)
|
||||
}
|
||||
|
||||
fun getActionEvents(): LiveData<Action> = actionLiveData
|
||||
|
||||
private fun sendActionEvent(action: Action) {
|
||||
actionLiveData.value = action
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FolderSettingsResult
|
||||
object FolderNotFound : FolderSettingsResult()
|
||||
data class FolderSettingsData(val folder: Folder, val dataStore: FolderSettingsDataStore) : FolderSettingsResult()
|
||||
|
||||
sealed class Action {
|
||||
object ShowClearFolderConfirmationDialog : Action()
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ import org.koin.dsl.module
|
|||
|
||||
val manageFoldersUiModule = module {
|
||||
viewModel { ManageFoldersViewModel(foldersLiveDataFactory = get()) }
|
||||
viewModel { FolderSettingsViewModel(preferences = get(), folderRepositoryManager = get()) }
|
||||
viewModel { FolderSettingsViewModel(preferences = get(), folderRepositoryManager = get(), messagingController = get()) }
|
||||
}
|
||||
|
|
10
app/ui/src/main/res/menu/folder_settings_option.xml
Normal file
10
app/ui/src/main/res/menu/folder_settings_option.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/clear_local_folder"
|
||||
android:title="@string/folder_settings_clear_local_folder_action"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
|
@ -662,6 +662,7 @@ Please submit bug reports, contribute new features and ask questions at
|
|||
<string name="folder_settings_folder_notify_mode_first_class">1st Class</string>
|
||||
<string name="folder_settings_folder_notify_mode_second_class">2nd Class</string>
|
||||
<string name="folder_settings_folder_notify_mode_inherited">Same as push class</string>
|
||||
<string name="folder_settings_clear_local_folder_action">Clear local messages</string>
|
||||
|
||||
<string name="account_settings_incoming_label">Incoming server</string>
|
||||
<string name="account_settings_incoming_summary">Configure the incoming mail server</string>
|
||||
|
@ -893,6 +894,10 @@ Please submit bug reports, contribute new features and ask questions at
|
|||
|
||||
<string name="select_text_now">Select text to copy.</string>
|
||||
|
||||
<string name="dialog_confirm_clear_local_folder_title">Clear local messages?</string>
|
||||
<string name="dialog_confirm_clear_local_folder_message">This will remove all local messages from the folder. No messages will be deleted from the server.</string>
|
||||
<string name="dialog_confirm_clear_local_folder_action">Clear messages</string>
|
||||
|
||||
<string name="dialog_confirm_delete_title">Confirm deletion</string>
|
||||
<string name="dialog_confirm_delete_message">Do you want to delete this message?</string>
|
||||
|
||||
|
|
Loading…
Reference in a new issue