Merge pull request #4835 from k9mail/local_folder_server_id
Continue work on referring to folders only by their database ID
This commit is contained in:
commit
8c759e3c5f
32 changed files with 282 additions and 270 deletions
|
@ -27,11 +27,6 @@ import org.jetbrains.annotations.Nullable;
|
|||
* Account stores all of the settings for a single account defined by the user. Each account is defined by a UUID.
|
||||
*/
|
||||
public class Account implements BaseAccount {
|
||||
/**
|
||||
* This local folder is used to store messages to be sent.
|
||||
*/
|
||||
public static final String OUTBOX = "K9MAIL_INTERNAL_OUTBOX";
|
||||
|
||||
/**
|
||||
* Fixed name of outbox - not actually displayed.
|
||||
*/
|
||||
|
|
|
@ -999,8 +999,9 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
void processPendingMarkAllAsRead(PendingMarkAllAsRead command, Account account) throws MessagingException {
|
||||
long folderId = command.folderId;
|
||||
LocalStore localStore = localStoreProvider.getInstance(account);
|
||||
LocalFolder localFolder = localStore.getFolder(command.folderId);
|
||||
LocalFolder localFolder = localStore.getFolder(folderId);
|
||||
|
||||
localFolder.open();
|
||||
String folderServerId = localFolder.getServerId();
|
||||
|
@ -1016,7 +1017,7 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, folderServerId);
|
||||
l.folderStatusChanged(account, folderId);
|
||||
}
|
||||
|
||||
Backend backend = getBackend(account);
|
||||
|
@ -1082,34 +1083,30 @@ public class MessagingController {
|
|||
Timber.e(e, "Couldn't set flags in local database");
|
||||
}
|
||||
|
||||
// Read folder name and UID of messages from the database
|
||||
Map<String, List<String>> folderMap;
|
||||
// Read folder ID and UID of messages from the database
|
||||
Map<Long, List<String>> folderMap;
|
||||
try {
|
||||
folderMap = localStore.getFoldersAndUids(ids, threadedList);
|
||||
folderMap = localStore.getFolderIdsAndUids(ids, threadedList);
|
||||
} catch (MessagingException e) {
|
||||
Timber.e(e, "Couldn't get folder name and UID of messages");
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over all folders
|
||||
for (Entry<String, List<String>> entry : folderMap.entrySet()) {
|
||||
String folderServerId = entry.getKey();
|
||||
for (Entry<Long, List<String>> entry : folderMap.entrySet()) {
|
||||
long folderId = entry.getKey();
|
||||
List<String> uids = entry.getValue();
|
||||
|
||||
// Notify listeners of changed folder status
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, folderServerId);
|
||||
l.folderStatusChanged(account, folderId);
|
||||
}
|
||||
|
||||
// TODO: Skip the remote part for all local-only folders
|
||||
|
||||
// Send flag change to server
|
||||
try {
|
||||
long folderId = getFolderId(account, folderServerId);
|
||||
queueSetFlag(account, folderId, newState, flag, entry.getValue());
|
||||
processPendingCommands(account);
|
||||
} catch (MessagingException e) {
|
||||
Timber.e(e, "Error while trying to set flags");
|
||||
}
|
||||
queueSetFlag(account, folderId, newState, flag, uids);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1130,9 +1127,8 @@ public class MessagingController {
|
|||
// Update the messages in the local store
|
||||
localFolder.setFlags(messages, Collections.singleton(flag), newState);
|
||||
|
||||
String folderServerId = localFolder.getServerId();
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, folderServerId);
|
||||
l.folderStatusChanged(account, folderId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1253,8 +1249,8 @@ public class MessagingController {
|
|||
|
||||
LocalMessage message = localFolder.getMessage(uid);
|
||||
if (message == null || message.getDatabaseId() == 0) {
|
||||
String folderServerId = localFolder.getServerId();
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folderServerId + ", uid=" + uid);
|
||||
String folderName = localFolder.getName();
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
|
||||
}
|
||||
|
||||
FetchProfile fp = new FetchProfile();
|
||||
|
@ -1274,8 +1270,8 @@ public class MessagingController {
|
|||
|
||||
LocalMessage message = localFolder.getMessage(uid);
|
||||
if (message == null || message.getDatabaseId() == 0) {
|
||||
String folderServerId = localFolder.getServerId();
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folderServerId + ", uid=" + uid);
|
||||
String folderName = localFolder.getName();
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
|
||||
}
|
||||
|
||||
FetchProfile fp = new FetchProfile();
|
||||
|
@ -1756,11 +1752,9 @@ public class MessagingController {
|
|||
|
||||
LocalFolder localSrcFolder = localStore.getFolder(srcFolderId);
|
||||
localSrcFolder.open();
|
||||
String srcFolderServerId = localSrcFolder.getServerId();
|
||||
|
||||
LocalFolder localDestFolder = localStore.getFolder(destFolderId);
|
||||
localDestFolder.open();
|
||||
String destFolderServerId = localDestFolder.getServerId();
|
||||
|
||||
boolean unreadCountAffected = false;
|
||||
List<String> uids = new LinkedList<>();
|
||||
|
@ -1799,7 +1793,7 @@ public class MessagingController {
|
|||
// If this copy operation changes the unread count in the destination
|
||||
// folder, notify the listeners.
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, destFolderServerId);
|
||||
l.folderStatusChanged(account, destFolderId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1823,8 +1817,8 @@ public class MessagingController {
|
|||
int unreadMessageCountSrc = localSrcFolder.getUnreadMessageCount();
|
||||
int unreadMessageCountDest = localDestFolder.getUnreadMessageCount();
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, srcFolderServerId);
|
||||
l.folderStatusChanged(account, destFolderServerId);
|
||||
l.folderStatusChanged(account, srcFolderId);
|
||||
l.folderStatusChanged(account, destFolderId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1863,7 +1857,7 @@ public class MessagingController {
|
|||
String uid = localFolder.getMessageUidById(id);
|
||||
if (uid != null) {
|
||||
MessageReference messageReference = new MessageReference(account.getUuid(), folderId, uid, null);
|
||||
deleteMessage(messageReference, null);
|
||||
deleteMessage(messageReference);
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
Timber.e(me, "Error deleting draft");
|
||||
|
@ -1871,26 +1865,18 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
public void deleteThreads(final List<MessageReference> messages) {
|
||||
actOnMessagesGroupedByAccountAndFolder(messages, new MessageActor() {
|
||||
@Override
|
||||
public void act(final Account account, final LocalFolder messageFolder,
|
||||
final List<LocalMessage> accountMessages) {
|
||||
suppressMessages(account, accountMessages);
|
||||
|
||||
putBackground("deleteThreads", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deleteThreadsSynchronous(account, messageFolder.getServerId(), accountMessages);
|
||||
}
|
||||
});
|
||||
}
|
||||
actOnMessagesGroupedByAccountAndFolder(messages, (account, messageFolder, accountMessages) -> {
|
||||
suppressMessages(account, accountMessages);
|
||||
putBackground("deleteThreads", null, () ->
|
||||
deleteThreadsSynchronous(account, messageFolder.getDatabaseId(), accountMessages)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private void deleteThreadsSynchronous(Account account, String folderServerId, List<LocalMessage> messages) {
|
||||
private void deleteThreadsSynchronous(Account account, long folderId, List<LocalMessage> messages) {
|
||||
try {
|
||||
List<LocalMessage> messagesToDelete = collectMessagesInThreads(account, messages);
|
||||
deleteMessagesSynchronous(account, folderServerId, messagesToDelete, null);
|
||||
deleteMessagesSynchronous(account, folderId, messagesToDelete);
|
||||
} catch (MessagingException e) {
|
||||
Timber.e(e, "Something went wrong while deleting threads");
|
||||
}
|
||||
|
@ -1914,26 +1900,16 @@ public class MessagingController {
|
|||
return messagesInThreads;
|
||||
}
|
||||
|
||||
public void deleteMessage(MessageReference message, final MessagingListener listener) {
|
||||
deleteMessages(Collections.singletonList(message), listener);
|
||||
public void deleteMessage(MessageReference message) {
|
||||
deleteMessages(Collections.singletonList(message));
|
||||
}
|
||||
|
||||
public void deleteMessages(List<MessageReference> messages, final MessagingListener listener) {
|
||||
actOnMessagesGroupedByAccountAndFolder(messages, new MessageActor() {
|
||||
|
||||
@Override
|
||||
public void act(final Account account, final LocalFolder messageFolder,
|
||||
final List<LocalMessage> accountMessages) {
|
||||
suppressMessages(account, accountMessages);
|
||||
|
||||
putBackground("deleteMessages", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deleteMessagesSynchronous(account, messageFolder.getServerId(), accountMessages, listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteMessages(List<MessageReference> messages) {
|
||||
actOnMessagesGroupedByAccountAndFolder(messages, (account, messageFolder, accountMessages) -> {
|
||||
suppressMessages(account, accountMessages);
|
||||
putBackground("deleteMessages", null, () ->
|
||||
deleteMessagesSynchronous(account, messageFolder.getDatabaseId(), accountMessages)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1966,9 +1942,7 @@ public class MessagingController {
|
|||
|
||||
}
|
||||
|
||||
private void deleteMessagesSynchronous(final Account account, final String folder,
|
||||
final List<LocalMessage> messages,
|
||||
MessagingListener listener) {
|
||||
private void deleteMessagesSynchronous(Account account, long folderId, List<LocalMessage> messages) {
|
||||
try {
|
||||
List<LocalMessage> localOnlyMessages = new ArrayList<>();
|
||||
List<LocalMessage> syncedMessages = new ArrayList<>();
|
||||
|
@ -1986,9 +1960,8 @@ public class MessagingController {
|
|||
Backend backend = getBackend(account);
|
||||
|
||||
LocalStore localStore = localStoreProvider.getInstance(account);
|
||||
LocalFolder localFolder = localStore.getFolder(folder);
|
||||
LocalFolder localFolder = localStore.getFolder(folderId);
|
||||
localFolder.open();
|
||||
long folderId = localFolder.getDatabaseId();
|
||||
|
||||
Map<String, String> uidMap = null;
|
||||
Long trashFolderId = account.getTrashFolderId();
|
||||
|
@ -2014,9 +1987,9 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, folder);
|
||||
l.folderStatusChanged(account, folderId);
|
||||
if (localTrashFolder != null) {
|
||||
l.folderStatusChanged(account, localTrashFolder.getServerId());
|
||||
l.folderStatusChanged(account, trashFolderId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2107,7 +2080,6 @@ public class MessagingController {
|
|||
LocalStore localStore = localStoreProvider.getInstance(account);
|
||||
LocalFolder localFolder = localStore.getFolder(trashFolderId);
|
||||
localFolder.open();
|
||||
String trashFolderServerId = localFolder.getServerId();
|
||||
|
||||
boolean isTrashLocalOnly = isTrashLocalOnly(account);
|
||||
if (isTrashLocalOnly) {
|
||||
|
@ -2118,7 +2090,7 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.folderStatusChanged(account, trashFolderServerId);
|
||||
l.folderStatusChanged(account, trashFolderId);
|
||||
}
|
||||
|
||||
if (!isTrashLocalOnly) {
|
||||
|
@ -2832,8 +2804,9 @@ public class MessagingController {
|
|||
|
||||
@Override
|
||||
public void folderStatusChanged(@NotNull String folderServerId) {
|
||||
long folderId = getFolderIdOrThrow(account, folderServerId);
|
||||
for (MessagingListener messagingListener : getListeners(listener)) {
|
||||
messagingListener.folderStatusChanged(account, folderServerId);
|
||||
messagingListener.folderStatusChanged(account, folderId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public interface MessagingListener {
|
|||
void checkMailStarted(Context context, Account account);
|
||||
void checkMailFinished(Context context, Account account);
|
||||
|
||||
void folderStatusChanged(Account account, String folderServerId);
|
||||
void folderStatusChanged(Account account, long folderId);
|
||||
|
||||
void messageUidChanged(Account account, long folderId, String oldUid, String newUid);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ public abstract class SimpleMessagingListener implements MessagingListener {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void folderStatusChanged(Account account, String folderServerId) {
|
||||
public void folderStatusChanged(Account account, long folderId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,17 +20,11 @@ class FolderRepository(
|
|||
.thenByDescending { it.isInTopGroup }
|
||||
.thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name }
|
||||
|
||||
fun getFolders(): List<Folder> {
|
||||
fun getRemoteFolders(): List<RemoteFolder> {
|
||||
val folders = localStoreProvider.getInstance(account).getPersonalNamespaces(false)
|
||||
return folders.map { Folder(it.databaseId, it.serverId, it.name, it.type.toFolderType(), it.isLocalOnly) }
|
||||
}
|
||||
|
||||
fun getRemoteFolders(): List<Folder> {
|
||||
val folders = localStoreProvider.getInstance(account).getPersonalNamespaces(false)
|
||||
|
||||
return folders
|
||||
.filterNot { it.isLocalOnly }
|
||||
.map { Folder(it.databaseId, it.serverId, it.name, it.type.toFolderType(), isLocalOnly = false) }
|
||||
.map { RemoteFolder(it.databaseId, it.serverId, it.name, it.type.toFolderType()) }
|
||||
}
|
||||
|
||||
fun getDisplayFolders(displayMode: FolderMode?): List<DisplayFolder> {
|
||||
|
@ -43,12 +37,122 @@ class FolderRepository(
|
|||
return displayFolders.sortedWith(sortForDisplay)
|
||||
}
|
||||
|
||||
fun getFolderDetails(folderId: Long): FolderDetails? {
|
||||
return getFolderDetails(selection = "id = ?", selectionArgs = arrayOf(folderId.toString())).firstOrNull()
|
||||
fun getFolder(folderId: Long): Folder? {
|
||||
val database = localStoreProvider.getInstance(account).database
|
||||
return database.execute(false) { db ->
|
||||
db.query(
|
||||
"folders",
|
||||
arrayOf(
|
||||
"id",
|
||||
"name",
|
||||
"local_only"
|
||||
),
|
||||
"id = ?",
|
||||
arrayOf(folderId.toString()),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
val id = cursor.getLong(0)
|
||||
Folder(
|
||||
id = id,
|
||||
name = cursor.getString(1),
|
||||
type = folderTypeOf(id),
|
||||
isLocalOnly = cursor.getInt(2) == 1
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getFolderDetails(): List<FolderDetails> {
|
||||
return getFolderDetails(selection = null, selectionArgs = null)
|
||||
fun getFolderDetails(folderId: Long): FolderDetails? {
|
||||
val database = localStoreProvider.getInstance(account).database
|
||||
return database.execute(false) { db ->
|
||||
db.query(
|
||||
"folders",
|
||||
arrayOf(
|
||||
"id",
|
||||
"name",
|
||||
"top_group",
|
||||
"integrate",
|
||||
"poll_class",
|
||||
"display_class",
|
||||
"notify_class",
|
||||
"push_class",
|
||||
"local_only"
|
||||
),
|
||||
"id = ?",
|
||||
arrayOf(folderId.toString()),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
cursor.map {
|
||||
val id = cursor.getLong(0)
|
||||
FolderDetails(
|
||||
folder = Folder(
|
||||
id = id,
|
||||
name = cursor.getString(1),
|
||||
type = folderTypeOf(id),
|
||||
isLocalOnly = cursor.getInt(8) == 1
|
||||
),
|
||||
isInTopGroup = cursor.getInt(2) == 1,
|
||||
isIntegrate = cursor.getInt(3) == 1,
|
||||
syncClass = cursor.getStringOrNull(4).toFolderClass(),
|
||||
displayClass = cursor.getStringOrNull(5).toFolderClass(),
|
||||
notifyClass = cursor.getStringOrNull(6).toFolderClass(),
|
||||
pushClass = cursor.getStringOrNull(7).toFolderClass()
|
||||
)
|
||||
}
|
||||
}
|
||||
}.firstOrNull()
|
||||
}
|
||||
|
||||
fun getRemoteFolderDetails(): List<RemoteFolderDetails> {
|
||||
val database = localStoreProvider.getInstance(account).database
|
||||
return database.execute(false) { db ->
|
||||
db.query(
|
||||
"folders",
|
||||
arrayOf(
|
||||
"id",
|
||||
"server_id",
|
||||
"name",
|
||||
"type",
|
||||
"top_group",
|
||||
"integrate",
|
||||
"poll_class",
|
||||
"display_class",
|
||||
"notify_class",
|
||||
"push_class"
|
||||
),
|
||||
"local_only = 0",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
cursor.map {
|
||||
val id = cursor.getLong(0)
|
||||
RemoteFolderDetails(
|
||||
folder = RemoteFolder(
|
||||
id = id,
|
||||
serverId = cursor.getString(1),
|
||||
name = cursor.getString(2),
|
||||
type = cursor.getString(3).toFolderType().toFolderType()
|
||||
),
|
||||
isInTopGroup = cursor.getInt(4) == 1,
|
||||
isIntegrate = cursor.getInt(5) == 1,
|
||||
syncClass = cursor.getStringOrNull(6).toFolderClass(),
|
||||
displayClass = cursor.getStringOrNull(7).toFolderClass(),
|
||||
notifyClass = cursor.getStringOrNull(8).toFolderClass(),
|
||||
pushClass = cursor.getStringOrNull(9).toFolderClass()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getFolderServerId(folderId: Long): String? {
|
||||
|
@ -102,51 +206,6 @@ class FolderRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getFolderDetails(selection: String?, selectionArgs: Array<String>?): List<FolderDetails> {
|
||||
val database = localStoreProvider.getInstance(account).database
|
||||
return database.execute(false) { db ->
|
||||
db.query(
|
||||
"folders",
|
||||
arrayOf(
|
||||
"id",
|
||||
"server_id",
|
||||
"name",
|
||||
"top_group",
|
||||
"integrate",
|
||||
"poll_class",
|
||||
"display_class",
|
||||
"notify_class",
|
||||
"push_class",
|
||||
"local_only"
|
||||
),
|
||||
selection,
|
||||
selectionArgs,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).use { cursor ->
|
||||
cursor.map {
|
||||
val id = cursor.getLong(0)
|
||||
FolderDetails(
|
||||
folder = Folder(
|
||||
id = id,
|
||||
serverId = cursor.getString(1),
|
||||
name = cursor.getString(2),
|
||||
type = folderTypeOf(id),
|
||||
isLocalOnly = cursor.getInt(9) == 1
|
||||
),
|
||||
isInTopGroup = cursor.getInt(3) == 1,
|
||||
isIntegrate = cursor.getInt(4) == 1,
|
||||
syncClass = cursor.getStringOrNull(5).toFolderClass(),
|
||||
displayClass = cursor.getStringOrNull(6).toFolderClass(),
|
||||
notifyClass = cursor.getStringOrNull(7).toFolderClass(),
|
||||
pushClass = cursor.getStringOrNull(8).toFolderClass()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateFolderDetails(folderDetails: FolderDetails) {
|
||||
val database = localStoreProvider.getInstance(account).database
|
||||
database.execute(false) { db ->
|
||||
|
@ -164,7 +223,7 @@ class FolderRepository(
|
|||
|
||||
private fun getDisplayFolders(db: SQLiteDatabase, displayMode: FolderMode): List<DisplayFolder> {
|
||||
val queryBuilder = StringBuilder("""
|
||||
SELECT f.id, f.server_id, f.name, f.top_group, f.local_only, (
|
||||
SELECT f.id, f.name, f.top_group, f.local_only, (
|
||||
SELECT COUNT(m.id)
|
||||
FROM messages m
|
||||
WHERE m.folder_id = f.id AND m.empty = 0 AND m.deleted = 0 AND m.read = 0
|
||||
|
@ -181,14 +240,13 @@ class FolderRepository(
|
|||
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(0)
|
||||
val serverId = cursor.getString(1)
|
||||
val name = cursor.getString(2)
|
||||
val name = cursor.getString(1)
|
||||
val type = folderTypeOf(id)
|
||||
val isInTopGroup = cursor.getInt(3) == 1
|
||||
val isLocalOnly = cursor.getInt(4) == 1
|
||||
val unreadCount = cursor.getInt(5)
|
||||
val isInTopGroup = cursor.getInt(2) == 1
|
||||
val isLocalOnly = cursor.getInt(3) == 1
|
||||
val unreadCount = cursor.getInt(4)
|
||||
|
||||
val folder = Folder(id, serverId, name, type, isLocalOnly)
|
||||
val folder = Folder(id, name, type, isLocalOnly)
|
||||
displayFolders.add(DisplayFolder(folder, isInTopGroup, unreadCount))
|
||||
}
|
||||
|
||||
|
@ -271,7 +329,9 @@ class FolderRepository(
|
|||
}
|
||||
}
|
||||
|
||||
data class Folder(val id: Long, val serverId: String, val name: String, val type: FolderType, val isLocalOnly: Boolean)
|
||||
data class Folder(val id: Long, val name: String, val type: FolderType, val isLocalOnly: Boolean)
|
||||
|
||||
data class RemoteFolder(val id: Long, val serverId: String, val name: String, val type: FolderType)
|
||||
|
||||
data class FolderDetails(
|
||||
val folder: Folder,
|
||||
|
@ -283,6 +343,16 @@ data class FolderDetails(
|
|||
val pushClass: FolderClass
|
||||
)
|
||||
|
||||
data class RemoteFolderDetails(
|
||||
val folder: RemoteFolder,
|
||||
val isInTopGroup: Boolean,
|
||||
val isIntegrate: Boolean,
|
||||
val syncClass: FolderClass,
|
||||
val displayClass: FolderClass,
|
||||
val notifyClass: FolderClass,
|
||||
val pushClass: FolderClass
|
||||
)
|
||||
|
||||
data class DisplayFolder(
|
||||
val folder: Folder,
|
||||
val isInTopGroup: Boolean,
|
||||
|
|
|
@ -87,7 +87,7 @@ public class LocalFolder {
|
|||
private FolderType type = FolderType.REGULAR;
|
||||
private String serverId = null;
|
||||
private String name;
|
||||
private long databaseId = -1;
|
||||
private long databaseId = -1L;
|
||||
private int visibleLimit = -1;
|
||||
private String prefId = null;
|
||||
|
||||
|
@ -172,10 +172,7 @@ public class LocalFolder {
|
|||
}
|
||||
|
||||
if (cursor.moveToFirst() && !cursor.isNull(LocalStore.FOLDER_ID_INDEX)) {
|
||||
int folderId = cursor.getInt(LocalStore.FOLDER_ID_INDEX);
|
||||
if (folderId > 0) {
|
||||
open(cursor);
|
||||
}
|
||||
open(cursor);
|
||||
} else {
|
||||
throw new MessagingException("LocalFolder.open(): Folder not found: " +
|
||||
serverId + " (" + databaseId + ")", true);
|
||||
|
@ -194,7 +191,7 @@ public class LocalFolder {
|
|||
}
|
||||
|
||||
void open(Cursor cursor) throws MessagingException {
|
||||
databaseId = cursor.getInt(LocalStore.FOLDER_ID_INDEX);
|
||||
databaseId = cursor.getLong(LocalStore.FOLDER_ID_INDEX);
|
||||
serverId = cursor.getString(LocalStore.FOLDER_SERVER_ID_INDEX);
|
||||
visibleLimit = cursor.getInt(LocalStore.FOLDER_VISIBLE_LIMIT_INDEX);
|
||||
status = cursor.getString(LocalStore.FOLDER_STATUS_INDEX);
|
||||
|
@ -221,7 +218,7 @@ public class LocalFolder {
|
|||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return (databaseId != -1 && serverId != null);
|
||||
return (databaseId != -1L && name != null);
|
||||
}
|
||||
|
||||
public String getServerId() {
|
||||
|
@ -352,7 +349,7 @@ public class LocalFolder {
|
|||
}
|
||||
|
||||
public int getUnreadMessageCount() throws MessagingException {
|
||||
if (databaseId == -1) {
|
||||
if (databaseId == -1L) {
|
||||
open();
|
||||
}
|
||||
|
||||
|
@ -857,7 +854,7 @@ public class LocalFolder {
|
|||
destFolder.getDatabaseId(),
|
||||
message.getUid(),
|
||||
message.getDatabaseId(),
|
||||
getServerId());
|
||||
getName());
|
||||
|
||||
String newUid = K9.LOCAL_UID_PREFIX + UUID.randomUUID().toString();
|
||||
message.setUid(newUid);
|
||||
|
@ -1643,14 +1640,15 @@ public class LocalFolder {
|
|||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof LocalFolder) {
|
||||
return ((LocalFolder)o).serverId.equals(serverId);
|
||||
return ((LocalFolder)o).databaseId == databaseId;
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return serverId.hashCode();
|
||||
long value = databaseId;
|
||||
return (int) (value ^ (value >>> 32));
|
||||
}
|
||||
|
||||
void destroyMessage(LocalMessage localMessage) throws MessagingException {
|
||||
|
|
|
@ -400,8 +400,8 @@ public class LocalStore {
|
|||
if (cursor.isNull(FOLDER_ID_INDEX)) {
|
||||
continue;
|
||||
}
|
||||
String folderServerId = cursor.getString(FOLDER_SERVER_ID_INDEX);
|
||||
LocalFolder folder = new LocalFolder(LocalStore.this, folderServerId);
|
||||
long folderId = cursor.getLong(FOLDER_ID_INDEX);
|
||||
LocalFolder folder = new LocalFolder(LocalStore.this, folderId);
|
||||
folder.open(cursor);
|
||||
|
||||
folders.add(folder);
|
||||
|
@ -793,17 +793,16 @@ public class LocalStore {
|
|||
|
||||
@Nullable
|
||||
private LocalMessage loadLocalMessageByMessageId(long messageId) throws MessagingException {
|
||||
Map<String, List<String>> foldersAndUids =
|
||||
getFoldersAndUids(Collections.singletonList(messageId), false);
|
||||
if (foldersAndUids.isEmpty()) {
|
||||
Map<Long, List<String>> folderIdsAndUids = getFolderIdsAndUids(Collections.singletonList(messageId), false);
|
||||
if (folderIdsAndUids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map.Entry<String,List<String>> entry = foldersAndUids.entrySet().iterator().next();
|
||||
String folderServerId = entry.getKey();
|
||||
Map.Entry<Long, List<String>> entry = folderIdsAndUids.entrySet().iterator().next();
|
||||
long folderId = entry.getKey();
|
||||
String uid = entry.getValue().get(0);
|
||||
|
||||
LocalFolder folder = getFolder(folderServerId);
|
||||
LocalFolder folder = getFolder(folderId);
|
||||
LocalMessage localMessage = folder.getMessage(uid);
|
||||
|
||||
FetchProfile fp = new FetchProfile();
|
||||
|
@ -919,17 +918,15 @@ public class LocalStore {
|
|||
boolean localOnly = folder.isLocalOnly();
|
||||
String databaseFolderType = FolderTypeConverter.toDatabaseFolderType(folder.getType());
|
||||
|
||||
if (K9.DEVELOPER_MODE) {
|
||||
Cursor cursor = db.query("folders", new String[] { "id", "server_id" },
|
||||
"server_id = ?", new String[] { serverId },null, null, null);
|
||||
if (K9.DEVELOPER_MODE && localOnly) {
|
||||
Cursor cursor = db.query("folders", new String[] { "id" },
|
||||
"name = ? AND local_only = 1", new String[] { name },null, null, null);
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
long folderId = cursor.getLong(0);
|
||||
String folderServerId = cursor.getString(1);
|
||||
|
||||
throw new AssertionError("Tried to create folder '" + serverId + "'" +
|
||||
" that already exists in the database as '" + folderServerId + "'" +
|
||||
" (" + folderId + ")");
|
||||
throw new AssertionError("Tried to create local folder '" + name + "'" +
|
||||
" that already exists in the database with ID " + folderId);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
|
@ -960,14 +957,10 @@ public class LocalStore {
|
|||
}
|
||||
|
||||
public long createLocalFolder(String folderName, FolderType type) throws MessagingException {
|
||||
return createLocalFolder(folderName, folderName, type);
|
||||
}
|
||||
|
||||
public long createLocalFolder(String folderServerId, String folderName, FolderType type) throws MessagingException {
|
||||
return database.execute(true, (DbCallback<Long>) db -> {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("name", folderName);
|
||||
values.put("server_id", folderServerId);
|
||||
values.putNull("server_id");
|
||||
values.put("local_only", 1);
|
||||
values.put("type", FolderTypeConverter.toDatabaseFolderType(type));
|
||||
values.put("visible_limit", 0);
|
||||
|
@ -1230,7 +1223,7 @@ public class LocalStore {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get folder server ID and UID for the supplied messages.
|
||||
* Get folder ID and UID for the supplied messages.
|
||||
*
|
||||
* @param messageIds
|
||||
* A list of primary keys in the "messages" table.
|
||||
|
@ -1240,13 +1233,13 @@ public class LocalStore {
|
|||
* If this is {@code false} only the UIDs for messages in {@code messageIds} are
|
||||
* returned.
|
||||
*
|
||||
* @return The list of UIDs for the messages grouped by folder server ID.
|
||||
* @return The list of UIDs for the messages grouped by folder ID.
|
||||
*
|
||||
*/
|
||||
public Map<String, List<String>> getFoldersAndUids(final List<Long> messageIds,
|
||||
public Map<Long, List<String>> getFolderIdsAndUids(final List<Long> messageIds,
|
||||
final boolean threadedList) throws MessagingException {
|
||||
|
||||
final Map<String, List<String>> folderMap = new HashMap<>();
|
||||
final Map<Long, List<String>> folderMap = new HashMap<>();
|
||||
|
||||
doBatchSetSelection(new BatchSetSelection() {
|
||||
|
||||
|
@ -1265,10 +1258,9 @@ public class LocalStore {
|
|||
throws UnavailableStorageException {
|
||||
|
||||
if (threadedList) {
|
||||
String sql = "SELECT m.uid, f.server_id " +
|
||||
String sql = "SELECT m.uid, m.folder_id " +
|
||||
"FROM threads t " +
|
||||
"LEFT JOIN messages m ON (t.message_id = m.id) " +
|
||||
"LEFT JOIN folders f ON (m.folder_id = f.id) " +
|
||||
"WHERE m.empty = 0 AND m.deleted = 0 " +
|
||||
"AND t.root" + selectionSet;
|
||||
|
||||
|
@ -1276,10 +1268,9 @@ public class LocalStore {
|
|||
|
||||
} else {
|
||||
String sql =
|
||||
"SELECT m.uid, f.server_id " +
|
||||
"FROM messages m " +
|
||||
"LEFT JOIN folders f ON (m.folder_id = f.id) " +
|
||||
"WHERE m.empty = 0 AND m.id" + selectionSet;
|
||||
"SELECT uid, folder_id " +
|
||||
"FROM messages " +
|
||||
"WHERE empty = 0 AND id" + selectionSet;
|
||||
|
||||
getDataFromCursor(db.rawQuery(sql, selectionArgs));
|
||||
}
|
||||
|
@ -1289,12 +1280,12 @@ public class LocalStore {
|
|||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
String uid = cursor.getString(0);
|
||||
String folderServerId = cursor.getString(1);
|
||||
Long folderId = cursor.getLong(1);
|
||||
|
||||
List<String> uidList = folderMap.get(folderServerId);
|
||||
List<String> uidList = folderMap.get(folderId);
|
||||
if (uidList == null) {
|
||||
uidList = new ArrayList<>();
|
||||
folderMap.put(folderServerId, uidList);
|
||||
folderMap.put(folderId, uidList);
|
||||
}
|
||||
|
||||
uidList.add(uid);
|
||||
|
|
|
@ -4,7 +4,7 @@ package com.fsck.k9.mailstore
|
|||
* Implements the automatic special folder selection strategy.
|
||||
*/
|
||||
class SpecialFolderSelectionStrategy {
|
||||
fun selectSpecialFolder(folders: List<Folder>, type: FolderType): Folder? {
|
||||
fun selectSpecialFolder(folders: List<RemoteFolder>, type: FolderType): RemoteFolder? {
|
||||
return folders.firstOrNull { folder -> folder.type == type }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.fsck.k9.mail.FolderClass
|
|||
* Updates special folders in [Account] if they are marked as [SpecialFolderSelection.AUTOMATIC] or if they are marked
|
||||
* as [SpecialFolderSelection.MANUAL] but have been deleted from the server.
|
||||
*/
|
||||
// TODO: Find a better way to deal with local-only special folders
|
||||
class SpecialFolderUpdater(
|
||||
private val preferences: Preferences,
|
||||
private val folderRepository: FolderRepository,
|
||||
|
@ -16,20 +17,23 @@ class SpecialFolderUpdater(
|
|||
private val account: Account
|
||||
) {
|
||||
fun updateSpecialFolders() {
|
||||
val folders = folderRepository.getFolders()
|
||||
val folders = folderRepository.getRemoteFolders()
|
||||
|
||||
updateInbox(folders)
|
||||
updateSpecialFolder(FolderType.ARCHIVE, folders)
|
||||
updateSpecialFolder(FolderType.DRAFTS, folders)
|
||||
updateSpecialFolder(FolderType.SENT, folders)
|
||||
updateSpecialFolder(FolderType.SPAM, folders)
|
||||
updateSpecialFolder(FolderType.TRASH, folders)
|
||||
|
||||
if (!account.isPop3()) {
|
||||
updateSpecialFolder(FolderType.ARCHIVE, folders)
|
||||
updateSpecialFolder(FolderType.DRAFTS, folders)
|
||||
updateSpecialFolder(FolderType.SENT, folders)
|
||||
updateSpecialFolder(FolderType.SPAM, folders)
|
||||
updateSpecialFolder(FolderType.TRASH, folders)
|
||||
}
|
||||
|
||||
removeImportedSpecialFoldersData()
|
||||
saveAccount()
|
||||
}
|
||||
|
||||
private fun updateInbox(folders: List<Folder>) {
|
||||
private fun updateInbox(folders: List<RemoteFolder>) {
|
||||
val oldInboxId = account.inboxFolderId
|
||||
val newInboxId = folders.firstOrNull { it.type == FolderType.INBOX }?.id
|
||||
if (newInboxId == oldInboxId) return
|
||||
|
@ -48,7 +52,7 @@ class SpecialFolderUpdater(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateSpecialFolder(type: FolderType, folders: List<Folder>) {
|
||||
private fun updateSpecialFolder(type: FolderType, folders: List<RemoteFolder>) {
|
||||
val importedServerId = getImportedSpecialFolderServerId(type)
|
||||
if (importedServerId != null) {
|
||||
val folderId = folders.firstOrNull { it.serverId == importedServerId }?.id
|
||||
|
@ -127,4 +131,6 @@ class SpecialFolderUpdater(
|
|||
private fun saveAccount() {
|
||||
preferences.saveAccount(account)
|
||||
}
|
||||
|
||||
private fun Account.isPop3() = storeUri.startsWith("pop3")
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class SpecialLocalFoldersCreator(
|
|||
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
|
||||
account.outboxFolderId = localStore.createLocalFolder(OUTBOX_SERVER_ID, OUTBOX_FOLDER_NAME, FolderType.OUTBOX)
|
||||
account.outboxFolderId = localStore.createLocalFolder(OUTBOX_FOLDER_NAME, FolderType.OUTBOX)
|
||||
|
||||
if (account.isPop3()) {
|
||||
check(account.draftsFolderId == null) { "Drafts folder was already set up" }
|
||||
|
@ -37,7 +37,6 @@ class SpecialLocalFoldersCreator(
|
|||
private fun Account.isPop3() = storeUri.startsWith("pop3")
|
||||
|
||||
companion object {
|
||||
private const val OUTBOX_SERVER_ID = Account.OUTBOX
|
||||
private const val OUTBOX_FOLDER_NAME = Account.OUTBOX_NAME
|
||||
private const val DRAFTS_FOLDER_NAME = "Drafts"
|
||||
private const val SENT_FOLDER_NAME = "Sent"
|
||||
|
|
|
@ -181,7 +181,7 @@ public class NotificationActionService extends Service {
|
|||
|
||||
List<String> messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES);
|
||||
List<MessageReference> messageReferences = toMessageReferenceList(messageReferenceStrings);
|
||||
controller.deleteMessages(messageReferences, null);
|
||||
controller.deleteMessages(messageReferences);
|
||||
}
|
||||
|
||||
private void archiveMessages(Intent intent, Account account, MessagingController controller) {
|
||||
|
|
|
@ -2,18 +2,18 @@ package com.fsck.k9.preferences
|
|||
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.mail.FolderClass
|
||||
import com.fsck.k9.mailstore.FolderDetails
|
||||
import com.fsck.k9.mailstore.FolderRepositoryManager
|
||||
import com.fsck.k9.mailstore.RemoteFolderDetails
|
||||
|
||||
class FolderSettingsProvider(private val folderRepositoryManager: FolderRepositoryManager) {
|
||||
fun getFolderSettings(account: Account): List<FolderSettings> {
|
||||
val folderRepository = folderRepositoryManager.getFolderRepository(account)
|
||||
return folderRepository.getFolderDetails()
|
||||
return folderRepository.getRemoteFolderDetails()
|
||||
.filterNot { it.containsOnlyDefaultValues() }
|
||||
.map { it.toFolderSettings() }
|
||||
}
|
||||
|
||||
private fun FolderDetails.containsOnlyDefaultValues(): Boolean {
|
||||
private fun RemoteFolderDetails.containsOnlyDefaultValues(): Boolean {
|
||||
return isInTopGroup == getDefaultValue("inTopGroup") &&
|
||||
isIntegrate == getDefaultValue("integrate") &&
|
||||
syncClass == getDefaultValue("syncMode") &&
|
||||
|
@ -29,7 +29,7 @@ class FolderSettingsProvider(private val folderRepositoryManager: FolderReposito
|
|||
return setting.defaultValue
|
||||
}
|
||||
|
||||
private fun FolderDetails.toFolderSettings(): FolderSettings {
|
||||
private fun RemoteFolderDetails.toFolderSettings(): FolderSettings {
|
||||
return FolderSettings(
|
||||
folder.serverId,
|
||||
isInTopGroup,
|
||||
|
|
|
@ -185,11 +185,10 @@ public class RawMessageProvider extends ContentProvider {
|
|||
LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account);
|
||||
LocalFolder localFolder = localStore.getFolder(folderId);
|
||||
localFolder.open();
|
||||
String folderServerId = localFolder.getServerId();
|
||||
|
||||
LocalMessage message = localFolder.getMessage(uid);
|
||||
if (message == null || message.getDatabaseId() == 0) {
|
||||
Timber.w("Message not found: folder=%s, uid=%s", folderServerId, uid);
|
||||
Timber.w("Message not found: folder=%s, uid=%s", folderId, uid);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class JmapAccountCreator(
|
|||
|
||||
private fun createOutboxFolder(account: Account) {
|
||||
val localStore = localStoreProvider.getInstance(account)
|
||||
account.outboxFolderId = localStore.createLocalFolder(Account.OUTBOX, Account.OUTBOX_NAME, FolderType.OUTBOX)
|
||||
account.outboxFolderId = localStore.createLocalFolder(Account.OUTBOX_NAME, FolderType.OUTBOX)
|
||||
}
|
||||
|
||||
private fun fetchFolderList(account: Account) {
|
||||
|
|
|
@ -101,7 +101,7 @@ public class MessageProvider extends ContentProvider {
|
|||
MessagingController messagingController = DI.get(MessagingController.class);
|
||||
messagingController.addListener(new SimpleMessagingListener() {
|
||||
@Override
|
||||
public void folderStatusChanged(Account account, String folderServerId) {
|
||||
public void folderStatusChanged(Account account, long folderId) {
|
||||
context.getContentResolver().notifyChange(CONTENT_URI, null);
|
||||
}
|
||||
});
|
||||
|
@ -166,7 +166,7 @@ public class MessageProvider extends ContentProvider {
|
|||
if (myAccount != null) {
|
||||
MessageReference messageReference = new MessageReference(myAccount.getUuid(), folderId, msgUid, null);
|
||||
MessagingController controller = MessagingController.getInstance(getContext());
|
||||
controller.deleteMessage(messageReference, null);
|
||||
controller.deleteMessage(messageReference);
|
||||
}
|
||||
|
||||
// FIXME return the actual number of deleted messages
|
||||
|
|
|
@ -29,7 +29,7 @@ class MessageListWidgetUpdateListener(private val context: Context) : SimpleMess
|
|||
updateMailListWidget()
|
||||
}
|
||||
|
||||
override fun folderStatusChanged(account: Account, folderServerId: String) {
|
||||
override fun folderStatusChanged(account: Account, folderId: Long) {
|
||||
updateMailListWidget()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,10 +78,10 @@ class UnreadWidgetDataProvider(
|
|||
|
||||
private fun getFolderDisplayName(account: Account, folderId: Long): String {
|
||||
val folderRepository = folderRepositoryManager.getFolderRepository(account)
|
||||
val folderDetails = folderRepository.getFolderDetails(folderId)
|
||||
return if (folderDetails != null) {
|
||||
val folder = folderRepository.getFolder(folderId)
|
||||
return if (folder != null) {
|
||||
val folderNameFormatter = folderNameFormatterFactory.create(context)
|
||||
folderNameFormatter.displayName(folderDetails.folder)
|
||||
folderNameFormatter.displayName(folder)
|
||||
} else {
|
||||
Timber.e("Error loading folder for account %s, folder ID: %d", account, folderId)
|
||||
""
|
||||
|
|
|
@ -23,7 +23,7 @@ class UnreadWidgetUpdateListener(private val unreadWidgetUpdater: UnreadWidgetUp
|
|||
updateUnreadWidget()
|
||||
}
|
||||
|
||||
override fun folderStatusChanged(account: Account, folderServerId: String) {
|
||||
override fun folderStatusChanged(account: Account, folderId: Long) {
|
||||
updateUnreadWidget()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ import com.fsck.k9.Account
|
|||
import com.fsck.k9.AppRobolectricTest
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.controller.MessagingController
|
||||
import com.fsck.k9.mail.FolderClass
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderDetails
|
||||
import com.fsck.k9.mailstore.FolderRepository
|
||||
import com.fsck.k9.mailstore.FolderRepositoryManager
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
|
@ -109,15 +107,7 @@ class UnreadWidgetDataProviderTest : AppRobolectricTest() {
|
|||
|
||||
fun createFolderRepository(): FolderRepository {
|
||||
return mock {
|
||||
on { getFolderDetails(FOLDER_ID) } doReturn FolderDetails(
|
||||
folder = FOLDER,
|
||||
isInTopGroup = true,
|
||||
isIntegrate = true,
|
||||
syncClass = FolderClass.NO_CLASS,
|
||||
displayClass = FolderClass.FIRST_CLASS,
|
||||
notifyClass = FolderClass.NO_CLASS,
|
||||
pushClass = FolderClass.NO_CLASS
|
||||
)
|
||||
on { getFolder(FOLDER_ID) } doReturn FOLDER
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +132,6 @@ class UnreadWidgetDataProviderTest : AppRobolectricTest() {
|
|||
const val LOCALIZED_FOLDER_NAME = "Posteingang"
|
||||
val FOLDER = Folder(
|
||||
id = FOLDER_ID,
|
||||
serverId = "irrelevant",
|
||||
name = "INBOX",
|
||||
type = FolderType.INBOX,
|
||||
isLocalOnly = false
|
||||
|
|
|
@ -12,7 +12,7 @@ import timber.log.Timber;
|
|||
|
||||
|
||||
class StoreSchemaDefinition implements SchemaDefinition {
|
||||
static final int DB_VERSION = 77;
|
||||
static final int DB_VERSION = 78;
|
||||
|
||||
private final MigrationsHelper migrationsHelper;
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package com.fsck.k9.storage.migrations
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Make sure local Outbox folder has correct 'server_id' value
|
||||
*/
|
||||
internal class MigrationTo77(private val db: SQLiteDatabase) {
|
||||
fun cleanUpOutboxServerId() {
|
||||
val values = ContentValues().apply {
|
||||
put("server_id", "K9MAIL_INTERNAL_OUTBOX")
|
||||
}
|
||||
|
||||
db.update("folders", values, "name = 'Outbox' AND local_only = 1", null)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.fsck.k9.storage.migrations
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Set 'server_id' value to NULL for local folders
|
||||
*/
|
||||
internal class MigrationTo78(private val db: SQLiteDatabase) {
|
||||
fun removeServerIdFromLocalFolders() {
|
||||
db.execSQL("UPDATE folders SET server_id = NULL WHERE local_only = 1")
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ object Migrations {
|
|||
if (oldVersion < 74) MigrationTo74(db, migrationsHelper.account).removeDeletedMessages()
|
||||
if (oldVersion < 75) MigrationTo75(db, migrationsHelper).updateAccountWithSpecialFolderIds()
|
||||
if (oldVersion < 76) MigrationTo76(db, migrationsHelper).cleanUpSpecialLocalFolders()
|
||||
if (oldVersion < 77) MigrationTo77(db).cleanUpOutboxServerId()
|
||||
// 77: No longer necessary
|
||||
if (oldVersion < 78) MigrationTo78(db).removeServerIdFromLocalFolders()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ class FolderInfoHolder(
|
|||
val folderId = localFolder.databaseId
|
||||
val folder = Folder(
|
||||
id = folderId,
|
||||
serverId = localFolder.serverId,
|
||||
name = localFolder.name,
|
||||
type = getFolderType(account, folderId),
|
||||
isLocalOnly = localFolder.isLocalOnly
|
||||
|
|
|
@ -727,7 +727,7 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
|
|||
if (showingThreadedList) {
|
||||
messagingController.deleteThreads(messages);
|
||||
} else {
|
||||
messagingController.deleteMessages(messages, null);
|
||||
messagingController.deleteMessages(messages);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.fsck.k9.ui.folders
|
|||
import android.content.res.Resources
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
import com.fsck.k9.mailstore.RemoteFolder
|
||||
import com.fsck.k9.ui.R
|
||||
|
||||
class FolderNameFormatter(private val resources: Resources) {
|
||||
|
@ -26,4 +27,9 @@ class FolderNameFormatter(private val resources: Resources) {
|
|||
FolderType.INBOX -> resources.getString(R.string.special_mailbox_name_inbox)
|
||||
else -> folder.name
|
||||
}
|
||||
|
||||
fun displayName(folder: RemoteFolder) = when (folder.type) {
|
||||
FolderType.INBOX -> resources.getString(R.string.special_mailbox_name_inbox)
|
||||
else -> folder.name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class FoldersLiveData(
|
|||
private val messagingListener = object : SimpleMessagingListener() {
|
||||
override fun folderStatusChanged(
|
||||
account: Account,
|
||||
folderServerId: String
|
||||
folderId: Long
|
||||
) {
|
||||
if (account?.uuid == accountUuid) {
|
||||
loadFoldersAsync()
|
||||
|
|
|
@ -6,7 +6,6 @@ import androidx.lifecycle.liveData
|
|||
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
|
||||
|
@ -57,7 +56,7 @@ class FolderSettingsViewModel(
|
|||
this@FolderSettingsViewModel.folderId = folderId
|
||||
|
||||
val folderSettingsData = FolderSettingsData(
|
||||
folder = createFolderObject(account, folderDetails.folder),
|
||||
folder = folderDetails.folder,
|
||||
dataStore = FolderSettingsDataStore(folderRepository, folderDetails)
|
||||
)
|
||||
emit(folderSettingsData)
|
||||
|
@ -76,17 +75,6 @@ class FolderSettingsViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createFolderObject(account: Account, folder: Folder): Folder {
|
||||
val folderType = FolderInfoHolder.getFolderType(account, folder.id)
|
||||
return Folder(
|
||||
id = folder.id,
|
||||
serverId = folder.serverId,
|
||||
name = folder.name,
|
||||
type = folderType,
|
||||
isLocalOnly = folder.isLocalOnly
|
||||
)
|
||||
}
|
||||
|
||||
fun showClearFolderConfirmationDialog() {
|
||||
sendActionEvent(Action.ShowClearFolderConfirmationDialog)
|
||||
}
|
||||
|
|
|
@ -317,7 +317,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||
mFragmentListener.disableDeleteAction();
|
||||
LocalMessage messageToDelete = mMessage;
|
||||
mFragmentListener.showNextMessageOrReturn();
|
||||
mController.deleteMessage(mMessageReference, null);
|
||||
mController.deleteMessage(mMessageReference);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ import com.fsck.k9.controller.MessagingController
|
|||
import com.fsck.k9.crypto.OpenPgpApiHelper
|
||||
import com.fsck.k9.fragment.ConfirmationDialogFragment
|
||||
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
import com.fsck.k9.mailstore.RemoteFolder
|
||||
import com.fsck.k9.ui.R
|
||||
import com.fsck.k9.ui.endtoend.AutocryptKeyTransferActivity
|
||||
import com.fsck.k9.ui.observe
|
||||
|
@ -291,7 +291,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
|
|||
}
|
||||
}
|
||||
|
||||
private fun setFolders(preferenceKey: String, folders: List<Folder>) {
|
||||
private fun setFolders(preferenceKey: String, folders: List<RemoteFolder>) {
|
||||
val folderListPreference = findPreference(preferenceKey) as? FolderListPreference ?: return
|
||||
folderListPreference.setFolders(folders)
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ import androidx.lifecycle.MutableLiveData
|
|||
import androidx.lifecycle.ViewModel
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.FolderRepositoryManager
|
||||
import com.fsck.k9.mailstore.FolderType
|
||||
import com.fsck.k9.mailstore.RemoteFolder
|
||||
import com.fsck.k9.mailstore.SpecialFolderSelectionStrategy
|
||||
import com.fsck.k9.ui.account.AccountsLiveData
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -68,7 +68,7 @@ class AccountSettingsViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getAutomaticSpecialFolders(folders: List<Folder>): Map<FolderType, Folder?> {
|
||||
private fun getAutomaticSpecialFolders(folders: List<RemoteFolder>): Map<FolderType, RemoteFolder?> {
|
||||
return mapOf(
|
||||
FolderType.ARCHIVE to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.ARCHIVE),
|
||||
FolderType.DRAFTS to specialFolderSelectionStrategy.selectSpecialFolder(folders, FolderType.DRAFTS),
|
||||
|
@ -79,4 +79,7 @@ class AccountSettingsViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
data class RemoteFolderInfo(val folders: List<Folder>, val automaticSpecialFolders: Map<FolderType, Folder?>)
|
||||
data class RemoteFolderInfo(
|
||||
val folders: List<RemoteFolder>,
|
||||
val automaticSpecialFolders: Map<FolderType, RemoteFolder?>
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.text.style.StyleSpan
|
|||
import android.util.AttributeSet
|
||||
import androidx.core.content.res.TypedArrayUtils
|
||||
import androidx.preference.ListPreference
|
||||
import com.fsck.k9.mailstore.Folder
|
||||
import com.fsck.k9.mailstore.RemoteFolder
|
||||
import com.fsck.k9.ui.R
|
||||
import com.fsck.k9.ui.folders.FolderNameFormatter
|
||||
import org.koin.core.KoinComponent
|
||||
|
@ -38,13 +38,13 @@ constructor(
|
|||
isEnabled = false
|
||||
}
|
||||
|
||||
fun setFolders(folders: List<Folder>) {
|
||||
fun setFolders(folders: List<RemoteFolder>) {
|
||||
entries = (listOf(noFolderSelectedName) + getFolderDisplayNames(folders)).toTypedArray()
|
||||
entryValues = (listOf(NO_FOLDER_SELECTED_VALUE) + getFolderValues(folders)).toTypedArray()
|
||||
isEnabled = true
|
||||
}
|
||||
|
||||
fun setFolders(folders: List<Folder>, automaticFolder: Folder?) {
|
||||
fun setFolders(folders: List<RemoteFolder>, automaticFolder: RemoteFolder?) {
|
||||
val automaticFolderName = if (automaticFolder != null) {
|
||||
folderNameFormatter.displayName(automaticFolder)
|
||||
} else {
|
||||
|
@ -73,9 +73,9 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getFolderDisplayNames(folders: List<Folder>) = folders.map { folderNameFormatter.displayName(it) }
|
||||
private fun getFolderDisplayNames(folders: List<RemoteFolder>) = folders.map { folderNameFormatter.displayName(it) }
|
||||
|
||||
private fun getFolderValues(folders: List<Folder>) = folders.map { MANUAL_PREFIX + it.id.toString() }
|
||||
private fun getFolderValues(folders: List<RemoteFolder>) = folders.map { MANUAL_PREFIX + it.id.toString() }
|
||||
|
||||
private fun String.italicize(): CharSequence {
|
||||
return SpannableString(this).apply { setSpan(StyleSpan(Typeface.ITALIC), 0, this.length, 0) }
|
||||
|
|
Loading…
Reference in a new issue