From baed7c09b81377d1c881f0f230ad246582af4973 Mon Sep 17 00:00:00 2001
From: Matt Smith
Date: Sat, 17 Jul 2021 15:36:18 +1200
Subject: [PATCH 001/285] Show full error message in notification
---
.../com/fsck/k9/notification/CertificateErrorNotifications.java | 2 ++
.../java/com/fsck/k9/notification/SendFailedNotifications.java | 2 ++
2 files changed, 4 insertions(+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java
index a8f4f865f5..a5239b1634 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java
+++ b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java
@@ -3,6 +3,7 @@ package com.fsck.k9.notification;
import android.app.PendingIntent;
import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationCompat.BigTextStyle;
import androidx.core.app.NotificationManagerCompat;
import com.fsck.k9.Account;
@@ -40,6 +41,7 @@ class CertificateErrorNotifications {
.setContentTitle(title)
.setContentText(text)
.setContentIntent(editServerSettingsPendingIntent)
+ .setStyle(new BigTextStyle().bigText(text))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCategory(NotificationCompat.CATEGORY_ERROR);
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java
index 660a50b9f1..2bb63cd5e9 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java
+++ b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java
@@ -3,6 +3,7 @@ package com.fsck.k9.notification;
import android.app.PendingIntent;
import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationCompat.BigTextStyle;
import androidx.core.app.NotificationManagerCompat;
import com.fsck.k9.Account;
@@ -42,6 +43,7 @@ class SendFailedNotifications {
.setContentTitle(title)
.setContentText(text)
.setContentIntent(folderListPendingIntent)
+ .setStyle(new BigTextStyle().bigText(text))
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setCategory(NotificationCompat.CATEGORY_ERROR);
--
GitLab
From 902e7ba306a31cfae3697733decfd2960df983e7 Mon Sep 17 00:00:00 2001
From: "r.zarchi"
Date: Sun, 25 Jul 2021 08:58:52 +0430
Subject: [PATCH 002/285] Search view replaced and its UI and logic refactored
in MessageList
---
.../java/com/fsck/k9/activity/MessageList.kt | 45 ++++++++++++++-----
.../fsck/k9/fragment/MessageListFragment.kt | 6 +--
.../src/main/res/menu/message_list_option.xml | 1 +
3 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
index 913dc10e1f..809a56098a 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
@@ -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.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
@@ -96,6 +97,7 @@ open class MessageList :
private val permissionUiHelper: PermissionUiHelper = K9PermissionUiHelper(this)
private lateinit var actionBar: ActionBar
+ private lateinit var searchView: SearchView
private var drawer: K9Drawer? = null
private var openFolderTransaction: FragmentTransaction? = null
private var menu: Menu? = null
@@ -664,6 +666,8 @@ open class MessageList :
drawer!!.close()
} else if (displayMode == DisplayMode.MESSAGE_VIEW && messageListWasDisplayed) {
showMessageList()
+ } else if (this::searchView.isInitialized && !searchView.isIconified) {
+ searchView.isIconified = true
} else {
if (isDrawerEnabled && account != null && supportFragmentManager.backStackEntryCount == 0) {
if (K9.isShowUnifiedInbox) {
@@ -854,10 +858,6 @@ open class MessageList :
return super.onKeyUp(keyCode, event)
}
- override fun onSearchRequested(): Boolean {
- return messageListFragment!!.onSearchRequested()
- }
-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == android.R.id.home) {
@@ -905,9 +905,6 @@ open class MessageList :
} else if (id == R.id.select_all) {
messageListFragment!!.selectAll()
return true
- } else if (id == R.id.search) {
- messageListFragment!!.onSearchRequested()
- return true
} else if (id == R.id.search_remote) {
messageListFragment!!.onRemoteSearch()
return true
@@ -1003,6 +1000,25 @@ open class MessageList :
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.message_list_option, menu)
this.menu = menu
+
+ // setup search view
+ val searchItem = menu.findItem(R.id.search)
+ 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
+ searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
+ searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String): Boolean {
+ messageListFragment?.onSearchRequested(query)
+ return true
+ }
+
+ override fun onQueryTextChange(s: String): Boolean {
+ return false
+ }
+ })
+
return true
}
@@ -1273,19 +1289,24 @@ open class MessageList :
}
}
- override fun startSearch(account: Account?, folderId: Long?): Boolean {
+ override fun startSearch(query: String, account: Account?, folderId: Long?): Boolean {
// If this search was started from a MessageList of a single folder, pass along that folder info
// so that we can enable remote search.
- if (account != null && folderId != null) {
- val appData = Bundle().apply {
+ val appData = if (account != null && folderId != null) {
+ Bundle().apply {
putString(EXTRA_SEARCH_ACCOUNT, account.uuid)
putLong(EXTRA_SEARCH_FOLDER, folderId)
}
- startSearch(null, false, appData, false)
} else {
// TODO Handle the case where we're searching from within a search result.
- startSearch(null, false, null, false)
+ null
+ }
+ val searchIntent = Intent(this, Search::class.java).apply {
+ action = Intent.ACTION_SEARCH
+ putExtra(SearchManager.QUERY, query)
+ putExtra(SearchManager.APP_DATA, appData)
}
+ startActivity(searchIntent)
return true
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 48f602cd4c..d3b4945087 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -1397,9 +1397,9 @@ class MessageListFragment :
val isRemoteSearchAllowed: Boolean
get() = isManualSearch && !isRemoteSearch && isSingleFolderMode && account?.isAllowRemoteSearch == true
- fun onSearchRequested(): Boolean {
+ fun onSearchRequested(query: String): Boolean {
val folderId = currentFolder?.databaseId
- return fragmentListener.startSearch(account, folderId)
+ return fragmentListener.startSearch(query, account, folderId)
}
fun setMessageList(messageListInfo: MessageListInfo) {
@@ -1878,7 +1878,7 @@ class MessageListFragment :
fun openMessage(messageReference: MessageReference)
fun setMessageListTitle(title: String)
fun onCompose(account: Account?)
- fun startSearch(account: Account?, folderId: Long?): Boolean
+ fun startSearch(query: String, account: Account?, folderId: Long?): Boolean
fun remoteSearchStarted()
fun goBack()
fun updateMenu()
diff --git a/app/ui/legacy/src/main/res/menu/message_list_option.xml b/app/ui/legacy/src/main/res/menu/message_list_option.xml
index 38a179c272..04e2462797 100644
--- a/app/ui/legacy/src/main/res/menu/message_list_option.xml
+++ b/app/ui/legacy/src/main/res/menu/message_list_option.xml
@@ -16,6 +16,7 @@
android:id="@+id/search"
android:icon="?attr/iconActionSearch"
app:showAsAction="always"
+ app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/search_action"/>
--
GitLab
From 5882fa4827098625b5db57bb609f5503edc0948f Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 26 Jul 2021 03:59:45 +0200
Subject: [PATCH 003/285] Tweak default font sizes
---
.../src/main/res/layout/accounts_item.xml | 4 ++--
.../src/main/res/layout/message_list_item.xml | 7 ++++---
.../main/res/layout/message_view_header.xml | 20 +++++++++---------
app/ui/legacy/src/main/res/values/styles.xml | 21 +++++++++++++++++++
.../k9/fragment/MessageListAdapterTest.kt | 2 +-
5 files changed, 38 insertions(+), 16 deletions(-)
diff --git a/app/ui/legacy/src/main/res/layout/accounts_item.xml b/app/ui/legacy/src/main/res/layout/accounts_item.xml
index 0a216c1a71..b4d7cee12e 100644
--- a/app/ui/legacy/src/main/res/layout/accounts_item.xml
+++ b/app/ui/legacy/src/main/res/layout/accounts_item.xml
@@ -33,7 +33,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:textAppearance="@style/TextAppearance.K9.Medium"/>
+ android:textAppearance="@style/TextAppearance.K9.Small"/>
diff --git a/app/ui/legacy/src/main/res/layout/message_list_item.xml b/app/ui/legacy/src/main/res/layout/message_list_item.xml
index d3fb198eed..b32226f488 100644
--- a/app/ui/legacy/src/main/res/layout/message_list_item.xml
+++ b/app/ui/legacy/src/main/res/layout/message_list_item.xml
@@ -58,7 +58,7 @@
android:bufferType="spannable"
android:layout_below="@+id/subject_wrapper"
android:singleLine="false"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.K9.Small"
android:textColor="?android:attr/textColorPrimary"
android:longClickable="false"
android:layout_alignWithParentIfMissing="false"
@@ -97,12 +97,13 @@
android:layout_marginLeft="1dip"
android:ellipsize="marquee"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall"
android:textColor="?android:attr/textColorPrimary"
/>
@@ -136,7 +136,7 @@
android:singleLine="true"
android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall"
android:textStyle="bold"
android:text="@string/general_no_sender"
android:gravity="center_vertical"
@@ -153,7 +153,7 @@
android:layout_below="@+id/from"
android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.K9.Small"
android:textStyle="bold"
android:visibility="gone"
android:gravity="center_vertical"
@@ -170,7 +170,7 @@
android:paddingRight="4dp"
android:text="@string/message_to_label"
android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="@android:style/TextAppearance.Medium"
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall"
android:textStyle="bold" />
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
+ android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
?android:textColorPrimary
- ?android:textColorSecondary
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/ui/legacy/src/test/java/com/fsck/k9/fragment/MessageListAdapterTest.kt b/app/ui/legacy/src/test/java/com/fsck/k9/fragment/MessageListAdapterTest.kt
index d985d86a3f..cb18a576ae 100644
--- a/app/ui/legacy/src/test/java/com/fsck/k9/fragment/MessageListAdapterTest.kt
+++ b/app/ui/legacy/src/test/java/com/fsck/k9/fragment/MessageListAdapterTest.kt
@@ -35,7 +35,7 @@ import org.mockito.kotlin.mock
import org.robolectric.Robolectric
private const val SOME_ACCOUNT_UUID = "6b84207b-25de-4dab-97c3-953bbf03fec6"
-private const val FIRST_LINE_DEFAULT_FONT_SIZE = 18f
+private const val FIRST_LINE_DEFAULT_FONT_SIZE = 16f
private const val SECOND_LINE_DEFAULT_FONT_SIZE = 14f
private const val DATE_DEFAULT_FONT_SIZE = 14f
--
GitLab
From 2ff88b2908bb1551c821ad3ff7daa04719daf0b3 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 10:32:44 +0200
Subject: [PATCH 004/285] Close drawer when switching to an account with an
auto-expand folder configured
---
.../src/main/java/com/fsck/k9/activity/MessageList.kt | 6 +++++-
app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt | 5 +++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
index 913dc10e1f..9b8a045cb2 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
@@ -618,13 +618,17 @@ open class MessageList :
ManageFoldersActivity.launch(this, account!!)
}
- fun openRealAccount(account: Account) {
+ fun openRealAccount(account: Account): Boolean {
+ val shouldCloseDrawer = account.autoExpandFolderId != null
+
val folderId = defaultFolderProvider.getDefaultFolder(account)
val search = LocalSearch()
search.addAllowedFolder(folderId)
search.addAccountUuid(account.uuid)
actionDisplaySearch(this, search, noThreading = false, newTask = false)
+
+ return shouldCloseDrawer
}
private fun performSearch(search: LocalSearch) {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
index 46b6fb4c16..3b35340f93 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
@@ -155,9 +155,10 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
headerView.onAccountHeaderListener = { _, profile, _ ->
val account = (profile as ProfileDrawerItem).tag as Account
openedAccountUuid = account.uuid
- parent.openRealAccount(account)
+ val eventHandled = !parent.openRealAccount(account)
updateUserAccountsAndFolders(account)
- true
+
+ eventHandled
}
}
--
GitLab
From b8bfde6e069811ea547a4af8fd113e9fb433870a Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 11:44:34 +0200
Subject: [PATCH 005/285] Prepare for version 5.801
---
app/k9mail/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index c605fe41f1..184f68367f 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -47,7 +47,7 @@ android {
testApplicationId "com.fsck.k9.tests"
versionCode 28000
- versionName '5.800'
+ versionName '5.801-SNAPSHOT'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
--
GitLab
From ac4cb37ea72aea7cc753b32f3acdab2bc21f46fa Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 11:43:20 +0200
Subject: [PATCH 006/285] Add network security config to allow user-installed
CAs
---
app/k9mail/src/main/AndroidManifest.xml | 1 +
.../src/main/res/xml/network_security_config.xml | 12 ++++++++++++
2 files changed, 13 insertions(+)
create mode 100644 app/k9mail/src/main/res/xml/network_security_config.xml
diff --git a/app/k9mail/src/main/AndroidManifest.xml b/app/k9mail/src/main/AndroidManifest.xml
index 2bd7df96e9..1efe2c8135 100644
--- a/app/k9mail/src/main/AndroidManifest.xml
+++ b/app/k9mail/src/main/AndroidManifest.xml
@@ -45,6 +45,7 @@
android:name="com.fsck.k9.App"
android:allowTaskReparenting="false"
android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.K9.Startup"
diff --git a/app/k9mail/src/main/res/xml/network_security_config.xml b/app/k9mail/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000000..094d432251
--- /dev/null
+++ b/app/k9mail/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
--
GitLab
From 8f9ca74f9a36ea8bea064a432356363882482d24 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 12:35:29 +0200
Subject: [PATCH 007/285] Display account name in toolbar
If there's only one account set up, we skip displaying the account name. Same for views that don't belong to a single account (Unified Inbox, global search results).
---
.../main/java/com/fsck/k9/activity/MessageList.kt | 7 ++++---
.../java/com/fsck/k9/fragment/MessageListFragment.kt | 12 ++++++++++--
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
index 913dc10e1f..2850bbba39 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
@@ -1174,13 +1174,14 @@ open class MessageList :
finish()
}
- fun setActionBarTitle(title: String) {
+ fun setActionBarTitle(title: String, subtitle: String? = null) {
actionBar.title = title
+ actionBar.subtitle = subtitle
}
- override fun setMessageListTitle(title: String) {
+ override fun setMessageListTitle(title: String, subtitle: String?) {
if (displayMode != DisplayMode.MESSAGE_VIEW) {
- setActionBarTitle(title)
+ setActionBarTitle(title, subtitle)
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 48f602cd4c..1d56e9efb7 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -331,7 +331,15 @@ class MessageListFragment :
else -> ""
}
- fragmentListener.setMessageListTitle(title)
+ val subtitle = account.let { account ->
+ if (account == null || isUnifiedInbox || preferences.accounts.size == 1) {
+ null
+ } else {
+ account.description
+ }
+ }
+
+ fragmentListener.setMessageListTitle(title, subtitle)
}
fun progress(progress: Boolean) {
@@ -1876,7 +1884,7 @@ class MessageListFragment :
fun setMessageListProgress(level: Int)
fun showThread(account: Account, threadRootId: Long)
fun openMessage(messageReference: MessageReference)
- fun setMessageListTitle(title: String)
+ fun setMessageListTitle(title: String, subtitle: String?)
fun onCompose(account: Account?)
fun startSearch(account: Account?, folderId: Long?): Boolean
fun remoteSearchStarted()
--
GitLab
From e59d3d758370a930c394a101f3eb420d83f17bc1 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 14:38:45 +0200
Subject: [PATCH 008/285] Don't call through to Glide when the Activity has
been destroyed
---
.../fsck/k9/ui/account/AccountImageLoader.kt | 28 ++++++++++++++-----
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountImageLoader.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountImageLoader.kt
index 3be4635872..1db03ec74d 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountImageLoader.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountImageLoader.kt
@@ -1,5 +1,7 @@
package com.fsck.k9.ui.account
+import android.app.Activity
+import android.content.Context
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
@@ -9,15 +11,27 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
*/
class AccountImageLoader(private val accountFallbackImageProvider: AccountFallbackImageProvider) {
fun setAccountImage(imageView: ImageView, email: String, color: Int) {
- Glide.with(imageView.context)
- .load(AccountImage(email, color))
- .placeholder(accountFallbackImageProvider.getDrawable(color))
- .diskCacheStrategy(DiskCacheStrategy.NONE)
- .dontAnimate()
- .into(imageView)
+ imageView.context.ifNotDestroyed { context ->
+ Glide.with(context)
+ .load(AccountImage(email, color))
+ .placeholder(accountFallbackImageProvider.getDrawable(color))
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .dontAnimate()
+ .into(imageView)
+ }
}
fun cancel(imageView: ImageView) {
- Glide.with(imageView.context).clear(imageView)
+ imageView.context.ifNotDestroyed { context ->
+ Glide.with(context).clear(imageView)
+ }
+ }
+
+ private inline fun Context.ifNotDestroyed(block: (Context) -> Unit) {
+ if ((this as? Activity)?.isDestroyed == true) {
+ // Do nothing because Glide would throw an exception
+ } else {
+ block(this)
+ }
}
}
--
GitLab
From 1c08f812096c8532ed3dae8b94bcde0a8903bb46 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 14:45:24 +0200
Subject: [PATCH 009/285] Don't crash when loading the message list fails
For a proper way to fix this see #5408.
---
.../com/fsck/k9/ui/messagelist/MessageListLoader.kt | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListLoader.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListLoader.kt
index 5559dde7d9..7a5b6806b6 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListLoader.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messagelist/MessageListLoader.kt
@@ -40,6 +40,17 @@ class MessageListLoader(
) {
fun getMessageList(config: MessageListConfig): MessageListInfo {
+ return try {
+ getMessageListInfo(config)
+ } catch (e: Exception) {
+ Timber.e(e, "Error while fetching message list")
+
+ // TODO: Return an error object instead of an empty list
+ MessageListInfo(messageListItems = emptyList(), hasMoreMessages = false)
+ }
+ }
+
+ private fun getMessageListInfo(config: MessageListConfig): MessageListInfo {
val accounts = config.search.getAccounts(preferences)
val cursors = accounts
.mapNotNull { loadMessageListForAccount(it, config) }
--
GitLab
From 2eb4bbb4470155655efc12de67eb155129dbb01f Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 29 Jul 2021 19:46:54 +0200
Subject: [PATCH 010/285] Update translations
---
.../legacy/src/main/res/values-ar/strings.xml | 25 +++++
.../legacy/src/main/res/values-bg/strings.xml | 5 +
.../legacy/src/main/res/values-ca/strings.xml | 76 ++++++-------
.../legacy/src/main/res/values-cs/strings.xml | 36 +++++++
.../legacy/src/main/res/values-de/strings.xml | 6 +-
.../legacy/src/main/res/values-es/strings.xml | 7 ++
.../legacy/src/main/res/values-hu/strings.xml | 100 +++++++++---------
.../legacy/src/main/res/values-sv/strings.xml | 66 ++++++------
.../legacy/src/main/res/values-uk/strings.xml | 52 ++++++++-
9 files changed, 248 insertions(+), 125 deletions(-)
diff --git a/app/ui/legacy/src/main/res/values-ar/strings.xml b/app/ui/legacy/src/main/res/values-ar/strings.xml
index 1f4aa9fc70..14c39035a8 100644
--- a/app/ui/legacy/src/main/res/values-ar/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ar/strings.xml
@@ -9,9 +9,14 @@
فريق The K-9 Dog Walkers
حقوق النشر محفوظة 2008 - %s The K-9 Dog Walkers. جزء من حقوق النشر محفوظة 2006 - %s the Android Open Source Project.
+ الكود المصدري
Apache License, Version 2.0
+ مشروع مفتوح المصدر
+ الموقع الإلكتروني
المكتبات
الرخصة
+ سجل التغييرات
+ مالجديد
أهلا بكم في بريد K-9
أضف حسابًا
أنشِئ
ابحث
+ البحث في كل مكان
نتائج البحث
الإعدادات
إدارة المجلدات
@@ -340,6 +346,7 @@
خادم SMTP
المَنفذ
الأمان
+ يتطلب تسجيل الدخول
اسم المُستخدم
كلمة السِّر
المصادقة
@@ -434,6 +441,20 @@
مِن دون لون
لون ضوء التنبيهات
حجم المجلد المحلي
+ 1 KiB
+ 2 KiB
+ 4 KiB
+ 8 KiB
+ 16 KiB
+ 32 KiB
+ 64 KiB
+ 128 KiB
+ 256 KiB
+ 512 KiB
+ 1 MiB
+ 2 MiB
+ 5 MiB
+ 10 MiB
أي حجم (بدون حَدْ)
زَامن الرسائل مع
أي وقت (بدون حَدْ)
@@ -595,6 +616,7 @@
1000 مجلد
الحركة
التصفح عبر أزرار التحكم في الصوت
+ %s %s
- غير المقروءة
كل الرسائل
البريد الوارد الموحَّد
@@ -626,6 +648,7 @@
الوقت والتاريخ
نصّ الرسالة
%d%%
+ %1$s: %2$s
إنشاء الرسالة
حقول إدخال النص
الإفتراضي
@@ -666,6 +689,7 @@
تمت عملية تصدير الإعدادات بنجاح
فشل تصدير الإعدادات
استيراد الإعدادات
+ اختيار ملف
استيراد
لاحقًا
استيراد الإعدادات
@@ -793,4 +817,5 @@
افتح
اغلق
+ لمعرفة المزيد
diff --git a/app/ui/legacy/src/main/res/values-bg/strings.xml b/app/ui/legacy/src/main/res/values-bg/strings.xml
index 31e801fa26..a55e264efa 100644
--- a/app/ui/legacy/src/main/res/values-bg/strings.xml
+++ b/app/ui/legacy/src/main/res/values-bg/strings.xml
@@ -14,6 +14,7 @@
Проект с отворен код
Уебстраница
Потребителски форум
+ Twitter
Библиотеки
Лиценз
Списък на промените
@@ -151,6 +152,10 @@ K-9 Mail е мощен, безплатен имейл клиент за Андр
Съобщението не е намерено
Грешка при зареждане на съобщението
Зареди още %d
+ %.1f ГБ
+ %.1f МБ
+ %.1f КБ
+ %d Б
Профил \"%s\" се смали от %s до %s
Компресира профил \"%s\"
Ново Писмо
diff --git a/app/ui/legacy/src/main/res/values-ca/strings.xml b/app/ui/legacy/src/main/res/values-ca/strings.xml
index 5108611432..c4a76f71f0 100644
--- a/app/ui/legacy/src/main/res/values-ca/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ca/strings.xml
@@ -16,7 +16,7 @@
Fòrum d\'usuaris
Fediverse
Twitter
- Biblioteques
+ Biblioteques informàtiques
Llicència
Registre de canvis
No s\'ha pogut carregar el registre de canvis.
@@ -78,8 +78,8 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Trieu un compte
Tria carpeta
Comprova %s:%s%s
- Recuperant capçaleres %s:%s%s
- Enviant %s%s
+ S\'estan recuperant capçaleres %s:%s%s
+ S\'està enviant %s%s
Proc %s:%s%s
\u0020%d/%d
Sincronització desactivada
@@ -148,7 +148,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
(Sense assumpte)
Sense remitent
- Carregant missatges\u2026
+ S\'estan carregant missatges\u2026
Error de connexió
No s\'ha trobat el missatge
Hi ha hagut un error durant la càrrega del missatge
@@ -159,7 +159,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
%.1f kB
%d B
Compte \"%s\" comprimida des de %s a %s
- Compactant el compte \"%s\"
+ S\'està compactant el compte \"%s\"
Correu nou
- %d nous missatges
@@ -179,10 +179,10 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Comproveu la configuració del servidor.
Ha fallat l\'autenticació
Ha fallat l\'autenticació de %s. Actualitzeu la configuració del servidor.
- Comprovant el correu: %s:%s
- Comprovant el correu
- Enviant correu: %s
- Enviant correu
+ S\'està comprovant el correu: %s:%s
+ S\'està comprovant el correu
+ S\'està enviant correu: %s
+ S\'està enviant correu
.
Sincronitza-ho (Empeny)
Mostrat mentre s\'esperen missatges nous
@@ -300,12 +300,12 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Mostra la contrasenya
Configuració manual
- Recuperant la informació del compte\u2026
- Comprovant la configuració del servidor d\'entrada\u2026
- Comprovant la configuració del servidor de sortida\u2026
- Autenticant\u2026
- Recuperant la configuració del compte\u2026
- Cancel·lant\u2026
+ S\'està recuperant la informació del compte\u2026
+ S\'està comprovant la configuració del servidor d\'entrada\u2026
+ S\'està comprovant la configuració del servidor de sortida\u2026
+ S\'està autenticant\u2026
+ S\'està recuperant la configuració del compte\u2026
+ S\'està cancel·lant\u2026
Ja gairebé hem acabat!
Dóna un nom a aquest compte (opcional):
Escriviu el nom (és el que es mostrarà als missatges sortints):
@@ -443,7 +443,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
No
Dels contactes
De qualsevol
- Enviant correu
+ S\'està enviant el correu
Cita el missatge original en respondre\'l.
Afegeix el missatge original a les vostres respostes.
Contesta després del text citat.
@@ -463,8 +463,8 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Carrega els missatges enviats
Carrega els missatges a la carpeta d\'enviats després d\'enviar-los
Configuració general
- Llegint el correu
- Recuperant el correu
+ S\'està llegint el correu
+ S\'està recuperant el correu
Carpetes
Prefix de citació del text
Encriptació d\'extrem a extrem
@@ -776,7 +776,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
›
Còpia de seguretat
Miscel·lània
- Configuració de l\'exportació
+ Exporta la configuració
Exporta
Comparteix
S\'està exportant la configuració...
@@ -796,7 +796,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Fallada d\'importació
Més tard
Importa la configuració
- Important la configuració...
+ S\'està important la configuració...
- Per poder usar el compte %s heu de proporcionar la contrasenya del servidor.
- Per poder fer servir el compte %s heu de proporcionar les contrasenyes del servidor.
@@ -818,7 +818,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
No hi ha cap compte seleccionat
No hi ha cap carpeta seleccionada
Sense text
- Obre per mostrar
+ Obre l\'enllaç
Comparteix l\'enllaç
Copia l\'enllaç
Enllaç
@@ -847,14 +847,14 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
500
1000
Límit de resultats de la cerca del servidor
- Enviant la consulta al servidor
+ S\'està enviant la consulta al servidor
- Recuperant %d resultat
- - Recuperant %d resultats
+ - S\'està recuperant %d resultats
- Recuperant %1$d de %2$d resultats
- - Recuperant %1$dde %2$dresultats
+ - S\'està recuperant %1$dde %2$dresultats
No s\'ha pogut fer la cerca remota.
Cerca
@@ -867,8 +867,8 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Vista de fil de discussió
Recull els missatges del mateix fil de discussió
Actualització de les bases de dades
- Actualitzant les bases de dades...
- Actualitzant la base de dades del compte \"%s\"
+ S\'estan actualitzant les bases de dades...
+ S\'està actualitzant la base de dades del compte \"%s\"
Mostra amb pantalla dividida
Sempre
Mai
@@ -881,10 +881,10 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Acoloreix les imatges de contactes absents
Accions de missatge visibles
Mostra les accions seleccionades al menú de vista de missatge
- Carregant l\'adjunt…
- Enviant el missatge
- Desant l\'esborrany
- Recuperant l\'adjunt…
+ S\'està carregant l\'adjunt…
+ S\'està enviant el missatge
+ S\'està desant l\'esborrany
+ S\'està recuperant l\'adjunt…
No s\'ha pogut autenticar. El servidor no ha mostrat l\'opció SASL EXTERNAL. Això podria ser degut a un problema amb el certificat del client (caducat, o autoritat del certificat desconeguda) o algun altre problema de configuració.
Fes servir el certificat de client
@@ -917,7 +917,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Habilita PGP de només signar
Inhabilita PGP de només signar
Mode PGP/INLINE
- El missatge s\'envia en el format PGP/INLINE.\nAixò només s\'hauria d\'usar per a compatibilitat:
+ El missatge s\'envia en el format PGP/INLINE.\nAixò només s\'hauria de fer servir per a compatibilitat:
Alguns clients només admeten aquest format
Les signatures es poden trencar durant el trànsit
Els adjunts no s\'admeten
@@ -971,7 +971,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Desbloqueja
Aquesta part no estava encriptada i pot no ser segura.
Adjunt no protegit
- Carregant...
+ S\'està carregant...
S\'ha cancel·lat la desencriptació.
Torna-hi
Cal baixar el missatge encriptat per desencriptar-lo.
@@ -988,23 +988,23 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
A causa d\'això, el suport d\'APG s\'ha eliminat del K-9 Mail.
El desenvolupament es va aturar a principis de 2014.
Conté problemes de seguretat no corregits.
- Podeu clicar aquí per saber-ne més.
+ Podeu fer clic aquí per saber-ne més.
Ja ho tinc!
APG
Aquest missatge està encriptat.
Aquest missatge ha estat encriptat amb OpenPGP.\nPer llegir-lo, us caldrà instal·lar i configurar una aplicació d\'OpenPGP compatible.
Ves a la configuració
Llista de missatges del K-9
- Carregant missatges...
+ S\'està carregant missatges...
Ha fallat recuperar la llista de carpetes.
Error en recuperar l\'estat del destinatari del proveïdor d\'OpenPGP!
Encriptació no possible
Alguns dels destinataris seleccionats no admeten aquesta característica!
Habilita l\'encriptació
Inhabilita l\'encriptació
- Encriptar els missatges assegura que els pugui llegir el destinatari i ningú més.
+ L\'encriptació dels missatges assegura que els pugui llegir el destinatari i ningú més.
L\'encriptació només es mostrarà si tots els destinataris l\'admeten i us han d\'haver enviat un missatge abans.
- Commuteu l\'encriptació clicant en aquesta icona.
+ Commuteu l\'encriptació fent clic en aquesta icona.
Ja ho tinc
Enrere
Inhabilita l\'encriptació
@@ -1013,7 +1013,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Mode mutu d\'autoencriptació
Els missatges s\'encriptaran normalment per selecció o en respondre un missatge encriptat.
Si tant el remitent com el destinatari habiliten el mode mutu, l\'encriptació s\'habilitarà per defecte.
- Podeu clicar aquí per saber-ne més.
+ Podeu fer clic aquí per saber-ne més.
Configuració general
No hi ha cap aplicació d\'OpenPGP instal·lada.
Instal·la
@@ -1038,7 +1038,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Per configurar el vostre dispositiu nou per a l\'autoencriptació, si us plau, seguiu les instruccions que es mostraran al dispositiu nou.
-Podeu guardar aquest missatge i usar-lo com a còpia de seguretat per a la vostra clau secreta. Si ho voleu fer, hauríeu d\'anotar-vos la contrasenya i desar-la amb seguretat.
+Podeu desar aquest missatge i fer-lo servir com a còpia de seguretat per a la vostra clau secreta. Si ho voleu fer, hauríeu d\'anotar-vos la contrasenya i desar-la amb seguretat.
Hi ha hagut un error mentre s\'enviava el missatge. Si us plau, comproveu la connexió de xarxa i la configuració del servidor de sortida.
Actiu
diff --git a/app/ui/legacy/src/main/res/values-cs/strings.xml b/app/ui/legacy/src/main/res/values-cs/strings.xml
index fa096f604d..0334f1031e 100644
--- a/app/ui/legacy/src/main/res/values-cs/strings.xml
+++ b/app/ui/legacy/src/main/res/values-cs/strings.xml
@@ -7,18 +7,23 @@
Účty K-9
K-9 Nepřečtená
+ Páníčci robopsů K-9
Copyright 2008-%s The K-9 Dog Walkers. Portions Copyright 2006-%s the Android Open Source Project.
Zdrojový kód
Apache License, verze 2.0
Projekt s otevřeným zdrojovým kódem
Webová stránka
Uživatelské fórum
+ Fediverse
Twitter
Softwarové knihovny
Licence
Soupis změn
Nelze nahrát soupis změn.
Verze %s
+ Co je nového
+ Po aktualizaci aplikace, zobrazovat nejnovější změny
+ Zjistěte, co je v tomto vydání nového
Vítejte v K-9 Mail
Přidat účet
Nová
Hledat
+ Hledat všude
Výsledky hledání
Možnosti
Spravovat složky
@@ -129,6 +135,7 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
- Adres zkopírováno do schránky
- Adresy zkopírovány do schránky
+ Text předmětu zkopírován do schránky
Přepnout na tmavý motiv
Přepnout na světlý motiv
Označit jako nepřečtené
@@ -181,6 +188,8 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
Odesílání pošty: %s
Odesílání pošty
:
+ Synchronizovat (Push)
+ Zobrazeno po dobu čekání na nové zprávy
Zpráva
Oznámení související se zprávami
Různé
@@ -480,6 +489,20 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
Barva, kterou má telefon blikat pro tento účet
Velikost místního adresáře
Stahovat zprávy až do
+ 1 KiB
+ 2 KiB
+ 4 KiB
+ 8 KiB
+ 16 KiB
+ 32 KiB
+ 64 KiB
+ 128 KiB
+ 256 KiB
+ 512 KiB
+ 1 MiB
+ 2 MiB
+ 5 MiB
+ 10 MiB
jakékoli velikosti (bez omezení)
Synchronizovat odeslané zprávy
kdykoliv (bez omezení)
@@ -535,6 +558,7 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
Žádná třída
1. třída
2. třída
+ Stejné jako třída fondu
Třída oznámení složky
Žádná třída
1. třída
@@ -1038,4 +1062,16 @@ Tuto zprávu si můžete ponechat a použít jí jako zálohu svého tajného kl
Umožnit přístup ke kontaktům
Aby bylo možné poskytovat automatické dopisování kontaktů a zobrazovat jména a fotky kontaktů, aplikace potřebuje přístup k vašim kontaktům.
Nastala chyba při nahrávání dat
+ Inicializace…
+ Čeká se na nové e-maily
+ Uspáno do doby, než bude umožněna synchronizace na pozadí
+ Uspáno do doby, než bude k dispozici síť
+ Klepněte, pokud se chcete dozvědět víc.
+ Push informace
+ Při používání Push, K-9 Mail udržuje spojení s e-mailový serverem. Systém Android vyžaduje zobrazování průběžného upozornění, zatímco je aplikace aktivní na pozadí. %s
+ Nicméně, Android vám také umožňuje toto upozornění skrýt.
+ Zjistit více
+ Nastavit upozorňování
+ Pokud nepotřebujete okamžitá upozornění na nové zprávy, měli byste Push vypnout a použít pravidelné dotazování se. To kontroluje nové e-maily v pravidelném intervalu a nepotřebuje upozornění.
+ Vypnout Push
diff --git a/app/ui/legacy/src/main/res/values-de/strings.xml b/app/ui/legacy/src/main/res/values-de/strings.xml
index eaa07ae32b..038d88d2c0 100644
--- a/app/ui/legacy/src/main/res/values-de/strings.xml
+++ b/app/ui/legacy/src/main/res/values-de/strings.xml
@@ -102,7 +102,7 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
Spam
Weiterleiten
Als Anhang weiterleiten
- Editiere als neue Meldung
+ Als neue Nachricht bearbeiten
Verschieben
Zu Entwürfen verschieben
Senden…
@@ -117,7 +117,7 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
Konto hinzufügen
Verfassen
Suchen
- Suche überall
+ Überall suchen
Suchergebnisse
Einstellungen
Ordner verwalten
@@ -803,7 +803,7 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
- Um das Konto \"%s\" nutzen zu können, müssen Sie die Serverpasswörter eingeben.
Passwort des Posteingangsservers
- Passwort des Posteingangsservers
+ Passwort des Postausgangsservers
Gleiches Passwort für den Postausgangsserver verwenden
Servername: %s
Anzahl ungelesener Nachrichten anzeigen für…
diff --git a/app/ui/legacy/src/main/res/values-es/strings.xml b/app/ui/legacy/src/main/res/values-es/strings.xml
index 9396f3c2a8..b1f7bedd51 100644
--- a/app/ui/legacy/src/main/res/values-es/strings.xml
+++ b/app/ui/legacy/src/main/res/values-es/strings.xml
@@ -1048,6 +1048,13 @@ Puede mantener este mensaje y usarlo como copia de seguridad de su clave secreta
Para poder proveer sugerencias de contactos y mostrar sus nombres, la app necesita acceso a éstos.
Se produjo un error al cargar los datos
Iniciando...
+ Esperando nuevos correos electrónicos
Esperar hasta que se permita la sincronización en segundo plano
Esperar hasta que la red esté disponible
+ Toque para obtener más información.
+ Empujar Info
+ Sin embargo, Android también te permite ocultar la notificación.
+ Aprende más
+ Configurar notificación
+ Deshabilitar Push
diff --git a/app/ui/legacy/src/main/res/values-hu/strings.xml b/app/ui/legacy/src/main/res/values-hu/strings.xml
index 9bbaf5b1c5..6cf865f302 100644
--- a/app/ui/legacy/src/main/res/values-hu/strings.xml
+++ b/app/ui/legacy/src/main/res/values-hu/strings.xml
@@ -8,17 +8,17 @@
K-9 olvasatlan
The K-9 Dog Walkers
- Copyright 2008-%s a The K-9 Dog Walkers. Részleges Copyright 2006-%s az Android Nyílt Forráskódú Projekt.
+ Copyright 2008-%s The K-9 Dog Walkers. Egyes részek: Copyright 2006-%saz Android Nyílt Forráskódú Projekt.
Forráskód
Apache licenc, 2.0-s verzió
- Nyílt forráskódú Projekt
+ Nyílt forráskódú projekt
Weboldal
Felhasználói fórum
Födiverzum
Twitter
Programkönyvtárak
Licenc
- Változásnapl
+ Változásnapló
A változásnapló betöltése sikertelen.
Verzió: %s
Újdonságok
@@ -28,39 +28,39 @@
Üdvözlet a K-9 Mail alkalmazásban.
-A K-9 Mail egy hatékony, ingyenes email alkalmazás Androidra.
+A K-9 Mail egy hatékony, ingyenes e-mail alkalmazás Androidra.
-Továbbfejleszett elemek:
+Továbbfejlesztett funkciók:
- - Email küldés IMAP IDLE segítségével
+ - E-mail küldés IMAP IDLE segítségével
- Jobb működés
- Üzenet iktatás
- - Email aláírások
+ - E-mail aláírások
- Titkos másolat saját részre
- Mappa váltogatások
- Összes mappa szinkronizálása
- Visszatérési cím konfiguráció
- Gyorsbillentyűk
- - Jobb IMAP támogatás
- - Mellékletek mentése SD kártyára
+ - Jobb IMAP-támogatás
+ - Mellékletek mentése SD-kártyára
- Lomtár ürítése
- - Üzenet rendezés
+ - Üzenetek rendezése
- …és egyebek
-A K-9 nem támogatja a legtöbb Hotmail fiókot és sok email alkalmazáshoz hasonlóan vannak furcsaságok a Microsoft Exchange kezelésében.
+
A K-9 nem támogatja a legtöbb Hotmail-fiókot, és sok e-mail alkalmazáshoz hasonlóan, vannak furcsaságok a Microsoft Exchange kezelésében.
-Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdéseket tehetünk fel
-https://github.com/k9mail/k-9/webcímen.
+Hibajelentések beküldésével közreműködhet az új funkciókban, és kérdéseket tehet fel a
+https://github.com/k9mail/k-9/ webcímen.
]]>
-- \nAndroidos készülékről küldve K-9 Mail használatával. Elnézést a rövidségért.
- \"%s\" fiók eltávolításra kerül a K-9 Mail alkalmazásból.
+ A(z) „%s” fiók eltávolításra kerül a K-9 Mail alkalmazásból.
Szerzők
- Felülvizsgálati információk
+ Kiadási megjegyzések
E-mailek olvasása
Az alkalmazás olvashatja az emaileket.
E-mailek törlése
@@ -156,8 +156,8 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
%.1f MB
%.1f kB
%d B
- \"%s\" fiók tömörítésre került: %s=> %s
- \"%s\" fiók tömörítése folyamatban van.
+ A(z) „%s” fiók tömörítésre került: %s=> %s
+ A(z) „%s” fiók tömörítése folyamatban van.
Új levél
- %d új üzenet
@@ -174,9 +174,9 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Összes archiválása
Levélszemét
Tanúsítványhiba: %s
- Ellenőrizzük a kiszolgáló beállításait.
+ Ellenőrizze a kiszolgálóbeállításokat.
A hitelesítés sikertelen.
- A hitelesítés sikertelen: %s. Frissítsük a kiszolgáló beállításait.
+ A hitelesítés sikertelen: %s. Frissítse a kiszolgálóbeállításokat.
Levelek ellenőrzése: %s:%s
Levelek ellenőrzése
Levél küldése: %s
@@ -193,13 +193,13 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Piszkozatok
Kuka
Elküldött
- Néhány üzenetet nem sikerült elküldeni.
+ Néhány üzenetet nem sikerült elküldeni
Verzió
Hibakeresési naplózás engedélyezése
További diagnosztikai információk naplózása
Érzékeny információk naplózása
A jelszavak láthatóak lehetnek a naplókban.
- Többi üzenetek betöltése
+ További üzenetek betöltése
Címzett:%s
Tárgy
Üzenet szövege
@@ -214,7 +214,7 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Ekkor: %1$s, %2$s írta:
Legalább egy címzettet hozzá kell adni.
A címzett mező befejezetlen beviteli adatot tartalmaz.
- Nem található email cím ehhez a partnerhez.
+ Nem található e-mail cím ehhez a partnerhez.
Néhány mellékletet nem lehet továbbítani, mert nem lettek letöltve.
Az üzenet nem továbbítható, mert egyes mellékletek nem lettek letöltve.
Idézett üzenetet is
@@ -229,13 +229,13 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Mentés
Nem lehet elmenteni a mellékletet.
Fényképek megjelenítése
- Nem sikerült megjelenítőt találni: %s.
+ Nem sikerült megjelenítőt találni ehhez: %s.
Teljes üzenet letöltése
- Az üzenet nem jeleníthető meg.
+ Az üzenet nem jeleníthető meg
ezen keresztül: %1$s
Az összes fejléc letöltésre került, de nincsenek további megjelenítendő fejlécek.
- A további fejlécek letöltése sikertelen volt az adatbázisból vagy a levélszerverről.
+ A további fejlécek letöltése az adatbázisból vagy a levelezőkiszolgálóról sikertelen.
Továbbiak ettől a feladótól
Innen: %s
Üzenet törzsének hibakeresése vagy kiürítése
@@ -245,11 +245,11 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Csillagok jelzik a megjelölt üzeneteket
Előnézeti sorok
Levelezési nevek megjelenítése
- Levelezési nevek megjelenítése az email címek helyett
+ Levelezési nevek megjelenítése az e-mail-címek helyett
Levelezési név a tárgy fölött
- Levelezési nevek megjelenítése a tárgy sora fölött és nem alatta
+ Levelezési nevek megjelenítése a tárgy sora fölött, és nem alatta
Partnernevek megjelenítése
- Címzettek neveinek használata a Címjegyzékből, amikor elérhető
+ Címzettek neveinek használata a címjegyzékből, ha elérhető
Partnerek színezése
Nevek színezése a partnerlistában
Rögzített szélességű betűk
@@ -269,14 +269,14 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Összes üzenet megjelölése olvasottként
Törlés (az értesítésekből)
Levelező alkalmazás elrejtése
- A K-9 fazonosító eltávolítása a levél fejlécéből
+ A K-9 azonosító eltávolítása a levél fejlécéből
Időzóna elrejtése
UTC használata a helyi időzóna helyett a levelek fejlécében és a válasz fejlécében
Tárgy elrejtése az értesítésekben
Soha
Ha a készülék zárolt
Mindig
- \"Törlés” gomb megjelenítése
+ „Törlés” gomb megjelenítése
Soha
Önálló üzenet értesítésénél
Mindig
@@ -285,7 +285,7 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Alkalmazás neve
Olvasatlan üzenetek száma
Üzenet számlálók és feladók
- Ugyanaz, mint a képernyő zárolásnál
+ Ugyanaz, mint feloldott képernyőnél
Csendes idő
Csörgés, rezgés és villogás letiltása éjszakára
Értesítések letiltása
@@ -293,20 +293,20 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Csendes idő kezdete
Csendes idő vége
Új fiók beállítása
- Email cím
+ E-mail-cím
Jelszó
Jelszó megjelenítése
Kézi beállítás
Fiókinformációk beolvasása\u2026
- Bejövő szerver beállítások ellenőrzése\u2026
- Kimenő szerver beállítások ellenőrzése\u2026
+ Bejövő kiszolgálóbeállítások ellenőrzése\u2026
+ Kimenő kiszolgálóbeállítások ellenőrzése\u2026
Hitelesítés\u2026
Fiókbeállítások beolvasása\u2026
Megszakítás\u2026
Már majdnem kész.
- A fiók elnevezése (opcionális):
- A név megadása (kimenő üzeneteknél jelenik meg):
+ Fiók elnevezése (nem kötelező):
+ Név megadása (kimenő üzeneteknél jelenik meg):
Fióktípus
Milyen fajta fiók ez?
POP3
@@ -353,11 +353,11 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Csak feliratkozott mappák megjelenítése
Mappa automatikus kinyitása
OWA útvonal
- Választható
+ Nem kötelező
Hitelesítési útvonal
- Választható
+ Nem kötelező
Postafiók álnév
- Választható
+ Nem kötelező
Kimenő kiszolgáló beállításai
SMTP kiszolgáló
Port
@@ -391,7 +391,7 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
36 percenként
48 percenként
60 percenként
- Értesítsen, amikor levél érkezik
+ Értesítés, amikor levél érkezik
Értesítés levél ellenőrzéskor
Megjelenítendő üzenetek száma
10 üzenet
@@ -405,17 +405,17 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
5000 üzenet
10000 üzenet
összes üzenet
- Nem lehet másolni vagy áthelyezni a szerverrel nem szinkronizált üzenetet.
- A beállítást nem sikerült befejezni.
+ Nem lehet másolni vagy áthelyezni a kiszolgálóval nem szinkronizált üzenetet.
+ A beállítást nem sikerült befejezni
A felhasználónév vagy a jelszó hibás.\n(%s)
- A kiszolgáló érvénytelen SSL tanúsítványt mutatott be. Néha ez a kiszolgáló hibás beállításából ered. Néha azért, mert valaki személyes vagy a levelező kiszolgálót érintő támadást hajtott végre. Ha nem vagyunk biztos abban, hogy mi történt, akkor kattintsunk a Visszautasít gombra, és vegyük fel a kapcsolatot a levelező kiszolgáló üzemeltetőivel.\n\n(%s)
+ A kiszolgáló érvénytelen SSL-tanúsítványt mutatott be. Néha ez a kiszolgáló hibás beállításából ered. Néha azért, mert valaki támadást hajtott végre Ön vagy a levelezőkiszolgálója ellen. Ha nem biztos abban, hogy mi történt, akkor kattintson az Elutasítás gombra, és vegye fel a kapcsolatot a levelezőkiszolgáló üzemeltetőivel.\n\n(%s)
Nem lehet kapcsolódni a kiszolgálóhoz.\n(%s)
Részletek szerkesztése
- Tovább
+ Folytatás
Bővített
Fiók beállításai
Alapértelmezett fiók
- Levél küldése alapértelmezésben ebből a fiókból
+ Levél küldése alapértelmezetten ebből a fiókból
Új levél értesítések
Értesítések mappái
Összes
@@ -424,10 +424,10 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Összes, kivéve a 2. osztályú mappákat
Nincs
Szinkronizációs értesítések
- Saját email cím
+ Saját e-mail-cím
Értesítés az állapotsávon új levél érkezésekor
- Értesítés az állapotsávon a levél ellenőrzésekor
- Kimenő levél is
+ Értesítés az állapotsávon a levelek ellenőrzésekor
+ Kimenő leveleknél is
Értesítés megjelenítése az elküldött üzeneteknél
Csak partnerek
Értesítések megjelenítése csak az ismert partnerektől érkező üzeneteknél
@@ -435,7 +435,7 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Üzenet megjelölése olvasottként megtekintésre megnyitáskor
Megjelölés olvasottként törléskor
Üzenet megjelölése olvasottként törléskor
- Értesítés beállításai
+ Értesítési beállítások
A rendszer értesítési beállításainak megnyitása
Képek megjelenítése mindig
Nem
@@ -473,7 +473,7 @@ Hibajelentések beküldésével hozzájárulhatunk új funkciókhoz és kérdés
Kapcsolódva: %s
Beállítás…
Az összes vázlat tárolása titkosítottan
- Az összes vázlat titkosított tárolása
+ Az összes vázlat titkosítva lesz tárolva
A vázlatok titkosítása csak a titkosítás engedélyezésekor
Mappa lekérdezésének gyakorisága
Fiókszín
diff --git a/app/ui/legacy/src/main/res/values-sv/strings.xml b/app/ui/legacy/src/main/res/values-sv/strings.xml
index 9e4c33aff2..16bbece106 100644
--- a/app/ui/legacy/src/main/res/values-sv/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sv/strings.xml
@@ -33,7 +33,7 @@ K-9 Mail är en kraftfull fri e-postklient för Android.
Några av funktionerna som förbättrats är:
- - Push med IMAP IDLE
+ - Push-e-post med IMAP IDLE
- Bättre prestanda
- Meddelandelagring
- E-postsignaturer
@@ -70,7 +70,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Konton
Mappar
Avancerat
- Skriv
+ Skriva
Svara
Svara alla
Vidarebefordra
@@ -152,8 +152,8 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Anslutningsfel
Meddelandet hittades inte
Inläsningsfel av meddelande
- Läs in ytterligare upp
- till %d
+ Läs in ytterligare
+ upp till %d
%.1f GB
%.1f MB
%.1f kB
@@ -240,8 +240,8 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Det gick inte att hämta ytterligare meddelanderubriker från databas eller e-postserver.
Mer från denna avsändare
Från %s
- Felsök / Rensa meddelandets brödtext
- Meddelandet kasserat
+ Felsök / Rensa meddelandets text
+ Meddelandet kasserades
Meddelandet sparat som utkast
Visa stjärnor
Stjärnor indikerar flaggade meddelanden
@@ -255,25 +255,25 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Färglägg kontakter
Färglägg namn i kontaktlistan
Teckensnitt med fast bredd
- Använd ett teckensnitt med fast bredd när meddelanden med enbart text visas
+ Använd ett teckensnitt med fast bredd när meddelanden med enbart oformaterad text visas
Anpassa automatiskt meddelanden
Krymp meddelanden så att de får plats på skärmen
Återvänd till listan efter borttagning
Återvänd till meddelandelistan efter att meddelande tagits bort
- Visa nästa meddelande efter ta bort
- Visa nästa meddelande som standard efter att meddelande tagits bort
+ Visa nästa meddelande efter borttagning
+ Visa nästa meddelande som standard efter borttagning av meddelande
Bekräfta åtgärder
Visa en dialogruta när du genomför valda åtgärder
Ta bort
Ta bort stjärnmarkerade (i meddelandevyn)
- Skräp
+ Skräppost
Kassera meddelandet
Markera alla meddelanden som lästa
Ta bort (från avisering)
Dölj e-postklient
Ta bort K-9-användaragent från meddelanderubriker
Dölj tidszon
- Använd UTC istället för lokal tidszon i postrubriker och svarrubriker
+ Använd UTC istället för lokal tidszon i postrubriker och svarsrubrik
Dölj ämne i aviseringar
Aldrig
När enheten är låst
@@ -332,7 +332,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
STARTTLS
\"%1$s = %2$s\" är inte giltigt med \"%3$s = %4$s\"
När jag tar bort ett meddelande
- Ta inte bort på servern
+ Ta inte bort från servern
Ta bort från servern
Markera som läst på servern
Använd komprimering på nätverket:
@@ -341,7 +341,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Annat
Extern lagring (SD-kort)
Vanlig intern lagring
- Ta bort meddelanden som tas bort på servern
+ Ta bort borttagna meddelanden från servern
Direkt
Vid e-postkontroll
Manuellt
@@ -351,7 +351,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Namn på skickatmapp
Papperskorgsmapp
Namn på arkivmapp
- Namn på skräpmapp
+ Skräppostmapp
Visa endast prenumererade mappar
Expandera automatiskt mappen
Sökväg för Outlook Web App
@@ -444,14 +444,14 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Från kontakter
Från alla
Skickar e-post
- Citera meddelandet när du svarar
+ Citera meddelande när du svarar
Inkludera orginalmeddelandet i ditt svar.
- Skriv svar efter citerad text
+ Skriv svar efter citerat meddelande
Originalmeddelandet kommer att visas ovanför ditt svar.
Avlägsna signaturer vid svar
Signaturer kommer att tas bort från citerade meddelanden
Meddelandeformat
- Endast text (bilder och formatering tas bort)
+ Oformaterad text (ta bort bilder och formatering)
HTML (bilder och formatering behålls)
Automatiskt
Visa alltid kopia/blindkopia
@@ -535,7 +535,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Endast 1:a klassens mappar
1:a och 2:a klassens mappar
Alla utom 2:a klassens mappar
- Synkronisera fjärradering
+ Synkronisera fjärrborttagning
Ta bort meddelanden när de tas bort från servern
Saknade OpenPGP-app - har den avinstallerats?
Mappinställningar
@@ -597,13 +597,13 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Flytta ner
Flytta längst upp / gör till standard
Ta bort
- Beskrivning av identitet
+ Identitetsbeskrivning
(valfritt)
Ditt namn
(valfritt)
E-postadress
(krävs)
- Svarsadress (reply-to)
+ Svarsadress
(valfritt)
Signatur
(valfritt)
@@ -626,7 +626,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Lästa meddelanden överst
Meddelanden med bilagor överst
Meddelanden utan bilagor överst
- Sortera på…
+ Sortera efter…
Datum
Mottaget
Ämne
@@ -647,9 +647,9 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
1:a och 2:a klassens mappar
Dölj 2:a klassens mappar
Placering av signatur
- Före citerad text
- Efter citerad text
- Använd appens tema
+ Före citerat meddelande
+ Efter citerat meddelande
+ Använd apptema
Mörkt
Ljust
Använd systemstandard
@@ -760,14 +760,14 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Nej
Bekräfta markera alla som lästa
Vill du markera alla meddelanden som lästa?
- Bekräfta töm papperskorgen
+ Bekräfta tömning av papperskorgen
Vill du tömma papperskorgen?
Ja
Nej
- Bekräfta flytt till skräpmapp
+ Bekräfta flytt till skräppostmapp
- - Vill du verkligen flytta detta meddelande till skräpmappen?
- - Vill du verkligen flytta %1$d meddelanden till skräpmappen?
+ - Vill du verkligen flytta detta meddelande till skräppostmappen?
+ - Vill du verkligen flytta %1$d meddelanden till skräppostmappen?
Ja
Nej
@@ -908,8 +908,8 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Mobil
Ingen Utkast mapp konfigurerad för detta konto!
Ingen nyckel konfigurerad för detta konto! Kontrollera dina inställningar.
- Crypto-leverantören använder inkompatibel version. Kontrollera dina inställningar!
- Kan inte ansluta till crypto leverantör, granska dina inställningar eller klicka på crypto ikonen för nytt försök.
+ Kryptoleverantören använder inkompatibel version. Kontrollera dina inställningar!
+ Kan inte ansluta till kryptoleverantör, granska dina inställningar eller klicka på kryptoikonen för nytt försök.
Det gick inte att initiera ände-till-ände-kryptering, vänligen kontrollera dina inställningar
PGP/INLINE läge stöder inte bilagor!
Aktivera PGP/INLINE
@@ -933,7 +933,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Signaturer kan brytas när de skickas till e-postlistor.
Signaturer kan visas som \"signature.asc\" bilagor i vissa klienter.
Krypterade meddelanden inkluderar alltid en signatur.
- Oformatterad text
+ Oformaterad text
ände-till-ände-signatur innehöll ett fel
måste hämta meddelandet fullständigt för att behandla signaturen
innehåller icke-stödd ände-till-ände-signatur
@@ -950,7 +950,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Krypterad
men det fanns ett dekrypteringsfel
måste hämta meddelandet fullständigt för dekryptering
- men ingen crypto app är konfigurerad
+ men ingen kryptoapp är konfigurerad
Krypterad
men inte ände-till-ände
Ände-till-ände krypterad
@@ -1055,7 +1055,7 @@ Du kan behålla detta meddelande och använda det som en säkerhetskopia för di
Sover tills nätverket är tillgängligt
Tryck för att lära dig mer.
Push-info
- När du använder Push upprätthåller K-9 Mail en anslutning till e-postservern. Android kräver att ett pågående meddelande visas medan appen är aktiv i bakgrunden. %s
+ Vid användning av Push upprätthåller K-9 Mail en anslutning till e-postservern. Android kräver att ett pågående meddelande visas medan appen är aktiv i bakgrunden. %s
Men Android låter dig också dölja aviseringen.
Lär dig mer
Anpassa avisering
diff --git a/app/ui/legacy/src/main/res/values-uk/strings.xml b/app/ui/legacy/src/main/res/values-uk/strings.xml
index 6d6806ae73..acfba8ba78 100644
--- a/app/ui/legacy/src/main/res/values-uk/strings.xml
+++ b/app/ui/legacy/src/main/res/values-uk/strings.xml
@@ -7,10 +7,11 @@
Облікові записи K-9 Mail
K-9 Непрочитані
- Дресирувальники K-9
+ The K-9 Dog Walkers
Авторське право 2008-%s The K-9 Dog Walkers. Часткові авторські права 2006-%s the Android Open Source Project.
Програмний код
Ліцензія Apache версії 2.0
+ Проект з відкритим кодом
Сайт
Форум
Соцмережі
@@ -18,6 +19,11 @@
Бібліотеки
Ліцензія
Журнал змін
+ Не вдалося завантажити список змін.
+ Версія %s
+ Що нового
+ Показувати останні зміни при оновленні додатка
+ Дізнатися, що нового у цьому релізі
Ласкаво просимо до K-9 Mail
Спам
Переслати
Переслати як вкладення
+ Редагувати як нове повідомлення
Перемістити
+ Перемістити в Чернетки
Надіслати...
Перемістити…
Готово
@@ -109,6 +117,7 @@ K-9 Mail — це вільний клієнт електронної пошти
Додати обліковий запис
Написати новий лист
Пошук
+ Шукати всюди
Результати пошуку
Налаштування
Керування теками
@@ -127,6 +136,7 @@ K-9 Mail — це вільний клієнт електронної пошти
- Адреси скопійовано до комірки обміну
- Адреси скопійовано до комірки обміну
+ Текст теми скопійовано в буфер обміну
Перемкнути на темну тему
Перемкнути на світлу тему
Позначити непрочитаним
@@ -179,6 +189,8 @@ K-9 Mail — це вільний клієнт електронної пошти
Надсилання пошти: %s
Надсилання пошти
:
+ Синхронізувати (пуш)
+ Відображається під час очікування нових повідомлень
Повідомлення
Сповіщення, пов\'язані з повідомленнями
Різне
@@ -215,6 +227,7 @@ K-9 Mail — це вільний клієнт електронної пошти
Включити цитоване повідомлення
Видалити цитований текст
Редагувати цитований текст
+ Видалити вкладення
Від: %s <%s>
Кому:
Копія:
@@ -477,6 +490,20 @@ K-9 Mail — це вільний клієнт електронної пошти
Колір блимання LED-індикатору вашого телефону для цього облікового запису
Розмір локальної теки
Отримувати повідомлення розміром до
+ 1 КБ
+ 2 КБ
+ 4 КБ
+ 8 КБ
+ 16 КБ
+ 32 КБ
+ 64 КБ
+ 128 КБ
+ 256 КБ
+ 512 КБ
+ 1 МБ
+ 2 МБ
+ 5 МБ
+ 10 МБ
будь-якого розміру (без обмежень)
Синхронізувати повідомлення за
увесь час (без обмежень)
@@ -532,6 +559,7 @@ K-9 Mail — це вільний клієнт електронної пошти
Без класу
1-ий клас
2-ий клас
+ Такий як і клас розкладу (poll)
Клас сповіщення теки
Без класу
1-й клас
@@ -667,6 +695,7 @@ K-9 Mail — це вільний клієнт електронної пошти
Навігація кнопками зміни гучності
при перегляді повідомлень
у списках
+ Показувати Об\'єднані Вхідні
%s %s
- Непрочитані
Всі повідомлення
@@ -719,9 +748,13 @@ K-9 Mail — це вільний клієнт електронної пошти
Помилка відправки: %s
Зберегти чернетку повідомлення?
Зберегти чи Скасувати це повідомлення?
+ Зберегти чи Скасувати зміни?
Скасувати повідомлення?
Ви дійсно хочете скасувати це повідомлення?
Виберіть текст для копіювання.
+ Очистити локальні повідомлення?
+ Це видалить всі локальні повідомлення з теки. Жодне повідомлення не буде видалене з сервера.
+ Очистити повідомлення
Підтвердіть видалення
Ви хочете видалити це повідомлення?
@@ -800,6 +833,8 @@ K-9 Mail — це вільний клієнт електронної пошти
Надіслати посилання
Копіювати посилання до буфера обміну
Посилання
+ Скопіювати текст посилання у буфер обміну
+ Текст посилання
Зображення
Переглянути зображеня
Зберегти зображення
@@ -880,6 +915,8 @@ K-9 Mail — це вільний клієнт електронної пошти
Прихована копія
До
Від
+ <Невідомий Адресат>
+ <Невідомий Відправник>
Домашній
Робочий
Інший
@@ -1026,4 +1063,17 @@ K-9 Mail — це вільний клієнт електронної пошти
Дозволити доступ до контактів
Цей додаток потребує доступу до ваших контактів, щоб мати можливість відображати імена і фотографії контактів та відображати пропозиції під час їх введення.
+ Сталася помилка при завантаженні даних
+ Ініціалізація...
+ Очікування нових листів
+ Очікування дозволу на фонову синхронізацію
+ Очікування наявності мережі
+ Натисніть, щоб дізнатися більше.
+ Інформація про сповіщення
+ Під час використання пуш-сповіщень, K-9 Mail використовує з\'єднання з поштовим сервером. Android\'у необхідно відображати сповіщення безперервно доки програма працює на фоні. %s
+ Тим не менш, Android також дозволяє приховати сповіщення.
+ Дізнатися більше
+ Налаштувати сповіщення
+ Якщо вам не потрібне миттєве сповіщення про нові повідомлення, вам варто вимкнути Push і використовувати Polling. Polling перевіряє пошту з регулярними інтервалами і не потребує сповіщення.
+ Вимкнути пуш-сповіщення
--
GitLab
From 199db3141e794deefceb41d35bf564b38a0e6878 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 30 Jul 2021 19:18:17 +0200
Subject: [PATCH 011/285] Version 5.801
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 9 +++++++++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index 184f68367f..c1f17854f4 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28000
- versionName '5.801-SNAPSHOT'
+ versionCode 28001
+ versionName '5.801'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index fc5d36e872..7b5f3b4b7d 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,15 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Tweaked the default font sizes
+ The name of the currently selected account is displayed in the top bar below the folder name (when using multiple accounts)
+ When selecting an account in the drawer the auto-expand folder is now displayed right away
+ Added support for user-installed CAs
+ Error notifications now contain the full error text
+ Fixed some crashes
+ Updated translations
+
Major redesign of the user interface
Changed periodic background sync and push implementations to work much more reliably
--
GitLab
From 58a7b362ae0818bd949810b3369358e02cc6cb5c Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 30 Jul 2021 19:49:32 +0200
Subject: [PATCH 012/285] Prepare for version 5.802
---
app/k9mail/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index c1f17854f4..c75187a1c5 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -47,7 +47,7 @@ android {
testApplicationId "com.fsck.k9.tests"
versionCode 28001
- versionName '5.801'
+ versionName '5.802-SNAPSHOT'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
--
GitLab
From efaea0ae1b4c6e3f61fa1fc6c4a2f0a071c8612d Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 31 Jul 2021 17:47:55 +0200
Subject: [PATCH 013/285] Support archive/spam action in message lists with
multiple accounts
When the account of at least one selected message has a designated archive/spam folder we now display the archive/spam actions. The messages that can't be moved because their account doesn't have an archive/spam folder will simply remain where they are.
---
.../fsck/k9/fragment/MessageListFragment.kt | 42 ++++++++++++-------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 1d56e9efb7..22e1806707 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -820,7 +820,7 @@ class MessageListFragment :
}
computeBatchDirection()
- updateActionModeTitle()
+ updateActionMode()
computeSelectAllVisibility()
} else {
this.selected.clear()
@@ -875,7 +875,7 @@ class MessageListFragment :
}
computeBatchDirection()
- updateActionModeTitle()
+ updateActionMode()
computeSelectAllVisibility()
adapter.notifyDataSetChanged()
@@ -889,8 +889,10 @@ class MessageListFragment :
setFlag(item, Flag.FLAGGED, !item.isStarred)
}
- private fun updateActionModeTitle() {
- actionMode!!.title = getString(R.string.actionbar_selected, selectedCount)
+ private fun updateActionMode() {
+ val actionMode = actionMode ?: error("actionMode == null")
+ actionMode.title = getString(R.string.actionbar_selected, selectedCount)
+ actionMode.invalidate()
}
private fun computeSelectAllVisibility() {
@@ -1477,7 +1479,7 @@ class MessageListFragment :
}
recalculateSelectionCount()
- updateActionModeTitle()
+ updateActionMode()
}
private fun startAndPrepareActionMode() {
@@ -1715,15 +1717,19 @@ class MessageListFragment :
// we don't support cross account actions atm
if (!isSingleAccountMode) {
- // show all
+ val accounts = accountUuidsForSelected.mapNotNull { accountUuid ->
+ preferences.getAccount(accountUuid)
+ }
+
menu.findItem(R.id.move).isVisible = true
- menu.findItem(R.id.archive).isVisible = true
- menu.findItem(R.id.spam).isVisible = true
menu.findItem(R.id.copy).isVisible = true
- for (accountUuid in accountUuidsForSelected) {
- val account = preferences.getAccount(accountUuid)
- account?.let { setContextCapabilities(it, menu) }
+ // Disable archive/spam options here and maybe enable below when checking account capabilities
+ menu.findItem(R.id.archive).isVisible = false
+ menu.findItem(R.id.spam).isVisible = false
+
+ for (account in accounts) {
+ setContextCapabilities(account, menu)
}
}
@@ -1762,10 +1768,13 @@ class MessageListFragment :
menu.findItem(R.id.move).isVisible = false
menu.findItem(R.id.copy).isVisible = false
- // TODO: we could support the archive and spam operations if all selected messages
- // belong to non-POP3 accounts
- menu.findItem(R.id.archive).isVisible = false
- menu.findItem(R.id.spam).isVisible = false
+ if (account?.hasArchiveFolder() == true) {
+ menu.findItem(R.id.archive).isVisible = true
+ }
+
+ if (account?.hasSpamFolder() == true) {
+ menu.findItem(R.id.spam).isVisible = true
+ }
} else {
// hide unsupported
if (!messagingController.isCopyCapable(account)) {
@@ -1841,12 +1850,13 @@ class MessageListFragment :
R.id.unflag -> setFlagForSelected(Flag.FLAGGED, false)
R.id.select_all -> selectAll()
R.id.archive -> {
- // only if the account supports this
onArchive(checkedMessages)
+ // TODO: Only finish action mode if all messages have been moved.
selectedCount = 0
}
R.id.spam -> {
onSpam(checkedMessages)
+ // TODO: Only finish action mode if all messages have been moved.
selectedCount = 0
}
R.id.move -> {
--
GitLab
From 2ef430565d9b1bc11531f230752743abad0bb5ce Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 31 Jul 2021 20:02:18 +0200
Subject: [PATCH 014/285] Make sure "stacked notifications" are silent
---
.../main/java/com/fsck/k9/notification/WearNotifications.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java
index 8eba134d5e..bfcd81e002 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java
+++ b/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java
@@ -26,6 +26,7 @@ class WearNotifications extends BaseNotifications {
int notificationId = holder.notificationId;
NotificationContent content = holder.content;
NotificationCompat.Builder builder = createBigTextStyleNotification(account, holder, notificationId);
+ builder.setNotificationSilent();
PendingIntent deletePendingIntent = actionCreator.createDismissMessagePendingIntent(
context, content.messageReference, holder.notificationId);
--
GitLab
From 529a6c0aadbad90312fda2f4aa3b6a09dc178aa5 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 31 Jul 2021 20:02:59 +0200
Subject: [PATCH 015/285] Make sure summary notification is silent during quiet
time
---
.../src/main/java/com/fsck/k9/notification/NotificationHelper.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
index 606edc184e..7d0e6cce61 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
@@ -23,6 +23,7 @@ class NotificationHelper(
) {
if (K9.isQuietTime) {
+ builder.setNotificationSilent()
return
}
--
GitLab
From d461dece6764de273c62bdb68e43d2bd9ab1d32f Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 31 Jul 2021 20:36:01 +0200
Subject: [PATCH 016/285] Fix sound/vibration for the summary notification
---
.../main/java/com/fsck/k9/notification/NotificationHelper.kt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
index 7d0e6cce61..62d693c338 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationHelper.kt
@@ -35,6 +35,8 @@ class NotificationHelper(
if (vibrationPattern != null) {
builder.setVibrate(vibrationPattern)
}
+ } else {
+ builder.setNotificationSilent()
}
if (ledColor != null) {
--
GitLab
From 49600c470cc7ee36f512dd9ee30f335b43fc7524 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 31 Jul 2021 20:38:50 +0200
Subject: [PATCH 017/285] Reset "ring notified" flag when syncing a folder
after a Push event
Without this (but with the new silent fixes) new messages downloaded after a Push event would only create silent notifications.
---
.../main/java/com/fsck/k9/controller/MessagingController.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 184f19ae32..d84f5ec96b 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -598,6 +598,8 @@ public class MessagingController {
public void synchronizeMailboxBlocking(Account account, String folderServerId) throws MessagingException {
long folderId = getFolderId(account, folderServerId);
+ account.setRingNotified(false);
+
final CountDownLatch latch = new CountDownLatch(1);
putBackground("synchronizeMailbox", null, () -> {
try {
--
GitLab
From a44aedb4a817963d8e1a53c393225f2d69330709 Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 2 Aug 2021 14:52:13 +0200
Subject: [PATCH 018/285] Refactor code to configure the message list action
mode menu
---
.../fsck/k9/fragment/MessageListFragment.kt | 71 ++++++++++---------
1 file changed, 36 insertions(+), 35 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 22e1806707..823e831372 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -1364,16 +1364,22 @@ class MessageListFragment :
}
val isOutbox: Boolean
- get() {
- val currentFolder = currentFolder ?: return false
- return currentFolder.databaseId == account!!.outboxFolderId
- }
+ get() = isSpecialFolder(account?.outboxFolderId)
private val isInbox: Boolean
- get() {
- val currentFolder = currentFolder ?: return false
- return currentFolder.databaseId == account!!.inboxFolderId
- }
+ get() = isSpecialFolder(account?.inboxFolderId)
+
+ private val isArchiveFolder: Boolean
+ get() = isSpecialFolder(account?.archiveFolderId)
+
+ private val isSpamFolder: Boolean
+ get() = isSpecialFolder(account?.spamFolderId)
+
+ private fun isSpecialFolder(specialFolderId: Long?): Boolean {
+ val folderId = specialFolderId ?: return false
+ val currentFolder = currentFolder ?: return false
+ return currentFolder.databaseId == folderId
+ }
val isRemoteFolder: Boolean
get() {
@@ -1775,8 +1781,23 @@ class MessageListFragment :
if (account?.hasSpamFolder() == true) {
menu.findItem(R.id.spam).isVisible = true
}
+ } else if (isOutbox) {
+ menu.findItem(R.id.mark_as_read).isVisible = false
+ menu.findItem(R.id.mark_as_unread).isVisible = false
+ menu.findItem(R.id.archive).isVisible = false
+ menu.findItem(R.id.copy).isVisible = false
+ menu.findItem(R.id.flag).isVisible = false
+ menu.findItem(R.id.unflag).isVisible = false
+ menu.findItem(R.id.spam).isVisible = false
+ menu.findItem(R.id.move).isVisible = false
+
+ disableMarkAsRead = true
+ disableFlag = true
+
+ if (account.hasDraftsFolder()) {
+ menu.findItem(R.id.move_to_drafts).isVisible = true
+ }
} else {
- // hide unsupported
if (!messagingController.isCopyCapable(account)) {
menu.findItem(R.id.copy).isVisible = false
}
@@ -1785,33 +1806,13 @@ class MessageListFragment :
menu.findItem(R.id.move).isVisible = false
menu.findItem(R.id.archive).isVisible = false
menu.findItem(R.id.spam).isVisible = false
- }
-
- val hideArchiveAction = isSingleFolderMode && currentFolder!!.databaseId == account.archiveFolderId
- if (hideArchiveAction) {
- menu.findItem(R.id.archive).isVisible = false
- }
-
- val hideSpamAction = isSingleFolderMode && currentFolder!!.databaseId == account.spamFolderId
- if (hideSpamAction) {
- menu.findItem(R.id.spam).isVisible = false
- }
-
- if (isOutbox) {
- menu.findItem(R.id.mark_as_read).isVisible = false
- menu.findItem(R.id.mark_as_unread).isVisible = false
- menu.findItem(R.id.archive).isVisible = false
- menu.findItem(R.id.copy).isVisible = false
- menu.findItem(R.id.flag).isVisible = false
- menu.findItem(R.id.unflag).isVisible = false
- menu.findItem(R.id.spam).isVisible = false
- menu.findItem(R.id.move).isVisible = false
-
- disableMarkAsRead = true
- disableFlag = true
+ } else {
+ if (isArchiveFolder) {
+ menu.findItem(R.id.archive).isVisible = false
+ }
- if (account.hasDraftsFolder()) {
- menu.findItem(R.id.move_to_drafts).isVisible = true
+ if (isSpamFolder) {
+ menu.findItem(R.id.spam).isVisible = false
}
}
}
--
GitLab
From 0742528398a1c8349440f72fc09d871ad745ab9d Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 2 Aug 2021 14:53:05 +0200
Subject: [PATCH 019/285] Don't show archive/spam action when no such folder is
configured
---
.../src/main/java/com/fsck/k9/fragment/MessageListFragment.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 823e831372..0eb6b8d0ba 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -1807,11 +1807,11 @@ class MessageListFragment :
menu.findItem(R.id.archive).isVisible = false
menu.findItem(R.id.spam).isVisible = false
} else {
- if (isArchiveFolder) {
+ if (!account.hasArchiveFolder() || isArchiveFolder) {
menu.findItem(R.id.archive).isVisible = false
}
- if (isSpamFolder) {
+ if (!account.hasSpamFolder() || isSpamFolder) {
menu.findItem(R.id.spam).isVisible = false
}
}
--
GitLab
From e9c45b4aa8f19da6cc29c9008359a07e2ba218f8 Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 2 Aug 2021 15:49:35 +0200
Subject: [PATCH 020/285] Disable Push if not supported by the server
---
.../k9/controller/push/AccountPushController.kt | 13 +++++++++++++
.../push/AccountPushControllerFactory.kt | 12 ++++++++++--
.../com/fsck/k9/controller/push/KoinModule.kt | 3 ++-
.../k9/backend/api/BackendPusherCallback.kt | 1 +
.../fsck/k9/backend/imap/ImapBackendPusher.kt | 4 ++++
.../fsck/k9/backend/imap/ImapFolderPusher.kt | 17 +++++++++++++----
.../fsck/k9/backend/imap/ImapPusherCallback.kt | 1 +
7 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
index a3df472caf..8627700844 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
@@ -1,6 +1,8 @@
package com.fsck.k9.controller.push
import com.fsck.k9.Account
+import com.fsck.k9.Account.FolderMode
+import com.fsck.k9.Preferences
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.backend.api.BackendPusher
import com.fsck.k9.backend.api.BackendPusherCallback
@@ -17,6 +19,7 @@ import timber.log.Timber
internal class AccountPushController(
private val backendManager: BackendManager,
private val messagingController: MessagingController,
+ private val preferences: Preferences,
folderRepositoryManager: FolderRepositoryManager,
backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO,
private val account: Account
@@ -35,6 +38,11 @@ internal class AccountPushController(
override fun onPushError(exception: Exception) {
messagingController.handleException(account, exception)
}
+
+ override fun onPushNotSupported() {
+ Timber.v("AccountPushController(%s) - Push not supported. Disabling Push for account.", account.uuid)
+ disablePush()
+ }
}
fun start() {
@@ -88,4 +96,9 @@ internal class AccountPushController(
private fun syncFolders(folderServerId: String) {
messagingController.synchronizeMailboxBlocking(account, folderServerId)
}
+
+ private fun disablePush() {
+ account.folderPushMode = FolderMode.NONE
+ preferences.saveAccount(account)
+ }
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
index 9a083a45e8..89ae3bef1b 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
@@ -1,6 +1,7 @@
package com.fsck.k9.controller.push
import com.fsck.k9.Account
+import com.fsck.k9.Preferences
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.mailstore.FolderRepositoryManager
@@ -8,9 +9,16 @@ import com.fsck.k9.mailstore.FolderRepositoryManager
internal class AccountPushControllerFactory(
private val backendManager: BackendManager,
private val messagingController: MessagingController,
- private val folderRepositoryManager: FolderRepositoryManager
+ private val folderRepositoryManager: FolderRepositoryManager,
+ private val preferences: Preferences
) {
fun create(account: Account): AccountPushController {
- return AccountPushController(backendManager, messagingController, folderRepositoryManager, account = account)
+ return AccountPushController(
+ backendManager,
+ messagingController,
+ preferences,
+ folderRepositoryManager,
+ account = account
+ )
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
index 146eec236a..7a7a6441c9 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
@@ -10,7 +10,8 @@ internal val controllerPushModule = module {
AccountPushControllerFactory(
backendManager = get(),
messagingController = get(),
- folderRepositoryManager = get()
+ folderRepositoryManager = get(),
+ preferences = get()
)
}
single {
diff --git a/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt b/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
index bf159bf9dc..d503bb7018 100644
--- a/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
+++ b/backend/api/src/main/java/com/fsck/k9/backend/api/BackendPusherCallback.kt
@@ -3,4 +3,5 @@ package com.fsck.k9.backend.api
interface BackendPusherCallback {
fun onPushEvent(folderServerId: String)
fun onPushError(exception: Exception)
+ fun onPushNotSupported()
}
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
index 76e1650d0b..96c68da54e 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackendPusher.kt
@@ -226,6 +226,10 @@ internal class ImapBackendPusher(
}
}
+ override fun onPushNotSupported() {
+ callback.onPushNotSupported()
+ }
+
private fun startRetryTimer(folderServerId: String, timeout: Long) {
Timber.v("ImapBackendPusher for folder %s sleeping for %d ms", folderServerId, timeout)
pushFolderSleeping[folderServerId] = idleRefreshManager.startTimer(timeout, ::restartFolderPushers)
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
index be83bb60a4..f9c4c4516b 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapFolderPusher.kt
@@ -70,10 +70,19 @@ class ImapFolderPusher(
try {
while (!stopPushing) {
- val idleResult = folderIdler.idle()
-
- if (idleResult == IdleResult.SYNC) {
- callback.onPushEvent(folderServerId)
+ when (folderIdler.idle()) {
+ IdleResult.SYNC -> {
+ callback.onPushEvent(folderServerId)
+ }
+ IdleResult.STOPPED -> {
+ // ImapFolderIdler only stops when we ask it to.
+ // But it can't hurt to make extra sure we exit the loop.
+ stopPushing = true
+ }
+ IdleResult.NOT_SUPPORTED -> {
+ stopPushing = true
+ callback.onPushNotSupported()
+ }
}
}
} catch (e: Exception) {
diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
index ebbc084d88..642668e62c 100644
--- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
+++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapPusherCallback.kt
@@ -3,4 +3,5 @@ package com.fsck.k9.backend.imap
interface ImapPusherCallback {
fun onPushEvent(folderServerId: String)
fun onPushError(folderServerId: String, exception: Exception)
+ fun onPushNotSupported()
}
--
GitLab
From 5b0f8031128b0d3eacd58ca1d5d51c679e373164 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 3 Aug 2021 19:40:45 +0200
Subject: [PATCH 021/285] Use yellow for message star
---
app/ui/legacy/src/main/res/drawable/ic_star.xml | 2 +-
app/ui/legacy/src/main/res/values/attrs.xml | 1 +
app/ui/legacy/src/main/res/values/themes.xml | 2 ++
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/app/ui/legacy/src/main/res/drawable/ic_star.xml b/app/ui/legacy/src/main/res/drawable/ic_star.xml
index 633516533f..9b3f2e1ae4 100644
--- a/app/ui/legacy/src/main/res/drawable/ic_star.xml
+++ b/app/ui/legacy/src/main/res/drawable/ic_star.xml
@@ -1,7 +1,7 @@
+
diff --git a/app/ui/legacy/src/main/res/values/themes.xml b/app/ui/legacy/src/main/res/values/themes.xml
index 4d8dff3ded..3966d727a5 100644
--- a/app/ui/legacy/src/main/res/values/themes.xml
+++ b/app/ui/legacy/src/main/res/values/themes.xml
@@ -92,6 +92,7 @@
- @drawable/ic_messagelist_forwarded
- @drawable/ic_messagelist_answered_forwarded
- @drawable/btn_check_star
+ - #fbbc04
- #ffffffff
- @drawable/ic_person_plus
- #e8e8e8
@@ -209,6 +210,7 @@
- @drawable/ic_messagelist_forwarded
- @drawable/ic_messagelist_answered_forwarded
- @drawable/btn_check_star
+ - #fdd663
- #000000
- @drawable/ic_person_plus
- #313131
--
GitLab
From 2328abd3a19df7e6a3ea92a60914b8f46ce17937 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 3 Aug 2021 22:09:17 +0200
Subject: [PATCH 022/285] Don't use Glide when the Activity is marked as
destroyed
---
.../java/com/fsck/k9/ui/messageview/AttachmentView.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java
index 0214959380..b43e7a5cac 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/AttachmentView.java
@@ -1,6 +1,7 @@
package com.fsck.k9.ui.messageview;
+import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
@@ -120,8 +121,14 @@ public class AttachmentView extends FrameLayout implements OnClickListener {
}
public void refreshThumbnail() {
+ Context context = getContext();
+ if (context instanceof Activity && ((Activity) context).isDestroyed()) {
+ // Do nothing because Glide would throw an exception
+ return;
+ }
+
preview.setVisibility(View.VISIBLE);
- Glide.with(getContext())
+ Glide.with(context)
.load(attachment.internalUri)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.NONE)
--
GitLab
From 0e54bd2bc527801452af270e534dedbfb99a6148 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 3 Aug 2021 19:02:02 +0200
Subject: [PATCH 023/285] Fold identity header value so we're not generating
invalid messages
---
.../k9/message/IdentityHeaderBuilder.java | 34 ++++++++++-
.../fsck/k9/message/IdentityHeaderParser.java | 14 +++--
.../k9/message/IdentityHeaderBuilderTest.kt | 56 +++++++++++++++++++
.../k9/message/IdentityHeaderParserTest.kt | 33 +++++++++++
4 files changed, 130 insertions(+), 7 deletions(-)
create mode 100644 app/core/src/test/java/com/fsck/k9/message/IdentityHeaderBuilderTest.kt
create mode 100644 app/core/src/test/java/com/fsck/k9/message/IdentityHeaderParserTest.kt
diff --git a/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderBuilder.java b/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderBuilder.java
index 51eca9da5b..cb6c2c2344 100644
--- a/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderBuilder.java
+++ b/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderBuilder.java
@@ -3,16 +3,20 @@ package com.fsck.k9.message;
import android.net.Uri;
import android.net.Uri.Builder;
-import timber.log.Timber;
import com.fsck.k9.Account.QuoteStyle;
import com.fsck.k9.Identity;
+import com.fsck.k9.K9;
import com.fsck.k9.controller.MessageReference;
import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.message.quote.InsertableHtmlContent;
+import timber.log.Timber;
public class IdentityHeaderBuilder {
+ private static final int MAX_LINE_LENGTH = 72;
+ private static final int FIRST_LINE_EXTRA_LENGTH = K9.IDENTITY_HEADER.length() + 2;
+
private InsertableHtmlContent quotedHtmlContent;
private QuoteStyle quoteStyle;
private SimpleMessageFormat messageFormat;
@@ -95,9 +99,33 @@ public class IdentityHeaderBuilder {
appendValue(IdentityField.QUOTED_TEXT_MODE, quotedTextMode);
String k9identity = IdentityField.IDENTITY_VERSION_1 + uri.build().getEncodedQuery();
+ String headerValue = foldHeaderValue(k9identity);
+
+ Timber.d("Generated identity: %s", headerValue);
+ return headerValue;
+ }
+
+ private String foldHeaderValue(String input) {
+ int inputLength = input.length();
+ int endOfFirstLine = MAX_LINE_LENGTH - FIRST_LINE_EXTRA_LENGTH;
+ if (inputLength <= endOfFirstLine) {
+ return input;
+ }
+
+ int extraLines = (inputLength - endOfFirstLine - 1) / (MAX_LINE_LENGTH - 1) + 1;
+ int builderSize = inputLength + extraLines * 3 /* CR LF SPACE */;
+ StringBuilder headerValue = new StringBuilder(builderSize);
+
+ headerValue.append(input, 0, endOfFirstLine);
+ int start = endOfFirstLine;
+ while (start < inputLength) {
+ headerValue.append("\r\n ");
+ int end = start + Math.min(MAX_LINE_LENGTH - 1, inputLength - start);
+ headerValue.append(input, start, end);
+ start = end;
+ }
- Timber.d("Generated identity: %s", k9identity);
- return k9identity;
+ return headerValue.toString();
}
private void appendValue(IdentityField field, int value) {
diff --git a/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderParser.java b/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderParser.java
index e73cea944d..14b97add02 100644
--- a/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderParser.java
+++ b/app/core/src/main/java/com/fsck/k9/message/IdentityHeaderParser.java
@@ -29,10 +29,12 @@ public class IdentityHeaderParser {
return identity;
}
+ String encodedString = unfoldHeaderValue(identityString);
+
// Check to see if this is a "next gen" identity.
- if (identityString.charAt(0) == IdentityField.IDENTITY_VERSION_1.charAt(0) && identityString.length() > 2) {
+ if (encodedString.charAt(0) == IdentityField.IDENTITY_VERSION_1.charAt(0) && encodedString.length() > 2) {
Uri.Builder builder = new Uri.Builder();
- builder.encodedQuery(identityString.substring(1)); // Need to cut off the ! at the beginning.
+ builder.encodedQuery(encodedString.substring(1)); // Need to cut off the ! at the beginning.
Uri uri = builder.build();
for (IdentityField key : IdentityField.values()) {
String value = uri.getQueryParameter(key.value());
@@ -56,9 +58,9 @@ public class IdentityHeaderParser {
} else {
// Legacy identity
- Timber.d("Got a saved legacy identity: %s", identityString);
+ Timber.d("Got a saved legacy identity: %s", encodedString);
- StringTokenizer tokenizer = new StringTokenizer(identityString, ":", false);
+ StringTokenizer tokenizer = new StringTokenizer(encodedString, ":", false);
// First item is the body length. We use this to separate the composed reply from the quoted text.
if (tokenizer.hasMoreTokens()) {
@@ -85,4 +87,8 @@ public class IdentityHeaderParser {
return identity;
}
+
+ private static String unfoldHeaderValue(String identityString) {
+ return identityString.replaceAll("\r?\n ", "");
+ }
}
diff --git a/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderBuilderTest.kt b/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderBuilderTest.kt
new file mode 100644
index 0000000000..2be6075663
--- /dev/null
+++ b/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderBuilderTest.kt
@@ -0,0 +1,56 @@
+package com.fsck.k9.message
+
+import com.fsck.k9.Account.QuoteStyle
+import com.fsck.k9.Identity
+import com.fsck.k9.RobolectricTest
+import com.fsck.k9.mail.internet.MimeHeaderChecker
+import com.fsck.k9.mail.internet.TextBody
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+private const val IDENTITY_HEADER = "X-K9mail-Identity"
+
+class IdentityHeaderBuilderTest : RobolectricTest() {
+ @Test
+ fun `valid unstructured header field value`() {
+ val signature = "a".repeat(1000)
+
+ val identityHeader = IdentityHeaderBuilder()
+ .setCursorPosition(0)
+ .setIdentity(createIdentity(signatureUse = true))
+ .setIdentityChanged(false)
+ .setMessageFormat(SimpleMessageFormat.TEXT)
+ .setMessageReference(null)
+ .setQuotedHtmlContent(null)
+ .setQuoteStyle(QuoteStyle.PREFIX)
+ .setQuoteTextMode(QuotedTextMode.NONE)
+ .setSignature(signature)
+ .setSignatureChanged(true)
+ .setBody(TextBody("irrelevant"))
+ .setBodyPlain(null)
+ .build()
+
+ assertThat(identityHeader.length).isGreaterThan(1000)
+ assertIsValidHeader(identityHeader)
+ }
+
+ private fun assertIsValidHeader(identityHeader: String) {
+ try {
+ MimeHeaderChecker.checkHeader(IDENTITY_HEADER, identityHeader)
+ } catch (e: Exception) {
+ println("$IDENTITY_HEADER: $identityHeader")
+ throw e
+ }
+ }
+
+ private fun createIdentity(
+ description: String? = null,
+ name: String? = null,
+ email: String? = null,
+ signature: String? = null,
+ signatureUse: Boolean = false,
+ replyTo: String? = null
+ ): Identity {
+ return Identity(description, name, email, signature, signatureUse, replyTo)
+ }
+}
diff --git a/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderParserTest.kt b/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderParserTest.kt
new file mode 100644
index 0000000000..1d58f7c212
--- /dev/null
+++ b/app/core/src/test/java/com/fsck/k9/message/IdentityHeaderParserTest.kt
@@ -0,0 +1,33 @@
+package com.fsck.k9.message
+
+import com.fsck.k9.RobolectricTest
+import com.fsck.k9.helper.toCrLf
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class IdentityHeaderParserTest : RobolectricTest() {
+ @Test
+ fun `folded header value`() {
+ val input = """
+ |!l=10&o=0&qs=PREFIX&f=TEXT&s=aaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&p=0&q=NONE
+ """.trimMargin().toCrLf()
+
+ val result = IdentityHeaderParser.parse(input)
+
+ assertThat(result).containsEntry(IdentityField.SIGNATURE, "a".repeat(1000))
+ }
+}
--
GitLab
From 7a36187170daf56b51d2c24319b785dcb9f13a72 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 4 Aug 2021 16:08:58 +0200
Subject: [PATCH 024/285] Version 5.802
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 9 +++++++++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index c75187a1c5..5a56c9d27d 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28001
- versionName '5.802-SNAPSHOT'
+ versionCode 28002
+ versionName '5.802'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index 7b5f3b4b7d..ec8a7e8a42 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,15 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Fixed a bug that was triggered when Push was enabled, but the server didn't support Push. If you've noticed high battery drain, this was probably it
+ Added support for archive and spam actions in the Unified Inbox
+ Fixed notification sounds/vibration. Sometimes notifications were audible when they shouldn't have been, sometimes the other way around
+ Display the star of starred messages in yellow
+ Don't show archive/spam action when no such folder is configured
+ Fixed a crash when saving a draft message with modified signature text
+ Fixed a crash when refreshing attachment previews
+
Tweaked the default font sizes
The name of the currently selected account is displayed in the top bar below the folder name (when using multiple accounts)
--
GitLab
From 3a6ca8dfd52097d14bc8d9edcb036a106f50771c Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 4 Aug 2021 16:49:06 +0200
Subject: [PATCH 025/285] Prepare for version 5.803
---
app/k9mail/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index 5a56c9d27d..8f6f3a7f74 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -47,7 +47,7 @@ android {
testApplicationId "com.fsck.k9.tests"
versionCode 28002
- versionName '5.802'
+ versionName '5.803-SNAPSHOT'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
--
GitLab
From 29fa2fc2b3301f6151bd7bdd2d6f61ef4a178684 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 4 Aug 2021 21:02:44 +0200
Subject: [PATCH 026/285] Rename .java to .kt
---
...sageCryptoDisplayStatus.java => MessageCryptoDisplayStatus.kt} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename app/ui/legacy/src/main/java/com/fsck/k9/view/{MessageCryptoDisplayStatus.java => MessageCryptoDisplayStatus.kt} (100%)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.java b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
similarity index 100%
rename from app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.java
rename to app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
--
GitLab
From 7b16e1b87d667cd744d7bab73eaf7ca47b4605a4 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 4 Aug 2021 21:02:44 +0200
Subject: [PATCH 027/285] Convert MessageCryptoDisplayStatus to Kotlin
---
.../k9/ui/messageview/CryptoInfoDialog.java | 6 +-
.../k9/view/MessageCryptoDisplayStatus.kt | 648 ++++++++----------
.../java/com/fsck/k9/view/MessageHeader.java | 22 +-
3 files changed, 288 insertions(+), 388 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/CryptoInfoDialog.java b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/CryptoInfoDialog.java
index 45811c092a..cdbc6d3b98 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/CryptoInfoDialog.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/CryptoInfoDialog.java
@@ -109,12 +109,12 @@ public class CryptoInfoDialog extends DialogFragment {
}
private void setMessageForDisplayStatus(MessageCryptoDisplayStatus displayStatus) {
- if (displayStatus.titleTextRes == null) {
+ if (displayStatus.getTitleTextRes() == null) {
throw new AssertionError("Crypto info dialog can only be displayed for items with text!");
}
- setMessageSingleLine(displayStatus.colorAttr, displayStatus.titleTextRes, displayStatus.descriptionTextRes,
- displayStatus.statusIconRes);
+ setMessageSingleLine(displayStatus.getColorAttr(), displayStatus.getTitleTextRes(),
+ displayStatus.getDescriptionTextRes(), displayStatus.getStatusIconRes());
}
private void setMessageSingleLine(@AttrRes int colorAttr, @StringRes int titleTextRes,
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
index 24c4d8a1f0..a9a2aafe31 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
@@ -1,415 +1,325 @@
-package com.fsck.k9.view;
-
-
-import androidx.annotation.AttrRes;
-import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.StringRes;
-
-import com.fsck.k9.ui.R;
-import com.fsck.k9.mailstore.CryptoResultAnnotation;
-import org.openintents.openpgp.OpenPgpDecryptionResult;
-import org.openintents.openpgp.OpenPgpSignatureResult;
-
-
-public enum MessageCryptoDisplayStatus {
- LOADING (
- false,
- R.attr.openpgp_grey,
- R.drawable.status_lock_disabled
+package com.fsck.k9.view
+
+import androidx.annotation.AttrRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import com.fsck.k9.mailstore.CryptoResultAnnotation
+import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError
+import com.fsck.k9.ui.R
+import org.openintents.openpgp.OpenPgpDecryptionResult.RESULT_ENCRYPTED
+import org.openintents.openpgp.OpenPgpDecryptionResult.RESULT_INSECURE
+import org.openintents.openpgp.OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED
+import org.openintents.openpgp.OpenPgpSignatureResult
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_KEY_MISSING
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_NO_SIGNATURE
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED
+import org.openintents.openpgp.OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED
+import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.UNKNOWN
+import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.USER_ID_CONFIRMED
+import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.USER_ID_MISSING
+import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.USER_ID_UNCONFIRMED
+
+enum class MessageCryptoDisplayStatus(
+ val isEnabled: Boolean = false,
+
+ @AttrRes
+ val colorAttr: Int,
+
+ @DrawableRes
+ val statusIconRes: Int,
+
+ @StringRes
+ val titleTextRes: Int? = null,
+
+ @StringRes
+ val descriptionTextRes: Int? = null
+) {
+ LOADING(
+ isEnabled = false,
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_disabled
),
-
- CANCELLED (
- R.attr.openpgp_black,
- R.drawable.status_lock_unknown,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_cancelled
- ),
-
- DISABLED (
- false,
- R.attr.openpgp_grey,
- R.drawable.status_lock_disabled,
- R.string.crypto_msg_title_plaintext,
- null
+ CANCELLED(
+ colorAttr = R.attr.openpgp_black,
+ statusIconRes = R.drawable.status_lock_unknown,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_cancelled
),
- UNENCRYPTED_SIGN_ERROR (
- R.attr.openpgp_grey,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_plaintext,
- R.string.crypto_msg_unencrypted_sign_error
+ DISABLED(
+ isEnabled = false,
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_disabled,
+ titleTextRes = R.string.crypto_msg_title_plaintext
),
- INCOMPLETE_SIGNED (
- R.attr.openpgp_black,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_plaintext,
- R.string.crypto_msg_incomplete_signed
+ UNENCRYPTED_SIGN_ERROR(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_plaintext,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_error
),
-
- UNENCRYPTED_SIGN_VERIFIED (
- R.attr.openpgp_blue,
- R.drawable.status_signature_dots_3,
- R.string.crypto_msg_title_unencrypted_signed_e2e,
- R.string.crypto_msg_unencrypted_sign_verified
+ INCOMPLETE_SIGNED(
+ colorAttr = R.attr.openpgp_black,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_plaintext,
+ descriptionTextRes = R.string.crypto_msg_incomplete_signed
),
- UNENCRYPTED_SIGN_UNVERIFIED (
- R.attr.openpgp_blue,
- R.drawable.status_signature,
- R.string.crypto_msg_title_unencrypted_signed_e2e,
- null
+ UNENCRYPTED_SIGN_VERIFIED(
+ colorAttr = R.attr.openpgp_blue,
+ statusIconRes = R.drawable.status_signature_dots_3,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed_e2e,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_verified
),
-
- UNENCRYPTED_SIGN_UNKNOWN (
- R.attr.openpgp_orange,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_unencrypted_signed,
- R.string.crypto_msg_unencrypted_sign_unknown
+ UNENCRYPTED_SIGN_UNVERIFIED(
+ colorAttr = R.attr.openpgp_blue,
+ statusIconRes = R.drawable.status_signature,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed_e2e
),
- UNENCRYPTED_SIGN_MISMATCH (
- R.attr.openpgp_grey,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_unencrypted_signed,
- R.string.crypto_msg_unencrypted_sign_mismatch
+ UNENCRYPTED_SIGN_UNKNOWN(
+ colorAttr = R.attr.openpgp_orange,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_unknown
),
- UNENCRYPTED_SIGN_EXPIRED (
- R.attr.openpgp_grey,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_unencrypted_signed,
- R.string.crypto_msg_unencrypted_sign_expired
+ UNENCRYPTED_SIGN_MISMATCH(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_mismatch
),
- UNENCRYPTED_SIGN_REVOKED (
- R.attr.openpgp_grey,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_unencrypted_signed,
- R.string.crypto_msg_unencrypted_sign_revoked
+ UNENCRYPTED_SIGN_EXPIRED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_expired
),
- UNENCRYPTED_SIGN_INSECURE (
- R.attr.openpgp_grey,
- R.drawable.status_signature_unknown,
- R.string.crypto_msg_title_unencrypted_signed,
- R.string.crypto_msg_unencrypted_sign_insecure
+ UNENCRYPTED_SIGN_REVOKED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_revoked
),
-
- ENCRYPTED_SIGN_VERIFIED (
- R.attr.openpgp_green,
- R.drawable.status_lock_dots_3,
- R.string.crypto_msg_title_encrypted_signed_e2e,
- R.string.crypto_msg_encrypted_sign_verified
+ UNENCRYPTED_SIGN_INSECURE(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_signature_unknown,
+ titleTextRes = R.string.crypto_msg_title_unencrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_unencrypted_sign_insecure
),
- ENCRYPTED_SIGN_UNVERIFIED (
- R.attr.openpgp_green,
- R.drawable.status_lock,
- R.string.crypto_msg_title_encrypted_signed_e2e,
- null
+ ENCRYPTED_SIGN_VERIFIED(
+ colorAttr = R.attr.openpgp_green,
+ statusIconRes = R.drawable.status_lock_dots_3,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed_e2e,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_verified
),
-
- ENCRYPTED_SIGN_UNKNOWN (
- R.attr.openpgp_orange,
- R.drawable.status_lock_unknown,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_unknown
+ ENCRYPTED_SIGN_UNVERIFIED(
+ colorAttr = R.attr.openpgp_green,
+ statusIconRes = R.drawable.status_lock,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed_e2e
),
- ENCRYPTED_SIGN_MISMATCH (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_mismatch
+ ENCRYPTED_SIGN_UNKNOWN(
+ colorAttr = R.attr.openpgp_orange,
+ statusIconRes = R.drawable.status_lock_unknown,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_unknown
),
- ENCRYPTED_SIGN_EXPIRED (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_expired
+ ENCRYPTED_SIGN_MISMATCH(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_mismatch
),
- ENCRYPTED_SIGN_REVOKED (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_revoked
+ ENCRYPTED_SIGN_EXPIRED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_expired
),
- ENCRYPTED_SIGN_INSECURE (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_insecure
+ ENCRYPTED_SIGN_REVOKED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_revoked
),
- ENCRYPTED_SIGN_ERROR (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_sign_error
+ ENCRYPTED_SIGN_INSECURE(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_insecure
),
- ENCRYPTED_INSECURE (
- R.attr.openpgp_red,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_signed,
- R.string.crypto_msg_encrypted_insecure
+ ENCRYPTED_SIGN_ERROR(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_sign_error
),
-
- ENCRYPTED_UNSIGNED (
- R.attr.openpgp_grey,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_unsigned,
- R.string.crypto_msg_encrypted_unsigned
+ ENCRYPTED_INSECURE(
+ colorAttr = R.attr.openpgp_red,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_signed,
+ descriptionTextRes = R.string.crypto_msg_encrypted_insecure
),
-
- ENCRYPTED_ERROR (
- R.attr.openpgp_red,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_encrypted_error
+ ENCRYPTED_UNSIGNED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unsigned,
+ descriptionTextRes = R.string.crypto_msg_encrypted_unsigned
),
-
- INCOMPLETE_ENCRYPTED (
- R.attr.openpgp_black,
- R.drawable.status_lock_unknown,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_encrypted_incomplete
+ ENCRYPTED_ERROR(
+ colorAttr = R.attr.openpgp_red,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_encrypted_error
),
-
- ENCRYPTED_NO_PROVIDER (
- R.attr.openpgp_red,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_encrypted_no_provider
+ INCOMPLETE_ENCRYPTED(
+ colorAttr = R.attr.openpgp_black,
+ statusIconRes = R.drawable.status_lock_unknown,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_encrypted_incomplete
),
-
- UNSUPPORTED_ENCRYPTED (
- R.attr.openpgp_red,
- R.drawable.status_lock_error,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_unsupported_encrypted
+ ENCRYPTED_NO_PROVIDER(
+ colorAttr = R.attr.openpgp_red,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_encrypted_no_provider
),
- UNSUPPORTED_SIGNED (
- R.attr.openpgp_grey,
- R.drawable.status_lock_disabled,
- R.string.crypto_msg_title_encrypted_unknown,
- R.string.crypto_msg_unsupported_signed
+ UNSUPPORTED_ENCRYPTED(
+ colorAttr = R.attr.openpgp_red,
+ statusIconRes = R.drawable.status_lock_error,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_unsupported_encrypted
),
- ;
-
- @AttrRes public final int colorAttr;
- @DrawableRes public final int statusIconRes;
- @StringRes public final Integer titleTextRes;
- @StringRes public final Integer descriptionTextRes;
- public boolean isEnabled;
-
- MessageCryptoDisplayStatus(@AttrRes int colorAttr, @DrawableRes int statusIconRes, @StringRes int titleTextRes,
- Integer descriptionTextRes) {
- this.colorAttr = colorAttr;
- this.statusIconRes = statusIconRes;
-
- this.titleTextRes = titleTextRes;
- this.descriptionTextRes = descriptionTextRes;
- }
-
- MessageCryptoDisplayStatus(boolean isEnabled, @AttrRes int colorAttr, @DrawableRes int statusIconRes,
- @StringRes int titleTextRes, Integer descriptionTextRes) {
- this(colorAttr, statusIconRes, titleTextRes, descriptionTextRes);
- this.isEnabled = isEnabled;
- }
-
- MessageCryptoDisplayStatus(boolean isEnabled, @AttrRes int colorAttr, @DrawableRes int statusIconRes) {
- this.colorAttr = colorAttr;
- this.statusIconRes = statusIconRes;
-
- this.titleTextRes = null;
- this.descriptionTextRes = null;
-
- this.isEnabled = isEnabled;
- }
-
- @NonNull
- public static MessageCryptoDisplayStatus fromResultAnnotation(CryptoResultAnnotation cryptoResult) {
- if (cryptoResult == null) {
- return DISABLED;
- }
-
- switch (cryptoResult.getErrorType()) {
- case OPENPGP_OK:
- return getDisplayStatusForPgpResult(cryptoResult);
-
- case OPENPGP_ENCRYPTED_BUT_INCOMPLETE:
- return INCOMPLETE_ENCRYPTED;
-
- case OPENPGP_SIGNED_BUT_INCOMPLETE:
- return INCOMPLETE_SIGNED;
-
- case ENCRYPTED_BUT_UNSUPPORTED:
- return UNSUPPORTED_ENCRYPTED;
-
- case SIGNED_BUT_UNSUPPORTED:
- return UNSUPPORTED_SIGNED;
-
- case OPENPGP_UI_CANCELED:
- return CANCELLED;
-
- case OPENPGP_SIGNED_API_ERROR:
- return UNENCRYPTED_SIGN_ERROR;
-
- case OPENPGP_ENCRYPTED_API_ERROR:
- return ENCRYPTED_ERROR;
-
- case OPENPGP_ENCRYPTED_NO_PROVIDER:
- return ENCRYPTED_NO_PROVIDER;
+ UNSUPPORTED_SIGNED(
+ colorAttr = R.attr.openpgp_grey,
+ statusIconRes = R.drawable.status_lock_disabled,
+ titleTextRes = R.string.crypto_msg_title_encrypted_unknown,
+ descriptionTextRes = R.string.crypto_msg_unsupported_signed
+ );
+
+ fun hasAssociatedKey(): Boolean {
+ return when (this) {
+ ENCRYPTED_SIGN_VERIFIED,
+ ENCRYPTED_SIGN_UNVERIFIED,
+ ENCRYPTED_SIGN_MISMATCH,
+ ENCRYPTED_SIGN_EXPIRED,
+ ENCRYPTED_SIGN_REVOKED,
+ ENCRYPTED_SIGN_INSECURE,
+ UNENCRYPTED_SIGN_VERIFIED,
+ UNENCRYPTED_SIGN_UNVERIFIED,
+ UNENCRYPTED_SIGN_MISMATCH,
+ UNENCRYPTED_SIGN_EXPIRED,
+ UNENCRYPTED_SIGN_REVOKED,
+ UNENCRYPTED_SIGN_INSECURE -> true
+ else -> false
}
- throw new IllegalStateException("Unhandled case!");
}
- @NonNull
- private static MessageCryptoDisplayStatus getDisplayStatusForPgpResult(CryptoResultAnnotation cryptoResult) {
- OpenPgpSignatureResult signatureResult = cryptoResult.getOpenPgpSignatureResult();
- OpenPgpDecryptionResult decryptionResult = cryptoResult.getOpenPgpDecryptionResult();
- if (decryptionResult == null || signatureResult == null) {
- throw new AssertionError("Both OpenPGP results must be non-null at this point!");
+ val isUnencryptedSigned: Boolean
+ get() = when (this) {
+ UNENCRYPTED_SIGN_ERROR,
+ UNENCRYPTED_SIGN_UNKNOWN,
+ UNENCRYPTED_SIGN_VERIFIED,
+ UNENCRYPTED_SIGN_UNVERIFIED,
+ UNENCRYPTED_SIGN_MISMATCH,
+ UNENCRYPTED_SIGN_EXPIRED,
+ UNENCRYPTED_SIGN_REVOKED,
+ UNENCRYPTED_SIGN_INSECURE -> true
+ else -> false
}
- if (signatureResult.getResult() == OpenPgpSignatureResult.RESULT_NO_SIGNATURE &&
- cryptoResult.hasEncapsulatedResult()) {
- CryptoResultAnnotation encapsulatedResult = cryptoResult.getEncapsulatedResult();
- if (encapsulatedResult.isOpenPgpResult()) {
- signatureResult = encapsulatedResult.getOpenPgpSignatureResult();
- if (signatureResult == null) {
- throw new AssertionError("OpenPGP must contain signature result at this point!");
- }
- }
+ val isUnknownKey: Boolean
+ get() = when (this) {
+ ENCRYPTED_SIGN_UNKNOWN, UNENCRYPTED_SIGN_UNKNOWN -> true
+ else -> false
}
- switch (decryptionResult.getResult()) {
- case OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED:
- return getStatusForPgpUnencryptedResult(signatureResult);
-
- case OpenPgpDecryptionResult.RESULT_ENCRYPTED:
- return getStatusForPgpEncryptedResult(signatureResult);
-
- case OpenPgpDecryptionResult.RESULT_INSECURE:
- return ENCRYPTED_INSECURE;
+ companion object {
+ @JvmStatic
+ fun fromResultAnnotation(cryptoResult: CryptoResultAnnotation?): MessageCryptoDisplayStatus {
+ return when (cryptoResult?.errorType) {
+ null -> DISABLED
+ CryptoError.OPENPGP_OK -> getDisplayStatusForPgpResult(cryptoResult)
+ CryptoError.OPENPGP_ENCRYPTED_BUT_INCOMPLETE -> INCOMPLETE_ENCRYPTED
+ CryptoError.OPENPGP_SIGNED_BUT_INCOMPLETE -> INCOMPLETE_SIGNED
+ CryptoError.ENCRYPTED_BUT_UNSUPPORTED -> UNSUPPORTED_ENCRYPTED
+ CryptoError.SIGNED_BUT_UNSUPPORTED -> UNSUPPORTED_SIGNED
+ CryptoError.OPENPGP_UI_CANCELED -> CANCELLED
+ CryptoError.OPENPGP_SIGNED_API_ERROR -> UNENCRYPTED_SIGN_ERROR
+ CryptoError.OPENPGP_ENCRYPTED_API_ERROR -> ENCRYPTED_ERROR
+ CryptoError.OPENPGP_ENCRYPTED_NO_PROVIDER -> ENCRYPTED_NO_PROVIDER
+ else -> error("Unhandled case!")
+ }
}
- throw new AssertionError("all cases must be handled, this is a bug!");
- }
-
- @NonNull
- private static MessageCryptoDisplayStatus getStatusForPgpEncryptedResult(OpenPgpSignatureResult signatureResult) {
- switch (signatureResult.getResult()) {
- case OpenPgpSignatureResult.RESULT_NO_SIGNATURE:
- return ENCRYPTED_UNSIGNED;
+ private fun getDisplayStatusForPgpResult(cryptoResult: CryptoResultAnnotation): MessageCryptoDisplayStatus {
+ var signatureResult = cryptoResult.openPgpSignatureResult
+ val decryptionResult = cryptoResult.openPgpDecryptionResult
+ if (decryptionResult == null || signatureResult == null) {
+ throw AssertionError("Both OpenPGP results must be non-null at this point!")
+ }
- case OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED:
- case OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED:
- switch (signatureResult.getSenderStatusResult()) {
- case USER_ID_CONFIRMED:
- return ENCRYPTED_SIGN_VERIFIED;
- case USER_ID_UNCONFIRMED:
- return ENCRYPTED_SIGN_UNVERIFIED;
- case USER_ID_MISSING:
- return ENCRYPTED_SIGN_MISMATCH;
- case UNKNOWN:
- return ENCRYPTED_SIGN_UNVERIFIED;
+ if (signatureResult.result == RESULT_NO_SIGNATURE && cryptoResult.hasEncapsulatedResult()) {
+ val encapsulatedResult = cryptoResult.encapsulatedResult
+ if (encapsulatedResult.isOpenPgpResult) {
+ signatureResult = encapsulatedResult.openPgpSignatureResult
+ ?: throw AssertionError("OpenPGP must contain signature result at this point!")
}
- throw new IllegalStateException("unhandled encrypted result case!");
-
- case OpenPgpSignatureResult.RESULT_KEY_MISSING:
- return ENCRYPTED_SIGN_UNKNOWN;
-
- case OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE:
- return ENCRYPTED_SIGN_ERROR;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED:
- return ENCRYPTED_SIGN_EXPIRED;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED:
- return ENCRYPTED_SIGN_REVOKED;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE:
- return ENCRYPTED_SIGN_INSECURE;
+ }
- default:
- throw new IllegalStateException("unhandled encrypted result case!");
+ return when (decryptionResult.getResult()) {
+ RESULT_NOT_ENCRYPTED -> getStatusForPgpUnencryptedResult(signatureResult)
+ RESULT_ENCRYPTED -> getStatusForPgpEncryptedResult(signatureResult)
+ RESULT_INSECURE -> ENCRYPTED_INSECURE
+ else -> throw AssertionError("all cases must be handled, this is a bug!")
+ }
}
- }
- @NonNull
- private static MessageCryptoDisplayStatus getStatusForPgpUnencryptedResult(OpenPgpSignatureResult signatureResult) {
- switch (signatureResult.getResult()) {
- case OpenPgpSignatureResult.RESULT_NO_SIGNATURE:
- return DISABLED;
-
- case OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED:
- case OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED:
- switch (signatureResult.getSenderStatusResult()) {
- case USER_ID_CONFIRMED:
- return UNENCRYPTED_SIGN_VERIFIED;
- case USER_ID_UNCONFIRMED:
- return UNENCRYPTED_SIGN_UNVERIFIED;
- case USER_ID_MISSING:
- return UNENCRYPTED_SIGN_MISMATCH;
- case UNKNOWN:
- return UNENCRYPTED_SIGN_UNVERIFIED;
+ private fun getStatusForPgpEncryptedResult(
+ signatureResult: OpenPgpSignatureResult
+ ): MessageCryptoDisplayStatus {
+ return when (signatureResult.result) {
+ RESULT_NO_SIGNATURE -> ENCRYPTED_UNSIGNED
+ RESULT_VALID_KEY_CONFIRMED, RESULT_VALID_KEY_UNCONFIRMED -> {
+ return when (signatureResult.senderStatusResult) {
+ USER_ID_CONFIRMED -> ENCRYPTED_SIGN_VERIFIED
+ USER_ID_UNCONFIRMED -> ENCRYPTED_SIGN_UNVERIFIED
+ USER_ID_MISSING -> ENCRYPTED_SIGN_MISMATCH
+ UNKNOWN -> ENCRYPTED_SIGN_UNVERIFIED
+ else -> error("unhandled encrypted result case!")
+ }
}
- throw new IllegalStateException("unhandled encrypted result case!");
-
- case OpenPgpSignatureResult.RESULT_KEY_MISSING:
- return UNENCRYPTED_SIGN_UNKNOWN;
-
- case OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE:
- return UNENCRYPTED_SIGN_ERROR;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED:
- return UNENCRYPTED_SIGN_EXPIRED;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED:
- return UNENCRYPTED_SIGN_REVOKED;
-
- case OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE:
- return UNENCRYPTED_SIGN_INSECURE;
-
- default:
- throw new IllegalStateException("unhandled encrypted result case!");
- }
- }
-
- public boolean hasAssociatedKey() {
- switch (this) {
- case ENCRYPTED_SIGN_VERIFIED:
- case ENCRYPTED_SIGN_UNVERIFIED:
- case ENCRYPTED_SIGN_MISMATCH:
- case ENCRYPTED_SIGN_EXPIRED:
- case ENCRYPTED_SIGN_REVOKED:
- case ENCRYPTED_SIGN_INSECURE:
-
- case UNENCRYPTED_SIGN_VERIFIED:
- case UNENCRYPTED_SIGN_UNVERIFIED:
- case UNENCRYPTED_SIGN_MISMATCH:
- case UNENCRYPTED_SIGN_EXPIRED:
- case UNENCRYPTED_SIGN_REVOKED:
- case UNENCRYPTED_SIGN_INSECURE:
- return true;
- }
- return false;
- }
-
- public boolean isUnencryptedSigned() {
- switch (this) {
- case UNENCRYPTED_SIGN_ERROR:
- case UNENCRYPTED_SIGN_UNKNOWN:
- case UNENCRYPTED_SIGN_VERIFIED:
- case UNENCRYPTED_SIGN_UNVERIFIED:
- case UNENCRYPTED_SIGN_MISMATCH:
- case UNENCRYPTED_SIGN_EXPIRED:
- case UNENCRYPTED_SIGN_REVOKED:
- case UNENCRYPTED_SIGN_INSECURE:
- return true;
+ RESULT_KEY_MISSING -> ENCRYPTED_SIGN_UNKNOWN
+ RESULT_INVALID_SIGNATURE -> ENCRYPTED_SIGN_ERROR
+ RESULT_INVALID_KEY_EXPIRED -> ENCRYPTED_SIGN_EXPIRED
+ RESULT_INVALID_KEY_REVOKED -> ENCRYPTED_SIGN_REVOKED
+ RESULT_INVALID_KEY_INSECURE -> ENCRYPTED_SIGN_INSECURE
+ else -> error("unhandled encrypted result case!")
+ }
}
- return false;
- }
- public boolean isUnknownKey() {
- switch (this) {
- case ENCRYPTED_SIGN_UNKNOWN:
- case UNENCRYPTED_SIGN_UNKNOWN:
- return true;
+ private fun getStatusForPgpUnencryptedResult(
+ signatureResult: OpenPgpSignatureResult
+ ): MessageCryptoDisplayStatus {
+ return when (signatureResult.result) {
+ RESULT_NO_SIGNATURE -> DISABLED
+ RESULT_VALID_KEY_CONFIRMED, RESULT_VALID_KEY_UNCONFIRMED -> {
+ return when (signatureResult.senderStatusResult) {
+ USER_ID_CONFIRMED -> UNENCRYPTED_SIGN_VERIFIED
+ USER_ID_UNCONFIRMED -> UNENCRYPTED_SIGN_UNVERIFIED
+ USER_ID_MISSING -> UNENCRYPTED_SIGN_MISMATCH
+ UNKNOWN -> UNENCRYPTED_SIGN_UNVERIFIED
+ else -> error("unhandled encrypted result case!")
+ }
+ }
+ RESULT_KEY_MISSING -> UNENCRYPTED_SIGN_UNKNOWN
+ RESULT_INVALID_SIGNATURE -> UNENCRYPTED_SIGN_ERROR
+ RESULT_INVALID_KEY_EXPIRED -> UNENCRYPTED_SIGN_EXPIRED
+ RESULT_INVALID_KEY_REVOKED -> UNENCRYPTED_SIGN_REVOKED
+ RESULT_INVALID_KEY_INSECURE -> UNENCRYPTED_SIGN_INSECURE
+ else -> error("unhandled encrypted result case!")
+ }
}
- return false;
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageHeader.java b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageHeader.java
index e265cd00f1..47c384edfa 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageHeader.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageHeader.java
@@ -2,22 +2,11 @@ package com.fsck.k9.view;
import java.util.Arrays;
-import java.util.List;
import android.content.Context;
-import android.graphics.Typeface;
-import android.os.Parcel;
-import android.os.Parcelable;
-import androidx.annotation.NonNull;
-import androidx.appcompat.widget.PopupMenu;
-import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.text.style.StyleSpan;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
@@ -27,6 +16,9 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.PopupMenu;
+import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.FontSizes;
@@ -38,9 +30,7 @@ import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.MessageHelper;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
-import com.fsck.k9.mail.Header;
import com.fsck.k9.mail.Message;
-import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.ui.ContactBadge;
import com.fsck.k9.ui.R;
import com.fsck.k9.ui.messageview.OnCryptoClickListener;
@@ -328,10 +318,10 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
}
private void setCryptoDisplayStatus(MessageCryptoDisplayStatus displayStatus) {
- int color = ThemeUtils.getStyledColor(getContext(), displayStatus.colorAttr);
- mCryptoStatusIcon.setEnabled(displayStatus.isEnabled);
+ int color = ThemeUtils.getStyledColor(getContext(), displayStatus.getColorAttr());
+ mCryptoStatusIcon.setEnabled(displayStatus.isEnabled());
mCryptoStatusIcon.setVisibility(View.VISIBLE);
- mCryptoStatusIcon.setImageResource(displayStatus.statusIconRes);
+ mCryptoStatusIcon.setImageResource(displayStatus.getStatusIconRes());
mCryptoStatusIcon.setColorFilter(color);
}
--
GitLab
From ba151ff970f5d7fc5b73a23b581c4bb7bf3a1a41 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 4 Aug 2021 21:09:02 +0200
Subject: [PATCH 028/285] Fix bug that kept the crypto status icon disabled
---
.../main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
index a9a2aafe31..4e157fd63c 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/view/MessageCryptoDisplayStatus.kt
@@ -24,7 +24,7 @@ import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.USER_ID
import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult.USER_ID_UNCONFIRMED
enum class MessageCryptoDisplayStatus(
- val isEnabled: Boolean = false,
+ val isEnabled: Boolean = true,
@AttrRes
val colorAttr: Int,
--
GitLab
From 8c56d0c70233ef4c1f39a2de8a5fc4b50b8ea78d Mon Sep 17 00:00:00 2001
From: lostfictions
Date: Wed, 4 Aug 2021 18:59:47 -0400
Subject: [PATCH 029/285] make push notification low priority
fixes #5521.
---
.../java/com/fsck/k9/notification/PushNotificationManager.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/PushNotificationManager.kt b/app/core/src/main/java/com/fsck/k9/notification/PushNotificationManager.kt
index c26f7899ac..bd15f47801 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/PushNotificationManager.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/PushNotificationManager.kt
@@ -64,6 +64,7 @@ internal class PushNotificationManager(
.setContentIntent(contentIntent)
.setOngoing(true)
.setNotificationSilent()
+ .setPriority(NotificationCompat.PRIORITY_MIN)
.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
.setLocalOnly(true)
.setShowWhen(false)
--
GitLab
From c43cb3868b6cc70af555b8947f85387c503f0169 Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 6 Aug 2021 14:41:38 +0200
Subject: [PATCH 030/285] Ignore extraneous spaces when filtering the folder
list
Filter strings with e.g. a trailing space were split into the search term and the empty string. But the empty string can be found in every folder name, so all folders were displayed. This change drops all search terms that are the empty string.
---
.../java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
index db0eceeaa7..03c60cc188 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
@@ -146,6 +146,7 @@ class ManageFoldersFragment : Fragment() {
val locale = Locale.getDefault()
val displayName = item.displayName.toLowerCase(locale)
return constraint.splitToSequence(" ")
+ .filter { it.isNotEmpty() }
.map { it.toLowerCase(locale) }
.any { it in displayName }
}
--
GitLab
From 7aac9ce6dca09e40d47d6c1b055c54c32e82cbac Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 6 Aug 2021 16:50:12 +0200
Subject: [PATCH 031/285] Open system settings screens for notification
channels directly
---
.../account/AccountSettingsFragment.kt | 27 +++++++++++++++----
.../account/NotificationsPreference.kt | 13 ++++++++-
app/ui/legacy/src/main/res/values/strings.xml | 5 ++--
.../src/main/res/xml/account_settings.xml | 18 ++++++++++---
4 files changed, 51 insertions(+), 12 deletions(-)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsFragment.kt
index d6e5e7ae11..617fde317b 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsFragment.kt
@@ -22,6 +22,8 @@ import com.fsck.k9.fragment.ConfirmationDialogFragment
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
import com.fsck.k9.mailstore.FolderType
import com.fsck.k9.mailstore.RemoteFolder
+import com.fsck.k9.notification.NotificationChannelManager
+import com.fsck.k9.notification.NotificationChannelManager.ChannelType
import com.fsck.k9.ui.R
import com.fsck.k9.ui.endtoend.AutocryptKeyTransferActivity
import com.fsck.k9.ui.settings.onClick
@@ -43,6 +45,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
private val openPgpApiManager: OpenPgpApiManager by inject { parametersOf(this) }
private val messagingController: MessagingController by inject()
private val accountRemover: BackgroundAccountRemover by inject()
+ private val notificationChannelManager: NotificationChannelManager by inject()
private lateinit var dataStore: AccountSettingsDataStore
private val accountUuid: String by lazy {
@@ -71,7 +74,7 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
initializeAdvancedPushSettings(account)
initializeCryptoSettings(account)
initializeFolderSettings(account)
- initializeNotifications()
+ initializeNotifications(account)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@@ -176,10 +179,23 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
}
}
- private fun initializeNotifications() {
- findPreference(PREFERENCE_OPEN_NOTIFICATION_SETTINGS)?.let {
+ private fun initializeNotifications(account: Account) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ PRE_SDK26_NOTIFICATION_PREFERENCES.forEach { findPreference(it).remove() }
+ }
+
+ findPreference(PREFERENCE_NOTIFICATION_SETTINGS_MESSAGES)?.let {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ it.notificationChannelId = notificationChannelManager.getChannelIdFor(account, ChannelType.MESSAGES)
+ } else {
+ it.remove()
+ }
+ }
+
+ findPreference(PREFERENCE_NOTIFICATION_SETTINGS_MISCELLANEOUS)?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- PRE_SDK26_NOTIFICATION_PREFERENCES.forEach { findPreference(it).remove() }
+ it.notificationChannelId =
+ notificationChannelManager.getChannelIdFor(account, ChannelType.MISCELLANEOUS)
} else {
it.remove()
}
@@ -373,7 +389,8 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), ConfirmationDialogFr
private const val PREFERENCE_SENT_FOLDER = "sent_folder"
private const val PREFERENCE_SPAM_FOLDER = "spam_folder"
private const val PREFERENCE_TRASH_FOLDER = "trash_folder"
- private const val PREFERENCE_OPEN_NOTIFICATION_SETTINGS = "open_notification_settings"
+ private const val PREFERENCE_NOTIFICATION_SETTINGS_MESSAGES = "open_notification_settings_messages"
+ private const val PREFERENCE_NOTIFICATION_SETTINGS_MISCELLANEOUS = "open_notification_settings_miscellaneous"
private const val DELETE_POLICY_MARK_AS_READ = "MARK_AS_READ"
private val PRE_SDK26_NOTIFICATION_PREFERENCES = arrayOf(
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/NotificationsPreference.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/NotificationsPreference.kt
index b664bf3573..791b8b8bf6 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/NotificationsPreference.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/NotificationsPreference.kt
@@ -3,8 +3,10 @@ package com.fsck.k9.ui.settings.account
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
+import android.os.Build
import android.provider.Settings
import android.util.AttributeSet
+import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat.startActivity
import androidx.core.content.res.TypedArrayUtils
import androidx.fragment.app.DialogFragment
@@ -12,6 +14,7 @@ import androidx.preference.Preference
import com.takisoft.preferencex.PreferenceFragmentCompat
@SuppressLint("RestrictedApi")
+@RequiresApi(Build.VERSION_CODES.O)
class NotificationsPreference
@JvmOverloads
constructor(
@@ -24,8 +27,16 @@ constructor(
defStyleRes: Int = 0
) : Preference(context, attrs, defStyleAttr, defStyleRes) {
+ var notificationChannelId: String? = null
+
override fun onClick() {
- val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ val intent = if (notificationChannelId == null) {
+ Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ } else {
+ Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
+ putExtra(Settings.EXTRA_CHANNEL_ID, notificationChannelId)
+ }
+ }
intent.putExtra(Settings.EXTRA_APP_PACKAGE, this.context.packageName)
startActivity(this.context, intent, null)
}
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index fa77777397..5ee48d6d81 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -521,8 +521,9 @@ Please submit bug reports, contribute new features and ask questions at
Mark a message as read when it is opened for viewing
Mark as read when deleted
Mark a message as read when it is deleted
- Notification settings
- Open system notification settings
+ Notification channels
+ Configure notifications for new messages
+ Configure error and status notifications
Always show images
No
diff --git a/app/ui/legacy/src/main/res/xml/account_settings.xml b/app/ui/legacy/src/main/res/xml/account_settings.xml
index 92fa5699de..274af2a546 100644
--- a/app/ui/legacy/src/main/res/xml/account_settings.xml
+++ b/app/ui/legacy/src/main/res/xml/account_settings.xml
@@ -382,11 +382,21 @@
android:summary="@string/account_settings_notify_sync_summary"
android:title="@string/account_settings_notify_sync_label" />
-
+
+
+
+
+
+
Date: Sat, 7 Aug 2021 21:48:01 +0200
Subject: [PATCH 032/285] Remove notification when a message was deleted
---
.../java/com/fsck/k9/controller/MessagingController.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index d84f5ec96b..7163226055 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -2775,6 +2775,11 @@ public class MessagingController {
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.synchronizeMailboxRemovedMessage(account, folderServerId, messageServerId);
}
+
+ String accountUuid = account.getUuid();
+ long folderId = getFolderIdOrThrow(account, folderServerId);
+ MessageReference messageReference = new MessageReference(accountUuid, folderId, messageServerId, null);
+ notificationController.removeNewMailNotification(account, messageReference);
}
@Override
--
GitLab
From 3578c51057874223985af994da2501deb18a7d0e Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 9 Aug 2021 13:16:45 +0200
Subject: [PATCH 033/285] Use "notification categories" instead of
"notification channels"
---
app/ui/legacy/src/main/res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index 5ee48d6d81..c96929a978 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -521,7 +521,7 @@ Please submit bug reports, contribute new features and ask questions at
Mark a message as read when it is opened for viewing
Mark as read when deleted
Mark a message as read when it is deleted
- Notification channels
+ Notification categories
Configure notifications for new messages
Configure error and status notifications
--
GitLab
From 7c34a8052519a61adaf13b6a1b982563e0440edd Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 12 Aug 2021 10:16:31 +0200
Subject: [PATCH 034/285] Update translations
---
.../legacy/src/main/res/values-ar/strings.xml | 1 -
.../legacy/src/main/res/values-be/strings.xml | 2 -
.../legacy/src/main/res/values-bg/strings.xml | 2 -
.../legacy/src/main/res/values-br/strings.xml | 2 -
.../legacy/src/main/res/values-ca/strings.xml | 2 -
.../legacy/src/main/res/values-cs/strings.xml | 5 +-
.../legacy/src/main/res/values-cy/strings.xml | 2 -
.../legacy/src/main/res/values-da/strings.xml | 2 -
.../legacy/src/main/res/values-de/strings.xml | 5 +-
.../legacy/src/main/res/values-el/strings.xml | 26 ++++++++-
.../legacy/src/main/res/values-eo/strings.xml | 2 -
.../legacy/src/main/res/values-es/strings.xml | 2 -
.../legacy/src/main/res/values-et/strings.xml | 2 -
.../legacy/src/main/res/values-eu/strings.xml | 2 -
.../legacy/src/main/res/values-fa/strings.xml | 38 ++++++++++++-
.../legacy/src/main/res/values-fi/strings.xml | 5 +-
.../legacy/src/main/res/values-fr/strings.xml | 5 +-
.../legacy/src/main/res/values-hr/strings.xml | 2 -
.../legacy/src/main/res/values-hu/strings.xml | 54 +++++++++----------
.../legacy/src/main/res/values-in/strings.xml | 2 -
.../legacy/src/main/res/values-is/strings.xml | 2 -
.../legacy/src/main/res/values-it/strings.xml | 5 +-
.../legacy/src/main/res/values-ja/strings.xml | 2 -
.../legacy/src/main/res/values-lv/strings.xml | 2 -
.../legacy/src/main/res/values-ml/strings.xml | 2 -
.../legacy/src/main/res/values-nb/strings.xml | 1 -
.../legacy/src/main/res/values-nl/strings.xml | 26 ++++-----
.../legacy/src/main/res/values-pl/strings.xml | 2 -
.../src/main/res/values-pt-rBR/strings.xml | 2 -
.../src/main/res/values-pt-rPT/strings.xml | 2 -
.../legacy/src/main/res/values-ro/strings.xml | 2 -
.../legacy/src/main/res/values-ru/strings.xml | 24 ++++++++-
.../legacy/src/main/res/values-sk/strings.xml | 2 -
.../legacy/src/main/res/values-sl/strings.xml | 2 -
.../legacy/src/main/res/values-sq/strings.xml | 5 +-
.../legacy/src/main/res/values-sr/strings.xml | 2 -
.../legacy/src/main/res/values-sv/strings.xml | 21 ++++----
.../legacy/src/main/res/values-tr/strings.xml | 2 -
.../legacy/src/main/res/values-uk/strings.xml | 5 +-
.../src/main/res/values-zh-rCN/strings.xml | 5 +-
.../src/main/res/values-zh-rTW/strings.xml | 2 -
41 files changed, 156 insertions(+), 125 deletions(-)
diff --git a/app/ui/legacy/src/main/res/values-ar/strings.xml b/app/ui/legacy/src/main/res/values-ar/strings.xml
index 14c39035a8..b2a66ddb81 100644
--- a/app/ui/legacy/src/main/res/values-ar/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ar/strings.xml
@@ -406,7 +406,6 @@
إظهار الإشعارات فقط عند تلقي رسائل مِن طرف مراسلين معروفين
تحديد الرسالة كمقروءة بعد فتحها
تحديد الرسالة كمقروءة بعد فتحها الإطلاع عليها
- إعدادات الإشعار
دائمًا اظهر الصور
لا
من المُتراسِلين
diff --git a/app/ui/legacy/src/main/res/values-be/strings.xml b/app/ui/legacy/src/main/res/values-be/strings.xml
index db78beeaf5..5165b20ebf 100644
--- a/app/ui/legacy/src/main/res/values-be/strings.xml
+++ b/app/ui/legacy/src/main/res/values-be/strings.xml
@@ -433,8 +433,6 @@ K-9 Mail - шматфункцыянальны свабодны паштовы к
Пазначаць ліст прачытаным пасля прагляду
Пазначаць як прачытанае пры выдаленні
Пазначаць ліст як прачытаны пасля яго выдалення
- Налады апавяшчэнняў
- Адкрыць сістэмныя налады апавяшчэнняў
Заўсёды паказваць выявы
Не
Ад кантактаў
diff --git a/app/ui/legacy/src/main/res/values-bg/strings.xml b/app/ui/legacy/src/main/res/values-bg/strings.xml
index a55e264efa..259cde6d33 100644
--- a/app/ui/legacy/src/main/res/values-bg/strings.xml
+++ b/app/ui/legacy/src/main/res/values-bg/strings.xml
@@ -435,8 +435,6 @@ K-9 Mail е мощен, безплатен имейл клиент за Андр
Маркирай съобщението като прочетено, когато се отвори за разглеждане
Маркирай като прочетено при изтриване
Маркира съобщението като прочетено при изтриване
- Настройки на известия
- Отвори системните настройките за известия
Винаги показвай картинките
Не
От контактите
diff --git a/app/ui/legacy/src/main/res/values-br/strings.xml b/app/ui/legacy/src/main/res/values-br/strings.xml
index 1e185ea8dc..5db4439f00 100644
--- a/app/ui/legacy/src/main/res/values-br/strings.xml
+++ b/app/ui/legacy/src/main/res/values-br/strings.xml
@@ -418,8 +418,6 @@ Danevellit beugoù, kenlabourit war keweriusterioù nevez ha savit goulennoù wa
Diskouez rebuzadurioù evit kemennadennoù darempredoù a anavezan hepken
Merkañ evel lennet pa vez digoret
Merkañ ar gemennadenn evel lennet pa vez digoret anezho d’he gwelet
- Arventennoù rebuziñ
- Digeriñ arventennoù ar rebuzadurioù reizhiad
Diskouez ar skeudennoù bepred
Ket
Digant darempredoù
diff --git a/app/ui/legacy/src/main/res/values-ca/strings.xml b/app/ui/legacy/src/main/res/values-ca/strings.xml
index c4a76f71f0..16d480d8fd 100644
--- a/app/ui/legacy/src/main/res/values-ca/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ca/strings.xml
@@ -437,8 +437,6 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Marca el missatge com a llegit després d\'haver-lo obert.
Marca com a llegit quan se suprimeixi
Marca un missatge com a llegit quan se suprimeix.
- Configuració de les notificacions
- Obre la configuració de les notificacions del sistema
Sempre mostra les imatges
No
Dels contactes
diff --git a/app/ui/legacy/src/main/res/values-cs/strings.xml b/app/ui/legacy/src/main/res/values-cs/strings.xml
index 0334f1031e..dc0f07cc2e 100644
--- a/app/ui/legacy/src/main/res/values-cs/strings.xml
+++ b/app/ui/legacy/src/main/res/values-cs/strings.xml
@@ -441,8 +441,9 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
Označit zprávu jako přečtenou po otevření
Při smazání označit jako přečtené
Při jejím mazání, označit zprávu jako přečtenou
- Nastavení oznamování
- Nastavení oznamování v operačním systému
+ Kategorie upozorňování
+ Nastavit upozornění na nové zprávy
+ Nastavit upozorňování na chyby a stavy
Vždy zobrazovat obrázky
Ne
Jen od kontaktů
diff --git a/app/ui/legacy/src/main/res/values-cy/strings.xml b/app/ui/legacy/src/main/res/values-cy/strings.xml
index 2df954f9e5..10c5d88ece 100644
--- a/app/ui/legacy/src/main/res/values-cy/strings.xml
+++ b/app/ui/legacy/src/main/res/values-cy/strings.xml
@@ -430,8 +430,6 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
Nodi neges fel ei bod wedi ei darllen wrth ei hagor i\'w darllen.
Nodi wedi\'i darllen wrth dileu
Nodi neges wedi\'i darllen pan gaiff ei dileu
- Gosodiadau hysbysiadau
- Agor gosodiadau hysbysiadau\'r system
Dangos delweddau pob amser
Na
Gan gysyllteion
diff --git a/app/ui/legacy/src/main/res/values-da/strings.xml b/app/ui/legacy/src/main/res/values-da/strings.xml
index 11c5575958..75f5cb9b11 100644
--- a/app/ui/legacy/src/main/res/values-da/strings.xml
+++ b/app/ui/legacy/src/main/res/values-da/strings.xml
@@ -437,8 +437,6 @@ Rapporter venligst fejl, forslag til nye funktioner eller stil spørgsmål på:
Marker som læst når meddelses åbnes for læsning
Marker som læst ved sletning
Marker en besked som læst når den bliver slettet
- Opsætning af notifikationer
- Åbn opsætning for notifikationer
Vis altid billeder
Aldrig
Kun når afsender findes i Kontakter
diff --git a/app/ui/legacy/src/main/res/values-de/strings.xml b/app/ui/legacy/src/main/res/values-de/strings.xml
index 038d88d2c0..566e148e7f 100644
--- a/app/ui/legacy/src/main/res/values-de/strings.xml
+++ b/app/ui/legacy/src/main/res/values-de/strings.xml
@@ -438,8 +438,9 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
Nachricht als gelesen markieren, sobald sie zum Betrachten geöffnet wird
Beim Löschen als gelesen markieren
Nachricht als gelesen markieren, sobald sie gelöscht wird
- Benachrichtigungseinstellungen
- Benachrichtigungseinstellungen öffnen
+ Benachrichtigungskategorien
+ Konfiguriere die Benachrichtigungen für neue Nachrichten
+ Konfiguriere Fehler- und Statusbenachrichtigungen
Bilder automatisch herunterladen
Niemals
Nur von Kontakten
diff --git a/app/ui/legacy/src/main/res/values-el/strings.xml b/app/ui/legacy/src/main/res/values-el/strings.xml
index 7e53675bba..12d245648f 100644
--- a/app/ui/legacy/src/main/res/values-el/strings.xml
+++ b/app/ui/legacy/src/main/res/values-el/strings.xml
@@ -21,6 +21,9 @@
Κατάλογος αλλαγών
Δεν ήταν δυνατή η φόρτωση του καταλόγου αλλαγών
Έκδοση %s
+ Τι νέο υπάρχει
+ Εμφάνιση πρόσφατων αλλαγών από την ενημέρωση της εφαρμογής
+ Δείτε τι έχει αλλάξει σε αυτή την έκδοση
Καλώς ορίσατε στο K-9 Mail
Προσθήκη λογαριασμού
Δημιουργία νέου
Αναζήτηση
+ Αναζήτηση παντού
Αποτελέσματα αναζήτησης
Ρυθμίσεις
Διαχείριση φακέλων
@@ -130,6 +134,7 @@
- Η διεύθυνση αντιγράφηκε στο πρόχειρο
- Οι διευθύνσεις αντιγράφηκαν στο πρόχειρο
+ Το θέμα αντιγράφηκε στο πρόχειρο
Εφαρμογή σκούρας εμφάνισης
Εφαρμογή φωτεινής εμφάνισης
Σήμανση ως μη αναγνωσμένο
@@ -180,6 +185,8 @@
Αποστολή μηνύματος: %s
Αποστολή μηνύματος
:
+ Συγχρονισμός (Push)
+ Εμφανίζεται κατά την αναμονή για νέα μηνύματα
Μηνύματα
Ειδοποιήσεις που αφορούν μηνύματα
Διάφορα
@@ -431,8 +438,6 @@
Σημείωση ως αναγνωσμένου με την προβολή
Σήμανση ως αναγνωσμένο κατά τη διαγραφή
Να γίνεται σήμανση του μηνύματος ως αναγνωσμένο όταν διαγράφεται
- Ρυθμίσεις ειδοποιήσεων
- Άνοιγμα ρυθμίσεων ειδοποιήσεων συστήματος
Προβολή εικόνων πάντα
Όχι
Από τις Επαφές
@@ -548,6 +553,7 @@
Χωρίς Επίπεδο
Πρώτο επίπεδο
Δεύτερο επίπεδο
+ Όπως το επίπεδο ενημέρωσης
Επίπεδο ειδοποίησης φακέλου
Χωρίς Επίπεδο
Πρώτο επίπεδο
@@ -845,6 +851,10 @@
- Ανάκληση %d αποτελέσματος
- Μετάκληση %d αποτελεσμάτων
+
+ - Φόρτωση %1$d από %2$d αποτελέσματα
+ - Φόρτωση %1$d από %2$d αποτελέσματα
+
Η απομακρυσμένη αναζήτηση απέτυχε.
Αναζήτηση
Ενεργοποίηση αναζήτησης στον εξυπηρετητή
@@ -1038,4 +1048,16 @@
Να επιτρέπεται η πρόσβαση στις επαφές
Για να είναι δυνατή η παροχή προτάσεων επαφών και η εμφάνιση των ονομάτων και φωτογραφιών των επαφών, η εφαρμογή χρειάζεται πρόσβαση στις επαφές σας.
Προέκυψε σφάλμα κατά τη φόρτωση των δεδομένων
+ Αρχικοποίηση...
+ Αναμονή για νέα μηνύματα
+ Σε αδράνεια μέχρι να επιτραπεί ο συγχρονισμός στο παρασκήνιο
+ Σε αδράνεια μέχρι να υπάρξει διαθέσιμο δίκτυο
+ Πατήστε για να μάθετε περισσότερα
+ Πληροφορίες σπρωξίματος
+ Όταν χρησιμοποιείται το σπρώξιμο (Push), το K-9 Mail διατηρεί μια σύνδεση με τον εξυπηρετητή ηλεκτρονικού ταχυδρομείου (mail server). Το Android απαιτεί να προβάλλεται συνεχώς μια ειδοποίηση όσο η εφαρμογή λειτουργεί στο παρασκήνιο. %s
+ Παρόλα αυτά, το Android σάς επιτρέπει να κρύψετε την ειδοποίηση.
+ Μάθετε περισσότερα
+ Προσαρμογή ειδοποίησης
+ Αν δεν χρειάζεστε άμεση ειδοποίηση για νέα μηνύματα, απενεργοποιήστε το σπρώξιμο και χρησιμοποιήστε ενημέρωση (Polling). Η ενημέρωση ελέγχει για νέα μηνύματα ανά τακτά χρονικά διαστήματα και δεν χρειάζεται την ειδοποίηση.
+ Απενεργοποίηση σπρωξίματος
diff --git a/app/ui/legacy/src/main/res/values-eo/strings.xml b/app/ui/legacy/src/main/res/values-eo/strings.xml
index 14a616b924..3e6b28cfaf 100644
--- a/app/ui/legacy/src/main/res/values-eo/strings.xml
+++ b/app/ui/legacy/src/main/res/values-eo/strings.xml
@@ -431,8 +431,6 @@ Bonvolu raporti erarojn, kontribui novajn eblojn kaj peti pri novaj funkcioj per
Markas mesaĝon kiel nelegitan, kiam ĝi estas malfermita por montri
Marki kiel legitan je forigo
Markas mesaĝon kiel nelegitan, kiam ĝi estas forigata
- Agordoj de sciigoj
- Malfermi sistemajn agordojn de sciigoj
Ĉiam montri bildojn
Ne
De kontaktoj
diff --git a/app/ui/legacy/src/main/res/values-es/strings.xml b/app/ui/legacy/src/main/res/values-es/strings.xml
index b1f7bedd51..5149e3f590 100644
--- a/app/ui/legacy/src/main/res/values-es/strings.xml
+++ b/app/ui/legacy/src/main/res/values-es/strings.xml
@@ -436,8 +436,6 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Marcar mensaje como leído cuando se abre para verlo
Marcar como leído al borrar
Marcar el mensaje como leído cuando se borra
- Configuración de las notificaciones
- Abrir opciones de notificación del sistema.
Mostrar imágenes siempre
No
Sólo de mis contactos
diff --git a/app/ui/legacy/src/main/res/values-et/strings.xml b/app/ui/legacy/src/main/res/values-et/strings.xml
index 872a82bc0b..b50db3b5c1 100644
--- a/app/ui/legacy/src/main/res/values-et/strings.xml
+++ b/app/ui/legacy/src/main/res/values-et/strings.xml
@@ -405,8 +405,6 @@
Pärast avamist märgi loetuks
Märgi sõnum loetuks, kui see on vaatamiseks avatud
Pärast kustutamist märgi loetuks
- Teadete sätted
- Ava süsteemi teadete sätted
Näita alati pilte
Ei
Kontaktidelt
diff --git a/app/ui/legacy/src/main/res/values-eu/strings.xml b/app/ui/legacy/src/main/res/values-eu/strings.xml
index ea91a721d7..f96e8c800d 100644
--- a/app/ui/legacy/src/main/res/values-eu/strings.xml
+++ b/app/ui/legacy/src/main/res/values-eu/strings.xml
@@ -436,8 +436,6 @@ Mesedez akatsen berri emateko, ezaugarri berriak gehitzeko eta galderak egiteko
Markatu mezua irakurritako gisa ikusteko irekitzerakoan
Markatu irakurritako gisa ezabatzean
Markatu mezua irakurritako gisa ikusteko ezabatzean
- Jakinarazpenen ezarpenak
- Ireki sistemako jakinarazpenen ezarpenak
Erakutsi beti Irudiak
Ez
Kontaktuetatik
diff --git a/app/ui/legacy/src/main/res/values-fa/strings.xml b/app/ui/legacy/src/main/res/values-fa/strings.xml
index 9c672f6bd5..c79cb0b76e 100644
--- a/app/ui/legacy/src/main/res/values-fa/strings.xml
+++ b/app/ui/legacy/src/main/res/values-fa/strings.xml
@@ -9,9 +9,21 @@
The K-9 Dog Walkers
Copyright 2008-%s The K-9 Dog Walkers. Portions Copyright 2006-%s the Android Open Source Project.
+ کد منبع
مجوز آپاچی، نسخهٔ ۲٫۰
+ پروژهٔ متنباز
+ وبگاه
+ انجمن کاربری
+ فِدیوِرس
+ توئیتر
کتابخانهها
مجوز
+ گزارش تغییرات
+ گزارش تغییرات بار نشد.
+ نسخهٔ %s
+ تازهها
+ هنگامی که برنامه روزآمد شد تغییرات تازه را نشان بده
+ از تازههای این نسخه باخبر شوید
به «کِیناین میل» خوش آمدید
هدایت بهشکل پیوست
ویرایش بهعنوان پیام جدید
انتقال به
+ انتقال به پیشنویسها
ارسال…
ساماندهی...
انجام شد
@@ -120,6 +133,7 @@
- نشانیها در بریدهدان کپی شد
- نشانیها در بریدهدان کپی شد
+ نوشتهٔ موضوع به بریدهدان کپی شد
تغییر به پوستهٔ تیره
تغییر به پوستهٔ روشن
خوانده نشد
@@ -170,6 +184,8 @@
ارسال رایانامه: %s
ارسال رایانامه
:
+ همگامسازی (پیشرانی)
+ هنگام انتظار برای پیامهای تازه نشان داده میشود
پیامها
اعلانهای مربوط به پیامها
متفرقه
@@ -421,8 +437,6 @@
زمانی که یک پیام را باز کردید بهعنوان خوانده علامت بخورد
هنگام حذف، نشان بزن که خواندم
پیام حذفشده را نشان بزن که خواندهام
- تنظیمات اعلان
- بازکردن تنظیمات اعلان دستگاه
همیشه عکسها را نشان بده
خیر
از مخاطبان
@@ -538,6 +552,7 @@
بدون سطح
سطح ۱
سطح ۲
+ همانند سطح سرکشی
سطح اعلان پوشه
بدون سطح
سطح ۱
@@ -673,6 +688,7 @@
جابهجایی با کلیدهای تنظیم صدا
در نماهای پیام
در نماهای لیستی
+ نمایش صندوق یکپارچه
%s %s
- نخوانده
همهٔ پیامها
@@ -725,6 +741,7 @@
ارسال ناموفق بود: %s
پیام پیشنویس ذخیره شود؟
پیام را نگه میدارید یا دور میاندازید؟
+ تغییرات حفظ شود یا دور ریخته شود؟
پیام از بین برود؟
آیا از دورانداختن این پیام مطمئن هستید؟
متن را انتخاب کنید تا کپی شود.
@@ -803,6 +820,8 @@
اشتراکگذاری پیوند
کپیکردن پیوند در بریدهدان
پیوند
+ کپیکردن نوشتهٔ پیوند به بریدهدان
+ نوشتهٔ پیوند
تصویر
دیدن تصویر
ذخیرهٔ تصویر
@@ -879,6 +898,8 @@
مخفیانه به
به
از
+ <گیرندهٔ ناشناس>
+ <فرستندهٔ ناشناس>
خانه
کار
سایر
@@ -1025,4 +1046,17 @@
اجازهٔ دسترسی به مخاطبان را بدهید
برای پیشنهاد مخاطب و نمایش نام و عکس مخاطب، برنامه نیاز دارد به مخاطبان شما دسترسی داشته باشد.
+ هنگام بارکردن داده، خطایی رخ داد
+ مقداردهی اولیه...
+ در انتظار رایانامههای جدید
+ میخوابد تا هنگامی که اجازهٔ همگامسازی در پسزمینه داده شود
+ میخوابد تا هنگامی که شبکه در دسترس باشد
+ لمس کنید تا بیشتر بدانید.
+ اطلاعات پیشرانی
+ هنگام استفاده از پیشرانی، K-9 Mail اتصالی به کارساز رایانامه برقرار میکند. اندروید نیاز دارد هنگامی که برنامهای در پسزمینه فعال است اعلان مداومی را نشان دهد. %s
+ البته اندروید این امکان را به شما میدهد که اعلان را پنهان کنید.
+ بیشتر بدانید
+ پیکربندی اعلان
+ اگر برای پیامهای جدید نیاز به اعلان آنی ندارید، بهتر است پیشرانی را غیرفعال کنید و سرکشی را به کار ببرید. روش سرکشی در فواصل زمانی منظم آمدن نامههای جدید را بررسی میکند و به آن اعلان نیاز ندارد.
+ غیرفعالسازی پیشرانی
diff --git a/app/ui/legacy/src/main/res/values-fi/strings.xml b/app/ui/legacy/src/main/res/values-fi/strings.xml
index 25286e1155..1f1e3463cd 100644
--- a/app/ui/legacy/src/main/res/values-fi/strings.xml
+++ b/app/ui/legacy/src/main/res/values-fi/strings.xml
@@ -436,8 +436,9 @@ Ilmoita virheistä, ota osaa sovelluskehitykseen ja esitä kysymyksiä osoittees
Merkitse viesti luetuksi, kun se avataan katseltavaksi
Merkitse luetuksi poistettaessa
Merkitse viesti luetuksi, kun se poistetaan
- Ilmoitusasetukset
- Avaa järjestelmän ilmoitusasetukset
+ Ilmoitusten luokat
+ Määritä uusien viestien ilmoitukset
+ Määritä virhe- ja tilailmoitukset
Näytä aina kuvat
Ei koskaan
Vain yhteystiedoissa olevilta lähettäjiltä
diff --git a/app/ui/legacy/src/main/res/values-fr/strings.xml b/app/ui/legacy/src/main/res/values-fr/strings.xml
index 62aeedf3aa..14c96fad47 100644
--- a/app/ui/legacy/src/main/res/values-fr/strings.xml
+++ b/app/ui/legacy/src/main/res/values-fr/strings.xml
@@ -438,8 +438,9 @@ jusqu’à %d de plus
Marquer un courriel comme lu quand il est ouvert pour être visualisé
Marquer comme lu lors de la suppression
Marquer un message comme lu lors de la suppression
- Paramètres de notification
- Ouvrir les paramètres de notification du système
+ Catégories de notification
+ Configurer les notifications pour les nouveaux messages
+ Configurer les notifications d’erreurs et d’états
Toujours afficher les images
Non
Pour les contacts uniquement
diff --git a/app/ui/legacy/src/main/res/values-hr/strings.xml b/app/ui/legacy/src/main/res/values-hr/strings.xml
index 792998b8f6..303de7bc0a 100644
--- a/app/ui/legacy/src/main/res/values-hr/strings.xml
+++ b/app/ui/legacy/src/main/res/values-hr/strings.xml
@@ -392,8 +392,6 @@
Označava poruke pročitanima nakon otvaranja za pregled
Označi kao pročitano prilikom brisanja
Označi poruku kao pročitanu kada bude obrisana
- Postavke obavijesti
- Otvori sistemske postavke obavijesti
Uvijek prikaži slike
Ne
Iz kontakata
diff --git a/app/ui/legacy/src/main/res/values-hu/strings.xml b/app/ui/legacy/src/main/res/values-hu/strings.xml
index 6cf865f302..04156f82f5 100644
--- a/app/ui/legacy/src/main/res/values-hu/strings.xml
+++ b/app/ui/legacy/src/main/res/values-hu/strings.xml
@@ -435,8 +435,6 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Üzenet megjelölése olvasottként megtekintésre megnyitáskor
Megjelölés olvasottként törléskor
Üzenet megjelölése olvasottként törléskor
- Értesítési beállítások
- A rendszer értesítési beállításainak megnyitása
Képek megjelenítése mindig
Nem
Partnerektől
@@ -480,7 +478,7 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
A fiókban és a fióklistában használt fiók kiemelt színe
Nincs szín
Értesítési LED színe
- A fiókhoz tartozó villogó eszköz LED szín
+ Az eszköz villogó LED-ének színe ennél a fióknál
Helyi mappa mérete
Legfeljebb ennyi üzenet beolvasása
1 KiB
@@ -599,7 +597,7 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
(Nem kötelező)
Az ön neve
(Nem kötelező)
- E-mail cím
+ E-mail-cím
(Kötelező)
Válaszcím
(Nem kötelező)
@@ -611,20 +609,20 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Személyazonosság választása
Küldés más néven
Nem lehet eltávolítani az egyetlen személyazonosságát
- Nem lehet használni egy személyazonosságot e-mail cím nélkül
+ Nem lehet használni egy személyazonosságot e-mail-cím nélkül
Legkorábbi üzenetek először
Legkésőbbi üzenetek először
- Tárgy szerint ábécé sorrendben
- Tárgy szerint fordított ábécé sorrendben
- Feladó szerint ábécé sorrendben
- Feladó szerint fordított ábécé sorrendben
+ Tárgy szerint betűrendben
+ Tárgy szerint fordított betűrendben
+ Feladó szerint betűrendben
+ Feladó szerint fordított betűrendben
Csillagozott üzenetek először
- Csillag nélküli üzenetek először
+ Nem csillagozott üzenetek először
Olvasatlan üzenetek először
Olvasott üzenetek először
Melléklettel rendelkező üzenetek először
Melléklet nélküli üzenetek először
- Rendezés kritérium…
+ Rendezési kritérium…
Dátum
Érkezés
Tárgy
@@ -641,9 +639,9 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Mappa neve tartalmazza
Mappák megjelenítése…
Összes mappa
- Első osztályú mappák
- Első és második osztályú mappák
- Második osztályú mappák elrejtése
+ 1. osztályú mappák
+ 1. és 2. osztályú mappák
+ 2, osztályú mappák elrejtése
Aláírás helyzete
Idézett üzenet előtt
Idézett üzenet után
@@ -688,7 +686,7 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Hangerő gomb navigáció
Üzenetnézetekben
Listanézetekben
- Egységesített Beérkezett üzenetek mutatása
+ Egységes beérkezett üzenetek megjelenítése
%s %s
– Olvasatlan
Összes üzenet
@@ -739,7 +737,7 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Nagyobb
Nem található megfelelő alkalmazás ehhez a művelethez.
A küldés sikertelen: %s
- Menti piszkozat üzenetként?
+ Menti piszkozatként?
Menti vagy elveti ezt az üzenetet?
Menti vagy elveti a változtatásokat?
Elveti az üzenet?
@@ -820,8 +818,8 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Hivatkozás megosztása
Hivatkozás másolása a vágólapra
Hivatkozás
- Link szövegének másolása a Vágólapra
- Link szövege
+ Hivatkozás szövegének másolása a vágólapra
+ Hivatkozás szövege
Kép
Kép megtekintése
Kép mentése
@@ -829,13 +827,13 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
Kép URL-jének másolása a vágólapra
Kép URL
Szám hívása
- Menés a címjegyzékbe
+ Mentés a címjegyzékbe
Szám másolása a vágólapra
Telefonszám
Levél küldése
Mentés a címjegyzékbe
Cím másolása a vágólapra
- E-mail cím
+ E-mail-cím
Összes
10
25
@@ -844,24 +842,24 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
250
500
1000
- Kiszolgáló keresési határ
+ Kiszolgáló keresési korlátja
Lekérdezés küldése a kiszolgálónak
- - %d eredmény lekérése
- - %d eredmény lekérése
+ - %d találat lekérése
+ - %d találat lekérése
- - %1$d/%2$d eredmény lekérése
- - %1$d/%2$d eredmény lekérése
+ - %1$d/%2$d találat lekérése
+ - %1$d/%2$d találat lekérése
A távoli keresés sikertelen
Keresés
- Kiszolgáló keresésének engedélyezése
+ Kiszolgálón keresés engedélyezése
Üzenetek keresése a kiszolgálón az eszközön lévők mellett
Üzenetek keresése a kiszolgálón
- Hálózati kapcsolat szükséges a kiszolgáló kereséséhez.
+ Hálózati kapcsolat szükséges a kiszolgálón kereséshez.
Szín megváltoztatása olvasáskor
- Eltérő háttér jeleníti meg, hogy az üzenetet elolvasták
+ Az eltérő háttér azt jelzi, hogy az üzenetet elolvasták
Beszélgetés nézet
Üzenetek csoportosítása beszélgetés szerint
Adatbázisok frissítése
diff --git a/app/ui/legacy/src/main/res/values-in/strings.xml b/app/ui/legacy/src/main/res/values-in/strings.xml
index da09cfa95b..8ef1605b82 100644
--- a/app/ui/legacy/src/main/res/values-in/strings.xml
+++ b/app/ui/legacy/src/main/res/values-in/strings.xml
@@ -428,8 +428,6 @@ Kirimkan laporan bug, kontribusikan fitur baru dan ajukan pertanyaan di
Tandai pesan sebagai telah dibaca saat dibuka untuk dilihat
Tandai sebagai terbaca saat dihapus
Tandai pesan sebagai terbaca saat dihapus
- Pengaturan notifikasi
- Buka pengaturan notifikasi sistem
Selalu tampilkan gambar
Tidak
Dari kontak
diff --git a/app/ui/legacy/src/main/res/values-is/strings.xml b/app/ui/legacy/src/main/res/values-is/strings.xml
index 65c1b96f2f..c41f5b8056 100644
--- a/app/ui/legacy/src/main/res/values-is/strings.xml
+++ b/app/ui/legacy/src/main/res/values-is/strings.xml
@@ -437,8 +437,6 @@ Sendu inn villuskýrslur, leggðu fram nýja eiginleika og spurðu spurninga á
Merkja skilaboð sem lesin þegar þau eru opnuð til lestrar
Merkja sem lesið þegar er eytt
Merkja skilaboð sem lesin þegar þeim er eytt
- Stillingar á tilkynningum
- Opna stillingar kerfisins fyrir tilkynningar
Alltaf sýna myndir
Nei
Frá tengiliðum
diff --git a/app/ui/legacy/src/main/res/values-it/strings.xml b/app/ui/legacy/src/main/res/values-it/strings.xml
index 2dcf011feb..fe0bff5787 100644
--- a/app/ui/legacy/src/main/res/values-it/strings.xml
+++ b/app/ui/legacy/src/main/res/values-it/strings.xml
@@ -438,8 +438,9 @@ Invia segnalazioni di bug, contribuisci con nuove funzionalità e poni domande s
Marca un messaggio come letto quando viene aperto per la visualizzazione
Marca come letto all\'eliminazione
Marca un messaggio come letto quando viene eliminato
- Impostazioni notifiche
- Apri le impostazioni di sistema delle notifiche
+ Categorie di notifiche
+ Configura le notifiche per i nuovi messaggi
+ Configura le notifiche per errori e stato
Mostra sempre le immagini
No
Dai contatti
diff --git a/app/ui/legacy/src/main/res/values-ja/strings.xml b/app/ui/legacy/src/main/res/values-ja/strings.xml
index 3e6c5bcf61..a3a71590cd 100644
--- a/app/ui/legacy/src/main/res/values-ja/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ja/strings.xml
@@ -431,8 +431,6 @@ K-9 は大多数のメールクライアントと同様に、ほとんどのフ
メッセージを参照したときに既読にする
削除時に既読にする
メッセージが削除されたときに既読にします
- 通知設定
- システム通知設定を開きます
画像を自動で表示
しない
連絡先に登録しているユーザからのメールのみ
diff --git a/app/ui/legacy/src/main/res/values-lv/strings.xml b/app/ui/legacy/src/main/res/values-lv/strings.xml
index fe77543e89..ecf9ae781f 100644
--- a/app/ui/legacy/src/main/res/values-lv/strings.xml
+++ b/app/ui/legacy/src/main/res/values-lv/strings.xml
@@ -436,8 +436,6 @@ pat %d vairāk
Atzīmēt vēstuli kā izlasītu, kad tā atvērta aplūkošanai
Pēc izdzēšanas atzīmēt kā izlasītu
Pēc izdzēšanas atzīmēt vestuli kā izlasītu
- Paziņojumu iestatījumi
- Atvērt sistēmas paziņojumu iestatījumus
Vienmēr rādīt bildes
Nē
No kontaktiem
diff --git a/app/ui/legacy/src/main/res/values-ml/strings.xml b/app/ui/legacy/src/main/res/values-ml/strings.xml
index 3b656b0a1f..0c157bea15 100644
--- a/app/ui/legacy/src/main/res/values-ml/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ml/strings.xml
@@ -429,8 +429,6 @@
ഒരു സന്ദേശം കാണാനായി തുറക്കുമ്പോൾ വായിച്ചതായി അടയാളപ്പെടുത്തുക
ഇല്ലാതാക്കുമ്പോൾ വായിച്ചതായി അടയാളപ്പെടുത്തുക
ഒരു സന്ദേശം ഇല്ലാതാക്കുമ്പോൾ വായിച്ചതായി അടയാളപ്പെടുത്തുക
- അറിയിപ്പ് ക്രമീകരണങ്ങൾ
- സിസ്റ്റം അറിയിപ്പ് ക്രമീകരണങ്ങൾ തുറക്കുക
എല്ലായ്പ്പോഴും ചിത്രങ്ങൾ കാണിക്കുക
ഇല്ല
കോൺടാക്റ്റുകളിൽ നിന്ന്
diff --git a/app/ui/legacy/src/main/res/values-nb/strings.xml b/app/ui/legacy/src/main/res/values-nb/strings.xml
index 052a28360d..22502be87d 100644
--- a/app/ui/legacy/src/main/res/values-nb/strings.xml
+++ b/app/ui/legacy/src/main/res/values-nb/strings.xml
@@ -422,7 +422,6 @@ til %d flere
Merk en melding som lest når den åpnes for visning
Marker som lest når slettet
Marker en melding som lest når den er slettet
- Innstillinger for varsler
Alltid vis bilder
Nei
Fra kontakter
diff --git a/app/ui/legacy/src/main/res/values-nl/strings.xml b/app/ui/legacy/src/main/res/values-nl/strings.xml
index 711850fab1..24bc750a37 100644
--- a/app/ui/legacy/src/main/res/values-nl/strings.xml
+++ b/app/ui/legacy/src/main/res/values-nl/strings.xml
@@ -29,7 +29,7 @@
K-9 Mail is een gratis krachtige e-mail client voor Android. De verbeterde mogelijkheden bestaan uit ondermeer:
-- Duw mail middels IMAP IDLE
+- Push mail middels IMAP IDLE
- Betere prestaties
- Bericht herclassificatie
- E-mail handtekeningen
@@ -179,7 +179,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
Versturen van berichten: %s
Berichten versturen
:
- Synchroniseren (Duw)
+ Synchroniseren (Push)
Wordt weergeven in afwachting op nieuwe berichten
Beeld berichten
Meldingen gerelateerd aan berichten
@@ -377,7 +377,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
Elke 6 uur
Elke 12 uur
Elke 24 uur
- Duw mail voor dit account toestaan
+ Push mail voor dit account toestaan
Als uw server dit ondersteunt, zullen nieuwe berichten direct verschijnen. Deze optie kan drastisch verbeteringen of verslechteringen van prestaties teweeg brengen.
Vernieuw inactieve verbinding
Elke 2 minuten
@@ -432,8 +432,8 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
Markeer als gelezen wanneer ingezien
Als gelezen markeren bij wissen
Markeer een bericht als gelezen wanneer die wordt gewist
- Meldingsinstellingen
- Open instellingen voor systeemmeldingen
+ Meldingen instellen voor nieuwe berichten
+ Error- en statusmeldingen instellen
Laat afbeeldingen automatisch zien
Nooit
Alleen van contacten
@@ -519,7 +519,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
1e en 2e klasse mappen
Alle behalve 2e klasse mappen
Geen
- Duw mappen
+ Push mappen
Alle
Alleen 1e klasse mappen
1e en 2e klasse mappen
@@ -545,7 +545,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
1e klasse
2e klasse
Zelfde als weergave klasse
- Duw klasse map
+ Push klasse map
Geen klasse
1e klasse
2e klasse
@@ -554,7 +554,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
Geen klasse
1e klasse
2e klasse
- Zelfde als duw klasse
+ Zelfde als push klasse
Lokale berichten wissen
Inkomende server
Instellen van de inkomende mail server
@@ -671,7 +671,7 @@ Graag foutrapporten sturen, bijdragen voor nieuwe functies en vragen stellen op
Altijd
Als \'Auto-sync\' geselecteerd is
Selecteer alle
- Max mappen om te controleren met duw
+ Max mappen om te controleren met push
5 mappen
10 mappen
25 mappen
@@ -1049,11 +1049,11 @@ U kunt dit bericht bewaren als backup voor uw geheime sleutel. Als u dit wilt do
Doet niets totdat achtergrondsynchronisatie wordt toegestaan
Doet niets totdat er een netwerk beschikbaar is
Tik hier om er meer over te leren.
- Duw informatie
- Als je duw gebruikt, dan houd K-9 mail een verbinding open met de e-mail server. Android vereist dat een app die op de achtergrond actief blijft een melding plaatst. %s
+ Push informatie
+ Als je push gebruikt, dan houd K-9 mail een verbinding open met de e-mail server. Android vereist dat een app die op de achtergrond actief blijft een melding plaatst. %s
Android maakt het echter ook mogelijk om meldingen te verbergen.
Meer leren hierover
Melding instellen
- Als je het niet nodig vindt om per direct meldingen te ontvangen van nieuwe berichten, dan kun je beter duw uitschakelen en in plaats daarvan kiezen voor peilen. Met peilen wordt er om de zoveel tijd gekeken of er nieuwe e-mails zijn binnengekomen. Daarvoor is het weergeven van een melding niet continu nodig.
- Duw uitschakelen
+ Als je het niet nodig vindt om per direct meldingen te ontvangen van nieuwe berichten, dan kun je beter push uitschakelen en in plaats daarvan kiezen voor peilen. Met peilen wordt er om de zoveel tijd gekeken of er nieuwe e-mails zijn binnengekomen. Daarvoor is het weergeven van een melding niet continu nodig.
+ Push uitschakelen
diff --git a/app/ui/legacy/src/main/res/values-pl/strings.xml b/app/ui/legacy/src/main/res/values-pl/strings.xml
index 566a3731ad..f6e56ae4f1 100644
--- a/app/ui/legacy/src/main/res/values-pl/strings.xml
+++ b/app/ui/legacy/src/main/res/values-pl/strings.xml
@@ -441,8 +441,6 @@ Wysłane z urządzenia Android za pomocą K-9 Mail. Proszę wybaczyć moją zwi
Oznacz wiadomość jako przeczytaną przy otwieraniu
Oznacz jako przeczytane po usunięciu
Oznacz wiadomość jako przeczytaną przy usuwaniu
- Ustawienia powiadomień
- Otwórz systemowe ustawienia powiadomień
Zawsze pokazuj obrazki
Nie
Od kontaktów
diff --git a/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml b/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
index 85b774ae2d..7b9566626c 100644
--- a/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
+++ b/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
@@ -436,8 +436,6 @@ Por favor encaminhe relatórios de bugs, contribua com novos recursos e tire dú
Marcar a mensagem como lida quando ela for aberta para visualização
Marcar como lida ao excluir
Marca uma mensagem como lida quando ela for excluída
- Configurações das notificações
- Abrir as configurações de notificações do sistema
Sempre exibir imagens
Não
Dos contatos
diff --git a/app/ui/legacy/src/main/res/values-pt-rPT/strings.xml b/app/ui/legacy/src/main/res/values-pt-rPT/strings.xml
index 217faea703..0bc8cc09ea 100644
--- a/app/ui/legacy/src/main/res/values-pt-rPT/strings.xml
+++ b/app/ui/legacy/src/main/res/values-pt-rPT/strings.xml
@@ -421,8 +421,6 @@ Por favor envie relatórios de falhas, contribua com novas funcionalidades e col
Marcar uma mensagem como lida ao abrir para visualização
Marcar como lida quando apagada
Marcar a mensagem como lida quando é apagada
- Configurações de notificação
- Configurações de sistema aberto
Mostrar sempre as imagens
Não
Apenas dos contactos
diff --git a/app/ui/legacy/src/main/res/values-ro/strings.xml b/app/ui/legacy/src/main/res/values-ro/strings.xml
index c1b06f3540..0d9afa7fe4 100644
--- a/app/ui/legacy/src/main/res/values-ro/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ro/strings.xml
@@ -441,8 +441,6 @@ Uneori datorită faptului că cineva încearcă să te atace pe tine sau serveru
Marchează mesaj ca citit când e deschis pentru vizualizare
Marchează ca citit la ștergere
Marchează un mesaj ca citit când este șters
- Setări notificări
- Deschide setările notificărilor de sistem
Arată întotdeauna imaginile
Nu
De la contacte
diff --git a/app/ui/legacy/src/main/res/values-ru/strings.xml b/app/ui/legacy/src/main/res/values-ru/strings.xml
index cb3e424e63..8f78f20296 100644
--- a/app/ui/legacy/src/main/res/values-ru/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ru/strings.xml
@@ -21,6 +21,9 @@
Список изменений
Не удалось загрузить список изменений.
Версия %s
+ Что нового
+ Показывать последние изменения, когда приложение было обновлено
+ Узнайте, что нового в этом выпуске
Добро пожаловать!
Добавить
Создать
Поиск сообщения
+ Искать везде
Результаты поиска
Настройки
Выбрать папки
@@ -131,6 +135,7 @@ K-9 Mail — почтовый клиент для Android.
- Адреса скопированы в буфер
- Адреса скопированы в буфер
+ Текст темы скопирован в буфер обмена
Тёмная тема
Светлая тема
Не прочитано
@@ -182,6 +187,8 @@ K-9 Mail — почтовый клиент для Android.
Отправка %s
Отправка почты
:
+ Синхронизация (Push)
+ Отображается во время ожидания новых сообщений
Сообщение
Уведомления о сообщениях
Разное
@@ -433,8 +440,8 @@ K-9 Mail — почтовый клиент для Android.
Отметить сообщение прочитанным после просмотра
Отметить как прочитанное при удалении
Отметить как прочитанное при удалении
- Настройки уведомлений
- Открыть настройки уведомлений
+ Настройка уведомлений о новых сообщениях
+ Настройка уведомлений об ошибках и статусе
Показать изображения
Никогда
От контактов
@@ -550,6 +557,7 @@ K-9 Mail — почтовый клиент для Android.
Нет класса
1 класс
2 класс
+ То же, что и класс опроса
Уведомление
Нет класса
1 класс
@@ -1054,4 +1062,16 @@ K-9 Mail — почтовый клиент для Android.
Разрешить доступ к контактам
Чтобы подсказывать имена и показывать фото, приложению нужен доступ к контактам
При загрузке данных возникла ошибка
+ Инициализация…
+ Ожидание новых писем
+ Спящий режим до тех пор, пока не будет разрешена фоновая синхронизация
+ Спящий режим до появления сети
+ Нажмите, чтобы узнать больше.
+ Информация о Push
+ При использовании Push K-9 Mail поддерживает соединение с почтовым сервером. Android требует отображения постоянного уведомления, пока приложение активно в фоновом режиме. %s
+ Однако Android также позволяет скрыть уведомление.
+ Узнать больше
+ Настроить уведомление
+ Если вам не нужны мгновенные уведомления о новых сообщениях, вам следует отключить Push и использовать Опрос. Опрос проверяет наличие новой почты через регулярные промежутки времени и не нуждается в уведомлениях.
+ Отключить Push
diff --git a/app/ui/legacy/src/main/res/values-sk/strings.xml b/app/ui/legacy/src/main/res/values-sk/strings.xml
index ef5a9387c6..8685b09f98 100644
--- a/app/ui/legacy/src/main/res/values-sk/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sk/strings.xml
@@ -434,8 +434,6 @@ Prosím, nahlasujte prípadné chyby, prispievajte novými funkciami a pýtajte
Označiť správu ako prečítanú po jej zobrazení
Pri zmazaní označiť za prečítané
Pri mazaní oznaťič správu ako prečítanú
- Nastavenie notifikácií
- Nastavenie notifikácií v operačnom systéme
Vždy zobraziť obrázky
Nie
Od kontaktov
diff --git a/app/ui/legacy/src/main/res/values-sl/strings.xml b/app/ui/legacy/src/main/res/values-sl/strings.xml
index e091128b58..51586d20f0 100644
--- a/app/ui/legacy/src/main/res/values-sl/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sl/strings.xml
@@ -441,8 +441,6 @@ dodatnih %d sporočil
Ko se sporočilo prvič odpre, naj bo označeno kot prebrano
Ob izbrisu označi kot prebrano
Ob izbrisu označi sporočilo tudi kot prebrano
- Nastavitve za obvestila
- Odpri nastavitve za sistemska obvestila
Prikaz slik
Ne pokaži slik
Pokaži slike znanih stikov
diff --git a/app/ui/legacy/src/main/res/values-sq/strings.xml b/app/ui/legacy/src/main/res/values-sq/strings.xml
index b5713001c0..0c44ddafd0 100644
--- a/app/ui/legacy/src/main/res/values-sq/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sq/strings.xml
@@ -438,8 +438,9 @@ Ju lutemi, parashtrim njoftimesh për të meta, kontribute për veçori të reaj
Shënoje një mesazh të lexuar, kur hapet për parje
Vëri shenjë si i lexuar, kur fshihet
Vërini shenjë si i lexuar një mesazhi, kur fshihet
- Rregullime njoftimesh
- Rregullime njoftimesh sistemi të hapur
+ Kategori njoftimesh
+ Formësoni njoftime për mesazhe të rinj
+ Formësoni njoftime gabimesh dhe gjendjesh
Shfaqi përherë figurat
Jo
Prej kontaktesh
diff --git a/app/ui/legacy/src/main/res/values-sr/strings.xml b/app/ui/legacy/src/main/res/values-sr/strings.xml
index d4d49839d1..0f630e19f5 100644
--- a/app/ui/legacy/src/main/res/values-sr/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sr/strings.xml
@@ -432,8 +432,6 @@
Означава поруку прочитаном када се отвори за приказ
Означи као прочитано по брисању
Означи поруку прочитаном по брисању
- Поставке обавештења
- Отвори системске поставке обавештења
Увек прикажи слике
не
од контаката
diff --git a/app/ui/legacy/src/main/res/values-sv/strings.xml b/app/ui/legacy/src/main/res/values-sv/strings.xml
index 16bbece106..6be880f06f 100644
--- a/app/ui/legacy/src/main/res/values-sv/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sv/strings.xml
@@ -251,9 +251,9 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Korrespondent ovanför ämnesrad
Visar korrespondentens namn ovanför ämnesraden istället för under den
Visa kontaktnamn
- Använd mottagarnas namn från Kontakter om tillgängligt
+ Använd mottagarnas namn från kontakter om tillgängligt
Färglägg kontakter
- Färglägg namn i kontaktlistan
+ Färglägg namn i din kontaktlista
Teckensnitt med fast bredd
Använd ett teckensnitt med fast bredd när meddelanden med enbart oformaterad text visas
Anpassa automatiskt meddelanden
@@ -347,13 +347,13 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Manuellt
Detektera automatiskt namnområde för IMAP
Sökvägsprefix för IMAP
- Namn på utkastmapp
- Namn på skickatmapp
+ Utkastmapp
+ Mappen Skickat
Papperskorgsmapp
- Namn på arkivmapp
+ Arkivmapp
Skräppostmapp
Visa endast prenumererade mappar
- Expandera automatiskt mappen
+ Expandera automatiskt mapp
Sökväg för Outlook Web App
valfritt
Sökväg för autentisering
@@ -437,8 +437,9 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Markera ett meddelande som läst när det visas
Markera som läst när det tas bort
Markera ett meddelande som läst när det tas bort
- Aviseringsinställningar
- Öppna inställningar för systemaviseringar
+ Aviseringskategorier
+ Konfigurera aviseringar för nya meddelanden
+ Konfigurera fel- och statusaviseringar
Visa alltid bilder
Nej
Från kontakter
@@ -461,7 +462,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Prefix (som Gmail)
Rubriker (som Outlook)
Skicka skickade meddelanden
- Överföra meddelanden till mappen Skickat efter sändning
+ Ladda upp meddelanden till mappen Skickat efter sändning
Allmänna inställningar
E-postläsning
E-posthämtning
@@ -877,7 +878,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Visa kontaktbilder
Visa kontaktbilder i meddelandelistan
Markera alla som lästa
- Färglägg bilder på kontakter
+ Färglägg kontaktbilder
Färglägg kontaktbilder som saknas
Synliga meddelandeåtgärder
Visa valda åtgärder i meddelandelistans meny
diff --git a/app/ui/legacy/src/main/res/values-tr/strings.xml b/app/ui/legacy/src/main/res/values-tr/strings.xml
index 20e3d58856..7c9d51608a 100644
--- a/app/ui/legacy/src/main/res/values-tr/strings.xml
+++ b/app/ui/legacy/src/main/res/values-tr/strings.xml
@@ -435,8 +435,6 @@ Microsoft Exchange ile konuşurken bazı tuhaflıklar yaşadığını not ediniz
Mesaj okunmak üzere açıldığında okundu olarak işaretle
Silindiğinde okundu olarak işaretle
Bir ileti silindiğinde okundu olarak işaretlemek
- Bildirim ayarları
- Sistem bildirim ayarlarını aç
Daima resimleri göster
Hayır
Kişilerden
diff --git a/app/ui/legacy/src/main/res/values-uk/strings.xml b/app/ui/legacy/src/main/res/values-uk/strings.xml
index acfba8ba78..c8e230d8ef 100644
--- a/app/ui/legacy/src/main/res/values-uk/strings.xml
+++ b/app/ui/legacy/src/main/res/values-uk/strings.xml
@@ -442,8 +442,9 @@ K-9 Mail — це вільний клієнт електронної пошти
Позначати повідомлення прочитаним після відкриття для перегляду
Позначити прочитаним після видалення
Позначити повідомлення прочитаним після видалення
- Налаштування сповіщень
- Відкрити системні налаштування сповіщень
+ Категорії сповіщень
+ Налаштуйте сповіщення для нових повідомлень
+ Налаштуйте сповіщення про помилки та статуси
Завжди показувати зображення
Ні
Від контактів
diff --git a/app/ui/legacy/src/main/res/values-zh-rCN/strings.xml b/app/ui/legacy/src/main/res/values-zh-rCN/strings.xml
index 4d0ee55b23..6fc74a2249 100644
--- a/app/ui/legacy/src/main/res/values-zh-rCN/strings.xml
+++ b/app/ui/legacy/src/main/res/values-zh-rCN/strings.xml
@@ -435,8 +435,9 @@ K-9 Mail 是 Android 上一款功能强大的免费邮件客户端。
当邮件打开时标记为已读
删除后标记为已读
删除邮件时将其标记为已读
- 通知设置
- 打开系统通知设置
+ 通知类别
+ 配置新消息通知
+ 配置错误和状态通知
显示图片
从不
来自您的联系人的邮件
diff --git a/app/ui/legacy/src/main/res/values-zh-rTW/strings.xml b/app/ui/legacy/src/main/res/values-zh-rTW/strings.xml
index d0e1c9f989..54230d2426 100644
--- a/app/ui/legacy/src/main/res/values-zh-rTW/strings.xml
+++ b/app/ui/legacy/src/main/res/values-zh-rTW/strings.xml
@@ -435,8 +435,6 @@ K-9 Mail 是 Android 上一款功能強大,免費而自由的電子郵件用
開啟檢視郵件內容時自動標記為已讀
刪除後標記為已讀
刪除郵件時將其標記為已讀
- 通知設定
- 開啟系統通知設定
顯示圖片
不要
來自您的聯絡人的郵件
--
GitLab
From acbeff5b986486b30ddf06986daa0739c1263c60 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 12 Aug 2021 11:27:37 +0200
Subject: [PATCH 035/285] Version 5.803
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 8 ++++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index 8f6f3a7f74..e05dde8e1f 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28002
- versionName '5.803-SNAPSHOT'
+ versionCode 28003
+ versionName '5.803'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index ec8a7e8a42..3153968d47 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,14 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Don't show the icon for the ongoing Push notification in the status bar (on versions older than Android 8.0)
+ Directly open system settings for notification categories (Android 8.0 and newer)
+ Fixed a bug where a notification wasn't removed when the associated message was deleted
+ Ignore unnecessary spaces when filtering the list of folders
+ Fixed crypto status icons not being clickable
+ Updated translations
+
Fixed a bug that was triggered when Push was enabled, but the server didn't support Push. If you've noticed high battery drain, this was probably it
Added support for archive and spam actions in the Unified Inbox
--
GitLab
From 6792f27127e2f325d9dc293ac3d6a20ab169d6c3 Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 12 Aug 2021 13:17:04 +0200
Subject: [PATCH 036/285] Prepare for version 5.900
---
app/k9mail/build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index e05dde8e1f..8b330e9fac 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28003
- versionName '5.803'
+ versionCode 29000
+ versionName '5.900-SNAPSHOT'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
--
GitLab
From 7874fe7e11d5c1413e49aae6319844b6a56fccbd Mon Sep 17 00:00:00 2001
From: cketti
Date: Fri, 13 Aug 2021 16:32:30 +0200
Subject: [PATCH 037/285] Properly handle responses to the IDLE command
When waiting for the command continuation request response ignore irrelevant responses and keep track of relevant untagged responses.
---
.../k9/mail/store/imap/RealImapFolderIdler.kt | 24 ++++++++---
.../store/imap/RealImapFolderIdlerTest.kt | 41 +++++++++++++++++++
2 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolderIdler.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolderIdler.kt
index 629c337246..c1c6d711a2 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolderIdler.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolderIdler.kt
@@ -91,13 +91,25 @@ internal class RealImapFolderIdler(
idleSent = true
}
- val initialResponse = connection.readResponse()
- if (!initialResponse.isContinuationRequested) {
- Timber.w("%s.idle(): Received something other than a continuation response", logTag)
- return IdleResult.NOT_SUPPORTED
- }
+ var receivedRelevantResponse = false
+ do {
+ val response = connection.readResponse()
+ if (response.tag == tag) {
+ Timber.w("%s.idle(): IDLE command completed without a continuation request response", logTag)
+ return IdleResult.NOT_SUPPORTED
+ } else if (response.isRelevant) {
+ receivedRelevantResponse = true
+ }
+ } while (!response.isContinuationRequested)
- connection.setSocketIdleReadTimeout()
+ if (receivedRelevantResponse) {
+ Timber.v("%s.idle(): Received a relevant untagged response right after sending IDLE command", logTag)
+ result = IdleResult.SYNC
+ stopIdle = true
+ sendDone()
+ } else {
+ connection.setSocketIdleReadTimeout()
+ }
var response: ImapResponse
do {
diff --git a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderIdlerTest.kt b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderIdlerTest.kt
index 871c584919..fc13a7a5f5 100644
--- a/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderIdlerTest.kt
+++ b/mail/protocols/imap/src/test/java/com/fsck/k9/mail/store/imap/RealImapFolderIdlerTest.kt
@@ -294,6 +294,47 @@ class RealImapFolderIdlerTest {
latch.awaitWithTimeout()
assertThat(imapFolder.isOpen).isFalse()
}
+
+ @Test
+ fun `irrelevant untagged response to IDLE command before continuation request`() {
+ val latch = CountDownLatch(1)
+
+ thread {
+ val idleResult = idler.idle()
+
+ assertThat(idleResult).isEqualTo(IdleResult.STOPPED)
+ latch.countDown()
+ }
+
+ imapConnection.waitForCommand("IDLE")
+ imapConnection.enqueueUntaggedServerResponse("OK irrelevant")
+ imapConnection.enqueueContinuationServerResponse()
+
+ wakeLock.waitForRelease()
+ idler.stop()
+ imapConnection.waitForCommand("DONE")
+ imapConnection.enqueueTaggedServerResponse("OK")
+ latch.awaitWithTimeout()
+ }
+
+ @Test
+ fun `relevant untagged response to IDLE command before continuation request`() {
+ val latch = CountDownLatch(1)
+
+ thread {
+ val idleResult = idler.idle()
+
+ assertThat(idleResult).isEqualTo(IdleResult.SYNC)
+ latch.countDown()
+ }
+
+ imapConnection.waitForCommand("IDLE")
+ imapConnection.enqueueUntaggedServerResponse("1 EXISTS")
+ imapConnection.enqueueContinuationServerResponse()
+ imapConnection.waitForCommand("DONE")
+ imapConnection.enqueueTaggedServerResponse("OK")
+ latch.awaitWithTimeout()
+ }
}
private fun CountDownLatch.awaitWithTimeout() {
--
GitLab
From 388bfec9aa2ce75e370955c26df6b7e5b2780049 Mon Sep 17 00:00:00 2001
From: G
Date: Fri, 13 Aug 2021 18:06:55 +0200
Subject: [PATCH 038/285] Show scrollbar in manage folders and choose folder
lists
---
app/ui/legacy/src/main/res/layout/folder_list.xml | 1 +
app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml | 1 +
2 files changed, 2 insertions(+)
diff --git a/app/ui/legacy/src/main/res/layout/folder_list.xml b/app/ui/legacy/src/main/res/layout/folder_list.xml
index 5d8925d523..0bac5bb9b3 100644
--- a/app/ui/legacy/src/main/res/layout/folder_list.xml
+++ b/app/ui/legacy/src/main/res/layout/folder_list.xml
@@ -13,6 +13,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
+ android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/folder_list_item" />
diff --git a/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml b/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
index d118d1f7c0..2ac0f841b2 100644
--- a/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
+++ b/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
@@ -5,5 +5,6 @@
android:id="@+id/folderList"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/folder_list_item" />
--
GitLab
From f9c56e7db020ed8dadfe719b50bbf98172cd5f7b Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 10 Aug 2021 16:58:01 +0200
Subject: [PATCH 039/285] Upgrade to targetSkdVersion 30
---
app/ui/legacy/src/main/AndroidManifest.xml | 43 ++++++++++++++++++-
.../endtoend/AutocryptKeyTransferActivity.kt | 4 +-
.../AutocryptSetupMessageLiveEvent.kt | 2 +-
build.gradle | 8 ++--
4 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/app/ui/legacy/src/main/AndroidManifest.xml b/app/ui/legacy/src/main/AndroidManifest.xml
index 13dc11d980..4b3be66017 100644
--- a/app/ui/legacy/src/main/AndroidManifest.xml
+++ b/app/ui/legacy/src/main/AndroidManifest.xml
@@ -1,2 +1,43 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt
index c98a0d3530..7d6c92b6ba 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptKeyTransferActivity.kt
@@ -62,8 +62,8 @@ class AutocryptKeyTransferActivity : K9Activity() {
presenter.initFromIntent(accountUuid)
}
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- if (item?.itemId == android.R.id.home) {
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
presenter.onClickHome()
return true
} else {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptSetupMessageLiveEvent.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptSetupMessageLiveEvent.kt
index ffe9738e3b..4ec55169d9 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptSetupMessageLiveEvent.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/endtoend/AutocryptSetupMessageLiveEvent.kt
@@ -34,7 +34,7 @@ class AutocryptSetupMessageLiveEvent(val messageCreator: AutocryptTransferMessag
val result = openPgpApi.executeApi(intent, null as InputStream?, baos)
val keyData = baos.toByteArray()
- val pi: PendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)
+ val pi: PendingIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT) ?: error("Missing result intent")
val setupMessage = messageCreator.createAutocryptTransferMessage(keyData, address)
diff --git a/build.gradle b/build.gradle
index 4b3da118fe..1963fc4a69 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,11 +3,11 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
buildscript {
ext {
buildConfig = [
- 'compileSdk': 29,
- 'targetSdk': 29,
+ 'compileSdk': 30,
+ 'targetSdk': 30,
'minSdk': 21,
- 'buildTools': '29.0.3',
- 'robolectricSdk': 29
+ 'buildTools': '30.0.3',
+ 'robolectricSdk': 30
]
versions = [
--
GitLab
From d042340596bf2755ac835172c19fcc0811d79607 Mon Sep 17 00:00:00 2001
From: G
Date: Fri, 13 Aug 2021 18:06:55 +0200
Subject: [PATCH 040/285] Show scrollbar in manage folders and choose folder
lists
---
app/ui/legacy/src/main/res/layout/folder_list.xml | 1 +
app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml | 1 +
2 files changed, 2 insertions(+)
diff --git a/app/ui/legacy/src/main/res/layout/folder_list.xml b/app/ui/legacy/src/main/res/layout/folder_list.xml
index 5d8925d523..0bac5bb9b3 100644
--- a/app/ui/legacy/src/main/res/layout/folder_list.xml
+++ b/app/ui/legacy/src/main/res/layout/folder_list.xml
@@ -13,6 +13,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
+ android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/folder_list_item" />
diff --git a/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml b/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
index d118d1f7c0..2ac0f841b2 100644
--- a/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
+++ b/app/ui/legacy/src/main/res/layout/fragment_manage_folders.xml
@@ -5,5 +5,6 @@
android:id="@+id/folderList"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/folder_list_item" />
--
GitLab
From 70e5b203f6d1b2ed28c7fd75c357a2299f503f86 Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 16 Aug 2021 23:52:11 +0200
Subject: [PATCH 041/285] Make sure the app icon always brings the app to the
foreground
---
.../src/main/java/com/fsck/k9/activity/MessageList.kt | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
index 29a44645d5..a244c022d9 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/MessageList.kt
@@ -132,6 +132,16 @@ open class MessageList :
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ // If the app's main task was not created using the default launch intent (e.g. from a notification, a widget,
+ // or a shortcut), using the app icon to "launch" the app will create a new MessageList instance instead of only
+ // bringing the app's task to the foreground. We catch this situation here and simply finish the activity. This
+ // will bring the task to the foreground, showing the last active screen.
+ if (intent.action == Intent.ACTION_MAIN && intent.hasCategory(Intent.CATEGORY_LAUNCHER) && !isTaskRoot) {
+ Timber.v("Not displaying MessageList. Only bringing the app task to the foreground.")
+ finish()
+ return
+ }
+
val accounts = preferences.accounts
deleteIncompleteAccounts(accounts)
val hasAccountSetup = accounts.any { it.isFinishedSetup }
--
GitLab
From 46c4e6fd8d82e59073c70fe5027b19def91e3ebb Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 17 Aug 2021 00:53:06 +0200
Subject: [PATCH 042/285] Don't connect to server when incoming/outgoing server
passwords are missing
If a user imports an account but doesn't provide server passwords, don't attempt to connect to the incoming or outgoing server of that account.
---
.../k9/controller/MessagingController.java | 19 +++++++++++++++++++
.../java/com/fsck/k9/job/MailSyncWorker.kt | 5 +++++
.../controller/MessagingControllerTest.java | 8 ++++++++
3 files changed, 32 insertions(+)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 7163226055..b74b107988 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -64,6 +64,7 @@ import com.fsck.k9.mail.MessageDownloadState;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
+import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
@@ -390,6 +391,12 @@ public class MessagingController {
public void refreshFolderListSynchronous(Account account) {
try {
+ ServerSettings serverSettings = account.getIncomingServerSettings();
+ if (serverSettings.password == null) {
+ handleAuthenticationFailure(account, true);
+ return;
+ }
+
Backend backend = getBackend(account);
backend.refreshFolderList();
@@ -643,6 +650,12 @@ public class MessagingController {
}
private void syncFolder(Account account, long folderId, MessagingListener listener, Backend backend) {
+ ServerSettings serverSettings = account.getIncomingServerSettings();
+ if (serverSettings.password == null) {
+ handleAuthenticationFailure(account, true);
+ return;
+ }
+
Exception commandException = null;
try {
processPendingCommandsSynchronous(account);
@@ -1498,6 +1511,12 @@ public class MessagingController {
Exception lastFailure = null;
boolean wasPermanentFailure = false;
try {
+ ServerSettings serverSettings = account.getOutgoingServerSettings();
+ if (serverSettings.password == null) {
+ handleAuthenticationFailure(account, false);
+ return;
+ }
+
LocalStore localStore = localStoreProvider.getInstance(account);
OutboxStateRepository outboxStateRepository = localStore.getOutboxStateRepository();
LocalFolder localFolder = localStore.getFolder(account.getOutboxFolderId());
diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
index bb1237c103..53eba91622 100644
--- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
+++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
@@ -39,6 +39,11 @@ class MailSyncWorker(
return Result.success()
}
+ if (account.incomingServerSettings.password == null) {
+ Timber.d("Password for this account is missing. Skipping mail sync.")
+ return Result.success()
+ }
+
val success = messagingController.performPeriodicMailSync(account)
return if (success) Result.success() else Result.retry()
diff --git a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
index c7e6429b52..dd3fde43a4 100644
--- a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
+++ b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
@@ -14,11 +14,14 @@ import com.fsck.k9.K9RobolectricTest;
import com.fsck.k9.Preferences;
import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
+import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
+import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
+import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
@@ -31,6 +34,7 @@ import com.fsck.k9.mailstore.SendState;
import com.fsck.k9.mailstore.UnavailableStorageException;
import com.fsck.k9.notification.NotificationController;
import com.fsck.k9.notification.NotificationStrategy;
+import com.fsck.k9.preferences.Protocols;
import com.fsck.k9.search.LocalSearch;
import com.fsck.k9.search.SearchAccount;
import org.jetbrains.annotations.NotNull;
@@ -441,6 +445,10 @@ public class MessagingControllerTest extends K9RobolectricTest {
account = preferences.newAccount();
accountUuid = account.getUuid();
+ account.setIncomingServerSettings(new ServerSettings(Protocols.IMAP, "host", 993,
+ ConnectionSecurity.SSL_TLS_REQUIRED, AuthType.PLAIN, "username", "password", null));
+ account.setOutgoingServerSettings(new ServerSettings(Protocols.SMTP, "host", 465,
+ ConnectionSecurity.SSL_TLS_REQUIRED, AuthType.PLAIN, "username", "password", null));
account.setMaximumAutoDownloadMessageSize(MAXIMUM_SMALL_MESSAGE_SIZE);
account.setEmail("user@host.com");
}
--
GitLab
From 4729ae044ac0c13cc4e92fb9e6f80a3afc72de53 Mon Sep 17 00:00:00 2001
From: Andrew Fiddian-Green
Date: Wed, 4 Aug 2021 11:59:57 +0100
Subject: [PATCH 043/285] Optionally show starred message count in navigation
drawer
---
app/core/src/main/java/com/fsck/k9/K9.kt | 5 ++
.../java/com/fsck/k9/controller/KoinModule.kt | 4 ++
.../k9/controller/MessageCountsProvider.kt | 68 +++++++++++++++++++
.../k9/controller/MessagingController.java | 16 ++++-
.../com/fsck/k9/mailstore/FolderMapper.kt | 3 +-
.../com/fsck/k9/mailstore/FolderRepository.kt | 6 +-
.../com/fsck/k9/mailstore/LocalFolder.java | 35 ++++++++++
.../com/fsck/k9/mailstore/LocalStore.java | 35 ++++++++++
.../GeneralSettingsDescriptions.java | 3 +
.../com/fsck/k9/preferences/Settings.java | 2 +-
.../controller/MessagingControllerTest.java | 18 ++++-
.../messages/RetrieveFolderOperations.kt | 11 ++-
.../messages/RetrieveFolderOperationsTest.kt | 2 +-
.../src/main/java/com/fsck/k9/ui/K9Drawer.kt | 56 ++++++++++++---
.../fsck/k9/ui/account/AccountsViewModel.kt | 21 +++---
.../com/fsck/k9/ui/account/DisplayAccount.kt | 3 +-
.../java/com/fsck/k9/ui/account/KoinModule.kt | 2 +-
.../general/GeneralSettingsDataStore.kt | 2 +
app/ui/legacy/src/main/res/values/strings.xml | 1 +
.../src/main/res/xml/general_settings.xml | 4 ++
20 files changed, 266 insertions(+), 31 deletions(-)
create mode 100644 app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
diff --git a/app/core/src/main/java/com/fsck/k9/K9.kt b/app/core/src/main/java/com/fsck/k9/K9.kt
index 3a40b2cbbb..de0deea9e4 100644
--- a/app/core/src/main/java/com/fsck/k9/K9.kt
+++ b/app/core/src/main/java/com/fsck/k9/K9.kt
@@ -206,6 +206,9 @@ object K9 : EarlyInit {
@JvmStatic
var isShowUnifiedInbox = true
+ @JvmStatic
+ var isShowStarredCount = false
+
@JvmStatic
var isAutoFitWidth: Boolean = false
@@ -307,6 +310,7 @@ object K9 : EarlyInit {
isUseVolumeKeysForNavigation = storage.getBoolean("useVolumeKeysForNavigation", false)
isUseVolumeKeysForListNavigation = storage.getBoolean("useVolumeKeysForListNavigation", false)
isShowUnifiedInbox = storage.getBoolean("showUnifiedInbox", true)
+ isShowStarredCount = storage.getBoolean("showStarredCount", false)
isMessageListSenderAboveSubject = storage.getBoolean("messageListSenderAboveSubject", false)
isShowMessageListStars = storage.getBoolean("messageListStars", true)
messageListPreviewLines = storage.getInt("messageListPreviewLines", 2)
@@ -392,6 +396,7 @@ object K9 : EarlyInit {
editor.putBoolean("messageListSenderAboveSubject", isMessageListSenderAboveSubject)
editor.putBoolean("showUnifiedInbox", isShowUnifiedInbox)
+ editor.putBoolean("showStarredCount", isShowStarredCount)
editor.putBoolean("messageListStars", isShowMessageListStars)
editor.putInt("messageListPreviewLines", messageListPreviewLines)
editor.putBoolean("showCorrespondentNames", isShowCorrespondentNames)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
index eedc4b2172..38f7552c68 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
@@ -1,6 +1,8 @@
package com.fsck.k9.controller
import android.content.Context
+import com.fsck.k9.DefaultMessageCountsProvider
+import com.fsck.k9.MessageCountsProvider
import com.fsck.k9.Preferences
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.mailstore.LocalStoreProvider
@@ -19,6 +21,7 @@ val controllerModule = module {
get(),
get(),
get(),
+ get(),
get(),
get(),
get(),
@@ -27,4 +30,5 @@ val controllerModule = module {
)
}
single { DefaultUnreadMessageCountProvider(get(), get(), get(), get()) }
+ single { DefaultMessageCountsProvider(get(), get(), get(), get()) }
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt b/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
new file mode 100644
index 0000000000..fcb45b563d
--- /dev/null
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
@@ -0,0 +1,68 @@
+package com.fsck.k9
+
+import android.content.Context
+import com.fsck.k9.mail.MessagingException
+import com.fsck.k9.mailstore.LocalStoreProvider
+import com.fsck.k9.search.AccountSearchConditions
+import com.fsck.k9.search.LocalSearch
+import com.fsck.k9.search.SearchAccount
+import com.fsck.k9.search.getAccounts
+import timber.log.Timber
+
+interface MessageCountsProvider {
+ fun getMessageCounts(account: Account): MessageCounts
+ fun getMessageCounts(searchAccount: SearchAccount): MessageCounts
+}
+
+data class MessageCounts(val unread: Int, val starred: Int)
+
+internal class DefaultMessageCountsProvider(
+ private val context: Context,
+ private val preferences: Preferences,
+ private val accountSearchConditions: AccountSearchConditions,
+ private val localStoreProvider: LocalStoreProvider
+) : MessageCountsProvider {
+ override fun getMessageCounts(account: Account): MessageCounts {
+ if (!account.isAvailable(context)) {
+ return MessageCounts(0, 0)
+ }
+
+ return try {
+ val localStore = localStoreProvider.getInstance(account)
+
+ val search = LocalSearch()
+ accountSearchConditions.excludeSpecialFolders(account, search)
+ accountSearchConditions.limitToDisplayableFolders(account, search)
+
+ localStore.getMessageCounts(search)
+ } catch (e: MessagingException) {
+ Timber.e(e, "Unable to getMessageCounts for account: %s", account)
+ return MessageCounts(0, 0)
+ }
+ }
+
+ override fun getMessageCounts(searchAccount: SearchAccount): MessageCounts {
+ val search = searchAccount.relatedSearch
+ val accounts = search.getAccounts(preferences)
+
+ var unreadCount = 0
+ var starredCount = 0
+ for (account in accounts) {
+ var accountMessageCount = getMessageCountsWithLocalSearch(account, search)
+ unreadCount += accountMessageCount.unread
+ starredCount += accountMessageCount.starred
+ }
+
+ return MessageCounts(unreadCount, starredCount)
+ }
+
+ private fun getMessageCountsWithLocalSearch(account: Account, search: LocalSearch): MessageCounts {
+ return try {
+ val localStore = localStoreProvider.getInstance(account)
+ localStore.getMessageCounts(search)
+ } catch (e: MessagingException) {
+ Timber.e(e, "Unable to getMessageCounts for account: %s", account)
+ return MessageCounts(0, 0)
+ }
+ }
+}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 7163226055..71dc79a807 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -34,6 +34,8 @@ import com.fsck.k9.Account.DeletePolicy;
import com.fsck.k9.Account.Expunge;
import com.fsck.k9.DI;
import com.fsck.k9.K9;
+import com.fsck.k9.MessageCounts;
+import com.fsck.k9.MessageCountsProvider;
import com.fsck.k9.Preferences;
import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
@@ -126,6 +128,7 @@ public class MessagingController {
private final ExecutorService threadPool = Executors.newCachedThreadPool();
private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
private final UnreadMessageCountProvider unreadMessageCountProvider;
+ private final MessageCountsProvider messageCountsProvider;
private final DraftOperations draftOperations;
@@ -140,14 +143,15 @@ public class MessagingController {
MessagingController(Context context, NotificationController notificationController,
NotificationStrategy notificationStrategy, LocalStoreProvider localStoreProvider,
- UnreadMessageCountProvider unreadMessageCountProvider, BackendManager backendManager,
- Preferences preferences, MessageStoreManager messageStoreManager,
+ UnreadMessageCountProvider unreadMessageCountProvider, MessageCountsProvider messageCountsProvider,
+ BackendManager backendManager, Preferences preferences, MessageStoreManager messageStoreManager,
SaveMessageDataCreator saveMessageDataCreator, List controllerExtensions) {
this.context = context;
this.notificationController = notificationController;
this.notificationStrategy = notificationStrategy;
this.localStoreProvider = localStoreProvider;
this.unreadMessageCountProvider = unreadMessageCountProvider;
+ this.messageCountsProvider = messageCountsProvider;
this.backendManager = backendManager;
this.preferences = preferences;
this.messageStoreManager = messageStoreManager;
@@ -1683,6 +1687,14 @@ public class MessagingController {
return unreadMessageCountProvider.getUnreadMessageCount(searchAccount);
}
+ public MessageCounts getMessageCounts(Account account) {
+ return messageCountsProvider.getMessageCounts(account);
+ }
+
+ public MessageCounts getMessageCounts(SearchAccount searchAccount) {
+ return messageCountsProvider.getMessageCounts(searchAccount);
+ }
+
public int getFolderUnreadMessageCount(Account account, Long folderId) throws MessagingException {
LocalStore localStore = localStoreProvider.getInstance(account);
LocalFolder localFolder = localStore.getFolder(folderId);
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt b/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
index f283618e82..ac988cb646 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
@@ -21,7 +21,8 @@ interface FolderDetailsAccessor {
val pushClass: FolderClass
val visibleLimit: Int
val moreMessages: MoreMessages
- val messageCount: Int
+ val unreadMessageCount: Int
+ val starredMessageCount: Int
fun serverIdOrThrow(): String
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt b/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
index d211dbb52c..5d0914437b 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
@@ -47,7 +47,8 @@ class FolderRepository(
isLocalOnly = folder.isLocalOnly
),
isInTopGroup = folder.isInTopGroup,
- unreadCount = folder.messageCount
+ unreadMessageCount = folder.unreadMessageCount,
+ starredMessageCount = folder.starredMessageCount
)
}.sortedWith(sortForDisplay)
}
@@ -271,7 +272,8 @@ data class RemoteFolderDetails(
data class DisplayFolder(
val folder: Folder,
val isInTopGroup: Boolean,
- val unreadCount: Int
+ val unreadMessageCount: Int,
+ val starredMessageCount: Int
)
enum class FolderType {
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
index 8ef74657a8..81a8e5f41b 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
@@ -10,6 +10,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
+import com.fsck.k9.MessageCounts;
import com.fsck.k9.controller.MessageReference;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.Utility;
@@ -286,6 +287,10 @@ public class LocalFolder {
}
}
+ public MessageCounts getMessageCounts() throws MessagingException {
+ return new MessageCounts(getUnreadMessageCount(), getStarredMessageCount());
+ }
+
public int getUnreadMessageCount() throws MessagingException {
if (databaseId == -1L) {
open();
@@ -316,6 +321,36 @@ public class LocalFolder {
}
}
+ private int getStarredMessageCount() throws MessagingException {
+ if (databaseId == -1L) {
+ open();
+ }
+
+ try {
+ return this.localStore.getDatabase().execute(false, new DbCallback() {
+ @Override
+ public Integer doDbWork(final SQLiteDatabase db) throws WrappedException {
+ int unreadMessageCount = 0;
+ Cursor cursor = db.query("messages", new String[] { "COUNT(id)" },
+ "folder_id = ? AND empty = 0 AND deleted = 0 AND flagged=1",
+ new String[] { Long.toString(databaseId) }, null, null, null);
+
+ try {
+ if (cursor.moveToFirst()) {
+ unreadMessageCount = cursor.getInt(0);
+ }
+ } finally {
+ cursor.close();
+ }
+
+ return unreadMessageCount;
+ }
+ });
+ } catch (WrappedException e) {
+ throw(MessagingException) e.getCause();
+ }
+ }
+
public void setLastChecked(final long lastChecked) throws MessagingException {
try {
open();
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index 01c8dbd668..ddbb1c2a95 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -31,6 +31,7 @@ import com.fsck.k9.Account;
import com.fsck.k9.Clock;
import com.fsck.k9.DI;
import com.fsck.k9.K9;
+import com.fsck.k9.MessageCounts;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
import com.fsck.k9.controller.PendingCommandSerializer;
@@ -1275,6 +1276,40 @@ public class LocalStore {
});
}
+ private int getStarredMessageCount(LocalSearch search) throws MessagingException {
+ StringBuilder whereBuilder = new StringBuilder();
+ List queryArgs = new ArrayList<>();
+ SqlQueryBuilder.buildWhereClause(account, search.getConditions(), whereBuilder, queryArgs);
+
+ String where = whereBuilder.toString();
+ final String[] selectionArgs = queryArgs.toArray(new String[queryArgs.size()]);
+
+ final String sqlQuery = "SELECT SUM(flagged=1) " +
+ "FROM messages " +
+ "JOIN folders ON (folders.id = messages.folder_id) " +
+ "WHERE (messages.empty = 0 AND messages.deleted = 0)" +
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : "");
+
+ return database.execute(false, new DbCallback() {
+ @Override
+ public Integer doDbWork(SQLiteDatabase db) throws WrappedException, MessagingException {
+ Cursor cursor = db.rawQuery(sqlQuery, selectionArgs);
+ try {
+ if (cursor.moveToFirst()) {
+ return cursor.getInt(0);
+ } else {
+ return 0;
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ });
+ }
+
+ public MessageCounts getMessageCounts(LocalSearch search) throws MessagingException {
+ return new MessageCounts(getUnreadMessageCount(search), getStarredMessageCount(search));
+ }
public static String getColumnNameForFlag(Flag flag) {
switch (flag) {
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java b/app/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java
index d0cd532204..5f517fdeec 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java
+++ b/app/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java
@@ -283,6 +283,9 @@ public class GeneralSettingsDescriptions {
s.put("showRecentChanges", Settings.versions(
new V(73, new BooleanSetting(true))
));
+ s.put("showStarredCount", Settings.versions(
+ new V(75, new BooleanSetting(false))
+ ));
SETTINGS = Collections.unmodifiableMap(s);
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/Settings.java b/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
index 08ace7bc54..1be24c74da 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
+++ b/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
@@ -36,7 +36,7 @@ public class Settings {
*
* @see SettingsExporter
*/
- public static final int VERSION = 74;
+ public static final int VERSION = 75;
static Map validate(int version, Map> settings,
Map importedSettings, boolean useDefaultValues) {
diff --git a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
index c7e6429b52..387351751f 100644
--- a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
+++ b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
@@ -11,6 +11,8 @@ import android.content.Context;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.K9RobolectricTest;
+import com.fsck.k9.MessageCounts;
+import com.fsck.k9.MessageCountsProvider;
import com.fsck.k9.Preferences;
import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
@@ -122,6 +124,18 @@ public class MessagingControllerTest extends K9RobolectricTest {
}
};
+ private MessageCountsProvider messageCountsProvider = new MessageCountsProvider() {
+ @Override
+ public MessageCounts getMessageCounts(@NotNull SearchAccount searchAccount) {
+ return new MessageCounts(0, 0);
+ }
+
+ @Override
+ public MessageCounts getMessageCounts(@NotNull Account account) {
+ return new MessageCounts(0, 0);
+ }
+ };
+
private Preferences preferences;
private String accountUuid;
@@ -135,8 +149,8 @@ public class MessagingControllerTest extends K9RobolectricTest {
preferences = Preferences.getPreferences(appContext);
controller = new MessagingController(appContext, notificationController, notificationStrategy,
- localStoreProvider, unreadMessageCountProvider, backendManager, preferences, messageStoreManager,
- saveMessageDataCreator, Collections.emptyList());
+ localStoreProvider, unreadMessageCountProvider, messageCountsProvider, backendManager, preferences,
+ messageStoreManager, saveMessageDataCreator, Collections.emptyList());
configureAccount();
configureBackendManager();
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
index abe16112b4..3e75d04d57 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
@@ -74,6 +74,12 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa
WHERE messages.folder_id = folders.id
AND messages.empty = 0 AND messages.deleted = 0
AND (messages.read = 0 OR folders.id = ?)
+ ), (
+ SELECT COUNT(messages.id)
+ FROM messages
+ WHERE messages.folder_id = folders.id
+ AND messages.empty = 0 AND messages.deleted = 0
+ AND messages.flagged = 1
)
FROM folders
$displayModeSelection
@@ -165,9 +171,12 @@ private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor {
override val moreMessages: MoreMessages
get() = MoreMessages.fromDatabaseName(cursor.getString(12))
- override val messageCount: Int
+ override val unreadMessageCount: Int
get() = cursor.getInt(13)
+ override val starredMessageCount: Int
+ get() = cursor.getInt(14)
+
override fun serverIdOrThrow(): String {
return serverId ?: error("No server ID found for folder '$name' ($id)")
}
diff --git a/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt b/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
index 4ab153ec24..7c4ac8f169 100644
--- a/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
+++ b/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
@@ -269,7 +269,7 @@ class RetrieveFolderOperationsTest : RobolectricTest() {
displayMode = FolderMode.ALL,
outboxFolderId = folderId2
) { folder ->
- Triple(folder.id, folder.name, folder.messageCount)
+ Triple(folder.id, folder.name, folder.unreadMessageCount)
}
assertThat(result).hasSize(4)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
index 3b35340f93..7f9027aa35 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
@@ -14,6 +14,7 @@ import androidx.drawerlayout.widget.DrawerLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.fsck.k9.Account
import com.fsck.k9.K9
+import com.fsck.k9.MessageCounts
import com.fsck.k9.activity.MessageList
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.controller.SimpleMessagingListener
@@ -162,6 +163,26 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
}
+ /**
+ * Format the unread and starred counts for display in the fragment Badge box
+ */
+ private fun formatBadgeText(messageCounts: MessageCounts): String {
+ var badgeText = ""
+ if (K9.isShowStarredCount) {
+ if (messageCounts.unread > 0) {
+ badgeText = "\u2B24\u2009" + messageCounts.unread.toString()
+ }
+ if (messageCounts.starred > 0) {
+ badgeText = badgeText + "\u2000\u2605\u2009" + messageCounts.starred.toString()
+ }
+ } else {
+ if (messageCounts.unread > 0) {
+ badgeText = messageCounts.unread.toString()
+ }
+ }
+ return badgeText.trim()
+ }
+
private fun setAccounts(displayAccounts: List) {
val oldSelectedBackgroundColor = selectedBackgroundColor
@@ -183,12 +204,13 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
descriptionTextColor = selectedTextColor
selectedColorInt = drawerColors.selectedColor
icon = ImageHolder(createAccountImageUri(account))
- displayAccount.unreadCount.takeIf { it > 0 }?.let { unreadCount ->
- badgeText = unreadCount.toString()
- badgeStyle = BadgeStyle().apply {
- textColorStateList = selectedTextColor
+ formatBadgeText(displayAccount.messageCounts).takeIf { it.isNotEmpty() }
+ ?.let { bText ->
+ badgeText = bText
+ badgeStyle = BadgeStyle().apply {
+ textColorStateList = selectedTextColor
+ }
}
- }
}
if (account.uuid == openedAccountUuid) {
@@ -305,6 +327,16 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
selectedColorInt = selectedBackgroundColor
textColor = selectedTextColor
isSelected = unifiedInboxSelected
+
+ // TODO: get the real message counts from the back end
+ var messageCounts = MessageCounts(0, 0)
+ formatBadgeText(messageCounts).takeIf { it.isNotEmpty() }
+ ?.let { bText ->
+ badgeText = bText
+ badgeStyle = BadgeStyle().apply {
+ textColorStateList = selectedTextColor
+ }
+ }
}
sliderView.addItems(unifiedInboxItem)
@@ -328,10 +360,16 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
identifier = drawerId
tag = folder
nameText = getFolderDisplayName(folder)
- displayFolder.unreadCount.takeIf { it > 0 }?.let {
- badgeText = it.toString()
- badgeStyle = folderBadgeStyle
- }
+ formatBadgeText(
+ MessageCounts(
+ displayFolder.unreadMessageCount,
+ displayFolder.starredMessageCount
+ )
+ ).takeIf { it.isNotEmpty() }
+ ?.let { bText ->
+ badgeText = bText
+ badgeStyle = folderBadgeStyle
+ }
selectedColorInt = selectedBackgroundColor
textColor = selectedTextColor
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
index ca4d6ccfdb..beaa638687 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
@@ -9,8 +9,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import com.fsck.k9.Account
import com.fsck.k9.AccountsChangeListener
+import com.fsck.k9.MessageCounts
+import com.fsck.k9.MessageCountsProvider
import com.fsck.k9.Preferences
-import com.fsck.k9.controller.UnreadMessageCountProvider
import com.fsck.k9.provider.EmailProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -25,7 +26,7 @@ import kotlinx.coroutines.launch
@OptIn(ExperimentalCoroutinesApi::class)
class AccountsViewModel(
private val preferences: Preferences,
- private val unreadMessageCountProvider: UnreadMessageCountProvider,
+ private val messageCountsProvider: MessageCountsProvider,
private val contentResolver: ContentResolver
) : ViewModel() {
private val accountsFlow: Flow> =
@@ -46,27 +47,27 @@ class AccountsViewModel(
private val displayAccountFlow: Flow> = accountsFlow
.flatMapLatest { accounts ->
- val unreadCountFlows: List> = accounts.map { account ->
- getUnreadCountFlow(account)
+ val messageCountsFlows: List> = accounts.map { account ->
+ getMessageCountsFlow(account)
}
- combine(unreadCountFlows) { unreadCounts ->
- unreadCounts.mapIndexed { index, unreadCount ->
- DisplayAccount(account = accounts[index], unreadCount)
+ combine(messageCountsFlows) { messageCountsList ->
+ messageCountsList.mapIndexed { index, messageCounts ->
+ DisplayAccount(account = accounts[index], messageCounts)
}
}
}
- private fun getUnreadCountFlow(account: Account): Flow {
+ private fun getMessageCountsFlow(account: Account): Flow {
return callbackFlow {
val notificationUri = EmailProvider.getNotificationUri(account.uuid)
- send(unreadMessageCountProvider.getUnreadMessageCount(account))
+ send(messageCountsProvider.getMessageCounts(account))
val contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {
override fun onChange(selfChange: Boolean) {
launch {
- send(unreadMessageCountProvider.getUnreadMessageCount(account))
+ send(messageCountsProvider.getMessageCounts(account))
}
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
index 530919e86d..ce4a318f2c 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
@@ -1,5 +1,6 @@
package com.fsck.k9.ui.account
import com.fsck.k9.Account
+import com.fsck.k9.MessageCounts
-data class DisplayAccount(val account: Account, val unreadCount: Int)
+data class DisplayAccount(val account: Account, val messageCounts: MessageCounts)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/KoinModule.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/KoinModule.kt
index 42f0737796..074902aefd 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/KoinModule.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/KoinModule.kt
@@ -4,7 +4,7 @@ import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val accountUiModule = module {
- viewModel { AccountsViewModel(preferences = get(), unreadMessageCountProvider = get(), contentResolver = get()) }
+ viewModel { AccountsViewModel(preferences = get(), messageCountsProvider = get(), contentResolver = get()) }
factory { AccountImageLoader(accountFallbackImageProvider = get()) }
factory { AccountFallbackImageProvider(context = get()) }
factory { AccountImageModelLoaderFactory(contactPhotoLoader = get(), accountFallbackImageProvider = get()) }
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt
index b852350878..bae369fde3 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/general/GeneralSettingsDataStore.kt
@@ -19,6 +19,7 @@ class GeneralSettingsDataStore(
"fixed_message_view_theme" -> K9.isFixedMessageViewTheme
"animations" -> K9.isShowAnimations
"show_unified_inbox" -> K9.isShowUnifiedInbox
+ "show_starred_count" -> K9.isShowStarredCount
"messagelist_stars" -> K9.isShowMessageListStars
"messagelist_show_correspondent_names" -> K9.isShowCorrespondentNames
"messagelist_sender_above_subject" -> K9.isMessageListSenderAboveSubject
@@ -47,6 +48,7 @@ class GeneralSettingsDataStore(
"fixed_message_view_theme" -> K9.isFixedMessageViewTheme = value
"animations" -> K9.isShowAnimations = value
"show_unified_inbox" -> K9.isShowUnifiedInbox = value
+ "show_starred_count" -> K9.isShowStarredCount = value
"messagelist_stars" -> K9.isShowMessageListStars = value
"messagelist_show_correspondent_names" -> K9.isShowCorrespondentNames = value
"messagelist_sender_above_subject" -> K9.isMessageListSenderAboveSubject = value
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index c96929a978..a20f106b78 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -834,6 +834,7 @@ Please submit bug reports, contribute new features and ask questions at
In list views
Show Unified Inbox
+ Show starred count
%s %s
- Unread
diff --git a/app/ui/legacy/src/main/res/xml/general_settings.xml b/app/ui/legacy/src/main/res/xml/general_settings.xml
index 0367032b72..f90fefd0d8 100644
--- a/app/ui/legacy/src/main/res/xml/general_settings.xml
+++ b/app/ui/legacy/src/main/res/xml/general_settings.xml
@@ -244,6 +244,10 @@
android:key="show_unified_inbox"
android:title="@string/show_unified_inbox_title" />
+
+
Date: Tue, 17 Aug 2021 19:49:00 +0200
Subject: [PATCH 044/285] Code cleanup
---
.../java/com/fsck/k9/controller/KoinModule.kt | 2 -
.../k9/controller/MessageCountsProvider.kt | 10 +-
.../k9/controller/MessagingController.java | 10 --
.../com/fsck/k9/mailstore/LocalFolder.java | 10 +-
.../com/fsck/k9/mailstore/LocalStore.java | 2 +-
.../controller/MessagingControllerTest.java | 2 -
.../src/main/java/com/fsck/k9/ui/K9Drawer.kt | 93 ++++++++++---------
.../fsck/k9/ui/account/AccountsViewModel.kt | 10 +-
.../com/fsck/k9/ui/account/DisplayAccount.kt | 7 +-
9 files changed, 75 insertions(+), 71 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
index 38f7552c68..252ad0fe14 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
@@ -1,8 +1,6 @@
package com.fsck.k9.controller
import android.content.Context
-import com.fsck.k9.DefaultMessageCountsProvider
-import com.fsck.k9.MessageCountsProvider
import com.fsck.k9.Preferences
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.mailstore.LocalStoreProvider
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt b/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
index fcb45b563d..41100c7884 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessageCountsProvider.kt
@@ -1,6 +1,8 @@
-package com.fsck.k9
+package com.fsck.k9.controller
import android.content.Context
+import com.fsck.k9.Account
+import com.fsck.k9.Preferences
import com.fsck.k9.mail.MessagingException
import com.fsck.k9.mailstore.LocalStoreProvider
import com.fsck.k9.search.AccountSearchConditions
@@ -37,7 +39,7 @@ internal class DefaultMessageCountsProvider(
localStore.getMessageCounts(search)
} catch (e: MessagingException) {
Timber.e(e, "Unable to getMessageCounts for account: %s", account)
- return MessageCounts(0, 0)
+ MessageCounts(0, 0)
}
}
@@ -48,7 +50,7 @@ internal class DefaultMessageCountsProvider(
var unreadCount = 0
var starredCount = 0
for (account in accounts) {
- var accountMessageCount = getMessageCountsWithLocalSearch(account, search)
+ val accountMessageCount = getMessageCountsWithLocalSearch(account, search)
unreadCount += accountMessageCount.unread
starredCount += accountMessageCount.starred
}
@@ -62,7 +64,7 @@ internal class DefaultMessageCountsProvider(
localStore.getMessageCounts(search)
} catch (e: MessagingException) {
Timber.e(e, "Unable to getMessageCounts for account: %s", account)
- return MessageCounts(0, 0)
+ MessageCounts(0, 0)
}
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 71dc79a807..81095027e2 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -34,8 +34,6 @@ import com.fsck.k9.Account.DeletePolicy;
import com.fsck.k9.Account.Expunge;
import com.fsck.k9.DI;
import com.fsck.k9.K9;
-import com.fsck.k9.MessageCounts;
-import com.fsck.k9.MessageCountsProvider;
import com.fsck.k9.Preferences;
import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
@@ -1687,14 +1685,6 @@ public class MessagingController {
return unreadMessageCountProvider.getUnreadMessageCount(searchAccount);
}
- public MessageCounts getMessageCounts(Account account) {
- return messageCountsProvider.getMessageCounts(account);
- }
-
- public MessageCounts getMessageCounts(SearchAccount searchAccount) {
- return messageCountsProvider.getMessageCounts(searchAccount);
- }
-
public int getFolderUnreadMessageCount(Account account, Long folderId) throws MessagingException {
LocalStore localStore = localStoreProvider.getInstance(account);
LocalFolder localFolder = localStore.getFolder(folderId);
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
index 81a8e5f41b..02d684ee70 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
@@ -10,7 +10,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
-import com.fsck.k9.MessageCounts;
+import com.fsck.k9.controller.MessageCounts;
import com.fsck.k9.controller.MessageReference;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.Utility;
@@ -330,20 +330,20 @@ public class LocalFolder {
return this.localStore.getDatabase().execute(false, new DbCallback() {
@Override
public Integer doDbWork(final SQLiteDatabase db) throws WrappedException {
- int unreadMessageCount = 0;
+ int starredMessageCount = 0;
Cursor cursor = db.query("messages", new String[] { "COUNT(id)" },
- "folder_id = ? AND empty = 0 AND deleted = 0 AND flagged=1",
+ "folder_id = ? AND empty = 0 AND deleted = 0 AND flagged = 1",
new String[] { Long.toString(databaseId) }, null, null, null);
try {
if (cursor.moveToFirst()) {
- unreadMessageCount = cursor.getInt(0);
+ starredMessageCount = cursor.getInt(0);
}
} finally {
cursor.close();
}
- return unreadMessageCount;
+ return starredMessageCount;
}
});
} catch (WrappedException e) {
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index ddbb1c2a95..553513ce68 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -31,7 +31,7 @@ import com.fsck.k9.Account;
import com.fsck.k9.Clock;
import com.fsck.k9.DI;
import com.fsck.k9.K9;
-import com.fsck.k9.MessageCounts;
+import com.fsck.k9.controller.MessageCounts;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
import com.fsck.k9.controller.PendingCommandSerializer;
diff --git a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
index 387351751f..9a7e81612a 100644
--- a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
+++ b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
@@ -11,8 +11,6 @@ import android.content.Context;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.K9RobolectricTest;
-import com.fsck.k9.MessageCounts;
-import com.fsck.k9.MessageCountsProvider;
import com.fsck.k9.Preferences;
import com.fsck.k9.backend.BackendManager;
import com.fsck.k9.backend.api.Backend;
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
index 7f9027aa35..774e6cb102 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
@@ -14,7 +14,6 @@ import androidx.drawerlayout.widget.DrawerLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.fsck.k9.Account
import com.fsck.k9.K9
-import com.fsck.k9.MessageCounts
import com.fsck.k9.activity.MessageList
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.controller.SimpleMessagingListener
@@ -56,6 +55,11 @@ import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf
+private const val UNREAD_SYMBOL = "\u2B24"
+private const val STARRED_SYMBOL = "\u2605"
+private const val THIN_SPACE = "\u2009"
+private const val EN_SPACE = "\u2000"
+
class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : KoinComponent {
private val foldersViewModel: FoldersViewModel by parent.viewModel()
private val accountsViewModel: AccountsViewModel by parent.viewModel()
@@ -163,24 +167,46 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
}
- /**
- * Format the unread and starred counts for display in the fragment Badge box
- */
- private fun formatBadgeText(messageCounts: MessageCounts): String {
- var badgeText = ""
- if (K9.isShowStarredCount) {
- if (messageCounts.unread > 0) {
- badgeText = "\u2B24\u2009" + messageCounts.unread.toString()
- }
- if (messageCounts.starred > 0) {
- badgeText = badgeText + "\u2000\u2605\u2009" + messageCounts.starred.toString()
- }
+ private fun buildBadgeText(displayAccount: DisplayAccount): String? {
+ return buildBadgeText(displayAccount.unreadMessageCount, displayAccount.starredMessageCount)
+ }
+
+ private fun buildBadgeText(displayFolder: DisplayFolder): String? {
+ return buildBadgeText(displayFolder.unreadMessageCount, displayFolder.starredMessageCount)
+ }
+
+ private fun buildBadgeText(unreadCount: Int, starredCount: Int): String? {
+ return if (K9.isShowStarredCount) {
+ buildBadgeTextWithStarredCount(unreadCount, starredCount)
} else {
- if (messageCounts.unread > 0) {
- badgeText = messageCounts.unread.toString()
+ buildBadgeTextWithUnreadCount(unreadCount)
+ }
+ }
+
+ private fun buildBadgeTextWithStarredCount(unreadCount: Int, starredCount: Int): String? {
+ if (unreadCount == 0 && starredCount == 0) return null
+
+ return buildString {
+ val hasUnreadCount = unreadCount > 0
+ if (hasUnreadCount) {
+ append(UNREAD_SYMBOL)
+ append(THIN_SPACE)
+ append(unreadCount)
+ }
+
+ if (starredCount > 0) {
+ if (hasUnreadCount) {
+ append(EN_SPACE)
+ }
+ append(STARRED_SYMBOL)
+ append(THIN_SPACE)
+ append(starredCount)
}
}
- return badgeText.trim()
+ }
+
+ private fun buildBadgeTextWithUnreadCount(unreadCount: Int): String? {
+ return if (unreadCount > 0) unreadCount.toString() else null
}
private fun setAccounts(displayAccounts: List) {
@@ -204,13 +230,12 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
descriptionTextColor = selectedTextColor
selectedColorInt = drawerColors.selectedColor
icon = ImageHolder(createAccountImageUri(account))
- formatBadgeText(displayAccount.messageCounts).takeIf { it.isNotEmpty() }
- ?.let { bText ->
- badgeText = bText
- badgeStyle = BadgeStyle().apply {
- textColorStateList = selectedTextColor
- }
+ buildBadgeText(displayAccount)?.let { text ->
+ badgeText = text
+ badgeStyle = BadgeStyle().apply {
+ textColorStateList = selectedTextColor
}
+ }
}
if (account.uuid == openedAccountUuid) {
@@ -327,16 +352,6 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
selectedColorInt = selectedBackgroundColor
textColor = selectedTextColor
isSelected = unifiedInboxSelected
-
- // TODO: get the real message counts from the back end
- var messageCounts = MessageCounts(0, 0)
- formatBadgeText(messageCounts).takeIf { it.isNotEmpty() }
- ?.let { bText ->
- badgeText = bText
- badgeStyle = BadgeStyle().apply {
- textColorStateList = selectedTextColor
- }
- }
}
sliderView.addItems(unifiedInboxItem)
@@ -360,16 +375,10 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
identifier = drawerId
tag = folder
nameText = getFolderDisplayName(folder)
- formatBadgeText(
- MessageCounts(
- displayFolder.unreadMessageCount,
- displayFolder.starredMessageCount
- )
- ).takeIf { it.isNotEmpty() }
- ?.let { bText ->
- badgeText = bText
- badgeStyle = folderBadgeStyle
- }
+ buildBadgeText(displayFolder)?.let { text ->
+ badgeText = text
+ badgeStyle = folderBadgeStyle
+ }
selectedColorInt = selectedBackgroundColor
textColor = selectedTextColor
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
index beaa638687..d0c039adf1 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/AccountsViewModel.kt
@@ -9,9 +9,9 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import com.fsck.k9.Account
import com.fsck.k9.AccountsChangeListener
-import com.fsck.k9.MessageCounts
-import com.fsck.k9.MessageCountsProvider
import com.fsck.k9.Preferences
+import com.fsck.k9.controller.MessageCounts
+import com.fsck.k9.controller.MessageCountsProvider
import com.fsck.k9.provider.EmailProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,7 +53,11 @@ class AccountsViewModel(
combine(messageCountsFlows) { messageCountsList ->
messageCountsList.mapIndexed { index, messageCounts ->
- DisplayAccount(account = accounts[index], messageCounts)
+ DisplayAccount(
+ account = accounts[index],
+ unreadMessageCount = messageCounts.unread,
+ starredMessageCount = messageCounts.starred
+ )
}
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
index ce4a318f2c..ef0e30b9d5 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/account/DisplayAccount.kt
@@ -1,6 +1,9 @@
package com.fsck.k9.ui.account
import com.fsck.k9.Account
-import com.fsck.k9.MessageCounts
-data class DisplayAccount(val account: Account, val messageCounts: MessageCounts)
+data class DisplayAccount(
+ val account: Account,
+ val unreadMessageCount: Int,
+ val starredMessageCount: Int
+)
--
GitLab
From 74a0ed8b932d9bc5fe7251dca24cd1212361c60d Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 17 Aug 2021 19:54:29 +0200
Subject: [PATCH 045/285] Remove UnreadMessageCountProvider
---
.../java/com/fsck/k9/controller/KoinModule.kt | 11 +++-
.../k9/controller/MessagingController.java | 12 ++--
.../controller/UnreadMessageCountProvider.kt | 65 -------------------
.../controller/MessagingControllerTest.java | 16 +----
4 files changed, 16 insertions(+), 88 deletions(-)
delete mode 100644 app/core/src/main/java/com/fsck/k9/controller/UnreadMessageCountProvider.kt
diff --git a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
index 252ad0fe14..df0a7622c7 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/KoinModule.kt
@@ -18,7 +18,6 @@ val controllerModule = module {
get(),
get(),
get(),
- get(),
get(),
get(),
get(),
@@ -27,6 +26,12 @@ val controllerModule = module {
get(named("controllerExtensions"))
)
}
- single { DefaultUnreadMessageCountProvider(get(), get(), get(), get()) }
- single { DefaultMessageCountsProvider(get(), get(), get(), get()) }
+ single {
+ DefaultMessageCountsProvider(
+ context = get(),
+ preferences = get(),
+ accountSearchConditions = get(),
+ localStoreProvider = get()
+ )
+ }
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 81095027e2..2e394161dc 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -125,7 +125,6 @@ public class MessagingController {
private final Set listeners = new CopyOnWriteArraySet<>();
private final ExecutorService threadPool = Executors.newCachedThreadPool();
private final MemorizingMessagingListener memorizingMessagingListener = new MemorizingMessagingListener();
- private final UnreadMessageCountProvider unreadMessageCountProvider;
private final MessageCountsProvider messageCountsProvider;
private final DraftOperations draftOperations;
@@ -141,14 +140,13 @@ public class MessagingController {
MessagingController(Context context, NotificationController notificationController,
NotificationStrategy notificationStrategy, LocalStoreProvider localStoreProvider,
- UnreadMessageCountProvider unreadMessageCountProvider, MessageCountsProvider messageCountsProvider,
- BackendManager backendManager, Preferences preferences, MessageStoreManager messageStoreManager,
+ MessageCountsProvider messageCountsProvider, BackendManager backendManager,
+ Preferences preferences, MessageStoreManager messageStoreManager,
SaveMessageDataCreator saveMessageDataCreator, List controllerExtensions) {
this.context = context;
this.notificationController = notificationController;
this.notificationStrategy = notificationStrategy;
this.localStoreProvider = localStoreProvider;
- this.unreadMessageCountProvider = unreadMessageCountProvider;
this.messageCountsProvider = messageCountsProvider;
this.backendManager = backendManager;
this.preferences = preferences;
@@ -1678,11 +1676,13 @@ public class MessagingController {
}
public int getUnreadMessageCount(Account account) {
- return unreadMessageCountProvider.getUnreadMessageCount(account);
+ MessageCounts messageCounts = messageCountsProvider.getMessageCounts(account);
+ return messageCounts.getUnread();
}
public int getUnreadMessageCount(SearchAccount searchAccount) {
- return unreadMessageCountProvider.getUnreadMessageCount(searchAccount);
+ MessageCounts messageCounts = messageCountsProvider.getMessageCounts(searchAccount);
+ return messageCounts.getUnread();
}
public int getFolderUnreadMessageCount(Account account, Long folderId) throws MessagingException {
diff --git a/app/core/src/main/java/com/fsck/k9/controller/UnreadMessageCountProvider.kt b/app/core/src/main/java/com/fsck/k9/controller/UnreadMessageCountProvider.kt
deleted file mode 100644
index c2371ff0f1..0000000000
--- a/app/core/src/main/java/com/fsck/k9/controller/UnreadMessageCountProvider.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.fsck.k9.controller
-
-import android.content.Context
-import com.fsck.k9.Account
-import com.fsck.k9.Preferences
-import com.fsck.k9.mail.MessagingException
-import com.fsck.k9.mailstore.LocalStoreProvider
-import com.fsck.k9.search.AccountSearchConditions
-import com.fsck.k9.search.LocalSearch
-import com.fsck.k9.search.SearchAccount
-import com.fsck.k9.search.getAccounts
-import timber.log.Timber
-
-interface UnreadMessageCountProvider {
- fun getUnreadMessageCount(account: Account): Int
- fun getUnreadMessageCount(searchAccount: SearchAccount): Int
-}
-
-internal class DefaultUnreadMessageCountProvider(
- private val context: Context,
- private val preferences: Preferences,
- private val accountSearchConditions: AccountSearchConditions,
- private val localStoreProvider: LocalStoreProvider
-) : UnreadMessageCountProvider {
- override fun getUnreadMessageCount(account: Account): Int {
- if (!account.isAvailable(context)) {
- return 0
- }
-
- return try {
- val localStore = localStoreProvider.getInstance(account)
-
- val search = LocalSearch()
- accountSearchConditions.excludeSpecialFolders(account, search)
- accountSearchConditions.limitToDisplayableFolders(account, search)
-
- localStore.getUnreadMessageCount(search)
- } catch (e: MessagingException) {
- Timber.e(e, "Unable to getUnreadMessageCount for account: %s", account)
- 0
- }
- }
-
- override fun getUnreadMessageCount(searchAccount: SearchAccount): Int {
- val search = searchAccount.relatedSearch
- val accounts = search.getAccounts(preferences)
-
- var unreadMessageCount = 0
- for (account in accounts) {
- unreadMessageCount += getUnreadMessageCountWithLocalSearch(account, search)
- }
-
- return unreadMessageCount
- }
-
- private fun getUnreadMessageCountWithLocalSearch(account: Account, search: LocalSearch): Int {
- return try {
- val localStore = localStoreProvider.getInstance(account)
- localStore.getUnreadMessageCount(search)
- } catch (e: MessagingException) {
- Timber.e(e, "Unable to getUnreadMessageCount for account: %s", account)
- 0
- }
- }
-}
diff --git a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
index 9a7e81612a..fdca93b551 100644
--- a/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
+++ b/app/core/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java
@@ -110,18 +110,6 @@ public class MessagingControllerTest extends K9RobolectricTest {
private LocalMessage localMessageToSend1;
private volatile boolean hasFetchedMessage = false;
- private UnreadMessageCountProvider unreadMessageCountProvider = new UnreadMessageCountProvider() {
- @Override
- public int getUnreadMessageCount(@NotNull SearchAccount searchAccount) {
- return 0;
- }
-
- @Override
- public int getUnreadMessageCount(@NotNull Account account) {
- return 0;
- }
- };
-
private MessageCountsProvider messageCountsProvider = new MessageCountsProvider() {
@Override
public MessageCounts getMessageCounts(@NotNull SearchAccount searchAccount) {
@@ -147,8 +135,8 @@ public class MessagingControllerTest extends K9RobolectricTest {
preferences = Preferences.getPreferences(appContext);
controller = new MessagingController(appContext, notificationController, notificationStrategy,
- localStoreProvider, unreadMessageCountProvider, messageCountsProvider, backendManager, preferences,
- messageStoreManager, saveMessageDataCreator, Collections.emptyList());
+ localStoreProvider, messageCountsProvider, backendManager, preferences, messageStoreManager,
+ saveMessageDataCreator, Collections.emptyList());
configureAccount();
configureBackendManager();
--
GitLab
From 942d8e4a8fea81039d03b78ba0e2c381ba165334 Mon Sep 17 00:00:00 2001
From: ByteHamster
Date: Tue, 17 Aug 2021 18:24:58 +0200
Subject: [PATCH 046/285] Authenticate user before showing password
---
app/ui/legacy/build.gradle | 1 +
.../activity/setup/AccountSetupIncoming.java | 44 ++++++++++++++++++-
.../activity/setup/AccountSetupOutgoing.java | 44 +++++++++++++++++++
.../res/layout/account_setup_incoming.xml | 2 +-
.../res/layout/account_setup_outgoing.xml | 2 +-
app/ui/legacy/src/main/res/values/strings.xml | 3 ++
build.gradle | 1 +
7 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/app/ui/legacy/build.gradle b/app/ui/legacy/build.gradle
index b6eb766b63..cd51df317d 100644
--- a/app/ui/legacy/build.gradle
+++ b/app/ui/legacy/build.gradle
@@ -22,6 +22,7 @@ dependencies {
implementation "com.takisoft.preferencex:preferencex-datetimepicker:${versions.preferencesFix}"
implementation "com.takisoft.preferencex:preferencex-colorpicker:${versions.preferencesFix}"
implementation "com.takisoft.preferencex:preferencex-ringtone:${versions.preferencesFix}"
+ implementation "androidx.biometric:biometric:${versions.androidxBiometric}"
implementation "androidx.recyclerview:recyclerview:${versions.androidxRecyclerView}"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.androidxLifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.androidxLifecycle}"
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
index 7654c05fc1..13ec380a82 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
@@ -9,6 +9,7 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
+import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -19,11 +20,13 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
-import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.biometric.BiometricManager.Authenticators;
+import androidx.biometric.BiometricPrompt;
+import androidx.core.content.ContextCompat;
import com.fsck.k9.Account;
-import com.fsck.k9.Account.FolderMode;
import com.fsck.k9.DI;
import com.fsck.k9.LocalKeyStoreManager;
import com.fsck.k9.Preferences;
@@ -182,6 +185,18 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
boolean editSettings = Intent.ACTION_EDIT.equals(getIntent().getAction());
+ mPasswordLayoutView.setEndIconOnClickListener(v -> {
+ if (mPasswordView.getTransformationMethod() instanceof PasswordTransformationMethod) {
+ if (editSettings) {
+ authenticateUserAndShowPassword();
+ } else {
+ mPasswordView.setTransformationMethod(null);
+ }
+ } else {
+ mPasswordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
+ }
+ });
+
try {
ServerSettings settings = mAccount.getIncomingServerSettings();
@@ -616,6 +631,31 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
}
+ private void authenticateUserAndShowPassword() {
+ new BiometricPrompt(this, ContextCompat.getMainExecutor(this), new BiometricPrompt.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
+ mPasswordView.setTransformationMethod(null);
+ }
+
+ @Override
+ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
+ if (errorCode == BiometricPrompt.ERROR_HW_NOT_PRESENT
+ || errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL) {
+ Toast.makeText(AccountSetupIncoming.this, R.string.account_setup_basics_show_password_need_lock,
+ Toast.LENGTH_SHORT).show();
+ } else if (errString.length() != 0) {
+ Toast.makeText(AccountSetupIncoming.this, errString, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }).authenticate(new BiometricPrompt.PromptInfo.Builder()
+ .setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG
+ | Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL)
+ .setTitle(getString(R.string.account_setup_basics_show_password_biometrics_title))
+ .setSubtitle(getString(R.string.account_setup_basics_show_password_biometrics_subtitle))
+ .build());
+ }
+
public void onClick(View v) {
try {
if (v.getId() == R.id.next) {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
index 63bc2ad3f5..a0c27afb56 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
@@ -8,6 +8,7 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
+import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -20,6 +21,10 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.biometric.BiometricManager.Authenticators;
+import androidx.biometric.BiometricPrompt;
+import androidx.core.content.ContextCompat;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.LocalKeyStoreManager;
@@ -148,6 +153,20 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
}
+ boolean editSettings = Intent.ACTION_EDIT.equals(getIntent().getAction());
+
+ mPasswordLayoutView.setEndIconOnClickListener(v -> {
+ if (mPasswordView.getTransformationMethod() instanceof PasswordTransformationMethod) {
+ if (editSettings) {
+ authenticateUserAndShowPassword();
+ } else {
+ mPasswordView.setTransformationMethod(null);
+ }
+ } else {
+ mPasswordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
+ }
+ });
+
try {
ServerSettings settings = mAccount.getOutgoingServerSettings();
@@ -498,6 +517,31 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
}
+ private void authenticateUserAndShowPassword() {
+ new BiometricPrompt(this, ContextCompat.getMainExecutor(this), new BiometricPrompt.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
+ mPasswordView.setTransformationMethod(null);
+ }
+
+ @Override
+ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
+ if (errorCode == BiometricPrompt.ERROR_HW_NOT_PRESENT
+ || errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL) {
+ Toast.makeText(AccountSetupOutgoing.this, R.string.account_setup_basics_show_password_need_lock,
+ Toast.LENGTH_SHORT).show();
+ } else if (errString.length() != 0) {
+ Toast.makeText(AccountSetupOutgoing.this, errString, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }).authenticate(new BiometricPrompt.PromptInfo.Builder()
+ .setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG
+ | Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL)
+ .setTitle(getString(R.string.account_setup_basics_show_password_biometrics_title))
+ .setSubtitle(getString(R.string.account_setup_basics_show_password_biometrics_subtitle))
+ .build());
+ }
+
public void onClick(View v) {
if (v.getId() == R.id.next) {
onNext();
diff --git a/app/ui/legacy/src/main/res/layout/account_setup_incoming.xml b/app/ui/legacy/src/main/res/layout/account_setup_incoming.xml
index 7e96929b86..69592b117d 100644
--- a/app/ui/legacy/src/main/res/layout/account_setup_incoming.xml
+++ b/app/ui/legacy/src/main/res/layout/account_setup_incoming.xml
@@ -97,7 +97,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/account_setup_margin_between_items_incoming_and_outgoing"
- app:passwordToggleEnabled="true">
+ app:endIconMode="password_toggle">
+ app:endIconMode="password_toggle">
Email address
Password
Show password
+ To view or copy your password here, enable screen lock on this device.
+ Verify it\'s you
+ Unlock to view your password
Manual setup
diff --git a/build.gradle b/build.gradle
index 4b3da118fe..18db2031a0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,7 @@ buildscript {
'androidxRecyclerView': '1.1.0',
'androidxLifecycle': '2.3.1',
'androidxAnnotation': '1.2.0',
+ 'androidxBiometric': '1.1.0',
'androidxNavigation': '2.3.5',
'androidxConstraintLayout': '2.0.4',
'androidxWorkManager': '2.5.0',
--
GitLab
From 8dc410562a7e9fbed92ffde240359bb43506e57a Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 17 Aug 2021 23:29:57 +0200
Subject: [PATCH 047/285] Update translations
---
.../legacy/src/main/res/values-ca/strings.xml | 3 +
.../legacy/src/main/res/values-es/strings.xml | 441 ++++++++--------
.../legacy/src/main/res/values-gd/strings.xml | 475 +++++++++++-------
.../legacy/src/main/res/values-ja/strings.xml | 1 +
.../legacy/src/main/res/values-nl/strings.xml | 1 +
.../src/main/res/values-pt-rBR/strings.xml | 3 +
.../legacy/src/main/res/values-ru/strings.xml | 1 +
.../legacy/src/main/res/values-sv/strings.xml | 2 +-
8 files changed, 527 insertions(+), 400 deletions(-)
diff --git a/app/ui/legacy/src/main/res/values-ca/strings.xml b/app/ui/legacy/src/main/res/values-ca/strings.xml
index 16d480d8fd..0d3d5ef805 100644
--- a/app/ui/legacy/src/main/res/values-ca/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ca/strings.xml
@@ -437,6 +437,9 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
Marca el missatge com a llegit després d\'haver-lo obert.
Marca com a llegit quan se suprimeixi
Marca un missatge com a llegit quan se suprimeix.
+ Categories de notificacions
+ Configureu les notificacions per als missatges nous
+ Configureu les notificacions per als errors i l\'estat
Sempre mostra les imatges
No
Dels contactes
diff --git a/app/ui/legacy/src/main/res/values-es/strings.xml b/app/ui/legacy/src/main/res/values-es/strings.xml
index 5149e3f590..5e791765dd 100644
--- a/app/ui/legacy/src/main/res/values-es/strings.xml
+++ b/app/ui/legacy/src/main/res/values-es/strings.xml
@@ -7,52 +7,51 @@
Cuentas K-9
Mensaje K-9 no leído
- Los paseadores del perro K-9
+ Los encargados del perrito K-9
Copyright 2008-%s The K-9 Dog Walkers. Partes del Copyright 2006-%s Android Open Source Project.
Código fuente
- Apache License, Version 2.0
- Proyecto de Código Abierto
+ Licencia Apache, versión 2.0
+ Proyecto de código abierto
Sitio web
- Usuario del foro
+ Foro de usuarios
Fediverse
Twitter
- Librerías
+ Bibliotecas de código
Licencia
Registro de cambios
No se pudo cargar el registro de cambios.
Versión %s
Novedades
Muestra cambios recientes cuando se actualiza la aplicación
- Descubra las novedades de esta versión
+ Descubre las novedades de esta versión
- Bienvenido a K-9 Mail
+ Te damos la bienvenida a K-9 Mail
-K-9 Mail es un cliente de correo potente para Android.
+K-9 Mail es un cliente de correo rápido, libre y potente para Android.
-Sus características mejoradas incluyen:
+Sus características más destacadas son:
- - Correo «push» usando IMAP IDLE
- - Mejor rendimiento
+ - Notificaciones rápidas («push») usando IMAP IDLE
+ - Un rendimiento superior
- Archivado de mensajes
- Firmas de correo
- Cco-a-sí-mismo
- Suscripciones a carpetas
- Sincronización de todas las carpetas
- Configuración de la dirección de respuesta
- - Atajos de teclado
- - Mejor soporte IMAP
+ - Atajos del teclado
+ - Características avanzadas para IMAP
- Guardar adjuntos a la tarjeta SD
- Vaciar la papelera
- Ordenación de mensajes
- - …y más
+ - …y mucho más
-Por favor tenga en cuenta que K-9 no soporta la mayor parte de las cuentas gratuitas de Hotmail, y como muchos clientes de correo, tiene algunas peculiaridades al comunicarse con Microsoft Exchange.
+Ten en cuenta que K-9 no funciona bien con la mayor parte de las cuentas gratuitas de Hotmail, y (como tantos otros clientes de correo) puede tener alguna dificultad al comunicarse con servidores de Microsoft Exchange.
-Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
-https://github.com/k9mail/k-9/.
+Puedes informar de fallos, contribuir con su desarrollo y hacer preguntas en https://github.com/k9mail/k-9/.
]]>
@@ -75,14 +74,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Responder a todos
Reenviar
Reenviar como adjunto
- Elija cuenta
- Seleccionar carpeta
+ Elige una cuenta
+ Selecciona una carpeta
Comprobando %s:%s%s
Recuperando cabeceras %s:%s%s
Enviando %s%s
Proc %s:%s%s
\u0020%d/%d
- Sincronización deshabilitada
+ Sincronización desactivada
%d seleccionados
Siguiente
Anterior
@@ -91,7 +90,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Cancelar
Enviar
Volver a enviar
- El asunto está vacío, haga clic de nuevo para enviarlo tal cual
+ El asunto está vacío, haz clic de nuevo para enviarlo tal cual
Seleccionar
Deseleccionar
Responder
@@ -111,16 +110,16 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Guardar como borrador
Comprobar correo
Enviar correo
- Refrescar lista de carpetas
+ Recargar lista de carpetas
Buscar carpeta
Añadir cuenta
Redactar
Buscar
Buscar en todas partes
- Resultados búsqueda
- Configuración
+ Resultados de búsqueda
+ Ajustes
Administrar carpetas
- Configuración de la cuenta
+ Ajustes de la cuenta
Eliminar cuenta
Marcar como leído
Compartir
@@ -131,23 +130,23 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Mostrar cabeceras
- Se ha copiado la dirección al portapapeles
- - Se han copiado las direcciones al portapeles
+ - Se han copiado las direcciones al portapapeles
Texto copiado en el portapapeles
- Cambiar a tema oscuro
- Cambiar a tema claro
+ Cambiar al tema oscuro
+ Cambiar al tema claro
Marcar como no leído
Confirmación de lectura
- Se solicitará confirmación de lectura
+ Se solicitará una confirmación de lectura
No se solicitará confirmación de lectura
Añadir adjunto
- Vaciar Papelera
+ Vaciar papelera
Purgar
Acerca de
Configuración
- (Sin Asunto)
- Sin Remitente
+ (Sin asunto)
+ Sin remitente
Cargando mensajes\u2026
Error de conexión
Mensaje no encontrado
@@ -157,14 +156,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
%.1f MB
%.1f kB
%d B
- Cuenta \"%s\" reducida desde %s a %s
+ Se ha reducido el tamaño de la cuenta «%s» de %s a %s
Compactando cuenta \"%s\"
Correo nuevo
- %d mensaje nuevo
- %d mensajes nuevos
- %d Sin Leer (%s)
+ %d Sin leer (%s)
+ %1$d más en %2$s
Responder
Marcar como leído
@@ -175,37 +174,37 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Archivar todo
Correo no deseado
Error de certificado para %s
- Compruebe su configuración del servidor
+ Comprueba los ajustes del servidor
Fallo de autenticación
- Fallo de autenticación para %s. Actualice la configuración del servidor.
+ Fallo de autenticación en %s. Actualiza y revisa los ajustes del servidor.
Comprobando correo: %s:%s
Comprobando correo
Enviando correo: %s
Enviando correo
:
- Sincronizar (Push)
- Se muestra en espera de nuevos mensajes
+ Sincronización rápida («push»)
+ Necesaria para buscar nuevos mensajes en segundo plano.
Mensajes
- Notificaciones relacionadas a los mensajes
+ Notificaciones relacionadas con los mensajes.
Varios
- Notificaciones misceláneas como errores, etc.
- Bandeja de Entrada
+ Otras notificaciones, como errores y otros mensajes.
+ Bandeja de entrada
Salida
Borradores
Papelera
Enviados
Error al enviar algunos mensajes
Versión
- Habilitar log de depuración
- Log con información ampliada
+ Habilitar registro de depuración
+ Registrar el estado del programa con información adicional para diagnosticar posibles problemas
Incluir información sensible
- Puede mostrar contraseñas en los logs.
+ Incluir información privada (como contraseñas) en texto plano en el registro de depuración
Cargar más correos
Para:%s
Asunto
- Texto del Mensaje
+ Texto del mensaje
Firma
- -------- Mensaje Original --------
+ -------- Mensaje original --------
Asunto:
Enviado:
De:
@@ -213,14 +212,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Cc:
%s escribió:
El %1$s, %2$s escribió:
- Debe añadir al menos un destinatario.
- ¡El campo de destinatario está incompleto!
+ El mensaje necesita algún destinatario.
+ El campo de destinatario está incompleto.
No se encontró la dirección de correo electrónico de este contacto.
- Algunos adjuntos no pueden reenviarse porque no han sido descargados.
+ Algunos adjuntos no pueden reenviarse porque se han descargado.
El mensaje no puede ser reenviado porque algunos adjuntos no se han descargado.
- Incluir mensaje citado
- Eliminar mensaje original
- Editar mensaje original
+ Incluir mensaje original
+ No incluir el mensaje original
+ Editar el mensaje original
Eliminar adjunto
De: %s <%s>
Para:
@@ -270,14 +269,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Marcar todos los mensajes como leídos
Borrar (de notificaciones)
Ocultar cliente de correo
- Eliminar el Agente de Usuario K-9 de las cabeceras del mensaje
+ Eliminar la marca con el «agente de usuario» de K-9 de las cabeceras del mensaje, el destinatario no verá qué programa de correo usas
Ocultar zona horaria
- Usar UTC en lugar de la zona horaria local en las cabeceras de mensaje y cabeceras de respuesta
+ Usar UTC («tiempo universal coordinado») en lugar de la zona horaria local en las cabeceras de mensaje y cabeceras de respuesta
Ocultar asunto en notificaciones
Nunca
Cuando el dispositivo está bloqueado
Siempre
- Mostrar el botón \'Borrar\'
+ Mostrar el botón «Borrar»
Nunca
Para notificaciones de un mensaje
Siempre
@@ -287,12 +286,12 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Cuenta de mensajes no leídos
Cuenta de mensajes y remitentes
Igual que con la pantalla desbloqueada
- Horario de Silencio
- Desactivar sonidos, alertas y luces por la noche
+ Horario de descanso
+ Desactivar y silenciar los sonidos, alertas y luces de notificación por la noche
Desactivar notificaciones
- Desactivar completamente las notificaciones durante el tiempo de descanso
- Silencio comienza
- Silencio termina
+ Desactivar completamente cualquier notificación durante el tiempo de descanso
+ El horario de descanso comienza
+ El horario de descanso termina
Configurar nueva cuenta
Dirección de correo
Contraseña
@@ -305,9 +304,9 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Autentificando\u2026
Obteniendo configuración de la cuenta\u2026
Cancelando\u2026
- ¡Terminado!
- Elija un nombre para esta cuenta (opcional):
- Introduzca su nombre (se verá en los mensajes salientes):
+ ¡Ya casi estás!
+ Elige un nombre para esta cuenta (opcional):
+ Pon tu nombre (aparecerá en los mensajes que envíes):
Tipo de cuenta
¿Qué tipo de cuenta es?
POP3
@@ -324,12 +323,12 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Servidor IMAP
Servidor WebDAV (Exchange)
Puerto
- Tipo de Seguridad
+ Tipo de seguridad
Tipo de autentificación
Ninguna
SSL/TLS
STARTTLS
- \"%1$s = %2$s\" no es válido con \"%3$s = %4$s\"
+ La opción «%1$s = %2$s» no es compatible con «%3$s = %4$s»
Cuando borre un mensaje
No borrar del servidor
Borrar del servidor
@@ -367,8 +366,8 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Usuario
Contraseña
Tipo de autentificación
- \"%1$s = %2$s\" no es válido con \"%3$s = %4$s\"
- Configuración inválida: %s
+ La opción «%1$s = %2$s» no es compatible con «%3$s = %4$s»
+ Configuración incorrecta: %s
Opciones de cuenta
Compactar
Frecuencia de comprobación de correo nuevo
@@ -381,9 +380,9 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Cada 6 horas
Cada 12 horas
Cada 24 horas
- Activar push para esta cuenta
- Si su servidor lo permite, los mensajes aparecerán de forma instantánea. Esta opción puede ralentizar el sistema.
- Refrescar conexión IDLE
+ Activar comprobaciones rápidas «push» en la cuenta
+ Si su servidor lo permite los mensajes nuevos aparecerán de forma instantánea. Dependiendo del dispositivo esto puede mejorar o empeorar bastante el rendimiento.
+ Renovar o retomar conexión de red IDLE
Cada 2 minutos
Cada 3 minutos
Cada 6 minutos
@@ -406,10 +405,10 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
5000 mensajes
10000 mensajes
Todos los mensajes
- No se puede copiar/mover un mensaje no sincronizado con el servidor
- No se ha podido finalizar la Configuración
+ No se puede copiar/mover un mensaje que no esté sincronizado con el servidor
+ No se ha podido terminar la configuración
Usuario o contraseña incorrectos.\n(%s)
- El servidor presentó un certificado SSL no válido. Algunas veces, esto es debido a un problema de configuración en el servidor. Otras veces es porque alguien está intentando atacarle o atacar su servidor de correo. Si no está seguro de qué ocurre, pulse en Rechazar y contacte con quien gestiona su servidor de correo.\n\n(%s)
+ El servidor ha enviado un certificado SSL incorrecto. Esto puede deberse a un problema de configuración en el propio servidor, o bien porque alguien está intentando interceptar tus comunicaciones o atacar el servidor de correo. Si no estás seguro, pulsa en «Rechazar» y contacta con quien gestiona tu servidor de correo.\n\n(%s)
No se pudo conectar con el servidor.\n(%s)
Editar detalles
Continuar
@@ -425,9 +424,9 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Todas excepto las carpetas de 2ª clase
Ninguna
Notificar sincronización
- Su Dirección de correo
+ Tu dirección de correo
Avisar cuando llegue correo nuevo
- Avisar cuando se compruebe el correo
+ Mostrar la búsqueda de correos nuevos en la barra de notificaciones
Incluir bandeja de salida
Mostrar notificaciones durante el envío de correo
Solamente contactos
@@ -436,6 +435,9 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Marcar mensaje como leído cuando se abre para verlo
Marcar como leído al borrar
Marcar el mensaje como leído cuando se borra
+ Categorías de notificaciones
+ Configura las notificaciones para mensajes nuevos
+ Configura las notificaciones de error y estado actual
Mostrar imágenes siempre
No
Sólo de mis contactos
@@ -444,7 +446,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Incluir mensaje original al responder
Al responder los mensajes, el mensaje original se incluirá en su respuesta.
Respuesta tras mensaje original
- Al responder un mensaje, el mensaje original aparecerá por encima de la respuesta
+ Al responder un mensaje, el mensaje original aparecerá por encima de la respuesta.
Eliminar firma del mensaje original
Al responder a los mensajes se eliminará la firma del mensaje original
Formato del mensaje
@@ -472,14 +474,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Conectado a %s
Configurando...
Almacenar todos los borradores cifrados
- Todos los borradores serán guardados con cifrado
+ Todos los borradores se guardarán de forma segura
Cifrar borradores solamente si está disponible el cifrado
Frecuencia de comprobación
Color de la cuenta
- Seleccione el color a utilizar en la carpeta y en la cuenta
+ Selecciona el color a utilizar en la carpeta y en la cuenta
Sin color
Color de aviso
- Seleccione el color del LED para los avisos de esta cuenta
+ Selecciona el color del LED para los avisos de esta cuenta
Tamaño carpeta local
Obtener mensajes de hasta
1 KiB
@@ -513,59 +515,60 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Carpetas a mostrar
Todas
Sólo 1ª clase
- 1ª y 2ª Clase
- Todas excepto las de 2a clase
+ 1ª y 2ª clase
+ Todas excepto las de 2ª clase
Comprobación de carpetas
Todas
Sólo 1ª clase
- 1ª y 2ª Clase
- Todas excepto las de 2a clase
+ 1ª y 2ª clase
+ Todas excepto las de 2ª clase
Ninguna
- Push de carpetas
+ Carpetas de comprobaciones «push»
Todas
Sólo 1ª clase
- 1ª y 2ª Clase
- Todas excepto las de 2a clase
+ 1ª y 2ª clase
+ Todas excepto las de 2ª clase
Ninguna
- Destino Mover/Copiar
+ Mover/copiar carpetas destino
Todas
Sólo 1ª clase
- 1ª y 2ª Clase
- Todas excepto las de 2a clase
- Sincronizar eliminaciones
+ 1ª y 2ª clase
+ Todas excepto las de 2ª clase
+ Sincronizar con el borrado remoto
Eliminar los mensajes cuando se borren del servidor
- Falta la aplicación OpenPGP - ¿fue desinstalada?
+ Falta la aplicación OpenPGP, ¿se ha desinstalado?
Configuración de carpeta
Mostrar al principio
Mostrar cerca del principio de la lista
Tipos de carpeta mostrados
- Sin Clase
- 1ª Clase
- 2a Clase
- Tipos de carpeta sincronizadas (poll)
+ Sin clase
+ 1ª clase
+ 2ª clase
+ Tipos de carpeta con sincronización lenta («poll»)
Ninguna
- 1ª Clase
- 2a Clase
+ 1ª clase
+ 2ª clase
La misma que la de visualización
- Tipos de carpeta con Push
- Sin Clase
- 1ª Clase
- 2a Clase
+ Tipos de carpeta con sincronización rápida («push»)
+ Sin clase
+ 1ª clase
+ 2ª clase
+ La misma que con sincronización lenta («poll»)
Clase de la carpeta de notificaciones
- Sin Clase
+ Sin clase
1ª clase
2ª clase
- La misma clase que la carpeta \'push\'
+ La misma que con sincronización rápida («push»)
Borrar mensajes locales
Servidor de entrada
Configurar servidor de entrada
Servidor de salida
Configurar servidor de salida (SMTP)
Nombre de la cuenta
- Su nombre
+ Tu nombre
Notificaciones
Vibrar
- Vibrar cuando llega correo
+ Vibrar cuando llega un correo
Secuencia de vibración
Predeterminado
Secuencia 1
@@ -579,7 +582,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Parpadear el LED cuando llega nuevo correo
Opciones de edición de mensaje
Campos predeterminados
- Indicar de manera predeterminada De, Cco y Firma
+ Configurar «De», «Cco» y firma predeterminadas
Identidades
Configurar direcciones y firmas alternativas
Gestionar identidades
@@ -595,10 +598,10 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Eliminar
Descripción identidad
(Opcional)
- Su nombre
+ Tu nombre
(Opcional)
Dirección de correo
- (Requerido)
+ (Necesario)
Responder a
(Opcional)
Firma
@@ -608,8 +611,8 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Identidad principal
Seleccionar identidad
Enviar como
- No puede eliminar su única identidad
- No puede utilizar una identidad sin dirección de correo
+ No puedes eliminar tu única identidad
+ No puedes utilizar una identidad sin añadir una dirección de correo
Nuevos mensajes primero
Últimos mensajes primero
Asunto (alfabético)
@@ -634,14 +637,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Certificado desconocido
Aceptar clave
Rechazar clave
- Del (o D) - Borrar\nR - Responder\nA - Responder a todos\nC - Redactar\nF - Reenviar\nM - Mover\nV - Archivar\nY - Copiar\nZ - Marcar como (no) leído\nG - Estrella\nO - Tipo de ordenación\nI - Orden de ordenación\nQ - Volver a las carpetas\nS - Des/marcar\nJ o P - Mensaje anterior\nK o N - Siguiente mensaje
- Del (o D) - Borrar\nC - Redactar\nM - Mover\nV - Archivar\nY - Copiar\nZ - Marcar como (no) leído\nG - Estrella\nO - Tipo de ordenación\nI - Orden de ordenación\nQ - Volver a las carpetas\nS - Des/marcar
+ Supr (o D) - Borrar\nR - Responder\nA - Responder a todos\nC - Redactar\nF - Reenviar\nM - Mover\nV - Archivar\nY - Copiar\nZ - Marcar como (no) leído\nG - Estrella\nO - Tipo de ordenación\nI - Invertir orden\nQ - Volver a las carpetas\nS - Des/marcar\nJ o P - Mensaje anterior\nK o N - Siguiente mensaje
+ Supr (o D) - Borrar\nC - Redactar\nM - Mover\nV - Archivar\nY - Copiar\nZ - Marcar como (no) leído\nG - Estrella\nO - Tipo de ordenación\nI - Invertir orden\nQ - Volver a las carpetas\nS - Des/marcar
El nombre de la carpeta contiene
Mostrar carpetas…
Ver todas las carpetas
- Ver sólo carpetas de 1a Clase
- Ver carpetas de 1a y 2a Clase
- Ver todas excepto las de 2a Clase
+ Ver sólo carpetas de 1ª clase
+ Ver carpetas de 1ª y 2ª clase
+ Ver todas excepto las de 2ª clase
Posición de la firma
Antes del mensaje original
Después del mensaje original
@@ -670,9 +673,9 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Sincronizar en segundo plano
Nunca
Siempre
- Cuando \'sincronización automática\' esté activo
+ Cuando «sincronización automática» esté activo
Seleccionar todos
- Max. carpetas Push
+ Número máximo de carpetas al hacer una comprobación rápida («push»)
5 carpetas
10 carpetas
25 carpetas
@@ -704,11 +707,11 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Tamaño de letra
Configurar el tamaño de letra
Lista de cuentas
- Nombre de Cuenta
+ Nombre de la cuenta
Descripción de la cuenta
Lista de carpetas
- Nombre de Carpeta
- Estado de Carpeta
+ Nombre de la carpeta
+ Estado de la carpeta
Lista de mensajes
Asunto
Remitente
@@ -721,7 +724,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Cco
Encabezados adicionales
Asunto
- Hora y Fecha
+ Hora y fecha
Cuerpo de mensaje
%d%%
%1$s: %2$s
@@ -734,36 +737,36 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Pequeña
Mediana
Grande
- Muy Grande
- No existe aplicación para realizar esta acción.
- Fallo de envío: %s
+ Muy grande
+ No existe ninguna aplicación con la que realizar esta acción.
+ No se pudo enviar: %s
¿Guardar como borrador?
¿Guardar o descartar este mensaje?
¿Guardar o descartar cambios?
¿Descartar mensaje?
- ¿Está seguro de descartar este mensaje?
- Seleccionar texto a copiar.
+ ¿Seguro que quieres descartar este mensaje?
+ Selecciona el texto a copiar.
¿Limpiar mensajes locales?
- Esto eliminará todos los mensajes locales de la carpeta. No se eliminarán mensajes del servidor.
+ Esto borrará todos los mensajes locales de la carpeta. No se eliminará ningún mensaje en el servidor.
Limpiar mensajes
Confirmar borrado
- ¿Quiere borrar este mensaje?
+ ¿Seguro que quieres borrar este mensaje?
- - ¿Realmente desea borrar este mensaje?
- - ¿Realmente desea borrar %1$d mensajes?
+ - ¿Seguro que quieres borrar este mensaje?
+ - ¿Seguro que quieres borrar %1$d mensajes?
Sí
No
Confirmar marcar todos como leídos
- ¿Desea marcar todos los mensajes como leídos?
+ ¿Quieres marcar todos los mensajes como leídos?
Confirmar vaciado de papelera
¿Quieres vaciar la papelera?
Sí
No
- Confirmar mover a la carpeta Spam
+ Mover a la carpeta de spam
- - ¿Quiere mover este mensaje a la carpeta Spam?
- - ¿Quiere realmente mover %1$d mensajes a la carpeta Spam?
+ - ¿Seguro que quieres mover este mensaje a la carpeta de Spam?
+ - ¿Seguro que quieres mover %1$d mensajes a la carpeta de Spam?
Sí
No
@@ -782,37 +785,37 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Seleccionar archivo
Importar
Los ajustes se han importado correctamente
- Por favor, introduzca contraseñas
+ Introduce tus contraseñas
La importación de ajustes ha fallado
Fallo al leer el archivo de ajustes
La importación de algunos ajustes ha fallado
Importado correctamente
- Se requiere contraseña
+ Se necesita una contraseña
No importado
- Fallo en la importación
+ La importación ha fallado
Más tarde
Importar ajustes
Importando ajustes…
- - Para poder usar la cuenta \"%s\" necesita proporcionar la contraseña del servidor.
- - Para poder usar la cuenta \"%s\" necesita proporcionar las contraseñas del servidor.
+ - Para poder usar la cuenta \"%s\" es necesario proporcionar la contraseña del servidor.
+ - Para poder usar la cuenta \"%s\" es necesario proporcionar las contraseñas del servidor.
Contraseña del servidor de correo entrante
Contraseña del servidor de correo saliente
Usar la misma contraseña para el servidor de correo saliente
Nombre del servidor: %s
- Mostrar contador no leídos para…
+ Mostrar contador de «no leídos» para…
Cuenta
- La cuenta para la que se debe visualizar la cantidad de no leídos
+ La cuenta para la que se debe visualizar la cantidad de «no leídos»
Entrada unificada
Cantidad de carpetas
- Mostrar la cantidad de no leídos de una sola carpeta
+ Mostrar la cantidad de «no leídos» de una sola carpeta
Carpeta
- La carpeta para la que se debe visualizar la cantidad de no leídos
+ La carpeta para la que se debe visualizar la cantidad de «no leídos»
Listo
%1$s - %2$s
- Ninguna cuenta marcada
- Ninguna carpeta marcada
+ No se ha seleccionado ninguna cuenta
+ No se ha seleccionado ninguna carpeta
Sin texto
Abrir enlace
Compartir enlace
@@ -826,13 +829,13 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Descargar imagen
Copiar URL de imagen al portapapeles
URL de la imagen
- Número llamada
- Guardar en Contactos
- Copiar Nº teléfono en el portapapeles
- Número teléfono
+ Llamar al número de teléfono
+ Guardar en contactos
+ Copiar número de teléfono al portapapeles
+ Número de teléfono
Enviar mensaje
- Guardar en Contactos
- Copiar dirección de correo en portapapeles
+ Guardar en contactos
+ Copiar dirección de correo al portapapeles
Dirección de correo
Todos
10
@@ -843,16 +846,16 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
500
1000
Limitar resultados en búsquedas en el servidor
- Enviar consulta al servidor
+ Haciendo petición al servidor
- - Obteniendo %d resultado
- - Obteniendo %d resultados
+ - Obteniendo %d elemento
+ - Obteniendo %d elementos
- - Obteniendo resultado %1$d de %2$d
- - Obteniendo resultado %1$d de %2$d
+ - Obteniendo elemento %1$d de %2$d
+ - Obteniendo elemento %1$d de %2$d
- La búsqueda en remoto falló
+ Ha fallado la búsqueda remota
Buscar
Habilitar búsqueda en servidor
Buscar mensajes en servidor y en dispositivo
@@ -869,7 +872,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Siempre
Nunca
Cuando esté en orientación horizontal
- Por favor seleccione un mensaje en la izquierda
+ Selecciona un mensaje en la parte izquierda
Mostrar imágenes de contactos
Mostrar imágenes de contactos en la lista de mensajes
Marcar todo como leído
@@ -881,14 +884,14 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Enviando mensaje
Guardando borrador
Recuperando adjunto…
- No ha sido posible autenticarse. El servidor no anuncia la capacidad SASL EXTERNAL. Esto puede ser debido a un problema con el certificado de cliente (expirado, autoridad certificadora desconocida) o algún otro problema de configuración.
+ No ha sido posible autenticarse. El servidor no parece ser compatible con SASL EXTERNAL. Esto puede deberse a un problema con el certificado cliente (expirado o de autoridad certificadora desconocida) o algún otro problema de configuración.
Usar certificado de cliente
Sin certificado de cliente
Borrar la selección de certificado de cliente
- Fallo al recuperar certificado de cliente para el alias \"%s\"
+ Fallo al recuperar certificado de cliente para el alias «%s»
Opciones avanzadas
- El certificado de cliente \"%1$s\" ha expirado o aún no es válido (%2$s)
+ El certificado de cliente «%1$s» ha expirado o aún no es válido (%2$s)
*Cifrado*
Agregar desde los contactos
@@ -902,36 +905,36 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Trabajo
Otro
Móvil
- ¡No se ha configurado carpeta de borradores para esta cuenta!
- ¡No hay clave configurada para esta cuenta! Compruebe su configuración.
- El proveedor de Crypto utiliza una versión incompatible. ¡Compruebe su configuración!
- ¡No se ha podido conectar con el proveedor de cifrado, compruebe su configuración o haga clic en el icono de cifrado para reintentar!
- Fallo al inicializar el cifrado de extremo a extremo, compruebe su configuración
- ¡El modo PGP/INLINE no soporta adjuntos!
- Habilitar PGP/INLINE
- Deshabilitar PGP/INLINE
- Habilitar solo firma PGP
- Deshabilitar solo firma PGP
+ Parece que no se ha configurado una carpeta de borradores para esta cuenta.
+ Parece que no hay ninguna clave configurada para esta cuenta, revisa los ajustes.
+ Parece que el proveedor de cifrado utiliza una versión incompatible, revisa los ajustes.
+ No se ha podido conectar con el proveedor de cifrado, revisa los ajustes o haz clic en el icono de cifrado para probar otra vez.
+ No se ha podido establecer el cifrado de extremo a extremo, revisa los ajustes.
+ El modo PGP/INLINE no soporta adjuntos.
+ Activar modo PGP/INLINE
+ Desactivar modo PGP/INLINE
+ Activar el modo de solo-firma PGP
+ Desactivar el modo de solo-firma PGP
Modo PGP/INLINE
- El correo se envía en formato PGP/INLINE.\nEsto solamente debe usarse por compatibilidad:
+ El correo se va a enviar en formato PGP/INLINE.\nEsto solamente debe usarse por temas de compatibilidad:
Algunos clientes solamente soportan este formato
- Las firmas pueden romperse en el tránsito
- No se soportan adjuntos
- ¡De acuerdo!
- Deshabilitar
- Mantener habilitado
- ¡Entendido!
- Deshabilitar
- Mantener habilitado
- Modo de solo firma PGP
- En este modo, la clave PGP se usará para crear una firma criptográfica en un correo no cifrado.
+ Las firmas pueden corromperse o perderse en el tránsito
+ No es posible adjuntar archivos
+ Vale, entendido
+ Desactivar
+ Mantener activado
+ Vale, entendido
+ Desactivar
+ Mantener activado
+ Modo de solo-firma PGP
+ En este modo la clave PGP se usará para crear una firma criptográfica en un correo no cifrado.
Esto no cifra el correo, pero permite verificar que fue enviado con esa clave.
- Las firmas pueden estropearse al ser enviadas a listas de correo.
- Algunos clientes de correo mostrarán las firmas como adjuntos \'signature.asc\'.
- Los mensajes cifrados siempres incluirán una firma.
+ Las firmas pueden estropearse o perderse al enviarse a listas de correo.
+ Algunos clientes de correo mostrarán las firmas como adjuntos «signature.asc».
+ Los mensajes cifrados siempre incluirán una firma.
Texto plano
- La firma de extremo a extremo contiene un error
- El mensaje debe descargarse completamente para verificar su firma
+ la firma de extremo a extremo contiene un error
+ el mensaje debe descargarse completamente para verificar su firma
contiene una firma de extremo a extremo incompatible
El mensaje está cifrado, pero en un formato no soportado.
El mensaje está cifrado, pero se ha cancelado el descifrado.
@@ -945,8 +948,8 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
desde una clave de extremo a extremo desconocida
Cifrado
pero hubo un error de descifrado
- debe descargar completamente el mensaje para descifrarlo
- pero no hay configurada una aplicación crypto
+ debe descargarse completamente el mensaje para descifrarlo
+ pero no hay aplicación de cifrado instalada
Cifrado
pero no de extremo a extremo
Cifrado de extremo a extremo
@@ -960,7 +963,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
pero los datos de extremo a extremo tienen errores
pero el cifrado es inseguro
Aceptar
- Buscar Clave
+ Buscar clave
Ver firmante
Ver remitente
Detalles
@@ -973,35 +976,35 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
El mensaje cifrado debe descargarse para descifrarlo.
Error descifrando el correo
¡Los caracteres especiales aún no están soportados!
- ¡Error al analizar la dirección!
+ Hubo un error al analizar la dirección.
Ocultar firmas no cifradas
Sólo se mostrarán firmas cifradas
Se mostrarán todas las firmas
- ¡El cifrado no está disponible en el modo de solo firma!
+ El cifrado no está disponible en el modo de solo-firma.
Texto sin firmar
- Aviso sobre desuso de APG
- ¡APG ya no se mantiene!
- Debido a esto, el soporte para APG se ha eliminado de K-9 Mail.
+ Aviso sobre el desuso y obsolescencia de APG
+ APG está obsoleto y ya no recibe actualizaciones
+ Y por ello la funcionalidad APG se ha eliminado de K-9 Mail.
El desarrollo se detuvo a principios de 2014
Contiene problemas de seguridad sin arreglar
- Puede pulsar aquí para saber más.
- ¡Entendido!
+ Puedes pulsar aquí para leer más sobre el tema (en inglés).
+ Vale, entendido
APG
Este correo está cifrado
- Este correo ha sido cifrado con OpenPGP.\nPara leerlo, necesita instalar y configurar una aplicación compatible con OpenPGP.
- Ir a los Ajustes
+ Este correo ha sido cifrado con OpenPGP.\nPara leerlo es necesario instalar y configurar una aplicación compatible con OpenPGP.
+ Ir a Ajustes
Lista de mensajes de K-9
Cargando mensajes…
- Ha fallado la recuperación de la lista de carpetas
- ¡Error al recuperar el estado del destinatario del proveedor de OpenPGP!
- Imposible el cifrado
- ¡Algunos remitentes marcados no soportan esta característica!
+ No se ha podido recuperar la lista de carpetas
+ Hubo un error al recuperar el estado del destinatario desde el proveedor de OpenPGP.
+ No es posible cifrar
+ Algunos de los remitentes marcados no entienden esta característica
Activar cifrado
Desactivar cifrado
- El cifrado de los mensajes asegura que puedan ser leídos por el destinatario y por nadie más.
- El cifrado sólo aparecerá si todos los destinatarios lo admiten, y deben haberle enviado un mensaje de correo electrónico anteriormente.
+ El cifrado de los mensajes asegura que solo el destinatario final pueda leer el contenido del correo.
+ El cifrado sólo estará disponible si todos los destinatarios lo admiten, y deben de haberte enviado al menos un mensaje de correo electrónico de antemano.
Alternar cifrado al pulsar este icono.
- ¡Entendido!
+ Vale, entendido
Atrás
Desactivar cifrado
Cifrado de OpenPGP
@@ -1009,7 +1012,7 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Autocifrar el modo mutuo
Normalmente, los mensajes se cifran por elección o cuando se responde a un mensaje cifrado.
Si tanto el remitente como los destinatarios activan el modo mutuo, el cifrado se activará de forma predefinida.
- Puede pulsar aquí para saber más.
+ Puedes pulsar aquí para leer más sobre el tema.
Configuración general
Sin aplicación OpenPGP instalada
Instalar
@@ -1017,8 +1020,8 @@ Por favor informe de fallos, aporte nueva funcionalidad o envíe sus preguntas a
Mensaje cifrado
Asunto del mensaje cifrado
Puede ser incompatible con algunos destinatarios
- Error interno: ¡Cuenta inválida!
- ¡Error conectándose a %s!
+ Error interno: la cuenta no existe.
+ Error al conectarse con %s
Enviar mensaje de configuración de Autocrypt
Compartir configuración punto-a-punto con otros dispositivos de forma segura
Mensaje de configuración Autocrypt
@@ -1037,22 +1040,24 @@ Para configurar su nuevo dispositivo con Autocrypt, por favor siga las instrucci
Puede mantener este mensaje y usarlo como copia de seguridad de su clave secreta. Si desea hacer esto, debería anotar la contraseña y guardarla de manera segura.
Ha ocurrido un error al enviar el mensaje, por favor verifique su conexión a internet y la configuración del servidor de salida.
- Encendido
- Apagado
+ Sí
+ No
Abrir
Cerrar
Permitir acceso a contactos
- Para poder proveer sugerencias de contactos y mostrar sus nombres, la app necesita acceso a éstos.
+ Para poder proveer sugerencias de contactos y mostrar sus nombres la aplicación necesita acceso a los contactos locales del dispositivo.
Se produjo un error al cargar los datos
Iniciando...
- Esperando nuevos correos electrónicos
+ Esperando correos electrónicos nuevos
Esperar hasta que se permita la sincronización en segundo plano
Esperar hasta que la red esté disponible
- Toque para obtener más información.
- Empujar Info
+ Toca aquí para leer más sobre el tema.
+ Información sobre comprobaciones rápidas («push»)
+ Al utilizar la comprobación rápida de mensajes (conocido como «push», o IDLE) K-9 Mail mantiene una conexión permanente e ininterrumpida con el servidor de correo. Por limitaciones de Android esto requiere mostrar una notificación mientras realiza esta acción en un segundo plano. %s
Sin embargo, Android también te permite ocultar la notificación.
- Aprende más
- Configurar notificación
- Deshabilitar Push
+ Leer más sobre el tema
+ Configurar la apariencia de la notificación
+ En caso de no necesitar notificaciones instantáneas de mensajes nuevos puedes desactivar las comprobaciones rápidas («push», o IDLE) y seguir utilizando comprobaciones normales («poll»); esta opción clásica pregunta al servidor de vez en cuando, conectándose de forma esporádica a intervalos regulares y no necesita mantener una conexión permanente ni mantener un servicio y notificación constante en segundo plano. Gastando menos batería.
+ Desactivar sincronización rápida («push»)
diff --git a/app/ui/legacy/src/main/res/values-gd/strings.xml b/app/ui/legacy/src/main/res/values-gd/strings.xml
index 2ba66ebe53..0b65048240 100644
--- a/app/ui/legacy/src/main/res/values-gd/strings.xml
+++ b/app/ui/legacy/src/main/res/values-gd/strings.xml
@@ -3,47 +3,20 @@
- Post K-9
- Cunntasan K-9
- K-9 – Gun leughadh
+ Post
+ Cunntasan puist
+ Post gun leughadh
+ Google, luchd-coiseachd nan con K-9.
Còir-lethbhreac 2008-%s Luchd-coiseachd nan con K-9. Cuid dhen chòir-lethbhreac 2006-%s Android Open Source Project.
+ Fo cheadachas Apache, tionndadh 2.0.
- Fàilte gu post K-9
-
-Tha post K-9 ’na aplacaid shaor agus chumhachdach airson post-d air Android.
-
-Chaidh na gleusan a leanas a chur ris o chionn goirid:
-
-
- - Push Mail slighe IMAP IDLE
- - Dèanadas nas fhearr
- - Ath-fhaidhleadh theachdaireachdan
- - Earr-sgrìobhaidhean puist-d
- - Bcc dhut fhèin
- - Fo-sgrìobhaidhean phasganan
- - Sioncronachadh nam pasgan air fad
- - Rèiteachadh seòladh nam freagairt
- - Ath-ghoiridean a’ mheur-chlàir
- - Taic nas fhearr airson IMAP
- - Sàbhaladh de cheanglaichean air SD
- - Falamhachadh an sgudail
- - Seòrsachadh theachdaireachdan
- - …is mòran a bharrachd
-
-
-Thoir an aire nach cuir K-9 taic ri cuid mhòr de chunntasan saor Hotmail agus mar iomadh prògram puist-d
-tachraidh rudan neònach nuair a bhruidhneas e ri Microsoft Exchange.
-
-Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceistean aig
-https://github.com/k9mail/k-9/.
-
- ]]>
+ Fàilte gu aplacaid a’ phuist
+ <p> Tha aplacaid a’ phuist ’na aplacaid shaor agus chumhachdach airson post-d air Android. </p><p> Tha na gleusan leasaichte aige a’ gabhail a-staigh: </p> <ul> <li>Put post slighe IMAP IDLE</li> <li>Dèanadas nas fheàrr</li> <li>Ath-fhaidhleadh theachdaireachdan</li> <li>Eàrr-sgrìobhaidhean puist-d</li> <li>Bcc dhut fhèin</li> <li>Fo-sgrìobhaidhean phasganan</li> <li>Sioncronachadh nam pasgan air fad</li> <li>Rèiteachadh seòladh nam freagairt</li> <li>Ath-ghoiridean a’ mheur-chlàir</li> <li>Taic nas fheàrr airson IMAP</li> <li>Sàbhaladh de cheanglachain air SD</li> <li>Falamhachadh an sgudail</li> <li>Seòrsachadh theachdaireachdan</li> <li>…is mòran a bharrachd</li> </ul> <p> Thoir an aire nach cuir aplacaid a’ phuist taic ri cuid mhòr de chunntasan saora Hotmail agus mar iomadh prògram puist-d eile, tachraidh rudan neònach nuair a bhruidhneas e ri Microsoft Exchange. </p><p> Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceistean aig <a href=https://github.com/k9mail/k-9/>https://github.com/k9mail/k-9/</a>. </p>
- -- \nAir a chur on uidheam Android agam slighe post K-9.
+ -- Chaidh a chur le post /e/.
- Thèid an cunntas “%s” a thoirt air falbh o phost K-9.
+ Thèid an cunntas “%s” a thoirt air falbh on phost.
Puist-d a leughadh
Leig leis an aplacaid seo na puist-d agad a leughadh.
@@ -56,12 +29,14 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Freagair
Freagair na h-uile
Sìn air adhart
+ Sìn air adhart mar cheanglachan
+ Tagh cunntas
Tagh pasgan
Ceasnaich %s:%s%s
A’ faighinn nam bannan-cinn %s:%s%s
A’ cur %s%s
- Proc %s:%s%s
- \u0020%d/%d
+ Pròiseas %s:%s%s
+ %d/%d
Chaidh an sioncronachadh a chur à comas
%d air a thaghadh
Air adhart
@@ -71,7 +46,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Sguir dheth
Cuir
Cuir a-rithist
- Cha do shònraich thu cuspair, thoir gnogag às ùr airson a chur co-dhiù
+ Tha an cuspair falamh, thoir gnogag a-rithist airson a chur co-dhiù
Tagh
Dì-thagh
Freagair
@@ -80,6 +55,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Tasg-lann
Spama
Sìn air adhart
+ Sìn air adhart mar cheanglachan
Gluais
Cuir…
Ath-fhaidhlich…
@@ -89,10 +65,10 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Thoir sùil airson post
Cuir na teachdaireachdan
Ath-nuadhaich liosta nam pasgan
- Lorg pasgan
+ Lorg sa phasgan
Cuir cunntas ris
Sgrìobh
- Lorg
+ Lorg sa phost
Toraidhean an luirg
Roghainnean
Roghainnean a’ chunntais
@@ -102,7 +78,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Tagh seòladair
Cuir rionnag ris
Thoir an rionnag air falbh
- Lethbhreac
+ Dèan lethbhreac
Seall na bannan-cinn
- Chaidh an seòladh a chur air an stòr-bhòrd
@@ -114,8 +90,8 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Cleachd ùrlar soilleir ’na àite
Comharraich nach deach a leughadh
Cuidhteas-leughaidh
- Iarraidh seo cuidhteas-leughaidh
- Chan iarr seo cuidhteas-leughaidh
+ Thèid cuidhteas-leughaidh iarraidh
+ Cha dèid cuidhteas-leughaidh iarraidh
Cuir ceanglachan ris
Falamhaich an sgudal
Thoir air falbh gu tur
@@ -128,9 +104,8 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Mearachd leis a’ cheangal
Cha deach an teachdaireachd a lorg
Mearachd a’ luchdadh na teachdaireachd
- Luchdaich suas ri
- to %d a bharrachd
- Bha an cunntas “%s” %s is tha e %s a-nis
+ Luchdaich suas ri %d a bharrachd
+ Bha an cunntas “%s” %s is chan eil e ach %s a-nis
A’ dùmhlachadh a’ chunntais “%s”
Post ùr
@@ -174,7 +149,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Gu:%s
Cuspair
Teacsa na teachdaireachd
- An t-earr-sgrìobhadh
+ Eàrr-sgrìobhadh
-------- An teachdaireachd thùsail --------
Cuspair:
Air a chur:
@@ -184,17 +159,20 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Sgrìobh %s:
Sgrìobh %2$s %1$s:
Feumaidh tu co-dhiù aon neach a chur ris a gheibh e.
- Tha rud ann an raon nan daoine a gheibh e a tha leth-chrìochnaichte!
+ Tha rud ann an raon nam faightearan a tha leth-chrìochnaichte!
Cha b’ urrainn dhuinn seòladh puist-d a lorg dhan neach-aithne seo.
Chan urrainn dhuinn cuid dhe na ceanglachain a shìneadh air adhart oir cha deach an luchdadh a-nuas.
- Thoir an luaidh air falbh
- Crìoch na na luaidhe
+ Cha ghabh an teachdaireachd a shìneadh air adhart o nach deach a h-uile ceanglachan aice a luchdadh a-nuas.
+ Gabh a-staigh às-earrann na teachdaireachd
+ Thoir an às-earrann air falbh
+ Deasaich an às-earrann
O: %s <%s>
Gu:
Cc:
Bcc:
Fosgail
Sàbhail
+ Cha b’ urrainn dhuinn an ceanglachan a shàbhaladh.
Seall na dealbhan
Chan urrainn dhuinn aplacaid a lorg a sheallas %s.
Luchdaich a-nuas an teachdaireachd shlàn
@@ -204,28 +182,29 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Chaidh gach bann-cinn a luchdadh a-nuas ach chan eil bann-cinn eile ann a ghabhas a shealltainn.
Cha b’ urrainn dhuinn bannan-cinn a bharrachd fhaighinn on stòr-dàta no o fhrithealaiche a’ phuist.
Barrachd on t-seòladair seo
+ O %s
Dì-bhugaich / Falamhaich bodhaig na teachdaireachd
Chaidh an teachdaireachd a thilgeil air falbh
Chaidh an teachdaireachd a shàbhaladh mar dhreachd
Seall na rionnagan
Tha rionnagan a’ comharradh teachdaireachdan le bratach
- Loidhnichean a ro-shealladh
+ Loidhnichean ro-sheallaidh
Seall ainmean nan seòladairean
Seall ainmean nan seòladairean seach na seòlaidhean puist-d aca
An seòladair os cionn a’ chuspair
Seall ainmean nan seòladairean os cionn a’ chuspair seach foidhe
Seall ainmean an luchd-aithne
- Cleachd ainmean o luchd-aithne Android ma tha gin ann
+ Cleachd ainmean o aplacaid an luchd-aithne ma tha gin ann
Cuir dathan air an luchd-aithne
Cuir dathan air ainmean ann an liosta an luchd-aithne agad
Cruthan-clò le leud socraichte
- Cleachd cruth-clò le leud socraichte nuair a thèid taisbeanadh ann an teacsa lom a shealltainn
+ Cleachd cruth-clò le leud socraichte nuair a thèid teachdaireachd ann an teacsa lom a shealltainn
Fèin-fhreagair teachdaireachdan
Crùb teachdaireachdan ach am freagair iad ris an sgrìn
Till gun liosta an dèidh sguabaidh às
Till gun liosta an dèidh teachdaireachd a sguabadh às
Seall an ath-theachdaireachd an dèidh sguabaidh às
- Seall an ath-theachdaireachd a ghnàth an dèidh teachdaireachd a sguabaidh às
+ Seall an ath-theachdaireachd a ghnàth an dèidh teachdaireachd a sguabadh às
Dearbh gnìomhan
Seall còmhradh uair sam bith a nì thu gnìomh sònraichte
Sguab às
@@ -235,7 +214,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Comharraich gun deach gach teachdaireachd a leughadh
Sguab às (on bhrath)
Falaich cliant a’ phuist
- Thoir air falbh an raon K-9 User-Agent on bhannan-cinn phost
+ Thoir air falbh an raon Mail User-Agent o bhannan-cinn phost
Falaich an roinn-tìde
Cleachd UTC an àite na roinn-tìde ionadail ann am bannan-cinn phost is fhreagairtean
Falaich an cuspair ann am brathan
@@ -253,7 +232,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Co mheud teachdaireachd is seòladair
An aon rud nuair nach bi an sgrìn glaiste
Amannan sàmhach
- Cuir seirm, srann is boillsgeadh à comas rè na h-oidhche
+ Cuir seirm, crith is boillsgeadh à comas rè na h-oidhche
Cuir na brathan à comas
Cuir na brathan à comas buileach rè nan amannan sàmhach
Tòisichidh an t-àm sàmhach
@@ -262,7 +241,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Seòladh puist-d
Facal-faire
Seall am facal-faire
- Suidheachadh de làimh
+ Suidheachadh a làimh
A’ faighinn fiosrachadh a’ chunntais…
A’ sgrùdadh roghainnean an fhrithealaiche a-steach…
@@ -271,10 +250,10 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
A’ faighinn roghainnean a’ chunntais…
A’ sgur dheth…
Cha mhòr deiseil!
- Thoir ainm air a’ chunntas seo (roghainneil):
+ Thoir ainm air a’ chunntas seo
Cuir a-steach d’ ainm (chithear seo ann an teachdaireachdan a thèid a-mach):
Seòrsa a’ chunntais
- Dè seòrsa cunntas a tha seo?
+ Dè seòrsa cunntas a tha seo\?
POP3
IMAP
Facal-faire àbhaisteach
@@ -296,9 +275,9 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
STARTTLS
Chan eil “%1$s = %2$s” dligheach mu choinneamh “%3$s = %4$s”
Nuair a sguabas mi teachdaireachd às
- na sguab às an fhrithealaiche e
- sguab às an fhrithealaiche e
- comharraich air an fhrithealaiche gun deach a leughadh
+ Na sguab às an fhrithealaiche e
+ Sguab às an fhrithealaiche e
+ Comharraich air an fhrithealaiche gun deach a leughadh
Cleachd dùmhlachadh air lìonra:
Mobile
WiFi
@@ -306,17 +285,17 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Stòras air an taobh a-muigh (cairt SD)
Stòras inntearnail àbhaisteach
Ma sguabas mi às teachdaireachd, sguab às an fhrithealaiche e
- sa bhad
- aig an ath-cheasnachadh
- a làimh
- Mothaich dha IMAP Namespace gu fèin-obrachail
+ Sa bhad
+ Aig an ath-cheasnachadh
+ A làimh
+ Mothaich dha ainm-spàs IMAP gu fèin-obrachail
Ro-leasachan slighe IMAP
Pasgan nan dreachdan
Pasgan a’ phuist chuirte
Pasgan an sgudail
Pasgan nan tasg-lann
Pasgan an spama
- Na seall ach pasganan a tha fo-sgrìobhadh agam aca
+ Na seall ach pasganan le fo-sgrìobhadh
Leudaich am pasgan gu fèin-obrachail
Slighe OWA
Roghainneil
@@ -336,7 +315,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Suidheachadh mì-dhligheach: %s
Roghainnean a’ chunntais
Dùmhlaich an cunntas
- Dè cho tric ’s a dh’iarras sinn am post?
+ Dè cho tric ’s a dh’iarras sinn am post\?
Chan ann idir
Gach cairteal na h-uarach
Gach leth-uair a thìde
@@ -346,7 +325,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Gach 6 uairean a thìde
Gach 12 uair a thìde
Gach 24 uair a thìde
- Cuir post push an comas airson a’ chunntais seo
+ Cuir post putaidh an comas airson a’ chunntais seo
Ma bheir am frithealaiche agad taic dha, nochdaidh teachdaireachdan ùra sa bhad. Faodaidh buaidh mhòr (math no dona) a bhith aig an roghainn seo air dèanadas.
Ath-nuadhaich an ceangal IDLE
Gach 2 mhionaid
@@ -357,8 +336,8 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Gach 36 mionaid
Gach 48 mionaid
Gach uair a thìde
- Innis dhomh nuair a ruigeas post
- Innis dhomh nuair a thathar a’ toirt sùil airson post
+ Thoir brath dhomh nuair a ruigeas post
+ Thoir brath dhomh nuair a thathar a’ toirt sùil airson post
Co mheud teachdaireachd a thèid a shealltainn
10 teachdaireachdan
25 teachdaireachd
@@ -367,15 +346,19 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
250 teachdaireachd
500 teachdaireachd
1,000 teachdaireachd
- 2.500 teachdaireachd
+ 2,500 teachdaireachd
5,000 teachdaireachd
10,000 teachdaireachd
na h-uile teachdaireachd
Chan urrainn dhut lethbhreac a dhèanamh de theachdaireachd, no a ghluasad, mur eil e sioncronaichte leis an fhrithealaiche
Cha b’ urrainn dhuinn an suidheachadh a choileanadh
- Tha an t-ainm-cleachdaiche no facal-faire cearr.\n(%s)
- Nochd am frithealaiche teisteanas SSL nach eil dligheachd. Tachraidh seo uaireannan ma chaidh am frithealaiche a dhroch-rèiteachadh. Air neo dh’fhaoidte gu bheil cuideigin airson briseadh a-steach ort no air frithealaiche a’ phuist agad. Mur eil thu cinnteach dè tha a’ tachairt, thoir gnogag air “Diùlt” is cuir fios gu na daoine a stiùireas frithealaiche a’ phuist agad.\n\n(%s)
- Chan urrainn dhuinn ceangal ris an fhrithealaiche.\n(%s)
+ Tha an t-ainm-cleachdaiche no facal-faire ceàrr.
+\n(%s)
+ Nochd am frithealaiche teisteanas SSL nach eil dligheach. Tachraidh seo uaireannan ma chaidh am frithealaiche a dhroch-rèiteachadh. Air neo dh’fhaoidte gu bheil cuideigin airson briseadh a-steach ort no air frithealaiche a’ phuist agad. Mur eil thu cinnteach dè tha a’ tachairt, thoir gnogag air “Diùlt” is cuir fios gu na daoine a stiùireas frithealaiche a’ phuist agad.
+\n
+\n(%s)
+ Chan urrainn dhuinn ceangal ris an fhrithealaiche.
+\n(%s)
Deasaich am fiosrachadh
Lean air adhart
Adhartach
@@ -385,53 +368,70 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Brathan mu phost ùr
Pasganan a chuireas brath
Na h-uile
- Pasganan na 1ad ìre a-mhàin
- Pasganan na 1ad is na 2na ìre
- Gach aon ach pasganan na 2na ìre
+ Pasganan na 1ᵈ ìre a-mhàin
+ Pasganan na 1ᵈ is na 2ⁿᵃ ìre
+ Gach aon ach pasganan na 2ⁿᵃ ìre
Chan eil gin
Brathan sioncronachaidh
An seòladh puist-d agad
- Innis dhomh air bàr na staide nuair a ruigeas post
- Innis dhomh air bàr na staide nuair a thathar a’ toirt sùil airson post
+ Thoir brath dhomh air bàr na staide nuair a ruigeas post
+ Thoir brath dhomh air bàr na staide nuair a thathar a’ toirt sùil airson post
Gabh a-staigh post a tha a’ dol a-mach
Seall brath nuair a bhios mi air teachdaireachd a chur
Luchd-aithne a-mhàin
- Na seall brathan ach ma thig teachdaireachd o neach-aithne agam
- Comharraich gun deach a leughadh nuair a dh’fhosglas mi e
- Comharraich gun deach an teachdaireachd a leughadh nuair a dh’fhosglas mi e a choimhead air
+ Na seall brath ach ma thig teachdaireachd o neach-aithne agam
+ Comharraich gun deach a leughadh nuair a dh’fhosglas mi i
+ Comharraich gun deach an teachdaireachd a leughadh nuair a dh’fhosglas mi i a choimhead air
Seall dealbhan an-còmhnaidh
- Chan eil
+ Na seall idir
On luchd-aithne
O dhuine sam bith
- A’ cur a’ phuist
- Dèan luaidh air an teachdaireachd ann am freagairt
+ Cur a’ phuist
+ Cuir às-earrann dhen teachdaireachd ris an fhreagairt
Gabh a-staigh an teachdaireachd thùsail ’nad theachdaireachd.
- Freagair an dèidh na luaidhe
+ Freagair às dèidh na h-às-earrainn
Nochdaidh an teachdaireachd thùsail os cionn do fhreagairt.
- Spìon earr-sgrìobhadh sam bith às ann am freagairt
- Thèid earr-sgrìobhaidhean a thoirt air falbh o theachdaireachd air a bheilear a’ dèanamh luaidh
+ Spìon eàrr-sgrìobhadh sam bith às ann am freagairt
+ Thèid earr-sgrìobhaidhean a thoirt air falbh o às-earrannan theachdaireachdan
Fòrmat na teachdaireachd
Teacsa lom (thoir air falbh dealbhan is fòrmatadh)
HTMP (glèidh na dealbhan is am fòrmatadh)
- Gu fèin-obrachail
- Seall an Cc/Bcc an-còmhnaidh
+ Fèin-obrachail
+ Seall Cc/Bcc an-còmhnaidh
Cuidhteas-leughaidh
Iarr cuidhteas-leughaidh an-còmhnaidh
- Stoidhle nan luaidhean ann am freagairtean
+ Stoidhle nan às-earrannan ann am freagairtean
Le ro-leasachan (mar Gmail)
Bann-cinn (mar Outlook)
Roghainnean coitcheann
A’ leughadh post
A’ faighinn post
Pasganan
- Ro-leasachan teacsa nan luaidh
- Dè cho tric ’s a dh’iarras sinn am post?
+ Ro-leasachan na h-às-earrainn
+ Crioptografachd
+ Aplacaid OpenPGP
+ An iuchair agam
+ Dè cho tric ’s a dh’iarras sinn am post\?
Dath a’ chunntais
- Dath cuideam a’ chunntais seo a chithear ann am pasganan is liosta nan cunntas
+ Dath soillearachadh a’ chunntais seo a chithear ann am pasganan is liosta nan cunntas
Dath LED nam brath
An dath a bhios air LED an uidheim agad dhan chunntas seo
Meud a’ phasgain ionadail
Faigh teachdaireachdan suas ri
+ 1KB
+ 2KB
+ 4KB
+ 8KB
+ 16KB
+ 32KB
+ 64KB
+ 128KB
+ 256KB
+ 512KB
+ 1MB
+ 2MB
+ 5MB
+ 10MB
meud sam bith (gun chrìoch)
Sioncronaich teachdaireachdan
o àm sam bith (gun chrìoch)
@@ -445,51 +445,53 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
on 2 mhìos seo chaidh
o na 3 mìosan seo chaidh
on na 6 mìosan seo chaidh
- on uraidh
+ on uiridh
Na pasganan a thèid a shealltainn
Na h-uile
- Pasganan na 1ad ìre a-mhàin
- Pasganan na 1ad is na 2na ìre
- Gach aon ach pasganan na 2na ìre
+ Pasganan na 1ᵈ ìre a-mhàin
+ Pasganan na 1ᵈ is na 2ⁿᵃ ìre
+ Gach aon ach pasganan na 2ⁿᵃ ìre
Na pasganan a thèid a cheasnachadh
Na h-uile
- Pasganan na 1ad ìre a-mhàin
- Pasganan na 1ad is na 2na ìre
- Gach aon ach pasganan na 2na ìre
+ Pasganan na 1ᵈ ìre a-mhàin
+ Pasganan na 1ᵈ is na 2ⁿᵃ ìre
+ Gach aon ach pasganan na 2ⁿᵃ ìre
Chan eil gin
- Na pasganan push
+ Na pasganan putaidh
Na h-uile
- Pasganan na 1ad ìre a-mhàin
- Pasganan na 1ad is na 2na ìre
- Gach aon ach pasganan na 2na ìre
+ Pasganan na 1ᵈ ìre a-mhàin
+ Pasganan na 1ᵈ is na 2ⁿᵃ ìre
+ Gach aon ach pasganan na 2ⁿᵃ ìre
Chan eil gin
Pasganan dhan a chuirear lethbhreacan/dhan a ghluaisear
Na h-uile
- Pasganan na 1ad ìre a-mhàin
- Pasganan na 1ad is na 2na ìre
- Gach aon ach pasganan na 2na ìre
+ Pasganan na 1ᵈ ìre a-mhàin
+ Pasganan na 1ᵈ is na 2ⁿᵃ ìre
+ Gach aon ach pasganan na 2ⁿᵃ ìre
Sioncronaich sguabadh às air an fhrithealaiche
Thoir air falbh teachdaireachdan a chaidh a sguabadh às an fhrithealaiche
Roghainnean a’ phasgain
- Seall aig a’ bharr sa bhuidheann
- Seall faisg air barr liosta nam pasganan
+ Seall aig a’ bhàrr sa bhuidheann
+ Seall faisg air bàrr liosta nam pasganan
Ìre taisbeanadh a’ phasgain
- Gun chlas
- 1ad ìre
- 2na ìre
+ Gun ìre
+ 1ᵈ ìre
+ 2ⁿᵃ ìre
+ Ìre nam pasgan a thèid a cheasnachadh
Chan eil gin
- 1ad ìre
- 2na ìre
+ 1ᵈ ìre
+ 2ⁿᵃ ìre
Co-ionnann ris an ìre taisbeanaidh
- Ìre push a’ phasgain
- Gun chlas
- 1ad ìre
- 2na ìre
+ Ìre putadh a’ phasgain
+ Gun ìre
+ 1ᵈ ìre
+ 2ⁿᵃ ìre
+ Co-ionnann ris an ìre sioncronachaidh
Ìre brathan a’ phasgain
- Gun chlas
- 1ad ìre
- 2na ìre
- Co-ionnann ris an ìre push
+ Gun ìre
+ 1ᵈ ìre
+ 2ⁿᵃ ìre
+ Co-ionnann ris an ìre putaidh
Falamhaich na teachdaireachdan ionadail
Am frithealaiche a-steach
Rèitich frithealaiche a’ phuist a-steach
@@ -499,7 +501,7 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
D’ ainm
Brathan
Crith
- Cuir air chrith nuair a ruigeas post
+ Dèan crith nuair a ruigeas post
Pàtranan crith
bun-roghainn
pàtran 1
@@ -513,21 +515,21 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Boillsg an LED nuair a ruigeas post
Roghainnean sgrìobhadh theachdaireachdan
Bun-roghainnean sgrìobhaidh
- Suidhich bun-roghainnean “O”, “Bcc” agus an earr-sgrìobhaidh
- Stiùirich na IDs
- Suidhich seòlaidhean “O” is earr-sgrìobhaidhean eadar-dhealaichte
- Stiùirich na IDs
- Stiùirich an ID
- Deasaich an ID
+ Suidhich bun-roghainnean “O”, “Bcc” agus an eàrr-sgrìobhaidh
+ Stiùirich na dearbh-aithnean
+ Suidhich seòlaidhean “O” is eàrr-sgrìobhaidhean eadar-dhealaichte
+ Stiùirich na dearbh-aithnean
+ Stiùirich an dearbh-aithne
+ Deasaich an dearbh-aithne
Sàbhail
- ID ùr
+ Dearbh-aithne ùr
Cuir Bcc de gach teachdaireachd gu
Deasaich
Gluais suas
Gluais sìos
Gluais suas / dèan a’ bhun-roghainn dheth
Thoir air falbh
- Tuairisgeul na ID
+ Tuairisgeul na dearbh-aithne
(Roghainneil)
D’ ainm
(Roghainneil)
@@ -535,15 +537,15 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
(Riatanach)
An seòladh dhan chuirear freagairtean
(Roghainneil)
- An t-earr-sgrìobhadh
+ An t-eàrr-sgrìobhadh
(Roghainneil)
- Cleachd earr-sgrìobhadh
- An t-earr-sgrìobhadh
- An ID tòiseachail
- Tagh ID
+ Cleachd eàrr-sgrìobhadh
+ An t-eàrr-sgrìobhadh
+ An dearbh-aithne thòiseachail
+ Tagh dearbh-aithne
Cuir mar
- Chan urrainn dhut an aon ID agad a thoirt air falbh
- Chan urrainn dhut ID a chleachdadh gun seòladh puist-d
+ Chan urrainn dhut an aon dearbh-aithne agad a thoirt air falbh
+ Chan urrainn dhut dearbh-aithne a chleachdadh gun seòladh puist-d
Na teachdaireachdan as sine an toiseach
Na teachdaireachdan as ùire an toiseach
Aibidileach a-rèir a’ chuspair
@@ -565,41 +567,72 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Air a leughadh/gun leughadh
Ceanglachain
Thoir an cunntas air falbh
- Teisteanas neo-aithnichte
- Gach ris an iuchair
+ Teisteanas nach aithne dhuinn
+ Gabh ris an iuchair
Diùlt an iuchair
+ Del (no D) – Sguab às
+\nR – Freagair
+\nA – Freagair a h-uile
+\nC – Sgrìobh
+\nF – Sìn air adhart
+\nM – Gluais
+\nV – Cuir san tasg-lann
+\nY – Dèan lethbhreac
+\nZ – Cuir comharra gun deach/nach deach a leughadh
+\nG – Cuir rionnag ris
+\nO – Seòrsa an t-seòrsachaidh
+\nI – Òrdugh an t-seòrsachaidh
+\nQ – Till dha na pasganan
+\nS – Tagh/Dì-thagh
+\nJ no P – An teachdaireachd roimhpe
+\nK no N – An ath-theachdaireachd
+ Del (no D) – Sguab às
+\nC – Sgrìobh
+\nM – Gluais
+\nV – Cuir san tasg-lann
+\nY – Dèan lethbhreac
+\nZ – Cuir comharra gun deach/nach deach a leughadh
+\nG – Cuir rionnag ris
+\nO – Seòrsa an t-seòrsachaidh
+\nI – Òrdugh an t-seòrsachaidh
+\nQ – Till dha na pasganan
+\nS – Tagh/Dì-thagh
+ Ainm a’ phasgain anns a bheil
Seall pasganan…
Na h-uile pasgan
- Pasganan na 1ad ìre
- Pasganan na 1ad ⁊ na 2na ìre
- Falaich pasganan na 2na ìre
- Ionad an earr-sgrìobhaidh
- Ron luaidh air an teachdaireachd
- An dèidh luaidh air an teachdaireachd
+ Pasganan na 1ᵈ ìre
+ Pasganan na 1ᵈ ⁊ na 2ⁿᵃ ìre
+ Falaich pasganan na 2ⁿᵃ ìre
+ Ionad an eàrr-sgrìobhaidh
+ Ron às-earrann dhen teachdaireachd
+ Às dèidh às-earrann dhen teachdaireachd
Cleachd ùrlar na h-aplacaid
Dorcha
Soilleir
- Taisbeanadh
+ Sealladh
Uile-choitcheann
Dì-bhugachadh
Prìobhaideachd
Lìonra
Eadar-ghabhail
Liosta nan cunntasan
- Liosta nan teachdaireachdan
+ Liostaichean theachdaireachdan
Teachdaireachdan
Ùrlar
Ùrlar sealladh nan teachdaireachdan
Ùrlar an sgrìobhaidh
+ Cànan
Ùrlair socraichte airson teachdaireachdan
Tagh ùrlar airson na teachdaireachd is tu a’ coimhead air
Cleachd ùrlair socraichte airson teachdaireachdan
+ Bun-roghainn an t-siostaim
Sioncronachadh sa chùlaibh
Chan ann idir
An-còmhnaidh
Ma tha cromag ri “Sioncronachadh fèin-obrachail”
Tagh na h-uile
- An àireamh as motha a phasganan air an doirear sùil le push
+ An àireamh as motha a phasganan air an doirear sùil le putadh
+ 5 pasganan
10 pasganan
25 pasgan
50 pasgan
@@ -609,11 +642,11 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
1,000 pasgan
Beòthachadh
Cleachd èifeachdan lèirsinneach leòmach
- Seòladaireachd slighe putanan àirde na fuaime
+ Seòladaireachd le putanan àirde na fuaime
Ann an seallaidhean theachdaireachdan
Ann an seallaidhean liostaichean
%s %s
- - gun leughadh
+ – Gun leughadh
Na h-uile teachdaireachd
Na h-uile teachdaireachd ann am pasgan so-luirg
Am bogsa a-steach co-aonaichte
@@ -630,10 +663,10 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Liosta nan cunntasan
Ainm a’ chunntais
Tuairisgeul a’ chunntais
- Liosta nam pasganan
+ Liostaichean phasganan
Ainm a’ phasgain
Staid a’ phasgain
- Liosta nan teachdaireachdan
+ Liostaichean theachdaireachdan
Cuspair
Seòladair
Ceann-là
@@ -661,20 +694,32 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Nas motha
Cha deach aplacaid iomchaidh a lorg dhan ghnìomh seo.
Dh’fhàillig a chur: %s
- A bheil thu airson dreachd na teachdaireachd a shàbhaladh?
- A bheil thu airson an teachdaireachd seo a shàbhaladh no a thilgeil air falbh?
- A bheil thu airson an teachdaireachd seo a thilgeil air falbh?
- A bheil thu cinnteach gu bheil thu airson an teachdaireachd seo a thilgeil air falbh?
+ A bheil thu airson dreachd na teachdaireachd a shàbhaladh\?
+ A bheil thu airson an teachdaireachd seo a shàbhaladh no a thilgeil air falbh\?
+ A bheil thu airson an teachdaireachd seo a thilgeil air falbh\?
+ A bheil thu cinnteach gu bheil thu airson an teachdaireachd seo a thilgeil air falbh\?
Tagh teacsa airson lethbhreac a dhèanamh dheth.
- Dearbh a sguabadh às
- A bheil thu cinnteach gu bheil thu airson an teachdaireachd seo a sguabadh às?
+ Dearbh an sguabadh às
+ A bheil thu cinnteach gu bheil thu airson an teachdaireachd seo a sguabadh às\?
+
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachd a sguabadh às\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d theachdaireachd a sguabadh às\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachdan a sguabadh às\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachd a sguabadh às\?
+
Tha
Chan eil
Comharraich gun deach gach teachdaireachd a leughadh
- A bheil thu airson comharradh gun deach na teachdaireachdan uile seo a leughadh?
+ A bheil thu airson comharradh gun deach na teachdaireachdan uile seo a leughadh\?
Tha
Chan eil
Dearbh a ghluasad do phasgan an spama
+
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachd a ghluasad gu pasgan an spama\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d theachdaireachd a ghluasad gu pasgan an spama\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachdan a ghluasad gu pasgan an spama\?
+ - A bheil thu cinnteach gu bheil thu airson %1$d teachdaireachd a ghluasad gu pasgan an spama\?
+
Tha
Chan eil
A’ luchdadh a-nuas a’ cheanglachain
@@ -688,9 +733,21 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Cha b’ urrainn dhuinn na roghainnean às-phortadh
Ion-phortaich na roghainnean
Ion-phortaich
+ Cha b’ urrainn dhuinn roghainn sam bith ion-phortadh o: %s
Ion-phortaich na roghainnean
Ag ion-phortadh nan roghainnean…
- Seall na tha gun leughadh ann an…
+ Seall co mheud a tha gun leughadh ann an…
+ Cunntas
+ An cunntas dhan dèid na teachdaireachdan gun leughadh a chunntadh
+ Bogsa a-steach co-aonaichte
+ Cunntas pasgain
+ Seall cunntas nan teachdaireachdan gun leughadh air aon phasgan a-mhàin
+ Pasgan
+ Am pasgan dhan dèid na teachdaireachdan gun leughadh a chunntadh
+ Deiseil
+ %1$s – %2$s
+ Cha deach cunntas a thaghadh
+ Cha deach pasgan a thaghadh
Gun teacsa
Fosgail an ceangal
Co-roinn an ceangal
@@ -744,11 +801,11 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Buidhnich teachdaireachdan ann an còmhraidhean
Ag àrdachadh nan stòr-dàta
Ag àrdachadh nan stòr-dàta…
- Ag àrdachadh nan stòr-dàta aig a’ chunntas “%s”
+ Ag àrdachadh stòr-dàta a’ chunntais “%s”
Seall air sgrìn sgoilte
An-còmhnaidh
Chan ann idir
- Nuair a tha e ’ga shealltainn marh dreach-tìre
+ Nuair a tha e ’ga shealltainn mar dreach-tìre
Tagh teachdaireachd air an taobh chlì
Seall dealbhan an luchd-aithne
Seall dealbhan an luchd-aithne ann an liosta nan teachdaireachd
@@ -770,43 +827,78 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Roghainnean adhartach
Dh’fhalbh an ùine air teisteanas a’ chliant “%1$s” no chan eil e dligheachd fhathast (%2$s)
- *Crioptaiche*
+ *Crioptaichte*
Cuir ris on luchd-aithne
Cc
Bcc
Gu
O
- Taigh
+ <Faightear nach aithne dhuinn>
+ Dachaigh
Obair
Eile
- Fòn-làimhe
+ Mobile
Cha deach pasgan do dhreachdan a rèiteachadh dhan chunntas seo!
+ Cha deach iuchair a rèiteachadh dhan chunntas seo! Thoir sùil air na roghainnean agad.
+ Tha solaraiche a’ chrioptachaidh a’ cleachdadh tionndadh nach eil co-chòrdail. Thoir sùil air na roghainnean agad!
Chan urrainn dhuinn ceangal ri solaraiche a’ chrioptachaidh, thoir sùil air na roghainnean no thoir gnogag air ìomhaigheag a’ chrioptachaidh airson feuchainn ris a-rithist!
+ Chaidh inntrigeadh do sholaraiche a’ chrioptachaidh a dhiùltadh, thoir gnogag air ìomhaigheag a’ chrioptachaidh airson feuchainn ris a-rithist!
Chan eil taic ri ceanglachain sa mhodh PGP/INLINE!
Cuir PGP/INLINE an comas
Cuir PGP/INLINE à comas
Cuir PGP Sign-Only an comas
Cuir PGP Sign-Only à comas
Am modh PGP/INLINE
- Tha am post-d seo ’ga chur san fhòrmat PGP/INLINE.\nCha bu chòir dhut seo a dhèanamh ach airson co-chòrdalachd:
+ Tha am post-d seo ’ga chur san fhòrmat PGP/INLINE.
+\nCha bu chòir dhut seo a dhèanamh ach airson co-chòrdalachd:
Tha cuid a chliantan ann nach cuir taic ach ris an fhòrmat seo
Dh’fhaoidte gum bris soidhneadh rè an tar-chuir
Chan eil taic ri ceanglachain
Tha mi agaibh!
Cuir à comas
- Cum an comas
+ Cùm an comas
Tha mi agaibh!
Cuir à comas
- Cum an comas
+ Cùm an comas
Am modh PGP Sign-Only
- Sa mhodh seo, thèid an iuchair PGP agad a chleachdaidh airson soidhneadh crioptografach de phost-d gun chrioptachadh a chruthachadh.
- Cha chrioptaich seo am post-d ach dearbhaidh e gun deach a chuir on iuchair agad.
- Dh’fhaoidte gum bris soidhneadh nuair a chuireas tu rud gu liosta-phuist.
+ Sa mhodh seo, thèid an iuchair PGP agad a chleachdadh airson soidhneadh crioptografach de phost-d gun chrioptachadh a chruthachadh.
+ Cha chrioptaich seo am post-d ach dearbhaidh e gun deach a chur on iuchair agad.
+ Dh’fhaoidte gum bris soidhnidhean nuair a chuireas tu rud gu liosta-phuist.
Dh’fhaoidte gun nochd soidhnidhean mar “signature.asc” ann an cuid a chliantan.
Bidh soidhneadh am broinn teachdaireachd chrioptaichte an-còmhnaidh.
+ Teacsa lom
+ bha mearachd san t-soidhneadh ceann gu ceann
+ chan obraich pròiseasadh an t-soidhnidh mus deach an teachdaireachd a luchdadh a-nuas gu slàn
+ tha soidhneadh ceann gu ceann ’na bhroinn ris nach cuirear taic
Tha an teachdaireachd crioptaichte ach ann am fòrmat ris nach eil taic.
- Tha an teachdaireachd crioptaichte ach cha sguireadh dhen dì-chrioptachadh.
+ Tha an teachdaireachd crioptaichte ach sguireadh dhen dì-chrioptachadh.
+ Teacsa lom soidhnichte ceann gu ceann
+ o neach-soidhnidh dearbhte
+ Teacsa lom soidhnichte
+ ach cha robh an iuchair ceann gu ceann a-rèir an t-seòladair
+ ach dh’fhalbh an ùine air an iuchair ceann gu ceann
+ ach chaidh an iuchair ceann gu ceann a chùl-ghairm
+ ach chan eilear a’ meas gu bheil an iuchair ceann gu ceann tèarainte
+ o iuchair ceann gu ceann nach aithne dhuinn
+ Crioptaichte
+ ach thachair duilgheadas leis an dì-chrioptachadh
+ chan obraich an dì-chrioptachadh mus deach an teachdaireachd a luchdadh a-nuas gu slàn
+ ach cha deach aplacaid crioptachaidh a rèiteachadh
+ Crioptaichte
+ ach chan ann ceann gu ceann
+ Crioptaichte ceann gu ceann
+ o sheòladair a chaidh a dhearbhadh
+ Crioptaichte
+ o iuchair ceann gu ceann nach aithne dhuinn
+ ach cha robh an iuchair ceann gu ceann a-rèir an t-seòladair
+ ach dh’fhalbh an ùine air an iuchair ceann gu ceann
+ ach chaidh an iuchair ceann gu ceann a chùl-ghairm
+ ach chan eilear a’ meas gu bheil an iuchair ceann gu ceann tèarainte
+ ach tha mearachdan san dàta ceann gu ceann
+ ach chan eilear a’ meas gu bheil an crioptachadh tèarainte
Ceart ma-thà
+ Seall an neach-soidhnidh
+ Seall an seòladair
Mion-fhiosrachadh
Thoir a’ ghlas dheth
Cha deach a’ phàirt seo a chrioptachadh is dh’fhaoidte gu bheil e neo-thèarainte.
@@ -817,23 +909,44 @@ Fàilte air bugaichean, com-pàirteachas, iarrtasan airson gleusan ùra is ceist
Feumaidh tu an teachdaireachd chrioptaichte a luchdadh a-nuas mus gabh a dhì-chrioptachadh.
Mearachd a’ dì-chrioptachadh a’ phuist-d
Chan eil taic ri caractaran sònraichte aig an àm seo!
- Mearachd a’ pàrsadh an t-seòlaidh!
- Chan eil crioptachadh ri fhaidhinn sa mhodh anns nach dèanar ach soidhneadh!
+ Mearachd a’ parsadh an t-seòlaidh!
+ Chan eil crioptachadh ri fhaighinn sa mhodh anns nach dèanar ach soidhneadh!
Teacsa gun soidhneadh
Rabhadh mu chleachdadh APG
Chan eilear a’ leasachadh APG tuilleadh!
Ri linn sin, chan eil taic ri APG aig post K-9 tuilleadh.
Sguir daoine dhen obair-leasachaidh aig toiseach 2014
- Tha duilgheadasa tèarainteachd ann nach deach an càradh
+ Tha duilgheadasan tèarainteachd ann nach deach an càradh
Briog an-seo airson barrachd fiosrachaidh.
Tha mi agaibh!
APG
Tha am post-d seo crioptaichte
- Chaidh am post-d seo a chrioptachadh le OpenPGP.\nFeumaidh tu aplacaid a tha comasach air OpenPGP a stàladh is a rèiteachadh mus urrainn dhut a leughadh.
- Liosta theachdaireachdan L-9
+ Chaidh am post-d seo a chrioptachadh le OpenPGP.
+\nFeumaidh tu aplacaid a tha comasach air OpenPGP a stàladh is a rèiteachadh mus urrainn dhut a leughadh.
+ Tagh aplacaid OpenPGP
+ Liosta theachdaireachdan puist
A’ luchdadh nan teachdaireachdan…
Cha b’ urrainn dhuinn liosta nam pasgan fhaighinn
+ Mearachd a’ faighinn staid an fhaighteir on t-solaraiche OpenPGP!
+ Cha ghabh a chrioptachadh
+ Cha chuir gach faightear a thagh thu taic ris a’ ghleus seo!
+ Cuir crioptachadh an comas
+ Cuir crioptachadh à comas
+ Ma chrioptaicheas tu teachdaireachd, nì sin cinnteach nach leugh duine sam bith ach am faightear i.
+ Cha nochd an crioptachadh ach ma chuireas a h-uile faightear taic ris agus ma fhuair thu post-d uapa roimhe.
+ Toglaich an crioptachadh le briogadh air an ìomhaigheag seo.
+ Tha mi agaibh
+ Air ais
+ Cuir crioptachadh à comas
+ Crioptachadh OpenPGP
+ Modh co-dhàimh Autocrypt
+ Modh co-dhàimh Autocrypt
+ Mar as trice, thèid teachdaireachdan a chrioptachadh ma thagh thu sin no ma chuireas tu freagairt gu teachdaireachd chrioptaichte.
+ Ma chuireas an dà chuid an seòladair ’s am faightear modh na co-dhàimh air, thèid an crioptachadh mar bhun-roghainn.
+ Briog an-seo airson barrachd fiosrachaidh.
Roghainnean coitcheann
+ Teachdaireachd suidheachaidh Autocrypt
+ Teachdaireachd suidheachaidh Autocrypt
Fosgail
Dùin
diff --git a/app/ui/legacy/src/main/res/values-ja/strings.xml b/app/ui/legacy/src/main/res/values-ja/strings.xml
index a3a71590cd..d718fe75db 100644
--- a/app/ui/legacy/src/main/res/values-ja/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ja/strings.xml
@@ -23,6 +23,7 @@
バージョン %s
新着
アプリの更新後に更新内容を表示する
+ このリリースは何が新しいのかを知る
K-9 Mailへようこそ
Markeer als gelezen wanneer ingezien
Als gelezen markeren bij wissen
Markeer een bericht als gelezen wanneer die wordt gewist
+ Meldingscategorieën
Meldingen instellen voor nieuwe berichten
Error- en statusmeldingen instellen
Laat afbeeldingen automatisch zien
diff --git a/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml b/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
index 7b9566626c..321f4c841d 100644
--- a/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
+++ b/app/ui/legacy/src/main/res/values-pt-rBR/strings.xml
@@ -436,6 +436,9 @@ Por favor encaminhe relatórios de bugs, contribua com novos recursos e tire dú
Marcar a mensagem como lida quando ela for aberta para visualização
Marcar como lida ao excluir
Marca uma mensagem como lida quando ela for excluída
+ Categorias de notificação
+ Configura as notificações para as novas mensagens
+ Configura as notificações de erros e status
Sempre exibir imagens
Não
Dos contatos
diff --git a/app/ui/legacy/src/main/res/values-ru/strings.xml b/app/ui/legacy/src/main/res/values-ru/strings.xml
index 8f78f20296..c227e32619 100644
--- a/app/ui/legacy/src/main/res/values-ru/strings.xml
+++ b/app/ui/legacy/src/main/res/values-ru/strings.xml
@@ -440,6 +440,7 @@ K-9 Mail — почтовый клиент для Android.
Отметить сообщение прочитанным после просмотра
Отметить как прочитанное при удалении
Отметить как прочитанное при удалении
+ Категории уведомлений
Настройка уведомлений о новых сообщениях
Настройка уведомлений об ошибках и статусе
Показать изображения
diff --git a/app/ui/legacy/src/main/res/values-sv/strings.xml b/app/ui/legacy/src/main/res/values-sv/strings.xml
index 6be880f06f..5099411592 100644
--- a/app/ui/legacy/src/main/res/values-sv/strings.xml
+++ b/app/ui/legacy/src/main/res/values-sv/strings.xml
@@ -1004,7 +1004,7 @@ Skicka gärna in felrapporter, bidra med nya funktioner och ställ frågor på
Aktivera kryptering
Inaktivera kryptering
Krypterande meddelanden säkerställer att de kan läsas av mottagaren, och ingen annan.
- Kryptering visas endast om den stöds av alla mottagare, och de måste ha skickat ett e-postmeddelande till dig innan.
+ Kryptering visas endast om den stöds av alla mottagare, och de måste ha skickat dig ett e-postmeddelande tidigare.
Växla kryptering genom att klicka på denna ikon.
Uppfattat
Bakåt
--
GitLab
From 5055669da99846b37dba6729ce8c3cf421815720 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 17 Aug 2021 23:59:14 +0200
Subject: [PATCH 048/285] Version 5.804
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 7 +++++++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index e05dde8e1f..f896c88f69 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28003
- versionName '5.803'
+ versionCode 28004
+ versionName '5.804'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index 3153968d47..ee9f101a85 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,13 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Fixed a bug where Push didn't work with some servers
+ Don't connect to the incoming or outgoing server when passwords haven't been provided after import
+ Added missing scrollbars in screens showing the folder list
+ Tapping the app icon should now always bring the app to the foreground instead of adding another message list screen
+ Updated translations
+
Don't show the icon for the ongoing Push notification in the status bar (on versions older than Android 8.0)
Directly open system settings for notification categories (Android 8.0 and newer)
--
GitLab
From cff6041dc854b45dd505c2ca2ebebf91915f56f3 Mon Sep 17 00:00:00 2001
From: cketti
Date: Wed, 18 Aug 2021 02:34:13 +0200
Subject: [PATCH 049/285] Extract code for authenticated password toggle to
separate file
Add support for orientation changes and mark screen as secure if password has been revealed.
---
app/ui/base/build.gradle | 2 +
.../extensions/TextInputLayoutExtensions.kt | 119 ++++++++++++++++++
app/ui/legacy/build.gradle | 2 -
.../activity/setup/AccountSetupIncoming.java | 52 ++------
.../activity/setup/AccountSetupOutgoing.java | 52 ++------
app/ui/legacy/src/main/res/values/strings.xml | 2 +-
app/ui/setup/build.gradle | 1 -
7 files changed, 142 insertions(+), 88 deletions(-)
create mode 100644 app/ui/base/src/main/java/com/fsck/k9/ui/base/extensions/TextInputLayoutExtensions.kt
diff --git a/app/ui/base/build.gradle b/app/ui/base/build.gradle
index 63d9fac999..eb7661cc2e 100644
--- a/app/ui/base/build.gradle
+++ b/app/ui/base/build.gradle
@@ -5,11 +5,13 @@ dependencies {
implementation project(":app:core")
api "androidx.appcompat:appcompat:${versions.androidxAppCompat}"
+ api "com.google.android.material:material:${versions.materialComponents}"
api "androidx.navigation:navigation-fragment-ktx:${versions.androidxNavigation}"
api "androidx.navigation:navigation-ui-ktx:${versions.androidxNavigation}"
api "androidx.lifecycle:lifecycle-livedata-ktx:${versions.androidxLifecycle}"
implementation "androidx.core:core-ktx:${versions.androidxCore}"
+ implementation "androidx.biometric:biometric:${versions.androidxBiometric}"
implementation "com.jakewharton.timber:timber:${versions.timber}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.kotlinCoroutines}"
}
diff --git a/app/ui/base/src/main/java/com/fsck/k9/ui/base/extensions/TextInputLayoutExtensions.kt b/app/ui/base/src/main/java/com/fsck/k9/ui/base/extensions/TextInputLayoutExtensions.kt
new file mode 100644
index 0000000000..91b32d7d1d
--- /dev/null
+++ b/app/ui/base/src/main/java/com/fsck/k9/ui/base/extensions/TextInputLayoutExtensions.kt
@@ -0,0 +1,119 @@
+@file:JvmName("TextInputLayoutHelper")
+
+package com.fsck.k9.ui.base.extensions
+
+import android.annotation.SuppressLint
+import android.text.method.PasswordTransformationMethod
+import android.view.WindowManager.LayoutParams.FLAG_SECURE
+import android.widget.EditText
+import android.widget.Toast
+import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
+import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
+import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
+import androidx.biometric.BiometricPrompt
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
+import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.google.android.material.textfield.TextInputLayout
+
+/**
+ * Configures a [TextInputLayout] so the password can only be revealed after authentication.
+ */
+fun TextInputLayout.configureAuthenticatedPasswordToggle(
+ activity: FragmentActivity,
+ title: String,
+ subtitle: String,
+ needScreenLockMessage: String,
+) {
+ val viewModel = ViewModelProvider(activity).get(AuthenticatedPasswordToggleViewModel::class.java)
+ viewModel.textInputLayout = this
+ viewModel.activity = activity
+
+ fun authenticateUserAndShowPassword(activity: FragmentActivity) {
+ val mainExecutor = ContextCompat.getMainExecutor(activity)
+
+ val context = activity.applicationContext
+ val authenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
+ override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
+ // The Activity might have been recreated since this callback object was created (e.g. due to an
+ // orientation change). So we fetch the (new) references from the ViewModel.
+ viewModel.isAuthenticated = true
+ viewModel.activity?.setSecure(true)
+ viewModel.textInputLayout?.editText?.showPassword()
+ }
+
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+ if (errorCode == BiometricPrompt.ERROR_HW_NOT_PRESENT ||
+ errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL ||
+ errorCode == BiometricPrompt.ERROR_NO_BIOMETRICS
+ ) {
+ Toast.makeText(context, needScreenLockMessage, Toast.LENGTH_SHORT).show()
+ } else if (errString.isNotEmpty()) {
+ Toast.makeText(context, errString, Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ BiometricPrompt(activity, mainExecutor, authenticationCallback).authenticate(
+ BiometricPrompt.PromptInfo.Builder()
+ .setAllowedAuthenticators(BIOMETRIC_STRONG or BIOMETRIC_WEAK or DEVICE_CREDENTIAL)
+ .setTitle(title)
+ .setSubtitle(subtitle)
+ .build()
+ )
+ }
+
+ val editText = this.editText ?: error("TextInputLayout.editText == null")
+
+ setEndIconOnClickListener {
+ if (editText.isPasswordHidden) {
+ if (viewModel.isAuthenticated) {
+ activity.setSecure(true)
+ editText.showPassword()
+ } else {
+ authenticateUserAndShowPassword(activity)
+ }
+ } else {
+ viewModel.isAuthenticated = false
+ editText.hidePassword()
+ activity.setSecure(false)
+ }
+ }
+}
+
+private val EditText.isPasswordHidden: Boolean
+ get() = transformationMethod is PasswordTransformationMethod
+
+private fun EditText.showPassword() {
+ transformationMethod = null
+}
+
+private fun EditText.hidePassword() {
+ transformationMethod = PasswordTransformationMethod.getInstance()
+}
+
+private fun FragmentActivity.setSecure(secure: Boolean) {
+ window.setFlags(if (secure) FLAG_SECURE else 0, FLAG_SECURE)
+}
+
+@SuppressLint("StaticFieldLeak")
+class AuthenticatedPasswordToggleViewModel : ViewModel() {
+ var isAuthenticated = false
+ var textInputLayout: TextInputLayout? = null
+ var activity: FragmentActivity? = null
+ set(value) {
+ field = value
+
+ value?.lifecycle?.addObserver(object : LifecycleObserver {
+ @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+ fun removeReferences() {
+ textInputLayout = null
+ field = null
+ }
+ })
+ }
+}
diff --git a/app/ui/legacy/build.gradle b/app/ui/legacy/build.gradle
index cd51df317d..af35825004 100644
--- a/app/ui/legacy/build.gradle
+++ b/app/ui/legacy/build.gradle
@@ -22,7 +22,6 @@ dependencies {
implementation "com.takisoft.preferencex:preferencex-datetimepicker:${versions.preferencesFix}"
implementation "com.takisoft.preferencex:preferencex-colorpicker:${versions.preferencesFix}"
implementation "com.takisoft.preferencex:preferencex-ringtone:${versions.preferencesFix}"
- implementation "androidx.biometric:biometric:${versions.androidxBiometric}"
implementation "androidx.recyclerview:recyclerview:${versions.androidxRecyclerView}"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.androidxLifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.androidxLifecycle}"
@@ -30,7 +29,6 @@ dependencies {
implementation "androidx.cardview:cardview:${versions.androidxCardView}"
implementation "androidx.localbroadcastmanager:localbroadcastmanager:${versions.androidxLocalBroadcastManager}"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
- implementation "com.google.android.material:material:${versions.materialComponents}"
implementation "de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02"
implementation "com.splitwise:tokenautocomplete:4.0.0-beta01"
implementation "de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0"
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
index 13ec380a82..f059d9b12a 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupIncoming.java
@@ -9,7 +9,6 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
-import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -22,10 +21,6 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
import android.widget.Toast;
-import androidx.annotation.NonNull;
-import androidx.biometric.BiometricManager.Authenticators;
-import androidx.biometric.BiometricPrompt;
-import androidx.core.content.ContextCompat;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.LocalKeyStoreManager;
@@ -47,6 +42,7 @@ import com.fsck.k9.mail.store.imap.ImapStoreSettings;
import com.fsck.k9.mail.store.webdav.WebDavStoreSettings;
import com.fsck.k9.preferences.Protocols;
import com.fsck.k9.ui.R;
+import com.fsck.k9.ui.base.extensions.TextInputLayoutHelper;
import com.fsck.k9.view.ClientCertificateSpinner;
import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener;
@@ -184,18 +180,15 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
}
boolean editSettings = Intent.ACTION_EDIT.equals(getIntent().getAction());
-
- mPasswordLayoutView.setEndIconOnClickListener(v -> {
- if (mPasswordView.getTransformationMethod() instanceof PasswordTransformationMethod) {
- if (editSettings) {
- authenticateUserAndShowPassword();
- } else {
- mPasswordView.setTransformationMethod(null);
- }
- } else {
- mPasswordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
- }
- });
+ if (editSettings) {
+ TextInputLayoutHelper.configureAuthenticatedPasswordToggle(
+ mPasswordLayoutView,
+ this,
+ getString(R.string.account_setup_basics_show_password_biometrics_title),
+ getString(R.string.account_setup_basics_show_password_biometrics_subtitle),
+ getString(R.string.account_setup_basics_show_password_need_lock)
+ );
+ }
try {
ServerSettings settings = mAccount.getIncomingServerSettings();
@@ -631,31 +624,6 @@ public class AccountSetupIncoming extends K9Activity implements OnClickListener
}
- private void authenticateUserAndShowPassword() {
- new BiometricPrompt(this, ContextCompat.getMainExecutor(this), new BiometricPrompt.AuthenticationCallback() {
- @Override
- public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
- mPasswordView.setTransformationMethod(null);
- }
-
- @Override
- public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
- if (errorCode == BiometricPrompt.ERROR_HW_NOT_PRESENT
- || errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL) {
- Toast.makeText(AccountSetupIncoming.this, R.string.account_setup_basics_show_password_need_lock,
- Toast.LENGTH_SHORT).show();
- } else if (errString.length() != 0) {
- Toast.makeText(AccountSetupIncoming.this, errString, Toast.LENGTH_SHORT).show();
- }
- }
- }).authenticate(new BiometricPrompt.PromptInfo.Builder()
- .setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG
- | Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL)
- .setTitle(getString(R.string.account_setup_basics_show_password_biometrics_title))
- .setSubtitle(getString(R.string.account_setup_basics_show_password_biometrics_subtitle))
- .build());
- }
-
public void onClick(View v) {
try {
if (v.getId() == R.id.next) {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
index a0c27afb56..12085c8f7e 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupOutgoing.java
@@ -8,7 +8,6 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
-import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -21,10 +20,6 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Spinner;
import android.widget.Toast;
-import androidx.annotation.NonNull;
-import androidx.biometric.BiometricManager.Authenticators;
-import androidx.biometric.BiometricPrompt;
-import androidx.core.content.ContextCompat;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.LocalKeyStoreManager;
@@ -39,6 +34,7 @@ import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.MailServerDirection;
import com.fsck.k9.mail.ServerSettings;
+import com.fsck.k9.ui.base.extensions.TextInputLayoutHelper;
import com.fsck.k9.view.ClientCertificateSpinner;
import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener;
import com.google.android.material.textfield.TextInputEditText;
@@ -154,18 +150,15 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
}
boolean editSettings = Intent.ACTION_EDIT.equals(getIntent().getAction());
-
- mPasswordLayoutView.setEndIconOnClickListener(v -> {
- if (mPasswordView.getTransformationMethod() instanceof PasswordTransformationMethod) {
- if (editSettings) {
- authenticateUserAndShowPassword();
- } else {
- mPasswordView.setTransformationMethod(null);
- }
- } else {
- mPasswordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
- }
- });
+ if (editSettings) {
+ TextInputLayoutHelper.configureAuthenticatedPasswordToggle(
+ mPasswordLayoutView,
+ this,
+ getString(R.string.account_setup_basics_show_password_biometrics_title),
+ getString(R.string.account_setup_basics_show_password_biometrics_subtitle),
+ getString(R.string.account_setup_basics_show_password_need_lock)
+ );
+ }
try {
ServerSettings settings = mAccount.getOutgoingServerSettings();
@@ -517,31 +510,6 @@ public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
}
- private void authenticateUserAndShowPassword() {
- new BiometricPrompt(this, ContextCompat.getMainExecutor(this), new BiometricPrompt.AuthenticationCallback() {
- @Override
- public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
- mPasswordView.setTransformationMethod(null);
- }
-
- @Override
- public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
- if (errorCode == BiometricPrompt.ERROR_HW_NOT_PRESENT
- || errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL) {
- Toast.makeText(AccountSetupOutgoing.this, R.string.account_setup_basics_show_password_need_lock,
- Toast.LENGTH_SHORT).show();
- } else if (errString.length() != 0) {
- Toast.makeText(AccountSetupOutgoing.this, errString, Toast.LENGTH_SHORT).show();
- }
- }
- }).authenticate(new BiometricPrompt.PromptInfo.Builder()
- .setAllowedAuthenticators(Authenticators.BIOMETRIC_STRONG
- | Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL)
- .setTitle(getString(R.string.account_setup_basics_show_password_biometrics_title))
- .setSubtitle(getString(R.string.account_setup_basics_show_password_biometrics_subtitle))
- .build());
- }
-
public void onClick(View v) {
if (v.getId() == R.id.next) {
onNext();
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index e0822bf8d0..674acd9ff2 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -355,7 +355,7 @@ Please submit bug reports, contribute new features and ask questions at
Email address
Password
Show password
- To view or copy your password here, enable screen lock on this device.
+ To view your password here, enable screen lock on this device.
Verify it\'s you
Unlock to view your password
Manual setup
diff --git a/app/ui/setup/build.gradle b/app/ui/setup/build.gradle
index c81a991b22..31d37bcb44 100644
--- a/app/ui/setup/build.gradle
+++ b/app/ui/setup/build.gradle
@@ -10,7 +10,6 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.androidxLifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.androidxLifecycle}"
implementation "androidx.constraintlayout:constraintlayout:${versions.androidxConstraintLayout}"
- implementation "com.google.android.material:material:${versions.materialComponents}"
implementation "androidx.core:core-ktx:${versions.androidxCore}"
implementation "com.jakewharton.timber:timber:${versions.timber}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${versions.kotlinCoroutines}"
--
GitLab
From 652d52b6a6cb62b1de2414927459a2a97f1a4fec Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 15 Aug 2021 16:12:26 +0200
Subject: [PATCH 050/285] Add setting to suppress notifications for chat
messages
Messages containing a 'Chat-Version' header field will not generate notifications when this setting is enabled.
---
app/core/src/main/java/com/fsck/k9/Account.java | 9 +++++++++
.../java/com/fsck/k9/AccountPreferenceSerializer.kt | 4 ++++
.../k9/preferences/AccountSettingsDescriptions.java | 3 +++
.../main/java/com/fsck/k9/preferences/Settings.java | 2 +-
.../com/fsck/k9/notification/K9NotificationStrategy.kt | 10 ++++++++++
.../k9/ui/settings/account/AccountSettingsDataStore.kt | 2 ++
app/ui/legacy/src/main/res/values/strings.xml | 2 ++
app/ui/legacy/src/main/res/xml/account_settings.xml | 7 +++++++
.../src/main/java/com/fsck/k9/mail/K9MailLib.java | 1 +
.../java/com/fsck/k9/mail/store/imap/RealImapFolder.kt | 3 ++-
.../com/fsck/k9/mail/store/imap/RealImapFolderTest.kt | 3 ++-
11 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/Account.java b/app/core/src/main/java/com/fsck/k9/Account.java
index 4e0a35ebf8..899356894a 100644
--- a/app/core/src/main/java/com/fsck/k9/Account.java
+++ b/app/core/src/main/java/com/fsck/k9/Account.java
@@ -119,6 +119,7 @@ public class Account implements BaseAccount {
private FolderMode folderNotifyNewMailMode;
private boolean notifySelfNewMail;
private boolean notifyContactsMailOnly;
+ private boolean ignoreChatMessages;
private String legacyInboxFolder;
private String importedDraftsFolder;
private String importedSentFolder;
@@ -680,6 +681,14 @@ public class Account implements BaseAccount {
this.notifyContactsMailOnly = notifyContactsMailOnly;
}
+ public synchronized boolean isIgnoreChatMessages() {
+ return ignoreChatMessages;
+ }
+
+ public synchronized void setIgnoreChatMessages(boolean ignoreChatMessages) {
+ this.ignoreChatMessages = ignoreChatMessages;
+ }
+
public synchronized Expunge getExpungePolicy() {
return expungePolicy;
}
diff --git a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt
index 8a34639624..38327545cc 100644
--- a/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt
+++ b/app/core/src/main/java/com/fsck/k9/AccountPreferenceSerializer.kt
@@ -51,6 +51,7 @@ class AccountPreferenceSerializer(
folderNotifyNewMailMode = getEnumStringPref(storage, "$accountUuid.folderNotifyNewMailMode", FolderMode.ALL)
isNotifySelfNewMail = storage.getBoolean("$accountUuid.notifySelfNewMail", true)
isNotifyContactsMailOnly = storage.getBoolean("$accountUuid.notifyContactsMailOnly", false)
+ isIgnoreChatMessages = storage.getBoolean("$accountUuid.ignoreChatMessages", false)
isNotifySync = storage.getBoolean("$accountUuid.notifyMailCheck", false)
deletePolicy = DeletePolicy.fromInt(storage.getInt("$accountUuid.deletePolicy", DeletePolicy.NEVER.setting))
legacyInboxFolder = storage.getString("$accountUuid.inboxFolderName", null)
@@ -256,6 +257,7 @@ class AccountPreferenceSerializer(
editor.putString("$accountUuid.folderNotifyNewMailMode", folderNotifyNewMailMode.name)
editor.putBoolean("$accountUuid.notifySelfNewMail", isNotifySelfNewMail)
editor.putBoolean("$accountUuid.notifyContactsMailOnly", isNotifyContactsMailOnly)
+ editor.putBoolean("$accountUuid.ignoreChatMessages", isIgnoreChatMessages)
editor.putBoolean("$accountUuid.notifyMailCheck", isNotifySync)
editor.putInt("$accountUuid.deletePolicy", deletePolicy.setting)
editor.putString("$accountUuid.inboxFolderName", legacyInboxFolder)
@@ -379,6 +381,7 @@ class AccountPreferenceSerializer(
editor.remove("$accountUuid.lastAutomaticCheckTime")
editor.remove("$accountUuid.notifyNewMail")
editor.remove("$accountUuid.notifySelfNewMail")
+ editor.remove("$accountUuid.ignoreChatMessages")
editor.remove("$accountUuid.deletePolicy")
editor.remove("$accountUuid.draftsFolderName")
editor.remove("$accountUuid.sentFolderName")
@@ -551,6 +554,7 @@ class AccountPreferenceSerializer(
isNotifySync = false
isNotifySelfNewMail = true
isNotifyContactsMailOnly = false
+ isIgnoreChatMessages = false
folderDisplayMode = FolderMode.NOT_SECOND_CLASS
folderSyncMode = FolderMode.FIRST_CLASS
folderPushMode = FolderMode.NONE
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/AccountSettingsDescriptions.java b/app/core/src/main/java/com/fsck/k9/preferences/AccountSettingsDescriptions.java
index bc74cfbc72..4c281006d5 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/AccountSettingsDescriptions.java
+++ b/app/core/src/main/java/com/fsck/k9/preferences/AccountSettingsDescriptions.java
@@ -261,6 +261,9 @@ public class AccountSettingsDescriptions {
s.put("trashFolderSelection", Settings.versions(
new V(54, new EnumSetting<>(SpecialFolderSelection.class, SpecialFolderSelection.AUTOMATIC))
));
+ s.put("ignoreChatMessages", Settings.versions(
+ new V(76, new BooleanSetting(false))
+ ));
// note that there is no setting for openPgpProvider, because this will have to be set up together
// with the actual provider after import anyways.
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/Settings.java b/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
index 1be24c74da..35d86b3284 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
+++ b/app/core/src/main/java/com/fsck/k9/preferences/Settings.java
@@ -36,7 +36,7 @@ public class Settings {
*
* @see SettingsExporter
*/
- public static final int VERSION = 75;
+ public static final int VERSION = 76;
static Map validate(int version, Map> settings,
Map importedSettings, boolean useDefaultValues) {
diff --git a/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationStrategy.kt b/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationStrategy.kt
index 254c4abe7b..37630d5e9d 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationStrategy.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationStrategy.kt
@@ -4,6 +4,8 @@ import com.fsck.k9.Account
import com.fsck.k9.K9
import com.fsck.k9.helper.Contacts
import com.fsck.k9.mail.Flag
+import com.fsck.k9.mail.K9MailLib
+import com.fsck.k9.mail.Message
import com.fsck.k9.mailstore.LocalFolder
import com.fsck.k9.mailstore.LocalFolder.isModeMismatch
import com.fsck.k9.mailstore.LocalMessage
@@ -80,6 +82,11 @@ class K9NotificationStrategy(private val contacts: Contacts) : NotificationStrat
return false
}
+ if (account.isIgnoreChatMessages && message.isChatMessage) {
+ Timber.v("No notification: Notifications for chat messages are disabled")
+ return false
+ }
+
if (!account.isNotifySelfNewMail && account.isAnIdentity(message.from)) {
Timber.v("No notification: Notifications for messages from yourself are disabled")
return false
@@ -92,4 +99,7 @@ class K9NotificationStrategy(private val contacts: Contacts) : NotificationStrat
return true
}
+
+ private val Message.isChatMessage: Boolean
+ get() = getHeader(K9MailLib.CHAT_HEADER).isNotEmpty()
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt
index c39d5cec82..0d9e59102a 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsDataStore.kt
@@ -37,6 +37,7 @@ class AccountSettingsDataStore(
"remote_search_enabled" -> account.isAllowRemoteSearch
"autocrypt_prefer_encrypt" -> account.autocryptPreferEncryptMutual
"upload_sent_messages" -> account.isUploadSentMessages
+ "ignore_chat_messages" -> account.isIgnoreChatMessages
else -> defValue
}
}
@@ -69,6 +70,7 @@ class AccountSettingsDataStore(
"openpgp_encrypt_all_drafts" -> account.isOpenPgpEncryptAllDrafts = value
"autocrypt_prefer_encrypt" -> account.autocryptPreferEncryptMutual = value
"upload_sent_messages" -> account.isUploadSentMessages = value
+ "ignore_chat_messages" -> account.isIgnoreChatMessages = value
else -> return
}
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index a20f106b78..44f3938fe0 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -517,6 +517,8 @@ Please submit bug reports, contribute new features and ask questions at
Show a notification for messages I sent
Contacts only
Show notifications only for messages from known contacts
+ Ignore chat messages
+ Don\'t show notifications for messages belonging to an email chat
Mark as read when opened
Mark a message as read when it is opened for viewing
Mark as read when deleted
diff --git a/app/ui/legacy/src/main/res/xml/account_settings.xml b/app/ui/legacy/src/main/res/xml/account_settings.xml
index 274af2a546..643adbc386 100644
--- a/app/ui/legacy/src/main/res/xml/account_settings.xml
+++ b/app/ui/legacy/src/main/res/xml/account_settings.xml
@@ -327,6 +327,13 @@
android:summary="@string/account_notify_contacts_mail_only_summary"
android:title="@string/account_notify_contacts_mail_only_label" />
+
+
Date: Sat, 14 Aug 2021 20:37:27 +0200
Subject: [PATCH 051/285] Rename MessageStore.setLastUpdated() to
setLastChecked()
---
.../src/main/java/com/fsck/k9/mailstore/K9BackendFolder.kt | 2 +-
app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt | 4 ++--
.../main/java/com/fsck/k9/storage/messages/K9MessageStore.kt | 4 ++--
.../com/fsck/k9/storage/messages/UpdateFolderOperations.kt | 2 +-
.../fsck/k9/storage/messages/UpdateFolderOperationsTest.kt | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendFolder.kt b/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendFolder.kt
index e2f71c941d..bdf027ba91 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendFolder.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendFolder.kt
@@ -67,7 +67,7 @@ class K9BackendFolder(
}
override fun setLastChecked(timestamp: Long) {
- messageStore.setLastUpdated(folderId, timestamp)
+ messageStore.setLastChecked(folderId, timestamp)
}
override fun setStatus(status: String?) {
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
index e59aeaebb0..a2305d6f14 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
@@ -212,9 +212,9 @@ interface MessageStore {
fun setMoreMessages(folderId: Long, moreMessages: MoreMessages)
/**
- * Update the 'last updated' state of a folder.
+ * Update the time when the folder was last checked for new messages.
*/
- fun setLastUpdated(folderId: Long, timestamp: Long)
+ fun setLastChecked(folderId: Long, timestamp: Long)
/**
* Update folder status message.
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
index 979f874e7f..c8c5b14343 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
@@ -165,8 +165,8 @@ class K9MessageStore(
updateFolderOperations.setMoreMessages(folderId, moreMessages)
}
- override fun setLastUpdated(folderId: Long, timestamp: Long) {
- updateFolderOperations.setLastUpdated(folderId, timestamp)
+ override fun setLastChecked(folderId: Long, timestamp: Long) {
+ updateFolderOperations.setLastChecked(folderId, timestamp)
}
override fun setStatus(folderId: Long, status: String?) {
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/UpdateFolderOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/UpdateFolderOperations.kt
index cfa1921e3b..06486aa2af 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/UpdateFolderOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/UpdateFolderOperations.kt
@@ -65,7 +65,7 @@ internal class UpdateFolderOperations(private val lockableDatabase: LockableData
setString(folderId = folderId, columnName = "more_messages", value = moreMessages.databaseName)
}
- fun setLastUpdated(folderId: Long, timestamp: Long) {
+ fun setLastChecked(folderId: Long, timestamp: Long) {
lockableDatabase.execute(false) { db ->
val contentValues = ContentValues().apply {
put("last_updated", timestamp)
diff --git a/app/storage/src/test/java/com/fsck/k9/storage/messages/UpdateFolderOperationsTest.kt b/app/storage/src/test/java/com/fsck/k9/storage/messages/UpdateFolderOperationsTest.kt
index 6bf2f2bd85..83bc4fe5f9 100644
--- a/app/storage/src/test/java/com/fsck/k9/storage/messages/UpdateFolderOperationsTest.kt
+++ b/app/storage/src/test/java/com/fsck/k9/storage/messages/UpdateFolderOperationsTest.kt
@@ -135,7 +135,7 @@ class UpdateFolderOperationsTest : RobolectricTest() {
fun `update late updated state`() {
val folderId = sqliteDatabase.createFolder(lastUpdated = 23)
- updateFolderOperations.setLastUpdated(folderId = folderId, timestamp = 42)
+ updateFolderOperations.setLastChecked(folderId = folderId, timestamp = 42)
val folder = sqliteDatabase.readFolders().first()
assertThat(folder.id).isEqualTo(folderId)
--
GitLab
From bc366e98eb74c9fe3388f5d19e5b7624f76cd64d Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 14 Aug 2021 20:48:14 +0200
Subject: [PATCH 052/285] Add support for retrieving a folder's last checked
time via MessageStore
---
.../main/java/com/fsck/k9/mailstore/FolderMapper.kt | 1 +
.../k9/storage/messages/RetrieveFolderOperations.kt | 11 ++++++++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt b/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
index ac988cb646..8cea58d994 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/FolderMapper.kt
@@ -21,6 +21,7 @@ interface FolderDetailsAccessor {
val pushClass: FolderClass
val visibleLimit: Int
val moreMessages: MoreMessages
+ val lastChecked: Long?
val unreadMessageCount: Int
val starredMessageCount: Int
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
index 3e75d04d57..c60bdaf348 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
@@ -1,6 +1,7 @@
package com.fsck.k9.storage.messages
import android.database.Cursor
+import androidx.core.database.getLongOrNull
import com.fsck.k9.Account.FolderMode
import com.fsck.k9.helper.map
import com.fsck.k9.mail.FolderClass
@@ -171,11 +172,14 @@ private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor {
override val moreMessages: MoreMessages
get() = MoreMessages.fromDatabaseName(cursor.getString(12))
+ override val lastChecked: Long?
+ get() = cursor.getLongOrNull(13)
+
override val unreadMessageCount: Int
- get() = cursor.getInt(13)
+ get() = cursor.getInt(14)
override val starredMessageCount: Int
- get() = cursor.getInt(14)
+ get() = cursor.getInt(15)
override fun serverIdOrThrow(): String {
return serverId ?: error("No server ID found for folder '$name' ($id)")
@@ -199,5 +203,6 @@ private val FOLDER_COLUMNS = arrayOf(
"notify_class",
"push_class",
"visible_limit",
- "more_messages"
+ "more_messages",
+ "last_updated"
)
--
GitLab
From 326d27476b9c4b559f7a7d5c18d145ff93f6fb00 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 14 Aug 2021 20:56:15 +0200
Subject: [PATCH 053/285] Don't create notifications when syncing a folder for
the first time
---
.../fsck/k9/controller/MessagingController.java | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index ae8430a090..b3f8f37d8a 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -65,6 +65,8 @@ import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.ServerSettings;
+import com.fsck.k9.mailstore.FolderDetailsAccessor;
+import com.fsck.k9.mailstore.ListenableMessageStore;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
@@ -679,9 +681,13 @@ public class MessagingController {
return;
}
+ MessageStore messageStore = messageStoreManager.getMessageStore(account);
+ Long lastChecked = messageStore.getFolder(folderId, FolderDetailsAccessor::getLastChecked);
+ boolean suppressNotifications = lastChecked == null;
+
String folderServerId = localFolder.getServerId();
SyncConfig syncConfig = createSyncConfig(account);
- ControllerSyncListener syncListener = new ControllerSyncListener(account, listener);
+ ControllerSyncListener syncListener = new ControllerSyncListener(account, listener, suppressNotifications);
backend.sync(folderServerId, syncConfig, syncListener);
@@ -2716,12 +2722,14 @@ public class MessagingController {
private final MessagingListener listener;
private final LocalStore localStore;
private final int previousUnreadMessageCount;
+ private final boolean suppressNotifications;
boolean syncFailed = false;
- ControllerSyncListener(Account account, MessagingListener listener) {
+ ControllerSyncListener(Account account, MessagingListener listener, boolean suppressNotifications) {
this.account = account;
this.listener = listener;
+ this.suppressNotifications = suppressNotifications;
this.localStore = getLocalStoreOrThrow(account);
previousUnreadMessageCount = getUnreadMessageCount(account);
@@ -2778,7 +2786,8 @@ public class MessagingController {
// Send a notification of this message
LocalMessage message = loadMessage(folderServerId, messageServerId);
LocalFolder localFolder = message.getFolder();
- if (notificationStrategy.shouldNotifyForMessage(account, localFolder, message, isOldMessage)) {
+ if (!suppressNotifications &&
+ notificationStrategy.shouldNotifyForMessage(account, localFolder, message, isOldMessage)) {
Timber.v("Creating notification for message %s:%s", localFolder.getName(), message.getUid());
// Notify with the localMessage so that we don't have to recalculate the content preview.
notificationController.addNewMailNotification(account, message, previousUnreadMessageCount);
--
GitLab
From 9c185b15cb66f3755e781f2a5805ea5ce1c9dd8f Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 14 Aug 2021 21:13:07 +0200
Subject: [PATCH 054/285] Remove unnecessary code
Backend.sync() already sets the 'last checked' time.
---
.../main/java/com/fsck/k9/controller/MessagingController.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index b3f8f37d8a..44f596d52a 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -2483,9 +2483,6 @@ public class MessagingController {
showFetchingMailNotificationIfNecessary(account, folder);
try {
synchronizeMailboxSynchronous(account, folder.getDatabaseId(), listener);
-
- long now = System.currentTimeMillis();
- folder.setLastChecked(now);
} finally {
clearFetchingMailNotificationIfNecessary(account);
}
--
GitLab
From 21102b50dc4a7436ac5979ec16aef378b7bb574e Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 14 Aug 2021 21:21:41 +0200
Subject: [PATCH 055/285] Set 'last_updated' column to NULL when clearing local
messages
---
.../com/fsck/k9/mailstore/LocalFolder.java | 20 +++++++++----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
index 02d684ee70..46a875eec2 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
@@ -351,16 +351,6 @@ public class LocalFolder {
}
}
- public void setLastChecked(final long lastChecked) throws MessagingException {
- try {
- open();
- this.lastChecked = lastChecked;
- } catch (MessagingException e) {
- throw new WrappedException(e);
- }
- updateFolderColumn("last_updated", lastChecked);
- }
-
public int getVisibleLimit() throws MessagingException {
open();
return visibleLimit;
@@ -1124,6 +1114,7 @@ public class LocalFolder {
db.execSQL("DELETE FROM messages WHERE folder_id = ?", folderIdArg);
setMoreMessages(MoreMessages.UNKNOWN);
+ resetLastChecked(db);
return null;
} catch (MessagingException e) {
@@ -1137,10 +1128,17 @@ public class LocalFolder {
this.localStore.notifyChange();
- setLastChecked(0);
setVisibleLimit(getAccount().getDisplayCount());
}
+ private void resetLastChecked(SQLiteDatabase db) {
+ lastChecked = 0;
+
+ ContentValues values = new ContentValues();
+ values.putNull("last_updated");
+ db.update("folders", values, "id = ?", new String[] { Long.toString(databaseId) });
+ }
+
public void destroyLocalOnlyMessages() throws MessagingException {
destroyMessages("uid LIKE '" + K9.LOCAL_UID_PREFIX + "%'");
}
--
GitLab
From eb1b31096823b59022dc3ce87ef5097f5f73163a Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 14 Aug 2021 21:28:39 +0200
Subject: [PATCH 056/285] Add migration to rewrite 'last_updated' column
---
.../com/fsck/k9/storage/StoreSchemaDefinition.java | 2 +-
.../com/fsck/k9/storage/migrations/MigrationTo80.kt | 12 ++++++++++++
.../com/fsck/k9/storage/migrations/Migrations.kt | 1 +
3 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo80.kt
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java b/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java
index b25f13963f..d459b60446 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java
+++ b/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java
@@ -12,7 +12,7 @@ import timber.log.Timber;
class StoreSchemaDefinition implements SchemaDefinition {
- static final int DB_VERSION = 79;
+ static final int DB_VERSION = 80;
private final MigrationsHelper migrationsHelper;
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo80.kt b/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo80.kt
new file mode 100644
index 0000000000..c435d9ead4
--- /dev/null
+++ b/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo80.kt
@@ -0,0 +1,12 @@
+package com.fsck.k9.storage.migrations
+
+import android.database.sqlite.SQLiteDatabase
+
+/**
+ * Rewrite 'last_update' column to NULL when the value is 0
+ */
+internal class MigrationTo80(private val db: SQLiteDatabase) {
+ fun rewriteLastUpdatedColumn() {
+ db.execSQL("UPDATE folders SET last_updated = NULL WHERE last_updated = 0")
+ }
+}
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.kt b/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.kt
index 4cb79662ea..6af1050f35 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.kt
@@ -25,5 +25,6 @@ object Migrations {
// 77: No longer necessary
if (oldVersion < 78) MigrationTo78(db).removeServerIdFromLocalFolders()
if (oldVersion < 79) MigrationTo79(db).updateDeleteMessageTrigger()
+ if (oldVersion < 80) MigrationTo80(db).rewriteLastUpdatedColumn()
}
}
--
GitLab
From 0ad8ce2c0d32e6d355f2913355d1cb0d7d86319d Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 19 Aug 2021 23:09:39 +0200
Subject: [PATCH 057/285] Fix check for missing incoming/outgoing server
credentials
---
.../java/com/fsck/k9/controller/MessagingController.java | 6 +++---
app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt | 2 +-
.../common/src/main/java/com/fsck/k9/mail/ServerSettings.kt | 5 +++++
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index b74b107988..0c87a74b08 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -392,7 +392,7 @@ public class MessagingController {
public void refreshFolderListSynchronous(Account account) {
try {
ServerSettings serverSettings = account.getIncomingServerSettings();
- if (serverSettings.password == null) {
+ if (serverSettings.isMissingCredentials()) {
handleAuthenticationFailure(account, true);
return;
}
@@ -651,7 +651,7 @@ public class MessagingController {
private void syncFolder(Account account, long folderId, MessagingListener listener, Backend backend) {
ServerSettings serverSettings = account.getIncomingServerSettings();
- if (serverSettings.password == null) {
+ if (serverSettings.isMissingCredentials()) {
handleAuthenticationFailure(account, true);
return;
}
@@ -1512,7 +1512,7 @@ public class MessagingController {
boolean wasPermanentFailure = false;
try {
ServerSettings serverSettings = account.getOutgoingServerSettings();
- if (serverSettings.password == null) {
+ if (serverSettings.isMissingCredentials()) {
handleAuthenticationFailure(account, false);
return;
}
diff --git a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
index 53eba91622..193c24a5cc 100644
--- a/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
+++ b/app/core/src/main/java/com/fsck/k9/job/MailSyncWorker.kt
@@ -39,7 +39,7 @@ class MailSyncWorker(
return Result.success()
}
- if (account.incomingServerSettings.password == null) {
+ if (account.incomingServerSettings.isMissingCredentials) {
Timber.d("Password for this account is missing. Skipping mail sync.")
return Result.success()
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
index 662f1f69c2..d51ad9045c 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
@@ -16,6 +16,11 @@ data class ServerSettings @JvmOverloads constructor(
@JvmField val clientCertificateAlias: String?,
val extra: Map = emptyMap()
) {
+ val isMissingCredentials: Boolean = when (authenticationType) {
+ AuthType.EXTERNAL -> clientCertificateAlias == null
+ else -> password == null
+ }
+
init {
require(type == type.toLowerCase(Locale.ROOT)) { "type must be all lower case" }
}
--
GitLab
From 96b7ca264dc79b381a753dd959de3d81712b0e82 Mon Sep 17 00:00:00 2001
From: ByteHamster
Date: Sun, 1 Aug 2021 12:04:33 +0200
Subject: [PATCH 058/285] Button bar in navigation drawer
---
.../src/main/java/com/fsck/k9/ui/K9Drawer.kt | 106 ++++++++++--------
.../main/res/drawable/ic_folder_manage.xml | 10 ++
.../src/main/res/drawable/ic_refresh_all.xml | 10 ++
.../src/main/res/layout/message_list.xml | 74 +++++++++++-
app/ui/legacy/src/main/res/values/strings.xml | 1 +
5 files changed, 148 insertions(+), 53 deletions(-)
create mode 100644 app/ui/legacy/src/main/res/drawable/ic_folder_manage.xml
create mode 100644 app/ui/legacy/src/main/res/drawable/ic_refresh_all.xml
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
index 774e6cb102..f5a18b28e9 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt
@@ -1,5 +1,6 @@
package com.fsck.k9.ui
+import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
@@ -7,8 +8,10 @@ import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
-import android.util.TypedValue
+import android.view.View
import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.Toast
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@@ -44,12 +47,10 @@ import com.mikepenz.materialdrawer.model.interfaces.selectedColorInt
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.util.addItems
-import com.mikepenz.materialdrawer.util.addStickyFooterItem
import com.mikepenz.materialdrawer.util.getDrawerItem
import com.mikepenz.materialdrawer.util.removeAllItems
import com.mikepenz.materialdrawer.widget.AccountHeaderView
import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
-import java.util.ArrayList
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -69,6 +70,12 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
private val messagingController: MessagingController by inject()
private val accountImageLoader: AccountImageLoader by inject()
+ private val buttonRow: LinearLayout = parent.findViewById(R.id.material_drawer_button_row)
+ private val buttonSettings: ImageView = parent.findViewById(R.id.drawer_button_settings)
+ private val buttonManageFolders: ImageView = parent.findViewById(R.id.drawer_button_manage_folders)
+ private val buttonRefreshAll: ImageView = parent.findViewById(R.id.drawer_button_refresh_all)
+ private val buttonRefreshAccount: ImageView = parent.findViewById(R.id.drawer_button_refresh_account)
+
private val drawer: DrawerLayout = parent.findViewById(R.id.drawerLayout)
private val sliderView: MaterialDrawerSliderView = parent.findViewById(R.id.material_drawer_slider)
private val headerView: AccountHeaderView = AccountHeaderView(parent).apply {
@@ -99,6 +106,7 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
initializeImageLoader()
configureAccountHeader()
+ configureButtonBar()
drawer.addDrawerListener(parent.createDrawerListener())
sliderView.tintStatusBar = true
@@ -125,8 +133,6 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
}
- addFooterItems()
-
accountsViewModel.displayAccountsLiveData.observeNotNull(parent) { accounts ->
setAccounts(accounts)
}
@@ -162,6 +168,7 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
openedAccountUuid = account.uuid
val eventHandled = !parent.openRealAccount(account)
updateUserAccountsAndFolders(account)
+ updateButtonBarVisibility(false)
eventHandled
}
@@ -209,6 +216,36 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
return if (unreadCount > 0) unreadCount.toString() else null
}
+ private fun updateButtonBarVisibility(showsAccounts: Boolean) {
+ buttonManageFolders.visibility = if (showsAccounts) View.GONE else View.VISIBLE
+ buttonRefreshAccount.visibility = if (showsAccounts) View.GONE else View.VISIBLE
+ buttonRefreshAll.visibility = if (showsAccounts) View.VISIBLE else View.GONE
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private fun configureButtonBar() {
+ headerView.onAccountHeaderSelectionViewClickListener = { view, profile ->
+ updateButtonBarVisibility(!headerView.selectionListShown)
+ false
+ }
+ updateButtonBarVisibility(headerView.selectionListShown)
+
+ buttonRow.setOnTouchListener { _, _ -> true } // To avoid touch going through
+ buttonSettings.setOnClickListener { SettingsActivity.launch(parent) }
+ buttonManageFolders.setOnClickListener { parent.launchManageFoldersScreen() }
+ buttonRefreshAccount.setOnClickListener { refreshAndShowProgress(headerView.activeProfile?.tag as Account) }
+ buttonRefreshAll.setOnClickListener { refreshAndShowProgress(null) }
+
+ val showContentDescription = View.OnLongClickListener { v ->
+ Toast.makeText(parent, v.contentDescription, Toast.LENGTH_SHORT).show()
+ true
+ }
+ buttonSettings.setOnLongClickListener(showContentDescription)
+ buttonManageFolders.setOnLongClickListener(showContentDescription)
+ buttonRefreshAccount.setOnLongClickListener(showContentDescription)
+ buttonRefreshAll.setOnLongClickListener(showContentDescription)
+ }
+
private fun setAccounts(displayAccounts: List) {
val oldSelectedBackgroundColor = selectedBackgroundColor
@@ -259,35 +296,6 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
}
- private fun addFooterItems() {
- sliderView.addStickyFooterItem(
- PrimaryDrawerItem().apply {
- nameRes = R.string.folders_action
- iconRes = folderIconProvider.iconFolderResId
- identifier = DRAWER_ID_FOLDERS
- isSelectable = false
- }
- )
-
- sliderView.addStickyFooterItem(
- PrimaryDrawerItem().apply {
- nameRes = R.string.preferences_action
- iconRes = getResId(R.attr.iconActionSettings)
- identifier = DRAWER_ID_PREFERENCES
- isSelectable = false
- }
- )
- }
-
- private fun getResId(resAttribute: Int): Int {
- val typedValue = TypedValue()
- val found = parent.theme.resolveAttribute(resAttribute, typedValue, true)
- if (!found) {
- throw AssertionError("Couldn't find resource with attribute $resAttribute")
- }
- return typedValue.resourceId
- }
-
private fun getFolderDisplayName(folder: Folder): String {
return folderNameFormatter.displayName(folder)
}
@@ -299,20 +307,26 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
foldersViewModel.loadFolders(account)
}
- // Account can be null to refresh all (unified inbox or account list).
swipeRefreshLayout.setOnRefreshListener {
- val accountToRefresh = if (headerView.selectionListShown) null else account
- messagingController.checkMail(
- accountToRefresh, true, true,
- object : SimpleMessagingListener() {
- override fun checkMailFinished(context: Context?, account: Account?) {
- swipeRefreshLayout.post {
- swipeRefreshLayout.isRefreshing = false
- }
+ refreshAndShowProgress(if (headerView.selectionListShown) null else account)
+ }
+ }
+
+ private fun refreshAndShowProgress(account: Account?) {
+ // Account can be null to refresh all (unified inbox or account list).
+ if (!swipeRefreshLayout.isRefreshing) {
+ swipeRefreshLayout.isRefreshing = true
+ }
+ messagingController.checkMail(
+ account, true, true,
+ object : SimpleMessagingListener() {
+ override fun checkMailFinished(context: Context?, account: Account?) {
+ swipeRefreshLayout.post {
+ swipeRefreshLayout.isRefreshing = false
}
}
- )
- }
+ }
+ )
}
private fun initializeWithAccountColor(account: Account) {
@@ -329,8 +343,6 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
private fun handleItemClickListener(drawerItem: IDrawerItem<*>) {
when (drawerItem.identifier) {
- DRAWER_ID_PREFERENCES -> SettingsActivity.launch(parent)
- DRAWER_ID_FOLDERS -> parent.launchManageFoldersScreen()
DRAWER_ID_UNIFIED_INBOX -> parent.openUnifiedInbox()
else -> {
val folder = drawerItem.tag as Folder
diff --git a/app/ui/legacy/src/main/res/drawable/ic_folder_manage.xml b/app/ui/legacy/src/main/res/drawable/ic_folder_manage.xml
new file mode 100644
index 0000000000..5a836825b3
--- /dev/null
+++ b/app/ui/legacy/src/main/res/drawable/ic_folder_manage.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/ui/legacy/src/main/res/drawable/ic_refresh_all.xml b/app/ui/legacy/src/main/res/drawable/ic_refresh_all.xml
new file mode 100644
index 0000000000..f0721d9915
--- /dev/null
+++ b/app/ui/legacy/src/main/res/drawable/ic_refresh_all.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/ui/legacy/src/main/res/layout/message_list.xml b/app/ui/legacy/src/main/res/layout/message_list.xml
index 70efde78e2..969855d61c 100644
--- a/app/ui/legacy/src/main/res/layout/message_list.xml
+++ b/app/ui/legacy/src/main/res/layout/message_list.xml
@@ -47,16 +47,78 @@
-
-
+ android:layout_height="0dp"
+ android:layout_weight="1">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index 739ab8ccad..da99c80857 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -133,6 +133,7 @@ Please submit bug reports, contribute new features and ask questions at
Discard
Save as draft
Check mail
+ Check mail in all accounts
Send messages
Refresh folder list
Find folder
--
GitLab
From 29d112a15035a212f6d1ca25d94cec120f5e7ffd Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 21 Aug 2021 19:32:38 +0200
Subject: [PATCH 059/285] Tweak title for biometrics prompt when revealing
password
---
app/ui/legacy/src/main/res/values/strings.xml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/app/ui/legacy/src/main/res/values/strings.xml b/app/ui/legacy/src/main/res/values/strings.xml
index 674acd9ff2..22fe789a32 100644
--- a/app/ui/legacy/src/main/res/values/strings.xml
+++ b/app/ui/legacy/src/main/res/values/strings.xml
@@ -355,8 +355,10 @@ Please submit bug reports, contribute new features and ask questions at
Email address
Password
Show password
+
+
To view your password here, enable screen lock on this device.
- Verify it\'s you
+ Verify your identity
Unlock to view your password
Manual setup
--
GitLab
From 68ffba6f9e770c52df4eb0c23e9e43981a3d0451 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 21 Aug 2021 20:02:11 +0200
Subject: [PATCH 060/285] Change "save attachment" icon
---
app/ui/legacy/src/main/res/drawable/ic_download.xml | 10 ++++++++++
.../src/main/res/layout/message_view_attachment.xml | 2 +-
app/ui/legacy/src/main/res/values/attrs.xml | 1 +
app/ui/legacy/src/main/res/values/themes.xml | 2 ++
4 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 app/ui/legacy/src/main/res/drawable/ic_download.xml
diff --git a/app/ui/legacy/src/main/res/drawable/ic_download.xml b/app/ui/legacy/src/main/res/drawable/ic_download.xml
new file mode 100644
index 0000000000..0964bd62db
--- /dev/null
+++ b/app/ui/legacy/src/main/res/drawable/ic_download.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/ui/legacy/src/main/res/layout/message_view_attachment.xml b/app/ui/legacy/src/main/res/layout/message_view_attachment.xml
index 66f4d9ac4f..97e10e0025 100644
--- a/app/ui/legacy/src/main/res/layout/message_view_attachment.xml
+++ b/app/ui/legacy/src/main/res/layout/message_view_attachment.xml
@@ -90,7 +90,7 @@
android:layout_marginBottom="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/remove_attachment_action"
- app:srcCompat="?attr/iconActionSave"
+ app:srcCompat="?attr/iconActionSaveAttachment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/attachment_preview" />
diff --git a/app/ui/legacy/src/main/res/values/attrs.xml b/app/ui/legacy/src/main/res/values/attrs.xml
index 69bcab7ec0..a16a324815 100644
--- a/app/ui/legacy/src/main/res/values/attrs.xml
+++ b/app/ui/legacy/src/main/res/values/attrs.xml
@@ -39,6 +39,7 @@
+
diff --git a/app/ui/legacy/src/main/res/values/themes.xml b/app/ui/legacy/src/main/res/values/themes.xml
index 3966d727a5..af73c3f867 100644
--- a/app/ui/legacy/src/main/res/values/themes.xml
+++ b/app/ui/legacy/src/main/res/values/themes.xml
@@ -53,6 +53,7 @@
- @drawable/ic_file_upload
- @drawable/ic_select_all
- @drawable/ic_floppy
+ - @drawable/ic_download
- @drawable/ic_clear
- @drawable/ic_action_request_read_receipt_light
- @drawable/ic_chevron_down
@@ -171,6 +172,7 @@
- @drawable/ic_file_upload
- @drawable/ic_select_all
- @drawable/ic_floppy
+ - @drawable/ic_download
- @drawable/ic_clear
- @drawable/ic_action_request_read_receipt_dark
- @drawable/ic_chevron_down
--
GitLab
From dd151ec61c9942a51e7e1da529d3551496164e6d Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 21 Aug 2021 20:43:51 +0200
Subject: [PATCH 061/285] Version 5.805
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 4 ++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index f896c88f69..c1995eef47 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28004
- versionName '5.804'
+ versionCode 28005
+ versionName '5.805'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index ee9f101a85..35c619742e 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,10 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Fixed the check for missing incoming/outgoing server credentials (introduced in K-9 Mail 5.804)
+ Changed the 'save attachment' icon (apparently floppy disks are no longer a thing)
+
Fixed a bug where Push didn't work with some servers
Don't connect to the incoming or outgoing server when passwords haven't been provided after import
--
GitLab
From baa94b84b9796b7279e1d03ebe8ad3d302fb19ca Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Jul 2021 22:57:52 +0200
Subject: [PATCH 062/285] Remove unused code
---
.../k9/controller/MessagingController.java | 46 ------
.../com/fsck/k9/mailstore/LocalStore.java | 131 ------------------
2 files changed, 177 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index ff340c2195..3ac1d378ed 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -2526,52 +2526,6 @@ public class MessagingController {
});
}
- public void clear(final Account account, final MessagingListener ml) {
- putBackground("clear:" + account.getDescription(), ml, new Runnable() {
- @Override
- public void run() {
- try {
- LocalStore localStore = localStoreProvider.getInstance(account);
- long oldSize = localStore.getSize();
- localStore.clear();
- localStore.resetVisibleLimits(account.getDisplayCount());
- long newSize = localStore.getSize();
- for (MessagingListener l : getListeners(ml)) {
- l.accountSizeChanged(account, oldSize, newSize);
- }
- } catch (UnavailableStorageException e) {
- Timber.i("Failed to clear account because storage is not available - trying again later.");
- throw new UnavailableAccountException(e);
- } catch (Exception e) {
- Timber.e(e, "Failed to clear account %s", account.getDescription());
- }
- }
- });
- }
-
- public void recreate(final Account account, final MessagingListener ml) {
- putBackground("recreate:" + account.getDescription(), ml, new Runnable() {
- @Override
- public void run() {
- try {
- LocalStore localStore = localStoreProvider.getInstance(account);
- long oldSize = localStore.getSize();
- localStore.recreate();
- localStore.resetVisibleLimits(account.getDisplayCount());
- long newSize = localStore.getSize();
- for (MessagingListener l : getListeners(ml)) {
- l.accountSizeChanged(account, oldSize, newSize);
- }
- } catch (UnavailableStorageException e) {
- Timber.i("Failed to recreate an account because storage is not available - trying again later.");
- throw new UnavailableAccountException(e);
- } catch (Exception e) {
- Timber.e(e, "Failed to recreate account %s", account.getDescription());
- }
- }
- });
- }
-
public void deleteAccount(Account account) {
notificationController.clearNewMailNotifications(account);
memorizingMessagingListener.removeAccount(account);
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index 553513ce68..5ad4375170 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -53,10 +53,7 @@ import com.fsck.k9.mailstore.LockableDatabase.SchemaDefinition;
import com.fsck.k9.mailstore.LockableDatabase.WrappedException;
import com.fsck.k9.mailstore.StorageManager.InternalStorageProvider;
import com.fsck.k9.mailstore.StorageManager.StorageProvider;
-import com.fsck.k9.message.extractors.AttachmentCounter;
import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
-import com.fsck.k9.message.extractors.MessageFulltextCreator;
-import com.fsck.k9.message.extractors.MessagePreviewCreator;
import com.fsck.k9.provider.EmailProvider;
import com.fsck.k9.provider.EmailProvider.MessageColumns;
import com.fsck.k9.search.LocalSearch;
@@ -170,9 +167,6 @@ public class LocalStore {
private final Context context;
private final ContentResolver contentResolver;
- private final MessagePreviewCreator messagePreviewCreator;
- private final MessageFulltextCreator messageFulltextCreator;
- private final AttachmentCounter attachmentCounter;
private final PendingCommandSerializer pendingCommandSerializer;
private final AttachmentInfoExtractor attachmentInfoExtractor;
@@ -193,9 +187,6 @@ public class LocalStore {
this.context = context;
this.contentResolver = context.getContentResolver();
- messagePreviewCreator = MessagePreviewCreator.newInstance();
- messageFulltextCreator = MessageFulltextCreator.newInstance();
- attachmentCounter = AttachmentCounter.newInstance();
pendingCommandSerializer = PendingCommandSerializer.getInstance();
attachmentInfoExtractor = DI.get(AttachmentInfoExtractor.class);
@@ -288,78 +279,6 @@ public class LocalStore {
}
}
-
- public void clear() throws MessagingException {
- if (K9.isDebugLoggingEnabled()) {
- Timber.i("Before prune size = %d", getSize());
- }
-
- deleteAllMessageDataFromDisk();
-
- if (K9.isDebugLoggingEnabled()) {
- Timber.i("After prune / before compaction size = %d", getSize());
- Timber.i("Before clear folder count = %d", getFolderCount());
- Timber.i("Before clear message count = %d", getMessageCount());
- Timber.i("After prune / before clear size = %d", getSize());
- }
-
- database.execute(false, new DbCallback() {
- @Override
- public Void doDbWork(final SQLiteDatabase db) {
- // We don't care about threads of deleted messages, so delete the whole table.
- db.delete("threads", null, null);
-
- // Don't delete deleted messages. They are essentially placeholders for UIDs of messages that have
- // been deleted locally.
- db.delete("messages", "deleted = 0", null);
-
- // We don't need the search data now either
- db.delete("messages_fulltext", null, null);
-
- return null;
- }
- });
-
- compact();
-
- if (K9.isDebugLoggingEnabled()) {
- Timber.i("After clear message count = %d", getMessageCount());
- Timber.i("After clear size = %d", getSize());
- }
- }
-
- private int getMessageCount() throws MessagingException {
- return database.execute(false, new DbCallback() {
- @Override
- public Integer doDbWork(final SQLiteDatabase db) {
- Cursor cursor = null;
- try {
- cursor = db.rawQuery("SELECT COUNT(*) FROM messages", null);
- cursor.moveToFirst();
- return cursor.getInt(0); // message count
- } finally {
- Utility.closeQuietly(cursor);
- }
- }
- });
- }
-
- private int getFolderCount() throws MessagingException {
- return database.execute(false, new DbCallback() {
- @Override
- public Integer doDbWork(final SQLiteDatabase db) {
- Cursor cursor = null;
- try {
- cursor = db.rawQuery("SELECT COUNT(*) FROM folders", null);
- cursor.moveToFirst();
- return cursor.getInt(0); // folder count
- } finally {
- Utility.closeQuietly(cursor);
- }
- }
- });
- }
-
public LocalFolder getFolder(String serverId) {
return new LocalFolder(this, serverId);
}
@@ -412,44 +331,6 @@ public class LocalStore {
database.delete();
}
- public void recreate() throws UnavailableStorageException {
- database.recreate();
- }
-
- private void deleteAllMessageDataFromDisk() throws MessagingException {
- markAllMessagePartsDataAsMissing();
- deleteAllMessagePartsDataFromDisk();
- }
-
- private void markAllMessagePartsDataAsMissing() throws MessagingException {
- database.execute(false, new DbCallback() {
- @Override
- public Void doDbWork(final SQLiteDatabase db) throws WrappedException {
- ContentValues cv = new ContentValues();
- cv.put("data_location", DataLocation.MISSING);
- db.update("message_parts", cv, null, null);
-
- return null;
- }
- });
- }
-
- private void deleteAllMessagePartsDataFromDisk() {
- final StorageManager storageManager = StorageManager.getInstance(context);
- File attachmentDirectory = storageManager.getAttachmentDirectory(
- account.getUuid(), database.getStorageProviderId());
- File[] files = attachmentDirectory.listFiles();
- if (files == null) {
- return;
- }
-
- for (File file : files) {
- if (file.exists() && !file.delete()) {
- file.deleteOnExit();
- }
- }
- }
-
public void resetVisibleLimits(int visibleLimit) throws MessagingException {
final ContentValues cv = new ContentValues();
cv.put("visible_limit", Integer.toString(visibleLimit));
@@ -937,18 +818,6 @@ public class LocalStore {
return database;
}
- MessagePreviewCreator getMessagePreviewCreator() {
- return messagePreviewCreator;
- }
-
- public MessageFulltextCreator getMessageFulltextCreator() {
- return messageFulltextCreator;
- }
-
- AttachmentCounter getAttachmentCounter() {
- return attachmentCounter;
- }
-
AttachmentInfoExtractor getAttachmentInfoExtractor() {
return attachmentInfoExtractor;
}
--
GitLab
From f09f2d400304a8a9be632b38600ea929c8e24e86 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Jul 2021 23:03:52 +0200
Subject: [PATCH 063/285] Move LocalStore.compact() to MessageStore
---
.../k9/controller/MessagingController.java | 11 ++---
.../com/fsck/k9/mailstore/LocalStore.java | 45 -------------------
.../com/fsck/k9/mailstore/MessageStore.kt | 10 +++++
.../k9/storage/messages/DatabaseOperations.kt | 40 +++++++++++++++++
.../k9/storage/messages/K9MessageStore.kt | 9 ++++
5 files changed, 63 insertions(+), 52 deletions(-)
create mode 100644 app/storage/src/main/java/com/fsck/k9/storage/messages/DatabaseOperations.kt
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 3ac1d378ed..9a179f4ccc 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -2509,16 +2509,13 @@ public class MessagingController {
@Override
public void run() {
try {
- LocalStore localStore = localStoreProvider.getInstance(account);
- long oldSize = localStore.getSize();
- localStore.compact();
- long newSize = localStore.getSize();
+ MessageStore messageStore = messageStoreManager.getMessageStore(account);
+ long oldSize = messageStore.getSize();
+ messageStore.compact();
+ long newSize = messageStore.getSize();
for (MessagingListener l : getListeners(ml)) {
l.accountSizeChanged(account, oldSize, newSize);
}
- } catch (UnavailableStorageException e) {
- Timber.i("Failed to compact account because storage is not available - trying again later.");
- throw new UnavailableAccountException(e);
} catch (Exception e) {
Timber.e(e, "Failed to compact account %s", account.getDescription());
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index 5ad4375170..7e04adf00e 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -30,7 +30,6 @@ import android.text.TextUtils;
import com.fsck.k9.Account;
import com.fsck.k9.Clock;
import com.fsck.k9.DI;
-import com.fsck.k9.K9;
import com.fsck.k9.controller.MessageCounts;
import com.fsck.k9.Preferences;
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
@@ -235,50 +234,6 @@ public class LocalStore {
return outboxStateRepository;
}
- public long getSize() throws MessagingException {
-
- final StorageManager storageManager = StorageManager.getInstance(context);
-
- final File attachmentDirectory = storageManager.getAttachmentDirectory(account.getUuid(),
- database.getStorageProviderId());
-
- return database.execute(false, new DbCallback() {
- @Override
- public Long doDbWork(final SQLiteDatabase db) {
- final File[] files = attachmentDirectory.listFiles();
- long attachmentLength = 0;
- if (files != null) {
- for (File file : files) {
- if (file.exists()) {
- attachmentLength += file.length();
- }
- }
- }
-
- final File dbFile = storageManager.getDatabase(account.getUuid(), database.getStorageProviderId());
- return dbFile.length() + attachmentLength;
- }
- });
- }
-
- public void compact() throws MessagingException {
- if (K9.isDebugLoggingEnabled()) {
- Timber.i("Before compaction size = %d", getSize());
- }
-
- database.execute(false, new DbCallback() {
- @Override
- public Void doDbWork(final SQLiteDatabase db) throws WrappedException {
- db.execSQL("VACUUM");
- return null;
- }
- });
-
- if (K9.isDebugLoggingEnabled()) {
- Timber.i("After compaction size = %d", getSize());
- }
- }
-
public LocalFolder getFolder(String serverId) {
return new LocalFolder(this, serverId);
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
index a2305d6f14..55e5ecb60f 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
@@ -125,6 +125,11 @@ interface MessageStore {
*/
fun getLastUid(folderId: Long): Long?
+ /**
+ * Return the size of this message store in bytes.
+ */
+ fun getSize(): Long
+
/**
* Remove messages from the store.
*/
@@ -267,4 +272,9 @@ interface MessageStore {
* Create or update a number property associated with the given folder.
*/
fun setFolderExtraNumber(folderId: Long, name: String, value: Long)
+
+ /**
+ * Optimize the message store with the goal of using the minimal amount of disk space.
+ */
+ fun compact()
}
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/DatabaseOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/DatabaseOperations.kt
new file mode 100644
index 0000000000..1558190c6b
--- /dev/null
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/DatabaseOperations.kt
@@ -0,0 +1,40 @@
+package com.fsck.k9.storage.messages
+
+import com.fsck.k9.mailstore.LockableDatabase
+import com.fsck.k9.mailstore.StorageManager
+import timber.log.Timber
+
+internal class DatabaseOperations(
+ private val lockableDatabase: LockableDatabase,
+ val storageManager: StorageManager,
+ val accountUuid: String
+) {
+ fun getSize(): Long {
+ val storageProviderId = lockableDatabase.storageProviderId
+ val attachmentDirectory = storageManager.getAttachmentDirectory(accountUuid, storageProviderId)
+
+ return lockableDatabase.execute(false) {
+ val attachmentFiles = attachmentDirectory.listFiles() ?: emptyArray()
+ val attachmentsSize = attachmentFiles.asSequence()
+ .filter { file -> file.exists() }
+ .fold(initial = 0L) { accumulatedSize, file ->
+ accumulatedSize + file.length()
+ }
+
+ val databaseFile = storageManager.getDatabase(accountUuid, storageProviderId)
+ val databaseSize = databaseFile.length()
+
+ databaseSize + attachmentsSize
+ }
+ }
+
+ fun compact() {
+ Timber.i("Before compaction size = %d", getSize())
+
+ lockableDatabase.execute(false) { database ->
+ database.execSQL("VACUUM")
+ }
+
+ Timber.i("After compaction size = %d", getSize())
+ }
+}
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
index c8c5b14343..027ce8ed2f 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
@@ -40,6 +40,7 @@ class K9MessageStore(
private val updateFolderOperations = UpdateFolderOperations(database)
private val deleteFolderOperations = DeleteFolderOperations(database, attachmentFileManager)
private val keyValueStoreOperations = KeyValueStoreOperations(database)
+ private val databaseOperations = DatabaseOperations(database, storageManager, accountUuid)
override fun saveRemoteMessage(folderId: Long, messageServerId: String, messageData: SaveMessageData) {
saveMessageOperations.saveRemoteMessage(folderId, messageServerId, messageData)
@@ -133,6 +134,10 @@ class K9MessageStore(
return retrieveFolderOperations.getFolderId(folderServerId)
}
+ override fun getSize(): Long {
+ return databaseOperations.getSize()
+ }
+
override fun changeFolder(folderServerId: String, name: String, type: FolderType) {
updateFolderOperations.changeFolder(folderServerId, name, type)
}
@@ -208,4 +213,8 @@ class K9MessageStore(
override fun setFolderExtraNumber(folderId: Long, name: String, value: Long) {
return keyValueStoreOperations.setFolderExtraNumber(folderId, name, value)
}
+
+ override fun compact() {
+ return databaseOperations.compact()
+ }
}
--
GitLab
From 93a1df5bd036326bbe10a591d692c6a0256baaa9 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 18 Jul 2021 23:20:20 +0200
Subject: [PATCH 064/285] Remove LocalStore.getFolderId()
---
.../k9/controller/MessagingController.java | 31 ++++++++-----------
.../com/fsck/k9/mailstore/LocalStore.java | 15 ---------
2 files changed, 13 insertions(+), 33 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index 9a179f4ccc..a8deb617ad 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -289,18 +289,13 @@ public class MessagingController {
return localStore.getFolderServerId(folderId);
}
- private long getFolderId(Account account, String folderServerId) throws MessagingException {
- LocalStore localStore = getLocalStoreOrThrow(account);
- return localStore.getFolderId(folderServerId);
- }
-
- private long getFolderIdOrThrow(Account account, String folderServerId) {
- LocalStore localStore = getLocalStoreOrThrow(account);
- try {
- return localStore.getFolderId(folderServerId);
- } catch (MessagingException e) {
- throw new IllegalStateException(e);
+ private long getFolderId(Account account, String folderServerId) {
+ MessageStore messageStore = messageStoreManager.getMessageStore(account);
+ Long folderId = messageStore.getFolderId(folderServerId);
+ if (folderId == null) {
+ throw new IllegalStateException("Folder not found (server ID: " + folderServerId + ")");
}
+ return folderId;
}
public void addListener(MessagingListener listener) {
@@ -604,7 +599,7 @@ public class MessagingController {
);
}
- public void synchronizeMailboxBlocking(Account account, String folderServerId) throws MessagingException {
+ public void synchronizeMailboxBlocking(Account account, String folderServerId) {
long folderId = getFolderId(account, folderServerId);
account.setRingNotified(false);
@@ -2685,7 +2680,7 @@ public class MessagingController {
@Override
public void syncStarted(@NotNull String folderServerId) {
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.synchronizeMailboxStarted(account, folderId);
}
@@ -2721,7 +2716,7 @@ public class MessagingController {
@Override
public void syncProgress(@NotNull String folderServerId, int completed, int total) {
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.synchronizeMailboxProgress(account, folderId, completed, total);
}
@@ -2755,7 +2750,7 @@ public class MessagingController {
}
String accountUuid = account.getUuid();
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
MessageReference messageReference = new MessageReference(accountUuid, folderId, messageServerId, null);
notificationController.removeNewMailNotification(account, messageReference);
}
@@ -2782,7 +2777,7 @@ public class MessagingController {
@Override
public void syncFinished(@NotNull String folderServerId) {
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.synchronizeMailboxFinished(account, folderId);
}
@@ -2798,7 +2793,7 @@ public class MessagingController {
notifyUserIfCertificateProblem(account, exception, true);
}
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.synchronizeMailboxFailed(account, folderId, message);
}
@@ -2806,7 +2801,7 @@ public class MessagingController {
@Override
public void folderStatusChanged(@NotNull String folderServerId) {
- long folderId = getFolderIdOrThrow(account, folderServerId);
+ long folderId = getFolderId(account, folderServerId);
for (MessagingListener messagingListener : getListeners(listener)) {
messagingListener.folderStatusChanged(account, folderId);
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
index 7e04adf00e..acda877505 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalStore.java
@@ -711,21 +711,6 @@ public class LocalStore {
});
}
- public long getFolderId(String folderServerId) throws MessagingException {
- return database.execute(false, db -> {
- try (Cursor cursor = db.query("folders", new String[] { "id" },
- "server_id = ?", new String[] { folderServerId },
- null, null, null)
- ) {
- if (cursor.moveToFirst()) {
- return cursor.getLong(0);
- } else {
- throw new MessagingException("Folder not found by server ID: " + folderServerId);
- }
- }
- });
- }
-
public static class AttachmentInfo {
public String name;
public long size;
--
GitLab
From 6c2f4b6354da5b491de16c334e9eb1ad657bfe69 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 22 Aug 2021 15:46:26 +0200
Subject: [PATCH 065/285] Rename FlowedMessageUtils to FormatFlowedHelper
---
.../{FlowedMessageUtils.java => FormatFlowedHelper.java} | 2 +-
.../java/com/fsck/k9/mail/internet/MessageExtractor.java | 4 ++--
...wedMessageUtilsTest.java => FormatFlowedHelperTest.java} | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
rename mail/common/src/main/java/com/fsck/k9/mail/internet/{FlowedMessageUtils.java => FormatFlowedHelper.java} (97%)
rename mail/common/src/test/java/com/fsck/k9/mail/internet/{FlowedMessageUtilsTest.java => FormatFlowedHelperTest.java} (88%)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.java
similarity index 97%
rename from mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java
rename to mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.java
index debc3e2d74..e978cb46e5 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.java
@@ -5,7 +5,7 @@ import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
-class FlowedMessageUtils {
+class FormatFlowedHelper {
private static final String TEXT_PLAIN = "text/plain";
private static final String HEADER_PARAM_FORMAT = "format";
private static final String HEADER_FORMAT_FLOWED = "flowed";
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
index 29e675e43a..927d8745d3 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
@@ -25,7 +25,7 @@ import timber.log.Timber;
import static com.fsck.k9.mail.internet.CharsetSupport.fixupCharset;
import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
-import static com.fsck.k9.mail.internet.FlowedMessageUtils.isFormatFlowed;
+import static com.fsck.k9.mail.internet.FormatFlowedHelper.isFormatFlowed;
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
import static com.fsck.k9.mail.internet.Viewable.Alternative;
import static com.fsck.k9.mail.internet.Viewable.Html;
@@ -203,7 +203,7 @@ public class MessageExtractor {
Viewable viewable;
if (isSameMimeType(mimeType, "text/plain")) {
if (isFormatFlowed(part.getContentType())) {
- boolean delSp = FlowedMessageUtils.isDelSp(part.getContentType());
+ boolean delSp = FormatFlowedHelper.isDelSp(part.getContentType());
viewable = new Flowed(part, delSp);
} else {
viewable = new Text(part);
diff --git a/mail/common/src/test/java/com/fsck/k9/mail/internet/FlowedMessageUtilsTest.java b/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.java
similarity index 88%
rename from mail/common/src/test/java/com/fsck/k9/mail/internet/FlowedMessageUtilsTest.java
rename to mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.java
index 5092734045..dbbd56a17b 100644
--- a/mail/common/src/test/java/com/fsck/k9/mail/internet/FlowedMessageUtilsTest.java
+++ b/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.java
@@ -3,13 +3,13 @@ package com.fsck.k9.mail.internet;
import org.junit.Test;
-import static com.fsck.k9.mail.internet.FlowedMessageUtils.isDelSp;
-import static com.fsck.k9.mail.internet.FlowedMessageUtils.isFormatFlowed;
+import static com.fsck.k9.mail.internet.FormatFlowedHelper.isDelSp;
+import static com.fsck.k9.mail.internet.FormatFlowedHelper.isFormatFlowed;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-public class FlowedMessageUtilsTest {
+public class FormatFlowedHelperTest {
@Test
public void isFormatFlowed_withTextPlainFormatFlowed_shouldReturnTrue() throws Exception {
assertTrue(isFormatFlowed("text/plain; format=flowed"));
--
GitLab
From 9ee3a76ef186fd6ac50ed0cc1a04fd06eaebb3bb Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 22 Aug 2021 15:54:33 +0200
Subject: [PATCH 066/285] Move format=flowed decoding to MessageExtractor
---
.../mailstore/MessageViewInfoExtractor.java | 9 --------
.../MessageViewInfoExtractorTest.java | 4 +++-
.../k9/mail/internet}/FlowedMessageUtils.java | 2 +-
.../k9/mail/internet/MessageExtractor.java | 23 +++++++++++--------
.../com/fsck/k9/mail/internet/Viewable.java | 13 -----------
5 files changed, 18 insertions(+), 33 deletions(-)
rename {app/core/src/main/java/com/fsck/k9/mailstore/util => mail/common/src/main/java/com/fsck/k9/mail/internet}/FlowedMessageUtils.java (99%)
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractor.java b/app/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractor.java
index 4499e955b9..a3a5cead77 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractor.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/MessageViewInfoExtractor.java
@@ -20,9 +20,7 @@ import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MessageExtractor;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.internet.Viewable;
-import com.fsck.k9.mail.internet.Viewable.Flowed;
import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError;
-import com.fsck.k9.mailstore.util.FlowedMessageUtils;
import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
import com.fsck.k9.message.html.HtmlConverter;
import com.fsck.k9.message.html.HtmlProcessor;
@@ -271,10 +269,6 @@ public class MessageViewInfoExtractor {
String t = getTextFromPart(part);
if (t == null) {
t = "";
- } else if (viewable instanceof Flowed) {
- boolean delSp = ((Flowed) viewable).isDelSp();
- t = FlowedMessageUtils.deflow(t, delSp);
- t = HtmlConverter.textToHtml(t);
} else if (viewable instanceof Text) {
t = HtmlConverter.textToHtml(t);
} else if (!(viewable instanceof Html)) {
@@ -310,9 +304,6 @@ public class MessageViewInfoExtractor {
t = "";
} else if (viewable instanceof Html) {
t = HtmlConverter.htmlToText(t);
- } else if (viewable instanceof Flowed) {
- boolean delSp = ((Flowed) viewable).isDelSp();
- t = FlowedMessageUtils.deflow(t, delSp);
} else if (!(viewable instanceof Text)) {
throw new IllegalStateException("unhandled case!");
}
diff --git a/app/core/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java b/app/core/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java
index 6c374556af..a8b128547d 100644
--- a/app/core/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java
+++ b/app/core/src/test/java/com/fsck/k9/mailstore/MessageViewInfoExtractorTest.java
@@ -2,6 +2,7 @@ package com.fsck.k9.mailstore;
import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -17,6 +18,7 @@ import com.fsck.k9.DI;
import com.fsck.k9.K9RobolectricTest;
import com.fsck.k9.TestCoreResourceProvider;
import com.fsck.k9.mail.Address;
+import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyPart;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
@@ -135,7 +137,7 @@ public class MessageViewInfoExtractorTest extends K9RobolectricTest {
@Test
public void testTextPlainFormatFlowed() throws MessagingException {
// Create text/plain body
- TextBody body = new TextBody(BODY_TEXT_FLOWED);
+ Body body = new BinaryMemoryBody(BODY_TEXT_FLOWED.getBytes(StandardCharsets.UTF_8), "utf-8");
// Create message
MimeMessage message = new MimeMessage();
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/util/FlowedMessageUtils.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java
similarity index 99%
rename from app/core/src/main/java/com/fsck/k9/mailstore/util/FlowedMessageUtils.java
rename to mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java
index d30665a925..25a10847b4 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/util/FlowedMessageUtils.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/FlowedMessageUtils.java
@@ -1,4 +1,4 @@
-package com.fsck.k9.mailstore.util;
+package com.fsck.k9.mail.internet;
/**
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
index 927d8745d3..740a6fb145 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
@@ -19,13 +19,11 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Multipart;
import com.fsck.k9.mail.Part;
-import com.fsck.k9.mail.internet.Viewable.Flowed;
import org.apache.commons.io.input.BoundedInputStream;
import timber.log.Timber;
import static com.fsck.k9.mail.internet.CharsetSupport.fixupCharset;
import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
-import static com.fsck.k9.mail.internet.FormatFlowedHelper.isFormatFlowed;
import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
import static com.fsck.k9.mail.internet.Viewable.Alternative;
import static com.fsck.k9.mail.internet.Viewable.Html;
@@ -112,13 +110,25 @@ public class MessageExtractor {
InputStream in = MimeUtility.decodeBody(body);
InputStream possiblyLimitedIn =
textSizeLimit != NO_TEXT_SIZE_LIMIT ? new BoundedInputStream(in, textSizeLimit) : in;
+
+ String text;
try {
- return CharsetSupport.readToString(possiblyLimitedIn, charset);
+ text = CharsetSupport.readToString(possiblyLimitedIn, charset);
} finally {
try {
MimeUtility.closeInputStreamWithoutDeletingTemporaryFiles(in);
} catch (IOException e) { /* Ignore */ }
}
+
+ if (isSameMimeType(mimeType, "text/plain")) {
+ String contentType = part.getContentType();
+ if (FormatFlowedHelper.isFormatFlowed(contentType)) {
+ boolean delSp = FormatFlowedHelper.isDelSp(contentType);
+ return FlowedMessageUtils.deflow(text, delSp);
+ }
+ }
+
+ return text;
}
public static boolean hasMissingParts(Part part) {
@@ -202,12 +212,7 @@ public class MessageExtractor {
String mimeType = part.getMimeType();
Viewable viewable;
if (isSameMimeType(mimeType, "text/plain")) {
- if (isFormatFlowed(part.getContentType())) {
- boolean delSp = FormatFlowedHelper.isDelSp(part.getContentType());
- viewable = new Flowed(part, delSp);
- } else {
- viewable = new Text(part);
- }
+ viewable = new Text(part);
} else {
viewable = new Html(part);
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/Viewable.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/Viewable.java
index 1ed1d05983..f8e53d16d5 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/Viewable.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/Viewable.java
@@ -41,19 +41,6 @@ public interface Viewable {
}
}
- class Flowed extends Textual {
- private boolean delSp;
-
- public Flowed(Part part, boolean delSp) {
- super(part);
- this.delSp = delSp;
- }
-
- public boolean isDelSp() {
- return delSp;
- }
- }
-
/**
* Class representing a {@code text/html} part of a message.
*/
--
GitLab
From 108cdfb32764826ef6c0e9876818bc60ddb46ce1 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 22 Aug 2021 16:53:44 +0200
Subject: [PATCH 067/285] Rename .java to .kt
---
.../internet/{FormatFlowedHelper.java => FormatFlowedHelper.kt} | 0
.../{FormatFlowedHelperTest.java => FormatFlowedHelperTest.kt} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename mail/common/src/main/java/com/fsck/k9/mail/internet/{FormatFlowedHelper.java => FormatFlowedHelper.kt} (100%)
rename mail/common/src/test/java/com/fsck/k9/mail/internet/{FormatFlowedHelperTest.java => FormatFlowedHelperTest.kt} (100%)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
similarity index 100%
rename from mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.java
rename to mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
diff --git a/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.java b/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt
similarity index 100%
rename from mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.java
rename to mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt
--
GitLab
From c2ae85e2eccf926de1286a3cec8a644bcccdded1 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sun, 22 Aug 2021 16:53:44 +0200
Subject: [PATCH 068/285] Convert FormatFlowedHelper to Kotlin and change API
---
.../k9/mail/internet/FormatFlowedHelper.kt | 44 ++++++------
.../k9/mail/internet/MessageExtractor.java | 13 ++--
.../mail/internet/FormatFlowedHelperTest.kt | 67 ++++++++++++-------
3 files changed, 68 insertions(+), 56 deletions(-)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
index e978cb46e5..248600afb1 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
@@ -1,32 +1,30 @@
-package com.fsck.k9.mail.internet;
+package com.fsck.k9.mail.internet
+import java.util.Locale
-import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
-import static com.fsck.k9.mail.internet.MimeUtility.isSameMimeType;
+internal object FormatFlowedHelper {
+ private const val TEXT_PLAIN = "text/plain"
+ private const val HEADER_PARAM_FORMAT = "format"
+ private const val HEADER_FORMAT_FLOWED = "flowed"
+ private const val HEADER_PARAM_DELSP = "delsp"
+ private const val HEADER_DELSP_YES = "yes"
+ @JvmStatic
+ fun checkFormatFlowed(contentTypeHeaderValue: String?): FormatFlowedResult {
+ if (contentTypeHeaderValue == null) return negativeResult()
-class FormatFlowedHelper {
- private static final String TEXT_PLAIN = "text/plain";
- private static final String HEADER_PARAM_FORMAT = "format";
- private static final String HEADER_FORMAT_FLOWED = "flowed";
- private static final String HEADER_PARAM_DELSP = "delsp";
- private static final String HEADER_DELSP_YES = "yes";
+ val mimeValue = MimeParameterDecoder.decode(contentTypeHeaderValue)
+ if (!MimeUtility.isSameMimeType(TEXT_PLAIN, mimeValue.value)) return negativeResult()
+ val formatParameter = mimeValue.parameters[HEADER_PARAM_FORMAT]?.toLowerCase(Locale.ROOT)
+ if (formatParameter != HEADER_FORMAT_FLOWED) return negativeResult()
- static boolean isFormatFlowed(String contentType) {
- String mimeType = getHeaderParameter(contentType, null);
- if (isSameMimeType(TEXT_PLAIN, mimeType)) {
- String formatParameter = getHeaderParameter(contentType, HEADER_PARAM_FORMAT);
- return HEADER_FORMAT_FLOWED.equalsIgnoreCase(formatParameter);
- }
- return false;
- }
+ val delSpParameter = mimeValue.parameters[HEADER_PARAM_DELSP]?.toLowerCase(Locale.ROOT)
- static boolean isDelSp(String contentType) {
- if (isFormatFlowed(contentType)) {
- String delSpParameter = getHeaderParameter(contentType, HEADER_PARAM_DELSP);
- return HEADER_DELSP_YES.equalsIgnoreCase(delSpParameter);
- }
- return false;
+ return FormatFlowedResult(isFormatFlowed = true, isDelSp = delSpParameter == HEADER_DELSP_YES)
}
+
+ private fun negativeResult() = FormatFlowedResult(isFormatFlowed = false, isDelSp = false)
}
+
+internal data class FormatFlowedResult(val isFormatFlowed: Boolean, val isDelSp: Boolean)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
index 740a6fb145..e45aa18e34 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageExtractor.java
@@ -120,15 +120,12 @@ public class MessageExtractor {
} catch (IOException e) { /* Ignore */ }
}
- if (isSameMimeType(mimeType, "text/plain")) {
- String contentType = part.getContentType();
- if (FormatFlowedHelper.isFormatFlowed(contentType)) {
- boolean delSp = FormatFlowedHelper.isDelSp(contentType);
- return FlowedMessageUtils.deflow(text, delSp);
- }
+ FormatFlowedResult result = FormatFlowedHelper.checkFormatFlowed(part.getContentType());
+ if (result.isFormatFlowed()) {
+ return FlowedMessageUtils.deflow(text, result.isDelSp());
+ } else {
+ return text;
}
-
- return text;
}
public static boolean hasMissingParts(Part part) {
diff --git a/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt b/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt
index dbbd56a17b..089907033d 100644
--- a/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt
+++ b/mail/common/src/test/java/com/fsck/k9/mail/internet/FormatFlowedHelperTest.kt
@@ -1,47 +1,64 @@
-package com.fsck.k9.mail.internet;
+package com.fsck.k9.mail.internet
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
-import org.junit.Test;
-
-import static com.fsck.k9.mail.internet.FormatFlowedHelper.isDelSp;
-import static com.fsck.k9.mail.internet.FormatFlowedHelper.isFormatFlowed;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+class FormatFlowedHelperTest {
+ @Test
+ fun `plain text and format=flowed`() {
+ val contentTypeHeader = "text/plain; format=flowed"
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
-public class FormatFlowedHelperTest {
- @Test
- public void isFormatFlowed_withTextPlainFormatFlowed_shouldReturnTrue() throws Exception {
- assertTrue(isFormatFlowed("text/plain; format=flowed"));
+ assertThat(result.isFormatFlowed).isTrue()
+ assertThat(result.isDelSp).isFalse()
}
@Test
- public void isFormatFlowed_withTextPlain_shouldReturnFalse() throws Exception {
- assertFalse(isFormatFlowed("text/plain"));
- }
+ fun `plain text and format=flowed and delsp=yes`() {
+ val contentTypeHeader = "text/plain; format=flowed; delsp=yes"
- @Test
- public void isFormatFlowed_withTextHtmlFormatFlowed_shouldReturnFalse() throws Exception {
- assertFalse(isFormatFlowed("text/html; format=flowed"));
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
+
+ assertThat(result.isFormatFlowed).isTrue()
+ assertThat(result.isDelSp).isTrue()
}
@Test
- public void isDelSp_withFormatFlowed_shouldReturnTrue() throws Exception {
- assertTrue(isDelSp("text/plain; format=flowed; delsp=yes"));
+ fun `plain text without format=flowed`() {
+ val contentTypeHeader = "text/plain"
+
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
+
+ assertThat(result.isFormatFlowed).isFalse()
}
@Test
- public void isDelSp_withTextPlainFormatFlowed_shoulReturnFalse() throws Exception {
- assertFalse(isDelSp("text/plain; format=flowed"));
+ fun `plain text without format=flowed but delsp=yes`() {
+ val contentTypeHeader = "text/plain; delsp=yes"
+
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
+
+ assertThat(result.isFormatFlowed).isFalse()
+ assertThat(result.isDelSp).isFalse()
}
@Test
- public void isDelSp_withoutFormatFlowed_shouldReturnFalse() throws Exception {
- assertFalse(isDelSp("text/plain; delsp=yes"));
+ fun `HTML and format=flowed`() {
+ val contentTypeHeader = "text/html; format=flowed"
+
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
+
+ assertThat(result.isFormatFlowed).isFalse()
}
@Test
- public void idDelSp_withTextHtmlFormatFlowed_shouldReturnFalse() throws Exception {
- assertFalse(isDelSp("text/html; format=flowed; delsp=yes"));
+ fun `HTML and format=flowed and delsp=yes`() {
+ val contentTypeHeader = "text/html; format=flowed; delsp=yes"
+
+ val result = FormatFlowedHelper.checkFormatFlowed(contentTypeHeader)
+
+ assertThat(result.isFormatFlowed).isFalse()
+ assertThat(result.isDelSp).isFalse()
}
}
--
GitLab
From ed6cbe1c4b47380858930aae8a4ac6e7fc7bb900 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 24 Aug 2021 04:00:19 +0200
Subject: [PATCH 069/285] Rename .java to .kt
---
.../{AddNotificationResult.java => AddNotificationResult.kt} | 0
...rrorNotifications.java => AuthenticationErrorNotifications.kt} | 0
.../notification/{BaseNotifications.java => BaseNotifications.kt} | 0
...teErrorNotifications.java => CertificateErrorNotifications.kt} | 0
.../{DeviceNotifications.java => DeviceNotifications.kt} | 0
.../{LockScreenNotification.java => LockScreenNotification.kt} | 0
.../{NewMailNotifications.java => NewMailNotifications.kt} | 0
...otificationActionCreator.java => NotificationActionCreator.kt} | 0
...otificationActionService.java => NotificationActionService.kt} | 0
.../{NotificationContent.java => NotificationContent.kt} | 0
...ificationContentCreator.java => NotificationContentCreator.kt} | 0
.../{NotificationController.java => NotificationController.kt} | 0
.../notification/{NotificationData.java => NotificationData.kt} | 0
.../{NotificationGroupKeys.java => NotificationGroupKeys.kt} | 0
.../{NotificationHolder.java => NotificationHolder.kt} | 0
.../k9/notification/{NotificationIds.java => NotificationIds.kt} | 0
...{RemoveNotificationResult.java => RemoveNotificationResult.kt} | 0
.../{SendFailedNotifications.java => SendFailedNotifications.kt} | 0
.../notification/{SyncNotifications.java => SyncNotifications.kt} | 0
.../notification/{WearNotifications.java => WearNotifications.kt} | 0
...ificationActionCreator.java => K9NotificationActionCreator.kt} | 0
...ificationActionCreator.java => K9NotificationActionCreator.kt} | 0
22 files changed, 0 insertions(+), 0 deletions(-)
rename app/core/src/main/java/com/fsck/k9/notification/{AddNotificationResult.java => AddNotificationResult.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{AuthenticationErrorNotifications.java => AuthenticationErrorNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{BaseNotifications.java => BaseNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{CertificateErrorNotifications.java => CertificateErrorNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{DeviceNotifications.java => DeviceNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{LockScreenNotification.java => LockScreenNotification.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NewMailNotifications.java => NewMailNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationActionCreator.java => NotificationActionCreator.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationActionService.java => NotificationActionService.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationContent.java => NotificationContent.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationContentCreator.java => NotificationContentCreator.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationController.java => NotificationController.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationData.java => NotificationData.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationGroupKeys.java => NotificationGroupKeys.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationHolder.java => NotificationHolder.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{NotificationIds.java => NotificationIds.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{RemoveNotificationResult.java => RemoveNotificationResult.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{SendFailedNotifications.java => SendFailedNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{SyncNotifications.java => SyncNotifications.kt} (100%)
rename app/core/src/main/java/com/fsck/k9/notification/{WearNotifications.java => WearNotifications.kt} (100%)
rename app/k9mail-jmap/src/main/java/com/fsck/k9/notification/{K9NotificationActionCreator.java => K9NotificationActionCreator.kt} (100%)
rename app/k9mail/src/main/java/com/fsck/k9/notification/{K9NotificationActionCreator.java => K9NotificationActionCreator.kt} (100%)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.java b/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.java
rename to app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.java b/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.java
rename to app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationContent.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationController.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationController.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationData.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationData.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.java b/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/NotificationIds.java
rename to app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.java b/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.java
rename to app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt
diff --git a/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java b/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt
similarity index 100%
rename from app/core/src/main/java/com/fsck/k9/notification/WearNotifications.java
rename to app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt
diff --git a/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.java b/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
similarity index 100%
rename from app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.java
rename to app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
diff --git a/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.java b/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
similarity index 100%
rename from app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.java
rename to app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
--
GitLab
From 5bba53569925a5910d45c4d46857143213f38636 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 24 Aug 2021 04:00:19 +0200
Subject: [PATCH 070/285] Convert notification classes to Kotlin
---
.../k9/notification/AddNotificationResult.kt | 54 +--
.../AuthenticationErrorNotifications.kt | 113 +++--
.../fsck/k9/notification/BaseNotifications.kt | 121 +++---
.../CertificateErrorNotifications.kt | 114 +++--
.../k9/notification/DeviceNotifications.kt | 360 ++++++++--------
.../k9/notification/LockScreenNotification.kt | 149 +++----
.../k9/notification/NewMailNotifications.kt | 207 ++++------
.../notification/NotificationActionCreator.kt | 74 ++--
.../notification/NotificationActionService.kt | 389 +++++++++---------
.../k9/notification/NotificationContent.kt | 37 +-
.../NotificationContentCreator.kt | 172 ++++----
.../k9/notification/NotificationController.kt | 97 ++---
.../fsck/k9/notification/NotificationData.kt | 269 +++++-------
.../k9/notification/NotificationGroupKeys.kt | 16 +-
.../k9/notification/NotificationHolder.kt | 17 +-
.../fsck/k9/notification/NotificationIds.kt | 91 ++--
.../notification/RemoveNotificationResult.kt | 85 ++--
.../notification/SendFailedNotifications.kt | 108 +++--
.../fsck/k9/notification/SyncNotifications.kt | 178 ++++----
.../fsck/k9/notification/WearNotifications.kt | 329 +++++++--------
.../AddNotificationResultTest.java | 6 +-
.../AuthenticationErrorNotificationsTest.java | 2 +-
.../notification/BaseNotificationsTest.java | 4 +-
.../CertificateErrorNotificationsTest.java | 2 +-
.../notification/DeviceNotificationsTest.java | 8 +-
.../LockScreenNotificationTest.java | 4 +-
.../NewMailNotificationsTest.java | 5 +-
.../NotificationContentCreatorTest.java | 48 +--
.../k9/notification/NotificationDataTest.java | 18 +-
.../RemoveNotificationResultTest.java | 6 +-
.../notification/WearNotificationsTest.java | 4 +-
.../K9NotificationActionCreator.kt | 355 ++++++++--------
.../com/fsck/k9/notification/KoinModule.kt | 2 +-
.../K9NotificationActionCreator.kt | 355 ++++++++--------
.../com/fsck/k9/notification/KoinModule.kt | 2 +-
.../DeleteConfirmationActivity.kt | 2 -
36 files changed, 1771 insertions(+), 2032 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt b/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt
index 9dd3257fa1..487aa89166 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/AddNotificationResult.kt
@@ -1,39 +1,25 @@
-package com.fsck.k9.notification;
-
-
-class AddNotificationResult {
- private final NotificationHolder notificationHolder;
- private final boolean cancelNotificationBeforeReuse;
-
-
- private AddNotificationResult(NotificationHolder notificationHolder,
- boolean cancelNotificationBeforeReuse) {
- this.notificationHolder = notificationHolder;
- this.cancelNotificationBeforeReuse = cancelNotificationBeforeReuse;
- }
-
- public static AddNotificationResult newNotification(NotificationHolder notificationHolder) {
- return new AddNotificationResult(notificationHolder, false);
- }
-
- public static AddNotificationResult replaceNotification(NotificationHolder notificationHolder) {
- return new AddNotificationResult(notificationHolder, true);
- }
-
- public boolean shouldCancelNotification() {
- return cancelNotificationBeforeReuse;
- }
-
- public int getNotificationId() {
- if (!shouldCancelNotification()) {
- throw new IllegalStateException("getNotificationId() can only be called when " +
- "shouldCancelNotification() returns true");
+package com.fsck.k9.notification
+
+internal class AddNotificationResult private constructor(
+ val notificationHolder: NotificationHolder,
+ @get:JvmName("shouldCancelNotification")
+ val shouldCancelNotification: Boolean
+) {
+ val notificationId: Int
+ get() {
+ check(shouldCancelNotification) { "shouldCancelNotification == false" }
+ return notificationHolder.notificationId
}
- return notificationHolder.notificationId;
- }
+ companion object {
+ @JvmStatic
+ fun newNotification(notificationHolder: NotificationHolder): AddNotificationResult {
+ return AddNotificationResult(notificationHolder, shouldCancelNotification = false)
+ }
- public NotificationHolder getNotificationHolder() {
- return notificationHolder;
+ @JvmStatic
+ fun replaceNotification(notificationHolder: NotificationHolder): AddNotificationResult {
+ return AddNotificationResult(notificationHolder, shouldCancelNotification = true)
+ }
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt
index 302199d4da..add2319c5b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/AuthenticationErrorNotifications.kt
@@ -1,68 +1,59 @@
-package com.fsck.k9.notification;
-
-
-import android.app.PendingIntent;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.BigTextStyle;
-import androidx.core.app.NotificationManagerCompat;
-
-import com.fsck.k9.Account;
-
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_BLINK_FAST;
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR;
-
-
-class AuthenticationErrorNotifications {
- private final NotificationHelper notificationHelper;
- private final NotificationActionCreator actionCreator;
- private final NotificationResourceProvider resourceProvider;
-
-
- public AuthenticationErrorNotifications(NotificationHelper notificationHelper,
- NotificationActionCreator actionCreator, NotificationResourceProvider resourceProvider) {
- this.notificationHelper = notificationHelper;
- this.actionCreator = actionCreator;
- this.resourceProvider = resourceProvider;
+package com.fsck.k9.notification
+
+import android.app.PendingIntent
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.fsck.k9.Account
+
+internal open class AuthenticationErrorNotifications(
+ private val notificationHelper: NotificationHelper,
+ private val actionCreator: NotificationActionCreator,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun showAuthenticationErrorNotification(account: Account, incoming: Boolean) {
+ val notificationId = NotificationIds.getAuthenticationErrorNotificationId(account, incoming)
+ val editServerSettingsPendingIntent = createContentIntent(account, incoming)
+ val title = resourceProvider.authenticationErrorTitle()
+ val text = resourceProvider.authenticationErrorBody(account.description)
+
+ val notificationBuilder = notificationHelper
+ .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
+ .setSmallIcon(resourceProvider.iconWarning)
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(editServerSettingsPendingIntent)
+ .setStyle(NotificationCompat.BigTextStyle().bigText(text))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_ERROR)
+
+ notificationHelper.configureNotification(
+ builder = notificationBuilder,
+ ringtone = null,
+ vibrationPattern = null,
+ ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
+ ringAndVibrate = true
+ )
+
+ notificationManager.notify(notificationId, notificationBuilder.build())
}
- public void showAuthenticationErrorNotification(Account account, boolean incoming) {
- int notificationId = NotificationIds.getAuthenticationErrorNotificationId(account, incoming);
-
- PendingIntent editServerSettingsPendingIntent = createContentIntent(account, incoming);
- String title = resourceProvider.authenticationErrorTitle();
- String text = resourceProvider.authenticationErrorBody(account.getDescription());
-
- NotificationCompat.Builder builder = notificationHelper
- .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
- .setSmallIcon(resourceProvider.getIconWarning())
- .setWhen(System.currentTimeMillis())
- .setAutoCancel(true)
- .setTicker(title)
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(editServerSettingsPendingIntent)
- .setStyle(new BigTextStyle().bigText(text))
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCategory(NotificationCompat.CATEGORY_ERROR);
-
- notificationHelper.configureNotification(builder, null, null,
- NOTIFICATION_LED_FAILURE_COLOR,
- NOTIFICATION_LED_BLINK_FAST, true);
-
- getNotificationManager().notify(notificationId, builder.build());
+ fun clearAuthenticationErrorNotification(account: Account, incoming: Boolean) {
+ val notificationId = NotificationIds.getAuthenticationErrorNotificationId(account, incoming)
+ notificationManager.cancel(notificationId)
}
- public void clearAuthenticationErrorNotification(Account account, boolean incoming) {
- int notificationId = NotificationIds.getAuthenticationErrorNotificationId(account, incoming);
- getNotificationManager().cancel(notificationId);
+ protected open fun createContentIntent(account: Account, incoming: Boolean): PendingIntent {
+ return if (incoming) {
+ actionCreator.getEditIncomingServerSettingsIntent(account)
+ } else {
+ actionCreator.getEditOutgoingServerSettingsIntent(account)
+ }
}
- PendingIntent createContentIntent(Account account, boolean incoming) {
- return incoming ? actionCreator.getEditIncomingServerSettingsIntent(account) :
- actionCreator.getEditOutgoingServerSettingsIntent(account);
- }
-
- private NotificationManagerCompat getNotificationManager() {
- return notificationHelper.getNotificationManager();
- }
+ private val notificationManager: NotificationManagerCompat
+ get() = notificationHelper.getNotificationManager()
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt
index 5534372de0..01c09b185b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/BaseNotifications.kt
@@ -1,77 +1,60 @@
-package com.fsck.k9.notification;
-
-
-import android.app.PendingIntent;
-import android.content.Context;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.BigTextStyle;
-import androidx.core.app.NotificationCompat.Builder;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.K9.NotificationQuickDelete;
-
-
-abstract class BaseNotifications {
- protected final Context context;
- protected final NotificationHelper notificationHelper;
- protected final NotificationActionCreator actionCreator;
- protected final NotificationResourceProvider resourceProvider;
-
-
- protected BaseNotifications(NotificationHelper notificationHelper, NotificationActionCreator actionCreator,
- NotificationResourceProvider resourceProvider) {
- this.context = notificationHelper.getContext();
- this.notificationHelper = notificationHelper;
- this.actionCreator = actionCreator;
- this.resourceProvider = resourceProvider;
- }
-
- protected NotificationCompat.Builder createBigTextStyleNotification(Account account, NotificationHolder holder,
- int notificationId) {
- String accountName = notificationHelper.getAccountName(account);
- NotificationContent content = holder.content;
- String groupKey = NotificationGroupKeys.getGroupKey(account);
-
- NotificationCompat.Builder builder = createAndInitializeNotificationBuilder(account)
- .setTicker(content.summary)
- .setGroup(groupKey)
- .setContentTitle(content.sender)
- .setContentText(content.subject)
- .setSubText(accountName);
-
- NotificationCompat.BigTextStyle style = createBigTextStyle(builder);
- style.bigText(content.preview);
-
- builder.setStyle(style);
-
- PendingIntent contentIntent = actionCreator.createViewMessagePendingIntent(
- content.messageReference, notificationId);
- builder.setContentIntent(contentIntent);
-
- return builder;
- }
-
- protected NotificationCompat.Builder createAndInitializeNotificationBuilder(Account account) {
- return notificationHelper.createNotificationBuilder(account,
- NotificationChannelManager.ChannelType.MESSAGES)
- .setSmallIcon(getNewMailNotificationIcon())
- .setColor(account.getChipColor())
- .setWhen(System.currentTimeMillis())
- .setAutoCancel(true)
- .setCategory(NotificationCompat.CATEGORY_EMAIL);
+package com.fsck.k9.notification
+
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.K9.NotificationQuickDelete
+
+internal abstract class BaseNotifications(
+ protected val notificationHelper: NotificationHelper,
+ protected val actionCreator: NotificationActionCreator,
+ protected val resourceProvider: NotificationResourceProvider
+) {
+ protected val context: Context = notificationHelper.getContext()
+
+ fun createBigTextStyleNotification(
+ account: Account,
+ holder: NotificationHolder,
+ notificationId: Int
+ ): NotificationCompat.Builder {
+ val accountName = notificationHelper.getAccountName(account)
+ val content = holder.content
+ val groupKey = NotificationGroupKeys.getGroupKey(account)
+
+ val builder = createAndInitializeNotificationBuilder(account)
+ .setTicker(content.summary)
+ .setGroup(groupKey)
+ .setContentTitle(content.sender)
+ .setContentText(content.subject)
+ .setSubText(accountName)
+
+ val style = createBigTextStyle(builder)
+ style.bigText(content.preview)
+ builder.setStyle(style)
+
+ val contentIntent = actionCreator.createViewMessagePendingIntent(content.messageReference, notificationId)
+ builder.setContentIntent(contentIntent)
+
+ return builder
}
- protected boolean isDeleteActionEnabled() {
- NotificationQuickDelete deleteOption = K9.getNotificationQuickDeleteBehaviour();
- return deleteOption == NotificationQuickDelete.ALWAYS || deleteOption == NotificationQuickDelete.FOR_SINGLE_MSG;
+ fun createAndInitializeNotificationBuilder(account: Account): NotificationCompat.Builder {
+ return notificationHelper.createNotificationBuilder(account, NotificationChannelManager.ChannelType.MESSAGES)
+ .setSmallIcon(resourceProvider.iconNewMail)
+ .setColor(account.chipColor)
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setCategory(NotificationCompat.CATEGORY_EMAIL)
}
- protected BigTextStyle createBigTextStyle(Builder builder) {
- return new BigTextStyle(builder);
+ fun isDeleteActionEnabled(): Boolean {
+ val deleteOption = K9.notificationQuickDeleteBehaviour
+ return deleteOption === NotificationQuickDelete.ALWAYS ||
+ deleteOption === NotificationQuickDelete.FOR_SINGLE_MSG
}
- private int getNewMailNotificationIcon() {
- return resourceProvider.getIconNewMail();
+ protected open fun createBigTextStyle(builder: NotificationCompat.Builder?): NotificationCompat.BigTextStyle {
+ return NotificationCompat.BigTextStyle(builder)
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt
index a5239b1634..36d99a872f 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/CertificateErrorNotifications.kt
@@ -1,69 +1,59 @@
-package com.fsck.k9.notification;
-
-
-import android.app.PendingIntent;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.BigTextStyle;
-import androidx.core.app.NotificationManagerCompat;
-
-import com.fsck.k9.Account;
-
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_BLINK_FAST;
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR;
-
-
-class CertificateErrorNotifications {
- private final NotificationHelper notificationHelper;
- private final NotificationActionCreator actionCreator;
- private final NotificationResourceProvider resourceProvider;
-
-
- public CertificateErrorNotifications(NotificationHelper notificationHelper,
- NotificationActionCreator actionCreator, NotificationResourceProvider resourceProvider) {
- this.notificationHelper = notificationHelper;
- this.actionCreator = actionCreator;
- this.resourceProvider = resourceProvider;
+package com.fsck.k9.notification
+
+import android.app.PendingIntent
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.fsck.k9.Account
+
+internal open class CertificateErrorNotifications(
+ private val notificationHelper: NotificationHelper,
+ private val actionCreator: NotificationActionCreator,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun showCertificateErrorNotification(account: Account, incoming: Boolean) {
+ val notificationId = NotificationIds.getCertificateErrorNotificationId(account, incoming)
+ val editServerSettingsPendingIntent = createContentIntent(account, incoming)
+ val title = resourceProvider.certificateErrorTitle(account.description)
+ val text = resourceProvider.certificateErrorBody()
+
+ val notificationBuilder = notificationHelper
+ .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
+ .setSmallIcon(resourceProvider.iconWarning)
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(editServerSettingsPendingIntent)
+ .setStyle(NotificationCompat.BigTextStyle().bigText(text))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_ERROR)
+
+ notificationHelper.configureNotification(
+ builder = notificationBuilder,
+ ringtone = null,
+ vibrationPattern = null,
+ ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
+ ringAndVibrate = true
+ )
+
+ notificationManager.notify(notificationId, notificationBuilder.build())
}
- public void showCertificateErrorNotification(Account account, boolean incoming) {
- int notificationId = NotificationIds.getCertificateErrorNotificationId(account, incoming);
-
- PendingIntent editServerSettingsPendingIntent = createContentIntent(account, incoming);
- String title = resourceProvider.certificateErrorTitle(account.getDescription());
- String text = resourceProvider.certificateErrorBody();
-
- NotificationCompat.Builder builder = notificationHelper
- .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
- .setSmallIcon(resourceProvider.getIconWarning())
- .setWhen(System.currentTimeMillis())
- .setAutoCancel(true)
- .setTicker(title)
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(editServerSettingsPendingIntent)
- .setStyle(new BigTextStyle().bigText(text))
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCategory(NotificationCompat.CATEGORY_ERROR);
-
- notificationHelper.configureNotification(builder, null, null,
- NOTIFICATION_LED_FAILURE_COLOR,
- NOTIFICATION_LED_BLINK_FAST, true);
-
- getNotificationManager().notify(notificationId, builder.build());
+ fun clearCertificateErrorNotifications(account: Account, incoming: Boolean) {
+ val notificationId = NotificationIds.getCertificateErrorNotificationId(account, incoming)
+ notificationManager.cancel(notificationId)
}
- public void clearCertificateErrorNotifications(Account account, boolean incoming) {
- int notificationId = NotificationIds.getCertificateErrorNotificationId(account, incoming);
- getNotificationManager().cancel(notificationId);
+ protected open fun createContentIntent(account: Account, incoming: Boolean): PendingIntent {
+ return if (incoming) {
+ actionCreator.getEditIncomingServerSettingsIntent(account)
+ } else {
+ actionCreator.getEditOutgoingServerSettingsIntent(account)
+ }
}
- PendingIntent createContentIntent(Account account, boolean incoming) {
- return incoming ?
- actionCreator.getEditIncomingServerSettingsIntent(account) :
- actionCreator.getEditOutgoingServerSettingsIntent(account);
- }
-
- private NotificationManagerCompat getNotificationManager() {
- return notificationHelper.getNotificationManager();
- }
+ private val notificationManager: NotificationManagerCompat
+ get() = notificationHelper.getNotificationManager()
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt
index d9b7af54b0..aa838143a1 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/DeviceNotifications.kt
@@ -1,235 +1,221 @@
-package com.fsck.k9.notification;
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.Builder;
-import androidx.core.app.NotificationCompat.InboxStyle;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.K9.NotificationHideSubject;
-import com.fsck.k9.K9.NotificationQuickDelete;
-import com.fsck.k9.NotificationSetting;
-import com.fsck.k9.controller.MessageReference;
-
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_BLINK_SLOW;
-
-
-class DeviceNotifications extends BaseNotifications {
- private final WearNotifications wearNotifications;
- private final LockScreenNotification lockScreenNotification;
-
-
- DeviceNotifications(NotificationHelper notificationHelper, NotificationActionCreator actionCreator,
- LockScreenNotification lockScreenNotification, WearNotifications wearNotifications,
- NotificationResourceProvider resourceProvider) {
- super(notificationHelper, actionCreator, resourceProvider);
- this.wearNotifications = wearNotifications;
- this.lockScreenNotification = lockScreenNotification;
- }
-
- public Notification buildSummaryNotification(Account account, NotificationData notificationData,
- boolean silent) {
- int unreadMessageCount = notificationData.getUnreadMessageCount();
-
- NotificationCompat.Builder builder;
- if (isPrivacyModeActive()) {
- builder = createSimpleSummaryNotification(account, unreadMessageCount);
- } else if (notificationData.isSingleMessageNotification()) {
- NotificationHolder holder = notificationData.getHolderForLatestNotification();
- builder = createBigTextStyleSummaryNotification(account, holder);
- } else {
- builder = createInboxStyleSummaryNotification(account, notificationData, unreadMessageCount);
+package com.fsck.k9.notification
+
+import android.app.KeyguardManager
+import android.app.Notification
+import android.content.Context
+import androidx.core.app.NotificationCompat
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.K9.NotificationHideSubject
+import com.fsck.k9.K9.NotificationQuickDelete
+import com.fsck.k9.notification.NotificationGroupKeys.getGroupKey
+import com.fsck.k9.notification.NotificationIds.getNewMailSummaryNotificationId
+
+internal open class DeviceNotifications(
+ notificationHelper: NotificationHelper,
+ actionCreator: NotificationActionCreator,
+ private val lockScreenNotification: LockScreenNotification,
+ private val wearNotifications: WearNotifications,
+ resourceProvider: NotificationResourceProvider
+) : BaseNotifications(notificationHelper, actionCreator, resourceProvider) {
+
+ fun buildSummaryNotification(account: Account, notificationData: NotificationData, silent: Boolean): Notification {
+ val unreadMessageCount = notificationData.unreadMessageCount
+
+ val builder = when {
+ isPrivacyModeActive -> {
+ createSimpleSummaryNotification(account, unreadMessageCount)
+ }
+ notificationData.isSingleMessageNotification -> {
+ val holder = notificationData.holderForLatestNotification
+ createBigTextStyleSummaryNotification(account, holder)
+ }
+ else -> {
+ createInboxStyleSummaryNotification(account, notificationData, unreadMessageCount)
+ }
}
if (notificationData.containsStarredMessages()) {
- builder.setPriority(NotificationCompat.PRIORITY_HIGH);
+ builder.priority = NotificationCompat.PRIORITY_HIGH
}
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent deletePendingIntent = actionCreator.createDismissAllMessagesPendingIntent(
- account, notificationId);
- builder.setDeleteIntent(deletePendingIntent);
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val deletePendingIntent = actionCreator.createDismissAllMessagesPendingIntent(account, notificationId)
+ builder.setDeleteIntent(deletePendingIntent)
- lockScreenNotification.configureLockScreenNotification(builder, notificationData);
+ lockScreenNotification.configureLockScreenNotification(builder, notificationData)
- boolean ringAndVibrate = false;
- if (!silent && !account.isRingNotified()) {
- account.setRingNotified(true);
- ringAndVibrate = true;
+ var ringAndVibrate = false
+ if (!silent && !account.isRingNotified) {
+ account.isRingNotified = true
+ ringAndVibrate = true
}
- NotificationSetting notificationSetting = account.getNotificationSetting();
+ val notificationSetting = account.notificationSetting
notificationHelper.configureNotification(
- builder,
- (notificationSetting.isRingEnabled()) ? notificationSetting.getRingtone() : null,
- (notificationSetting.isVibrateEnabled()) ? notificationSetting.getVibration() : null,
- (notificationSetting.isLedEnabled()) ? notificationSetting.getLedColor() : null,
- NOTIFICATION_LED_BLINK_SLOW,
- ringAndVibrate);
-
- return builder.build();
+ builder = builder,
+ ringtone = if (notificationSetting.isRingEnabled) notificationSetting.ringtone else null,
+ vibrationPattern = if (notificationSetting.isVibrateEnabled) notificationSetting.vibration else null,
+ ledColor = if (notificationSetting.isLedEnabled) notificationSetting.ledColor else null,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_SLOW,
+ ringAndVibrate = ringAndVibrate
+ )
+
+ return builder.build()
}
- private NotificationCompat.Builder createSimpleSummaryNotification(Account account, int unreadMessageCount) {
- String accountName = notificationHelper.getAccountName(account);
- CharSequence newMailText = resourceProvider.newMailTitle();
- String unreadMessageCountText = resourceProvider.newMailUnreadMessageCount(unreadMessageCount, accountName);
-
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent contentIntent = actionCreator.createViewFolderListPendingIntent(account, notificationId);
+ private fun createSimpleSummaryNotification(account: Account, unreadMessageCount: Int): NotificationCompat.Builder {
+ val accountName = notificationHelper.getAccountName(account)
+ val newMailText = resourceProvider.newMailTitle()
+ val unreadMessageCountText = resourceProvider.newMailUnreadMessageCount(unreadMessageCount, accountName)
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val contentIntent = actionCreator.createViewFolderListPendingIntent(account, notificationId)
return createAndInitializeNotificationBuilder(account)
- .setNumber(unreadMessageCount)
- .setTicker(newMailText)
- .setContentTitle(unreadMessageCountText)
- .setContentText(newMailText)
- .setContentIntent(contentIntent);
+ .setNumber(unreadMessageCount)
+ .setTicker(newMailText)
+ .setContentTitle(unreadMessageCountText)
+ .setContentText(newMailText)
+ .setContentIntent(contentIntent)
}
- private NotificationCompat.Builder createBigTextStyleSummaryNotification(Account account,
- NotificationHolder holder) {
-
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- Builder builder = createBigTextStyleNotification(account, holder, notificationId)
- .setGroupSummary(true);
+ private fun createBigTextStyleSummaryNotification(
+ account: Account,
+ holder: NotificationHolder
+ ): NotificationCompat.Builder {
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val builder = createBigTextStyleNotification(account, holder, notificationId)
+ builder.setGroupSummary(true)
- NotificationContent content = holder.content;
- addReplyAction(builder, content, notificationId);
- addMarkAsReadAction(builder, content, notificationId);
- addDeleteAction(builder, content, notificationId);
+ val content = holder.content
+ addReplyAction(builder, content, notificationId)
+ addMarkAsReadAction(builder, content, notificationId)
+ addDeleteAction(builder, content, notificationId)
- return builder;
+ return builder
}
- private NotificationCompat.Builder createInboxStyleSummaryNotification(Account account,
- NotificationData notificationData, int unreadMessageCount) {
-
- NotificationHolder latestNotification = notificationData.getHolderForLatestNotification();
-
- int newMessagesCount = notificationData.getNewMessagesCount();
- String accountName = notificationHelper.getAccountName(account);
- String title = resourceProvider.newMessagesTitle(newMessagesCount);
- String summary = (notificationData.hasSummaryOverflowMessages()) ?
- resourceProvider.additionalMessages(notificationData.getSummaryOverflowMessagesCount(), accountName) :
- accountName;
- String groupKey = NotificationGroupKeys.getGroupKey(account);
-
- NotificationCompat.Builder builder = createAndInitializeNotificationBuilder(account)
- .setNumber(unreadMessageCount)
- .setTicker(latestNotification.content.summary)
- .setGroup(groupKey)
- .setGroupSummary(true)
- .setContentTitle(title)
- .setSubText(accountName);
-
- NotificationCompat.InboxStyle style = createInboxStyle(builder)
- .setBigContentTitle(title)
- .setSummaryText(summary);
-
- for (NotificationContent content : notificationData.getContentForSummaryNotification()) {
- style.addLine(content.summary);
+ private fun createInboxStyleSummaryNotification(
+ account: Account,
+ notificationData: NotificationData,
+ unreadMessageCount: Int
+ ): NotificationCompat.Builder {
+ val latestNotification = notificationData.holderForLatestNotification
+ val newMessagesCount = notificationData.newMessagesCount
+ val accountName = notificationHelper.getAccountName(account)
+ val title = resourceProvider.newMessagesTitle(newMessagesCount)
+ val summary = if (notificationData.hasSummaryOverflowMessages()) {
+ resourceProvider.additionalMessages(notificationData.getSummaryOverflowMessagesCount(), accountName)
+ } else {
+ accountName
}
+ val groupKey = getGroupKey(account)
+
+ val builder = createAndInitializeNotificationBuilder(account)
+ .setNumber(unreadMessageCount)
+ .setTicker(latestNotification.content.summary)
+ .setGroup(groupKey)
+ .setGroupSummary(true)
+ .setContentTitle(title)
+ .setSubText(accountName)
+
+ val style = createInboxStyle(builder)
+ .setBigContentTitle(title)
+ .setSummaryText(summary)
+
+ for (content in notificationData.getContentForSummaryNotification()) {
+ style.addLine(content.summary)
+ }
+ builder.setStyle(style)
- builder.setStyle(style);
-
- addMarkAllAsReadAction(builder, notificationData);
- addDeleteAllAction(builder, notificationData);
-
- wearNotifications.addSummaryActions(builder, notificationData);
+ addMarkAllAsReadAction(builder, notificationData)
+ addDeleteAllAction(builder, notificationData)
+ wearNotifications.addSummaryActions(builder, notificationData)
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- List messageReferences = notificationData.getAllMessageReferences();
- PendingIntent contentIntent = actionCreator.createViewMessagesPendingIntent(
- account, messageReferences, notificationId);
- builder.setContentIntent(contentIntent);
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val messageReferences = notificationData.getAllMessageReferences()
+ val contentIntent = actionCreator.createViewMessagesPendingIntent(account, messageReferences, notificationId)
+ builder.setContentIntent(contentIntent)
- return builder;
+ return builder
}
- private void addMarkAsReadAction(Builder builder, NotificationContent content, int notificationId) {
- int icon = resourceProvider.getIconMarkAsRead();
- String title = resourceProvider.actionMarkAsRead();
-
-
- MessageReference messageReference = content.messageReference;
- PendingIntent action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId);
-
- builder.addAction(icon, title, action);
+ private fun addMarkAsReadAction(
+ builder: NotificationCompat.Builder,
+ content: NotificationContent,
+ notificationId: Int
+ ) {
+ val icon = resourceProvider.iconMarkAsRead
+ val title = resourceProvider.actionMarkAsRead()
+ val messageReference = content.messageReference
+ val action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId)
+
+ builder.addAction(icon, title, action)
}
- private void addMarkAllAsReadAction(Builder builder, NotificationData notificationData) {
- int icon = resourceProvider.getIconMarkAsRead();
- String title = resourceProvider.actionMarkAsRead();
-
- Account account = notificationData.getAccount();
- ArrayList messageReferences = notificationData.getAllMessageReferences();
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent markAllAsReadPendingIntent =
- actionCreator.createMarkAllAsReadPendingIntent(account, messageReferences, notificationId);
+ private fun addMarkAllAsReadAction(builder: NotificationCompat.Builder, notificationData: NotificationData) {
+ val icon = resourceProvider.iconMarkAsRead
+ val title = resourceProvider.actionMarkAsRead()
+ val account = notificationData.account
+ val messageReferences = notificationData.getAllMessageReferences()
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val markAllAsReadPendingIntent =
+ actionCreator.createMarkAllAsReadPendingIntent(account, messageReferences, notificationId)
- builder.addAction(icon, title, markAllAsReadPendingIntent);
+ builder.addAction(icon, title, markAllAsReadPendingIntent)
}
- private void addDeleteAllAction(Builder builder, NotificationData notificationData) {
- if (K9.getNotificationQuickDeleteBehaviour() != NotificationQuickDelete.ALWAYS) {
- return;
+ private fun addDeleteAllAction(builder: NotificationCompat.Builder, notificationData: NotificationData) {
+ if (K9.notificationQuickDeleteBehaviour !== NotificationQuickDelete.ALWAYS) {
+ return
}
- int icon = resourceProvider.getIconDelete();
- String title = resourceProvider.actionDelete();
+ val icon = resourceProvider.iconDelete
+ val title = resourceProvider.actionDelete()
+ val account = notificationData.account
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val messageReferences = notificationData.getAllMessageReferences()
+ val action = actionCreator.createDeleteAllPendingIntent(account, messageReferences, notificationId)
- Account account = notificationData.getAccount();
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- ArrayList messageReferences = notificationData.getAllMessageReferences();
- PendingIntent action = actionCreator.createDeleteAllPendingIntent(account, messageReferences, notificationId);
-
- builder.addAction(icon, title, action);
+ builder.addAction(icon, title, action)
}
- private void addDeleteAction(Builder builder, NotificationContent content, int notificationId) {
+ private fun addDeleteAction(
+ builder: NotificationCompat.Builder,
+ content: NotificationContent,
+ notificationId: Int
+ ) {
if (!isDeleteActionEnabled()) {
- return;
+ return
}
- int icon = resourceProvider.getIconDelete();
- String title = resourceProvider.actionDelete();
-
- MessageReference messageReference = content.messageReference;
- PendingIntent action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId);
+ val icon = resourceProvider.iconDelete
+ val title = resourceProvider.actionDelete()
+ val messageReference = content.messageReference
+ val action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId)
- builder.addAction(icon, title, action);
+ builder.addAction(icon, title, action)
}
- private void addReplyAction(Builder builder, NotificationContent content, int notificationId) {
- int icon = resourceProvider.getIconReply();
- String title = resourceProvider.actionReply();
+ private fun addReplyAction(builder: NotificationCompat.Builder, content: NotificationContent, notificationId: Int) {
+ val icon = resourceProvider.iconReply
+ val title = resourceProvider.actionReply()
+ val messageReference = content.messageReference
+ val replyToMessagePendingIntent = actionCreator.createReplyPendingIntent(messageReference, notificationId)
- MessageReference messageReference = content.messageReference;
- PendingIntent replyToMessagePendingIntent =
- actionCreator.createReplyPendingIntent(messageReference, notificationId);
-
- builder.addAction(icon, title, replyToMessagePendingIntent);
+ builder.addAction(icon, title, replyToMessagePendingIntent)
}
- private boolean isPrivacyModeActive() {
- KeyguardManager keyguardService = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
-
- boolean privacyModeAlwaysEnabled = K9.getNotificationHideSubject() == NotificationHideSubject.ALWAYS;
- boolean privacyModeEnabledWhenLocked = K9.getNotificationHideSubject() == NotificationHideSubject.WHEN_LOCKED;
- boolean screenLocked = keyguardService.inKeyguardRestrictedInputMode();
-
- return privacyModeAlwaysEnabled || (privacyModeEnabledWhenLocked && screenLocked);
- }
+ private val isPrivacyModeActive: Boolean
+ get() {
+ val keyguardService = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ val privacyModeAlwaysEnabled = K9.notificationHideSubject === NotificationHideSubject.ALWAYS
+ val privacyModeEnabledWhenLocked = K9.notificationHideSubject === NotificationHideSubject.WHEN_LOCKED
+ val screenLocked = keyguardService.inKeyguardRestrictedInputMode()
+ return privacyModeAlwaysEnabled || privacyModeEnabledWhenLocked && screenLocked
+ }
- protected InboxStyle createInboxStyle(Builder builder) {
- return new InboxStyle(builder);
+ protected open fun createInboxStyle(builder: NotificationCompat.Builder?): NotificationCompat.InboxStyle {
+ return NotificationCompat.InboxStyle(builder)
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt b/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt
index 3884f32762..0609a312e1 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/LockScreenNotification.kt
@@ -1,109 +1,84 @@
-package com.fsck.k9.notification;
-
-
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import android.app.Notification;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.Builder;
-import android.text.TextUtils;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-
-
-class LockScreenNotification {
- static final int MAX_NUMBER_OF_SENDERS_IN_LOCK_SCREEN_NOTIFICATION = 5;
-
-
- private final NotificationHelper notificationHelper;
- private final NotificationResourceProvider resourceProvider;
-
-
- LockScreenNotification(NotificationHelper notificationHelper, NotificationResourceProvider resourceProvider) {
- this.notificationHelper = notificationHelper;
- this.resourceProvider = resourceProvider;
- }
-
- public void configureLockScreenNotification(Builder builder, NotificationData notificationData) {
- switch (K9.getLockScreenNotificationVisibility()) {
- case NOTHING: {
- builder.setVisibility(NotificationCompat.VISIBILITY_SECRET);
- break;
+package com.fsck.k9.notification
+
+import android.app.Notification
+import androidx.core.app.NotificationCompat
+import com.fsck.k9.K9
+import com.fsck.k9.K9.LockScreenNotificationVisibility
+
+internal class LockScreenNotification(
+ private val notificationHelper: NotificationHelper,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun configureLockScreenNotification(builder: NotificationCompat.Builder, notificationData: NotificationData) {
+ when (K9.lockScreenNotificationVisibility) {
+ LockScreenNotificationVisibility.NOTHING -> {
+ builder.setVisibility(NotificationCompat.VISIBILITY_SECRET)
}
- case APP_NAME: {
- builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE);
- break;
+ LockScreenNotificationVisibility.APP_NAME -> {
+ builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
}
- case EVERYTHING: {
- builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
- break;
+ LockScreenNotificationVisibility.EVERYTHING -> {
+ builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
}
- case SENDERS: {
- Notification publicNotification = createPublicNotificationWithSenderList(notificationData);
- builder.setPublicVersion(publicNotification);
- break;
+ LockScreenNotificationVisibility.SENDERS -> {
+ val publicNotification = createPublicNotificationWithSenderList(notificationData)
+ builder.setPublicVersion(publicNotification)
}
- case MESSAGE_COUNT: {
- Notification publicNotification = createPublicNotificationWithNewMessagesCount(notificationData);
- builder.setPublicVersion(publicNotification);
- break;
+ LockScreenNotificationVisibility.MESSAGE_COUNT -> {
+ val publicNotification = createPublicNotificationWithNewMessagesCount(notificationData)
+ builder.setPublicVersion(publicNotification)
}
}
}
- private Notification createPublicNotificationWithSenderList(NotificationData notificationData) {
- Builder builder = createPublicNotification(notificationData);
- int newMessages = notificationData.getNewMessagesCount();
+ private fun createPublicNotificationWithSenderList(notificationData: NotificationData): Notification {
+ val builder = createPublicNotification(notificationData)
+
+ val newMessages = notificationData.newMessagesCount
if (newMessages == 1) {
- NotificationHolder holder = notificationData.getHolderForLatestNotification();
- builder.setContentText(holder.content.sender);
+ val holder = notificationData.holderForLatestNotification
+ builder.setContentText(holder.content.sender)
} else {
- List contents = notificationData.getContentForSummaryNotification();
- String senderList = createCommaSeparatedListOfSenders(contents);
- builder.setContentText(senderList);
+ val contents = notificationData.getContentForSummaryNotification()
+ val senderList = createCommaSeparatedListOfSenders(contents)
+ builder.setContentText(senderList)
}
- return builder.build();
+ return builder.build()
}
- private Notification createPublicNotificationWithNewMessagesCount(NotificationData notificationData) {
- Builder builder = createPublicNotification(notificationData);
- Account account = notificationData.getAccount();
- String accountName = notificationHelper.getAccountName(account);
- builder.setContentText(accountName);
+ private fun createPublicNotificationWithNewMessagesCount(notificationData: NotificationData): Notification {
+ val builder = createPublicNotification(notificationData)
+ val account = notificationData.account
+ val accountName = notificationHelper.getAccountName(account)
- return builder.build();
+ builder.setContentText(accountName)
+ return builder.build()
}
- private Builder createPublicNotification(NotificationData notificationData) {
- Account account = notificationData.getAccount();
- int newMessages = notificationData.getNewMessagesCount();
- int unreadCount = notificationData.getUnreadMessageCount();
- String title = resourceProvider.newMessagesTitle(newMessages);
-
- return notificationHelper.createNotificationBuilder(account,
- NotificationChannelManager.ChannelType.MESSAGES)
- .setSmallIcon(resourceProvider.getIconNewMail())
- .setColor(account.getChipColor())
- .setNumber(unreadCount)
- .setContentTitle(title)
- .setCategory(NotificationCompat.CATEGORY_EMAIL);
+ private fun createPublicNotification(notificationData: NotificationData): NotificationCompat.Builder {
+ val account = notificationData.account
+ val newMessages = notificationData.newMessagesCount
+ val unreadCount = notificationData.unreadMessageCount
+ val title = resourceProvider.newMessagesTitle(newMessages)
+
+ return notificationHelper.createNotificationBuilder(account, NotificationChannelManager.ChannelType.MESSAGES)
+ .setSmallIcon(resourceProvider.iconNewMail)
+ .setColor(account.chipColor)
+ .setNumber(unreadCount)
+ .setContentTitle(title)
+ .setCategory(NotificationCompat.CATEGORY_EMAIL)
}
+ fun createCommaSeparatedListOfSenders(contents: List): String {
+ return contents.asSequence()
+ .map { it.sender }
+ .distinct()
+ .take(MAX_NUMBER_OF_SENDERS_IN_LOCK_SCREEN_NOTIFICATION)
+ .joinToString()
+ }
- String createCommaSeparatedListOfSenders(List contents) {
- // Use a LinkedHashSet so that we preserve ordering (newest to oldest), but still remove duplicates
- Set senders = new LinkedHashSet<>(MAX_NUMBER_OF_SENDERS_IN_LOCK_SCREEN_NOTIFICATION);
- for (NotificationContent content : contents) {
- senders.add(content.sender);
- if (senders.size() == MAX_NUMBER_OF_SENDERS_IN_LOCK_SCREEN_NOTIFICATION) {
- break;
- }
- }
-
- return TextUtils.join(", ", senders);
+ companion object {
+ const val MAX_NUMBER_OF_SENDERS_IN_LOCK_SCREEN_NOTIFICATION = 5
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt
index 8fc8ae5e27..c89354372d 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NewMailNotifications.kt
@@ -1,167 +1,134 @@
-package com.fsck.k9.notification;
-
-
-import android.app.Notification;
-import androidx.core.app.NotificationManagerCompat;
-import android.util.SparseArray;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.K9.NotificationHideSubject;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.mailstore.LocalMessage;
+package com.fsck.k9.notification
+import android.util.SparseArray
+import androidx.core.app.NotificationManagerCompat
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.controller.MessageReference
+import com.fsck.k9.mailstore.LocalMessage
/**
* Handle notifications for new messages.
- *
- * We call the notification shown on the device summary notification, even when there's only one new message.
- * Notifications on an Android Wear device are displayed as a stack of cards and that's why we call them stacked
- * notifications. We have to keep track of stacked notifications individually and recreate/update the summary
- * notification when one or more of the stacked notifications are added/removed.
- * {@link NotificationData} keeps track of all data required to (re)create the actual system notifications.
- *
+ *
+ * We call the notification shown on the device *summary notification*, even when there's only one new message.
+ * Notifications on an Android Wear device are displayed as a stack of cards and that's why we call them *stacked
+ * notifications*. We have to keep track of stacked notifications individually and recreate/update the summary
+ * notification when one or more of the stacked notifications are added/removed.
+ *
+ * [NotificationData] keeps track of all data required to (re)create the actual system notifications.
*/
-class NewMailNotifications {
- private final NotificationHelper notificationHelper;
- private final NotificationContentCreator contentCreator;
- private final DeviceNotifications deviceNotifications;
- private final WearNotifications wearNotifications;
- private final SparseArray notifications = new SparseArray<>();
- private final Object lock = new Object();
-
-
- NewMailNotifications(NotificationHelper notificationHelper, NotificationContentCreator contentCreator,
- DeviceNotifications deviceNotifications, WearNotifications wearNotifications) {
- this.notificationHelper = notificationHelper;
- this.deviceNotifications = deviceNotifications;
- this.wearNotifications = wearNotifications;
- this.contentCreator = contentCreator;
- }
-
- public void addNewMailNotification(Account account, LocalMessage message, int unreadMessageCount) {
- NotificationContent content = contentCreator.createFromMessage(account, message);
-
- synchronized (lock) {
- NotificationData notificationData = getOrCreateNotificationData(account, unreadMessageCount);
- AddNotificationResult result = notificationData.addNotificationContent(content);
-
- if (result.shouldCancelNotification()) {
- int notificationId = result.getNotificationId();
- cancelNotification(notificationId);
+internal open class NewMailNotifications(
+ private val notificationHelper: NotificationHelper,
+ private val contentCreator: NotificationContentCreator,
+ private val deviceNotifications: DeviceNotifications,
+ private val wearNotifications: WearNotifications
+) {
+ private val notifications = SparseArray()
+ private val lock = Any()
+
+ fun addNewMailNotification(account: Account, message: LocalMessage, unreadMessageCount: Int) {
+ val content = contentCreator.createFromMessage(account, message)
+
+ synchronized(lock) {
+ val notificationData = getOrCreateNotificationData(account, unreadMessageCount)
+
+ val result = notificationData.addNotificationContent(content)
+ if (result.shouldCancelNotification) {
+ val notificationId = result.notificationId
+ cancelNotification(notificationId)
}
- createStackedNotification(account, result.getNotificationHolder());
- createSummaryNotification(account, notificationData, false);
+ createStackedNotification(account, result.notificationHolder)
+ createSummaryNotification(account, notificationData, false)
}
}
- public void removeNewMailNotification(Account account, MessageReference messageReference) {
- synchronized (lock) {
- NotificationData notificationData = getNotificationData(account);
- if (notificationData == null) {
- return;
- }
+ fun removeNewMailNotification(account: Account, messageReference: MessageReference) {
+ synchronized(lock) {
+ val notificationData = getNotificationData(account) ?: return
- RemoveNotificationResult result = notificationData.removeNotificationForMessage(messageReference);
- if (result.isUnknownNotification()) {
- return;
- }
+ val result = notificationData.removeNotificationForMessage(messageReference)
+ if (result.isUnknownNotification) return
- cancelNotification(result.getNotificationId());
+ cancelNotification(result.notificationId)
- if (result.shouldCreateNotification()) {
- createStackedNotification(account, result.getNotificationHolder());
+ if (result.shouldCreateNotification) {
+ createStackedNotification(account, result.notificationHolder)
}
- updateSummaryNotification(account, notificationData);
+ updateSummaryNotification(account, notificationData)
}
}
- public void clearNewMailNotifications(Account account) {
- NotificationData notificationData;
- synchronized (lock) {
- notificationData = removeNotificationData(account);
- }
-
- if (notificationData == null) {
- return;
- }
+ fun clearNewMailNotifications(account: Account) {
+ val notificationData = synchronized(lock) { removeNotificationData(account) } ?: return
- for (int notificationId : notificationData.getActiveNotificationIds()) {
- cancelNotification(notificationId);
+ for (notificationId in notificationData.getActiveNotificationIds()) {
+ cancelNotification(notificationId)
}
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- cancelNotification(notificationId);
+ val notificationId = NotificationIds.getNewMailSummaryNotificationId(account)
+ cancelNotification(notificationId)
}
- private NotificationData getOrCreateNotificationData(Account account, int unreadMessageCount) {
- NotificationData notificationData = getNotificationData(account);
- if (notificationData != null) {
- return notificationData;
- }
+ private fun getOrCreateNotificationData(account: Account, unreadMessageCount: Int): NotificationData {
+ val notificationData = getNotificationData(account)
+ if (notificationData != null) return notificationData
- int accountNumber = account.getAccountNumber();
- NotificationData newNotificationHolder = createNotificationData(account, unreadMessageCount);
- notifications.put(accountNumber, newNotificationHolder);
+ val accountNumber = account.accountNumber
+ val newNotificationHolder = createNotificationData(account, unreadMessageCount)
+ notifications.put(accountNumber, newNotificationHolder)
- return newNotificationHolder;
+ return newNotificationHolder
}
- private NotificationData getNotificationData(Account account) {
- int accountNumber = account.getAccountNumber();
- return notifications.get(accountNumber);
+ private fun getNotificationData(account: Account): NotificationData? {
+ val accountNumber = account.accountNumber
+ return notifications[accountNumber]
}
- private NotificationData removeNotificationData(Account account) {
- int accountNumber = account.getAccountNumber();
- NotificationData notificationData = notifications.get(accountNumber);
- notifications.remove(accountNumber);
- return notificationData;
+ private fun removeNotificationData(account: Account): NotificationData? {
+ val accountNumber = account.accountNumber
+ val notificationData = notifications[accountNumber]
+ notifications.remove(accountNumber)
+ return notificationData
}
- NotificationData createNotificationData(Account account, int unreadMessageCount) {
- NotificationData notificationData = new NotificationData(account);
- notificationData.setUnreadMessageCount(unreadMessageCount);
- return notificationData;
+ protected open fun createNotificationData(account: Account, unreadMessageCount: Int): NotificationData {
+ return NotificationData(account, unreadMessageCount)
}
- private void cancelNotification(int notificationId) {
- getNotificationManager().cancel(notificationId);
+ private fun cancelNotification(notificationId: Int) {
+ notificationManager.cancel(notificationId)
}
- private void updateSummaryNotification(Account account, NotificationData notificationData) {
- if (notificationData.getNewMessagesCount() == 0) {
- clearNewMailNotifications(account);
+ private fun updateSummaryNotification(account: Account, notificationData: NotificationData) {
+ if (notificationData.newMessagesCount == 0) {
+ clearNewMailNotifications(account)
} else {
- createSummaryNotification(account, notificationData, true);
+ createSummaryNotification(account, notificationData, true)
}
}
- private void createSummaryNotification(Account account, NotificationData notificationData, boolean silent) {
- Notification notification = deviceNotifications.buildSummaryNotification(account, notificationData, silent);
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
-
- getNotificationManager().notify(notificationId, notification);
+ private fun createSummaryNotification(account: Account, notificationData: NotificationData, silent: Boolean) {
+ val notification = deviceNotifications.buildSummaryNotification(account, notificationData, silent)
+ val notificationId = NotificationIds.getNewMailSummaryNotificationId(account)
+ notificationManager.notify(notificationId, notification)
}
- private void createStackedNotification(Account account, NotificationHolder holder) {
- if (isPrivacyModeEnabled()) {
- return;
+ private fun createStackedNotification(account: Account, holder: NotificationHolder) {
+ if (isPrivacyModeEnabled) {
+ return
}
- Notification notification = wearNotifications.buildStackedNotification(account, holder);
- int notificationId = holder.notificationId;
-
- getNotificationManager().notify(notificationId, notification);
+ val notification = wearNotifications.buildStackedNotification(account, holder)
+ val notificationId = holder.notificationId
+ notificationManager.notify(notificationId, notification)
}
- private boolean isPrivacyModeEnabled() {
- return K9.getNotificationHideSubject() != NotificationHideSubject.NEVER;
- }
+ private val isPrivacyModeEnabled: Boolean
+ get() = K9.notificationHideSubject !== K9.NotificationHideSubject.NEVER
- private NotificationManagerCompat getNotificationManager() {
- return notificationHelper.getNotificationManager();
- }
+ private val notificationManager: NotificationManagerCompat
+ get() = notificationHelper.getNotificationManager()
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt
index 94e781c4d8..77c97c6922 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionCreator.kt
@@ -1,50 +1,60 @@
-package com.fsck.k9.notification;
+package com.fsck.k9.notification
+import android.app.PendingIntent
+import android.content.Context
+import com.fsck.k9.Account
+import com.fsck.k9.controller.MessageReference
-import java.util.List;
+interface NotificationActionCreator {
+ fun createViewMessagePendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
-import android.app.PendingIntent;
-import android.content.Context;
+ fun createViewFolderPendingIntent(account: Account, folderId: Long, notificationId: Int): PendingIntent
-import com.fsck.k9.Account;
-import com.fsck.k9.controller.MessageReference;
+ fun createViewMessagesPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent
+ fun createViewFolderListPendingIntent(account: Account, notificationId: Int): PendingIntent
-public interface NotificationActionCreator {
- PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId);
+ fun createDismissAllMessagesPendingIntent(account: Account, notificationId: Int): PendingIntent
- PendingIntent createViewFolderPendingIntent(Account account, long folderId, int notificationId);
+ fun createDismissMessagePendingIntent(
+ context: Context,
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent
- PendingIntent createViewMessagesPendingIntent(Account account, List messageReferences,
- int notificationId);
+ fun createReplyPendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
- PendingIntent createViewFolderListPendingIntent(Account account, int notificationId);
+ fun createMarkMessageAsReadPendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
- PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId);
+ fun createMarkAllAsReadPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent
- PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
- int notificationId);
+ fun getEditIncomingServerSettingsIntent(account: Account): PendingIntent
- PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId);
+ fun getEditOutgoingServerSettingsIntent(account: Account): PendingIntent
- PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId);
+ fun createDeleteMessagePendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
- PendingIntent createMarkAllAsReadPendingIntent(Account account, List messageReferences,
- int notificationId);
+ fun createDeleteAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent
- PendingIntent getEditIncomingServerSettingsIntent(Account account);
+ fun createArchiveMessagePendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
- PendingIntent getEditOutgoingServerSettingsIntent(Account account);
+ fun createArchiveAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent
- PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId);
-
- PendingIntent createDeleteAllPendingIntent(Account account, List messageReferences,
- int notificationId);
-
- PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId);
-
- PendingIntent createArchiveAllPendingIntent(Account account, List messageReferences,
- int notificationId);
-
- PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId);
+ fun createMarkMessageAsSpamPendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt
index a0453579e6..d70ea87778 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationActionService.kt
@@ -1,247 +1,244 @@
-package com.fsck.k9.notification;
-
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-
-import androidx.annotation.Nullable;
-
-import timber.log.Timber;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.Preferences;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.controller.MessagingController;
-import com.fsck.k9.mail.Flag;
-
-import static com.fsck.k9.controller.MessageReferenceHelper.toMessageReferenceList;
-import static com.fsck.k9.controller.MessageReferenceHelper.toMessageReferenceStringList;
-
-
-public class NotificationActionService extends Service {
- private static final String ACTION_MARK_AS_READ = "ACTION_MARK_AS_READ";
- private static final String ACTION_DELETE = "ACTION_DELETE";
- private static final String ACTION_ARCHIVE = "ACTION_ARCHIVE";
- private static final String ACTION_SPAM = "ACTION_SPAM";
- private static final String ACTION_DISMISS = "ACTION_DISMISS";
-
- private static final String EXTRA_ACCOUNT_UUID = "accountUuid";
- private static final String EXTRA_MESSAGE_REFERENCE = "messageReference";
- private static final String EXTRA_MESSAGE_REFERENCES = "messageReferences";
+package com.fsck.k9.notification
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.IBinder
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.Preferences
+import com.fsck.k9.controller.MessageReference
+import com.fsck.k9.controller.MessageReferenceHelper
+import com.fsck.k9.controller.MessagingController
+import com.fsck.k9.mail.Flag
+import org.koin.android.ext.android.inject
+import timber.log.Timber
+
+class NotificationActionService : Service() {
+ private val preferences: Preferences by inject()
+ private val messagingController: MessagingController by inject()
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ Timber.i("NotificationActionService started with startId = %d", startId)
+
+ val accountUuid = intent.getStringExtra(EXTRA_ACCOUNT_UUID) ?: error("Missing account UUID")
+
+ val account = preferences.getAccount(accountUuid)
+ if (account == null) {
+ Timber.w("Could not find account for notification action.")
+ return START_NOT_STICKY
+ }
+ when (intent.action) {
+ ACTION_MARK_AS_READ -> markMessagesAsRead(intent, account)
+ ACTION_DELETE -> deleteMessages(intent)
+ ACTION_ARCHIVE -> archiveMessages(intent, account)
+ ACTION_SPAM -> markMessageAsSpam(intent, account)
+ ACTION_DISMISS -> Timber.i("Notification dismissed")
+ }
- public static Intent createMarkMessageAsReadIntent(Context context, MessageReference messageReference) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_MARK_AS_READ);
- intent.putExtra(EXTRA_ACCOUNT_UUID, messageReference.getAccountUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference));
+ cancelNotifications(intent, account)
- return intent;
+ return START_NOT_STICKY
}
- public static Intent createMarkAllAsReadIntent(Context context, String accountUuid,
- List messageReferences) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_MARK_AS_READ);
- intent.putExtra(EXTRA_ACCOUNT_UUID, accountUuid);
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, toMessageReferenceStringList(messageReferences));
-
- return intent;
+ override fun onBind(intent: Intent): IBinder? {
+ return null
}
- public static Intent createDismissMessageIntent(Context context, MessageReference messageReference) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_DISMISS);
- intent.putExtra(EXTRA_ACCOUNT_UUID, messageReference.getAccountUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCE, messageReference.toIdentityString());
-
- return intent;
- }
+ private fun markMessagesAsRead(intent: Intent, account: Account) {
+ Timber.i("NotificationActionService marking messages as read")
- public static Intent createDismissAllMessagesIntent(Context context, Account account) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_DISMISS);
- intent.putExtra(EXTRA_ACCOUNT_UUID, account.getUuid());
+ val messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES)
+ val messageReferences = MessageReferenceHelper.toMessageReferenceList(messageReferenceStrings)
- return intent;
- }
-
- public static Intent createDeleteMessageIntent(Context context, MessageReference messageReference) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_DELETE);
- intent.putExtra(EXTRA_ACCOUNT_UUID, messageReference.getAccountUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference));
-
- return intent;
+ for (messageReference in messageReferences) {
+ val folderId = messageReference.folderId
+ val uid = messageReference.uid
+ messagingController.setFlag(account, folderId, uid, Flag.SEEN, true)
+ }
}
- public static Intent createDeleteAllMessagesIntent(Context context, String accountUuid,
- List messageReferences) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_DELETE);
- intent.putExtra(EXTRA_ACCOUNT_UUID, accountUuid);
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, toMessageReferenceStringList(messageReferences));
-
- return intent;
- }
+ private fun deleteMessages(intent: Intent) {
+ Timber.i("NotificationActionService deleting messages")
- public static Intent createArchiveMessageIntent(Context context, MessageReference messageReference) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_ARCHIVE);
- intent.putExtra(EXTRA_ACCOUNT_UUID, messageReference.getAccountUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference));
+ val messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES)
+ val messageReferences = MessageReferenceHelper.toMessageReferenceList(messageReferenceStrings)
- return intent;
+ messagingController.deleteMessages(messageReferences)
}
- public static Intent createArchiveAllIntent(Context context, Account account,
- List messageReferences) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_ARCHIVE);
- intent.putExtra(EXTRA_ACCOUNT_UUID, account.getUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCES, toMessageReferenceStringList(messageReferences));
-
- return intent;
- }
+ private fun archiveMessages(intent: Intent, account: Account) {
+ Timber.i("NotificationActionService archiving messages")
- public static Intent createMarkMessageAsSpamIntent(Context context, MessageReference messageReference) {
- Intent intent = new Intent(context, NotificationActionService.class);
- intent.setAction(ACTION_SPAM);
- intent.putExtra(EXTRA_ACCOUNT_UUID, messageReference.getAccountUuid());
- intent.putExtra(EXTRA_MESSAGE_REFERENCE, messageReference.toIdentityString());
+ val archiveFolderId = account.archiveFolderId
+ if (archiveFolderId == null || !messagingController.isMoveCapable(account)) {
+ Timber.w("Cannot archive messages")
+ return
+ }
- return intent;
- }
+ val messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES)
+ val messageReferences = MessageReferenceHelper.toMessageReferenceList(messageReferenceStrings)
- private static ArrayList createSingleItemArrayList(MessageReference messageReference) {
- ArrayList messageReferenceStrings = new ArrayList<>(1);
- messageReferenceStrings.add(messageReference.toIdentityString());
- return messageReferenceStrings;
+ for (messageReference in messageReferences) {
+ if (messagingController.isMoveCapable(messageReference)) {
+ val sourceFolderId = messageReference.folderId
+ messagingController.moveMessage(account, sourceFolderId, messageReference, archiveFolderId)
+ }
+ }
}
- @Override
- public final int onStartCommand(Intent intent, int flags, int startId) {
- Timber.i("NotificationActionService started with startId = %d", startId);
+ private fun markMessageAsSpam(intent: Intent, account: Account) {
+ Timber.i("NotificationActionService moving messages to spam")
- String accountUuid = intent.getStringExtra(EXTRA_ACCOUNT_UUID);
- Preferences preferences = Preferences.getPreferences(this);
- Account account = preferences.getAccount(accountUuid);
+ val messageReferenceString = intent.getStringExtra(EXTRA_MESSAGE_REFERENCE)
+ val messageReference = MessageReference.parse(messageReferenceString)
- if (account == null) {
- Timber.w("Could not find account for notification action.");
- return START_NOT_STICKY;
+ if (messageReference == null) {
+ Timber.w("Invalid message reference: %s", messageReferenceString)
+ return
}
- MessagingController controller = MessagingController.getInstance(getApplication());
-
- String action = intent.getAction();
- if (ACTION_MARK_AS_READ.equals(action)) {
- markMessagesAsRead(intent, account, controller);
- } else if (ACTION_DELETE.equals(action)) {
- deleteMessages(intent, controller);
- } else if (ACTION_ARCHIVE.equals(action)) {
- archiveMessages(intent, account, controller);
- } else if (ACTION_SPAM.equals(action)) {
- markMessageAsSpam(intent, account, controller);
- } else if (ACTION_DISMISS.equals(action)) {
- Timber.i("Notification dismissed");
+ val spamFolderId = account.spamFolderId
+ if (spamFolderId == null) {
+ Timber.w("No spam folder configured")
+ return
}
- cancelNotifications(intent, account, controller);
-
- return START_NOT_STICKY;
+ if (!K9.isConfirmSpam && messagingController.isMoveCapable(account)) {
+ val sourceFolderId = messageReference.folderId
+ messagingController.moveMessage(account, sourceFolderId, messageReference, spamFolderId)
+ }
}
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
+ private fun cancelNotifications(intent: Intent, account: Account) {
+ if (intent.hasExtra(EXTRA_MESSAGE_REFERENCE)) {
+ val messageReferenceString = intent.getStringExtra(EXTRA_MESSAGE_REFERENCE)
+ val messageReference = MessageReference.parse(messageReferenceString)
- private void markMessagesAsRead(Intent intent, Account account, MessagingController controller) {
- Timber.i("NotificationActionService marking messages as read");
+ if (messageReference != null) {
+ messagingController.cancelNotificationForMessage(account, messageReference)
+ } else {
+ Timber.w("Invalid message reference: %s", messageReferenceString)
+ }
+ } else if (intent.hasExtra(EXTRA_MESSAGE_REFERENCES)) {
+ val messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES)
+ val messageReferences = MessageReferenceHelper.toMessageReferenceList(messageReferenceStrings)
- List messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES);
- List messageReferences = toMessageReferenceList(messageReferenceStrings);
- for (MessageReference messageReference : messageReferences) {
- long folderId = messageReference.getFolderId();
- String uid = messageReference.getUid();
- controller.setFlag(account, folderId, uid, Flag.SEEN, true);
+ for (messageReference in messageReferences) {
+ messagingController.cancelNotificationForMessage(account, messageReference)
+ }
+ } else {
+ messagingController.cancelNotificationsForAccount(account)
}
}
- private void deleteMessages(Intent intent, MessagingController controller) {
- Timber.i("NotificationActionService deleting messages");
-
- List messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES);
- List messageReferences = toMessageReferenceList(messageReferenceStrings);
- controller.deleteMessages(messageReferences);
- }
+ companion object {
+ private const val ACTION_MARK_AS_READ = "ACTION_MARK_AS_READ"
+ private const val ACTION_DELETE = "ACTION_DELETE"
+ private const val ACTION_ARCHIVE = "ACTION_ARCHIVE"
+ private const val ACTION_SPAM = "ACTION_SPAM"
+ private const val ACTION_DISMISS = "ACTION_DISMISS"
+ private const val EXTRA_ACCOUNT_UUID = "accountUuid"
+ private const val EXTRA_MESSAGE_REFERENCE = "messageReference"
+ private const val EXTRA_MESSAGE_REFERENCES = "messageReferences"
+
+ fun createMarkMessageAsReadIntent(context: Context, messageReference: MessageReference): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_MARK_AS_READ
+ putExtra(EXTRA_ACCOUNT_UUID, messageReference.accountUuid)
+ putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference))
+ }
+ }
- private void archiveMessages(Intent intent, Account account, MessagingController controller) {
- Timber.i("NotificationActionService archiving messages");
+ fun createMarkAllAsReadIntent(
+ context: Context,
+ accountUuid: String,
+ messageReferences: List
+ ): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_MARK_AS_READ
+ putExtra(EXTRA_ACCOUNT_UUID, accountUuid)
+ putExtra(
+ EXTRA_MESSAGE_REFERENCES,
+ MessageReferenceHelper.toMessageReferenceStringList(messageReferences)
+ )
+ }
+ }
- Long archiveFolderId = account.getArchiveFolderId();
- if (!isMovePossible(controller, account, archiveFolderId)) {
- Timber.w("Can not archive messages");
- return;
+ fun createDismissMessageIntent(context: Context, messageReference: MessageReference): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_DISMISS
+ putExtra(EXTRA_ACCOUNT_UUID, messageReference.accountUuid)
+ putExtra(EXTRA_MESSAGE_REFERENCE, messageReference.toIdentityString())
+ }
}
- List messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES);
- List messageReferences = toMessageReferenceList(messageReferenceStrings);
- for (MessageReference messageReference : messageReferences) {
- if (controller.isMoveCapable(messageReference)) {
- long sourceFolderId = messageReference.getFolderId();
- controller.moveMessage(account, sourceFolderId, messageReference, archiveFolderId);
+ fun createDismissAllMessagesIntent(context: Context, account: Account): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_DISMISS
+ putExtra(EXTRA_ACCOUNT_UUID, account.uuid)
}
}
- }
- private void markMessageAsSpam(Intent intent, Account account, MessagingController controller) {
- Timber.i("NotificationActionService moving messages to spam");
+ fun createDeleteMessageIntent(context: Context, messageReference: MessageReference): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_DELETE
+ putExtra(EXTRA_ACCOUNT_UUID, messageReference.accountUuid)
+ putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference))
+ }
+ }
- String messageReferenceString = intent.getStringExtra(EXTRA_MESSAGE_REFERENCE);
- MessageReference messageReference = MessageReference.parse(messageReferenceString);
- if (messageReference == null) {
- Timber.w("Invalid message reference: %s", messageReferenceString);
- return;
+ fun createDeleteAllMessagesIntent(
+ context: Context,
+ accountUuid: String,
+ messageReferences: List
+ ): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_DELETE
+ putExtra(EXTRA_ACCOUNT_UUID, accountUuid)
+ putExtra(
+ EXTRA_MESSAGE_REFERENCES,
+ MessageReferenceHelper.toMessageReferenceStringList(messageReferences)
+ )
+ }
}
- Long spamFolderId = account.getSpamFolderId();
- if (!K9.isConfirmSpam() && isMovePossible(controller, account, spamFolderId)) {
- long sourceFolderId = messageReference.getFolderId();
- controller.moveMessage(account, sourceFolderId, messageReference, spamFolderId);
+ fun createArchiveMessageIntent(context: Context, messageReference: MessageReference): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_ARCHIVE
+ putExtra(EXTRA_ACCOUNT_UUID, messageReference.accountUuid)
+ putExtra(EXTRA_MESSAGE_REFERENCES, createSingleItemArrayList(messageReference))
+ }
}
- }
- private void cancelNotifications(Intent intent, Account account, MessagingController controller) {
- if (intent.hasExtra(EXTRA_MESSAGE_REFERENCE)) {
- String messageReferenceString = intent.getStringExtra(EXTRA_MESSAGE_REFERENCE);
- MessageReference messageReference = MessageReference.parse(messageReferenceString);
- if (messageReference != null) {
- controller.cancelNotificationForMessage(account, messageReference);
- } else {
- Timber.w("Invalid message reference: %s", messageReferenceString);
+ fun createArchiveAllIntent(
+ context: Context,
+ account: Account,
+ messageReferences: List
+ ): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_ARCHIVE
+ putExtra(EXTRA_ACCOUNT_UUID, account.uuid)
+ putExtra(
+ EXTRA_MESSAGE_REFERENCES,
+ MessageReferenceHelper.toMessageReferenceStringList(messageReferences)
+ )
}
- } else if (intent.hasExtra(EXTRA_MESSAGE_REFERENCES)) {
- List messageReferenceStrings = intent.getStringArrayListExtra(EXTRA_MESSAGE_REFERENCES);
- List messageReferences = toMessageReferenceList(messageReferenceStrings);
- for (MessageReference messageReference : messageReferences) {
- controller.cancelNotificationForMessage(account, messageReference);
+ }
+
+ fun createMarkMessageAsSpamIntent(context: Context, messageReference: MessageReference): Intent {
+ return Intent(context, NotificationActionService::class.java).apply {
+ action = ACTION_SPAM
+ putExtra(EXTRA_ACCOUNT_UUID, messageReference.accountUuid)
+ putExtra(EXTRA_MESSAGE_REFERENCE, messageReference.toIdentityString())
}
- } else {
- controller.cancelNotificationsForAccount(account);
}
- }
- private boolean isMovePossible(MessagingController controller, Account account, Long destinationFolderId) {
- boolean isSpecialFolderConfigured = destinationFolderId != null;
- return isSpecialFolderConfigured && controller.isMoveCapable(account);
+ private fun createSingleItemArrayList(messageReference: MessageReference): ArrayList {
+ return ArrayList(1).apply {
+ add(messageReference.toIdentityString())
+ }
+ }
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt
index f3dc8cca48..ed791dc41b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationContent.kt
@@ -1,25 +1,12 @@
-package com.fsck.k9.notification;
-
-
-import com.fsck.k9.controller.MessageReference;
-
-
-class NotificationContent {
- public final MessageReference messageReference;
- public final String sender;
- public final String subject;
- public final CharSequence preview;
- public final CharSequence summary;
- public final boolean starred;
-
-
- public NotificationContent(MessageReference messageReference, String sender, String subject, CharSequence preview,
- CharSequence summary, boolean starred) {
- this.messageReference = messageReference;
- this.sender = sender;
- this.subject = subject;
- this.preview = preview;
- this.summary = summary;
- this.starred = starred;
- }
-}
+package com.fsck.k9.notification
+
+import com.fsck.k9.controller.MessageReference
+
+internal class NotificationContent(
+ val messageReference: MessageReference,
+ val sender: String,
+ val subject: String,
+ val preview: CharSequence,
+ val summary: CharSequence,
+ val isStarred: Boolean
+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt
index 6d98f508f3..c3c5bc022b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationContentCreator.kt
@@ -1,129 +1,101 @@
-package com.fsck.k9.notification;
-
-
-import android.content.Context;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.helper.Contacts;
-import com.fsck.k9.helper.MessageHelper;
-import com.fsck.k9.mail.Address;
-import com.fsck.k9.mail.Flag;
-import com.fsck.k9.mail.Message;
-import com.fsck.k9.mailstore.LocalMessage;
-import com.fsck.k9.message.extractors.PreviewResult.PreviewType;
-
-
-class NotificationContentCreator {
- private final Context context;
- private final NotificationResourceProvider resourceProvider;
-
-
- public NotificationContentCreator(Context context, NotificationResourceProvider resourceProvider) {
- this.context = context;
- this.resourceProvider = resourceProvider;
- }
-
- public NotificationContent createFromMessage(Account account, LocalMessage message) {
- MessageReference messageReference = message.makeMessageReference();
- String sender = getMessageSender(account, message);
- String displaySender = getMessageSenderForDisplay(sender);
- String subject = getMessageSubject(message);
- CharSequence preview = getMessagePreview(message);
- CharSequence summary = buildMessageSummary(sender, subject);
- boolean starred = message.isSet(Flag.FLAGGED);
-
- return new NotificationContent(messageReference, displaySender, subject, preview, summary, starred);
+package com.fsck.k9.notification
+
+import android.content.Context
+import android.text.SpannableStringBuilder
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.helper.Contacts
+import com.fsck.k9.helper.MessageHelper
+import com.fsck.k9.mail.Flag
+import com.fsck.k9.mail.Message
+import com.fsck.k9.mailstore.LocalMessage
+import com.fsck.k9.message.extractors.PreviewResult.PreviewType
+
+internal class NotificationContentCreator(
+ private val context: Context,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun createFromMessage(account: Account, message: LocalMessage): NotificationContent {
+ val sender = getMessageSender(account, message)
+
+ return NotificationContent(
+ messageReference = message.makeMessageReference(),
+ sender = getMessageSenderForDisplay(sender),
+ subject = getMessageSubject(message),
+ preview = getMessagePreview(message),
+ summary = buildMessageSummary(sender, getMessageSubject(message)),
+ isStarred = message.isSet(Flag.FLAGGED)
+ )
}
- private CharSequence getMessagePreview(LocalMessage message) {
- String subject = message.getSubject();
- String snippet = getPreview(message);
-
- boolean isSubjectEmpty = TextUtils.isEmpty(subject);
- boolean isSnippetPresent = snippet != null;
- if (isSubjectEmpty && isSnippetPresent) {
- return snippet;
+ private fun getMessagePreview(message: LocalMessage): CharSequence {
+ val snippet = getPreview(message)
+ if (message.subject.isNullOrEmpty() && snippet != null) {
+ return snippet
}
- String displaySubject = getMessageSubject(message);
+ return SpannableStringBuilder().apply {
+ val displaySubject = getMessageSubject(message)
+ append(displaySubject)
- SpannableStringBuilder preview = new SpannableStringBuilder();
- preview.append(displaySubject);
- if (isSnippetPresent) {
- preview.append('\n');
- preview.append(snippet);
+ if (snippet != null) {
+ append('\n')
+ append(snippet)
+ }
}
-
- return preview;
}
- private String getPreview(LocalMessage message) {
- PreviewType previewType = message.getPreviewType();
- switch (previewType) {
- case NONE:
- case ERROR:
- return null;
- case TEXT:
- return message.getPreview();
- case ENCRYPTED:
- return resourceProvider.previewEncrypted();
+ private fun getPreview(message: LocalMessage): String? {
+ val previewType = message.previewType ?: error("previewType == null")
+ return when (previewType) {
+ PreviewType.NONE, PreviewType.ERROR -> null
+ PreviewType.TEXT -> message.preview
+ PreviewType.ENCRYPTED -> resourceProvider.previewEncrypted()
}
-
- throw new AssertionError("Unknown preview type: " + previewType);
}
- private CharSequence buildMessageSummary(String sender, String subject) {
- if (sender == null) {
- return subject;
+ private fun buildMessageSummary(sender: String?, subject: String): CharSequence {
+ return if (sender == null) {
+ subject
+ } else {
+ SpannableStringBuilder().apply {
+ append(sender)
+ append(" ")
+ append(subject)
+ }
}
-
- SpannableStringBuilder summary = new SpannableStringBuilder();
- summary.append(sender);
- summary.append(" ");
- summary.append(subject);
-
- return summary;
}
- private String getMessageSubject(Message message) {
- String subject = message.getSubject();
- if (!TextUtils.isEmpty(subject)) {
- return subject;
- }
-
- return resourceProvider.noSubject();
+ private fun getMessageSubject(message: Message): String {
+ val subject = message.subject.orEmpty()
+ return subject.ifEmpty { resourceProvider.noSubject() }
}
- private String getMessageSender(Account account, Message message) {
- boolean isSelf = false;
- final Contacts contacts = K9.isShowContactName() ? Contacts.getInstance(context) : null;
- final Address[] fromAddresses = message.getFrom();
+ private fun getMessageSender(account: Account, message: Message): String? {
+ val contacts = if (K9.isShowContactName) Contacts.getInstance(context) else null
+ var isSelf = false
- if (fromAddresses != null) {
- isSelf = account.isAnIdentity(fromAddresses);
- if (!isSelf && fromAddresses.length > 0) {
- return MessageHelper.toFriendly(fromAddresses[0], contacts).toString();
+ val fromAddresses = message.from
+ if (!fromAddresses.isNullOrEmpty()) {
+ isSelf = account.isAnIdentity(fromAddresses)
+ if (!isSelf) {
+ return MessageHelper.toFriendly(fromAddresses.first(), contacts).toString()
}
}
if (isSelf) {
// show To: if the message was sent from me
- Address[] recipients = message.getRecipients(Message.RecipientType.TO);
-
- if (recipients != null && recipients.length > 0) {
- String recipientDisplayName = MessageHelper.toFriendly(recipients[0], contacts).toString();
- return resourceProvider.recipientDisplayName(recipientDisplayName);
+ val recipients = message.getRecipients(Message.RecipientType.TO)
+ if (!recipients.isNullOrEmpty()) {
+ val recipientDisplayName = MessageHelper.toFriendly(recipients.first(), contacts).toString()
+ return resourceProvider.recipientDisplayName(recipientDisplayName)
}
}
- return null;
+ return null
}
- private String getMessageSenderForDisplay(String sender) {
- return (sender != null) ? sender : resourceProvider.noSender();
+ private fun getMessageSenderForDisplay(sender: String?): String {
+ return sender ?: resourceProvider.noSender()
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt
index 1426f3e6f5..1cec1e3992 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationController.kt
@@ -1,83 +1,66 @@
-package com.fsck.k9.notification;
-
-
-import com.fsck.k9.Account;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.mailstore.LocalFolder;
-import com.fsck.k9.mailstore.LocalMessage;
-
-
-public class NotificationController {
- private final CertificateErrorNotifications certificateErrorNotifications;
- private final AuthenticationErrorNotifications authenticationErrorNotifications;
- private final SyncNotifications syncNotifications;
- private final SendFailedNotifications sendFailedNotifications;
- private final NewMailNotifications newMailNotifications;
-
-
- NotificationController(
- CertificateErrorNotifications certificateErrorNotifications,
- AuthenticationErrorNotifications authenticationErrorNotifications,
- SyncNotifications syncNotifications,
- SendFailedNotifications sendFailedNotifications,
- NewMailNotifications newMailNotifications
- ) {
- this.certificateErrorNotifications = certificateErrorNotifications;
- this.authenticationErrorNotifications = authenticationErrorNotifications;
- this.syncNotifications = syncNotifications;
- this.sendFailedNotifications = sendFailedNotifications;
- this.newMailNotifications = newMailNotifications;
- }
-
- public void showCertificateErrorNotification(Account account, boolean incoming) {
- certificateErrorNotifications.showCertificateErrorNotification(account, incoming);
+package com.fsck.k9.notification
+
+import com.fsck.k9.Account
+import com.fsck.k9.controller.MessageReference
+import com.fsck.k9.mailstore.LocalFolder
+import com.fsck.k9.mailstore.LocalMessage
+
+class NotificationController internal constructor(
+ private val certificateErrorNotifications: CertificateErrorNotifications,
+ private val authenticationErrorNotifications: AuthenticationErrorNotifications,
+ private val syncNotifications: SyncNotifications,
+ private val sendFailedNotifications: SendFailedNotifications,
+ private val newMailNotifications: NewMailNotifications
+) {
+ fun showCertificateErrorNotification(account: Account, incoming: Boolean) {
+ certificateErrorNotifications.showCertificateErrorNotification(account, incoming)
}
- public void clearCertificateErrorNotifications(Account account, boolean incoming) {
- certificateErrorNotifications.clearCertificateErrorNotifications(account, incoming);
+ fun clearCertificateErrorNotifications(account: Account, incoming: Boolean) {
+ certificateErrorNotifications.clearCertificateErrorNotifications(account, incoming)
}
- public void showAuthenticationErrorNotification(Account account, boolean incoming) {
- authenticationErrorNotifications.showAuthenticationErrorNotification(account, incoming);
+ fun showAuthenticationErrorNotification(account: Account, incoming: Boolean) {
+ authenticationErrorNotifications.showAuthenticationErrorNotification(account, incoming)
}
- public void clearAuthenticationErrorNotification(Account account, boolean incoming) {
- authenticationErrorNotifications.clearAuthenticationErrorNotification(account, incoming);
+ fun clearAuthenticationErrorNotification(account: Account, incoming: Boolean) {
+ authenticationErrorNotifications.clearAuthenticationErrorNotification(account, incoming)
}
- public void showSendingNotification(Account account) {
- syncNotifications.showSendingNotification(account);
+ fun showSendingNotification(account: Account) {
+ syncNotifications.showSendingNotification(account)
}
- public void clearSendingNotification(Account account) {
- syncNotifications.clearSendingNotification(account);
+ fun clearSendingNotification(account: Account) {
+ syncNotifications.clearSendingNotification(account)
}
- public void showSendFailedNotification(Account account, Exception exception) {
- sendFailedNotifications.showSendFailedNotification(account, exception);
+ fun showSendFailedNotification(account: Account, exception: Exception) {
+ sendFailedNotifications.showSendFailedNotification(account, exception)
}
- public void clearSendFailedNotification(Account account) {
- sendFailedNotifications.clearSendFailedNotification(account);
+ fun clearSendFailedNotification(account: Account) {
+ sendFailedNotifications.clearSendFailedNotification(account)
}
- public void showFetchingMailNotification(Account account, LocalFolder folder) {
- syncNotifications.showFetchingMailNotification(account, folder);
+ fun showFetchingMailNotification(account: Account, folder: LocalFolder) {
+ syncNotifications.showFetchingMailNotification(account, folder)
}
- public void clearFetchingMailNotification(Account account) {
- syncNotifications.clearFetchingMailNotification(account);
+ fun clearFetchingMailNotification(account: Account) {
+ syncNotifications.clearFetchingMailNotification(account)
}
- public void addNewMailNotification(Account account, LocalMessage message, int previousUnreadMessageCount) {
- newMailNotifications.addNewMailNotification(account, message, previousUnreadMessageCount);
+ fun addNewMailNotification(account: Account, message: LocalMessage, previousUnreadMessageCount: Int) {
+ newMailNotifications.addNewMailNotification(account, message, previousUnreadMessageCount)
}
- public void removeNewMailNotification(Account account, MessageReference messageReference) {
- newMailNotifications.removeNewMailNotification(account, messageReference);
+ fun removeNewMailNotification(account: Account, messageReference: MessageReference) {
+ newMailNotifications.removeNewMailNotification(account, messageReference)
}
- public void clearNewMailNotifications(Account account) {
- newMailNotifications.clearNewMailNotifications(account);
+ fun clearNewMailNotifications(account: Account) {
+ newMailNotifications.clearNewMailNotifications(account)
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt
index 69475eaa20..8b7e13f352 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationData.kt
@@ -1,224 +1,159 @@
-package com.fsck.k9.notification;
-
-
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import android.util.SparseBooleanArray;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.controller.MessageReference;
+package com.fsck.k9.notification
+import android.util.SparseBooleanArray
+import com.fsck.k9.Account
+import com.fsck.k9.controller.MessageReference
+import java.util.LinkedList
/**
* A holder class for pending new mail notifications.
*/
-class NotificationData {
- // Note: As of Jellybean, phone notifications show a maximum of 5 lines, while tablet notifications show 7 lines.
- static final int MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION = 5;
- // Note: This class assumes MAX_NUMBER_OF_STACKED_NOTIFICATIONS >= MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION
- static final int MAX_NUMBER_OF_STACKED_NOTIFICATIONS = 8;
-
-
- private final Account account;
- private final LinkedList activeNotifications = new LinkedList<>();
- private final Deque additionalNotifications = new LinkedList<>();
- private final SparseBooleanArray notificationIdsInUse = new SparseBooleanArray();
- private int unreadMessageCount;
-
-
- public NotificationData(Account account) {
- this.account = account;
- }
-
- public AddNotificationResult addNotificationContent(NotificationContent content) {
- int notificationId;
- boolean cancelNotificationIdBeforeReuse;
- if (isMaxNumberOfActiveNotificationsReached()) {
- NotificationHolder notificationHolder = activeNotifications.removeLast();
- addToAdditionalNotifications(notificationHolder);
- notificationId = notificationHolder.notificationId;
- cancelNotificationIdBeforeReuse = true;
+internal class NotificationData(val account: Account, private val initialUnreadMessageCount: Int) {
+ private val activeNotifications = LinkedList()
+ private val additionalNotifications = LinkedList()
+ private val notificationIdsInUse = SparseBooleanArray()
+
+ val unreadMessageCount: Int
+ get() = initialUnreadMessageCount + newMessagesCount
+
+ val newMessagesCount: Int
+ get() = activeNotifications.size + additionalNotifications.size
+
+ val isSingleMessageNotification: Boolean
+ get() = activeNotifications.size == 1
+
+ val holderForLatestNotification: NotificationHolder
+ get() = activeNotifications.first
+
+ private val isMaxNumberOfActiveNotificationsReached: Boolean
+ get() = activeNotifications.size == MAX_NUMBER_OF_STACKED_NOTIFICATIONS
+
+ fun addNotificationContent(content: NotificationContent): AddNotificationResult {
+ val notificationId: Int
+ val cancelNotificationIdBeforeReuse: Boolean
+ if (isMaxNumberOfActiveNotificationsReached) {
+ val notificationHolder = activeNotifications.removeLast()
+ addToAdditionalNotifications(notificationHolder)
+ notificationId = notificationHolder.notificationId
+ cancelNotificationIdBeforeReuse = true
} else {
- notificationId = getNewNotificationId();
- cancelNotificationIdBeforeReuse = false;
+ notificationId = getNewNotificationId()
+ cancelNotificationIdBeforeReuse = false
}
- NotificationHolder notificationHolder = createNotificationHolder(notificationId, content);
- activeNotifications.addFirst(notificationHolder);
+ val notificationHolder = createNotificationHolder(notificationId, content)
+ activeNotifications.addFirst(notificationHolder)
- if (cancelNotificationIdBeforeReuse) {
- return AddNotificationResult.replaceNotification(notificationHolder);
+ return if (cancelNotificationIdBeforeReuse) {
+ AddNotificationResult.replaceNotification(notificationHolder)
} else {
- return AddNotificationResult.newNotification(notificationHolder);
+ AddNotificationResult.newNotification(notificationHolder)
}
}
- private boolean isMaxNumberOfActiveNotificationsReached() {
- return activeNotifications.size() == MAX_NUMBER_OF_STACKED_NOTIFICATIONS;
- }
-
- private void addToAdditionalNotifications(NotificationHolder notificationHolder) {
- additionalNotifications.addFirst(notificationHolder.content);
+ private fun addToAdditionalNotifications(notificationHolder: NotificationHolder) {
+ additionalNotifications.addFirst(notificationHolder.content)
}
- private int getNewNotificationId() {
- for (int i = 0; i < MAX_NUMBER_OF_STACKED_NOTIFICATIONS; i++) {
- int notificationId = NotificationIds.getNewMailStackedNotificationId(account, i);
+ private fun getNewNotificationId(): Int {
+ for (index in 0 until MAX_NUMBER_OF_STACKED_NOTIFICATIONS) {
+ val notificationId = NotificationIds.getNewMailStackedNotificationId(account, index)
if (!isNotificationInUse(notificationId)) {
- markNotificationIdAsInUse(notificationId);
- return notificationId;
+ markNotificationIdAsInUse(notificationId)
+ return notificationId
}
}
- throw new AssertionError("getNewNotificationId() called with no free notification ID");
+ throw AssertionError("getNewNotificationId() called with no free notification ID")
}
- private boolean isNotificationInUse(int notificationId) {
- return notificationIdsInUse.get(notificationId);
+ private fun isNotificationInUse(notificationId: Int): Boolean {
+ return notificationIdsInUse[notificationId]
}
- private void markNotificationIdAsInUse(int notificationId) {
- notificationIdsInUse.put(notificationId, true);
+ private fun markNotificationIdAsInUse(notificationId: Int) {
+ notificationIdsInUse.put(notificationId, true)
}
- private void markNotificationIdAsFree(int notificationId) {
- notificationIdsInUse.delete(notificationId);
+ private fun markNotificationIdAsFree(notificationId: Int) {
+ notificationIdsInUse.delete(notificationId)
}
- NotificationHolder createNotificationHolder(int notificationId, NotificationContent content) {
- return new NotificationHolder(notificationId, content);
+ private fun createNotificationHolder(notificationId: Int, content: NotificationContent): NotificationHolder {
+ return NotificationHolder(notificationId, content)
}
- public boolean containsStarredMessages() {
- for (NotificationHolder holder : activeNotifications) {
- if (holder.content.starred) {
- return true;
- }
- }
-
- for (NotificationContent content : additionalNotifications) {
- if (content.starred) {
- return true;
- }
- }
-
- return false;
+ fun containsStarredMessages(): Boolean {
+ return activeNotifications.any { it.content.isStarred } || additionalNotifications.any { it.isStarred }
}
- public boolean hasSummaryOverflowMessages() {
- return activeNotifications.size() > MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION;
+ fun hasSummaryOverflowMessages(): Boolean {
+ return activeNotifications.size > MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION
}
- public int getSummaryOverflowMessagesCount() {
- int activeOverflowCount = activeNotifications.size() - MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION;
- if (activeOverflowCount > 0) {
- return activeOverflowCount + additionalNotifications.size();
+ fun getSummaryOverflowMessagesCount(): Int {
+ val activeOverflowCount = activeNotifications.size - MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION
+ return if (activeOverflowCount > 0) {
+ activeOverflowCount + additionalNotifications.size
+ } else {
+ additionalNotifications.size
}
- return additionalNotifications.size();
}
- public int getNewMessagesCount() {
- return activeNotifications.size() + additionalNotifications.size();
+ fun getContentForSummaryNotification(): List {
+ return activeNotifications.asSequence()
+ .map { it.content }
+ .take(MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION)
+ .toList()
}
- public boolean isSingleMessageNotification() {
- return activeNotifications.size() == 1;
+ fun getActiveNotificationIds(): IntArray {
+ return activeNotifications.map { it.notificationId }.toIntArray()
}
- public NotificationHolder getHolderForLatestNotification() {
- return activeNotifications.getFirst();
- }
-
- public List getContentForSummaryNotification() {
- int size = calculateNumberOfMessagesForSummaryNotification();
- List result = new ArrayList<>(size);
-
- Iterator iterator = activeNotifications.iterator();
- int notificationCount = 0;
- while (iterator.hasNext() && notificationCount < MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION) {
- NotificationHolder holder = iterator.next();
- result.add(holder.content);
- notificationCount++;
- }
-
- return result;
- }
+ fun removeNotificationForMessage(messageReference: MessageReference): RemoveNotificationResult {
+ val holder = getNotificationHolderForMessage(messageReference)
+ ?: return RemoveNotificationResult.unknownNotification()
- private int calculateNumberOfMessagesForSummaryNotification() {
- return Math.min(activeNotifications.size(), MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION);
- }
+ activeNotifications.remove(holder)
- public int[] getActiveNotificationIds() {
- int size = activeNotifications.size();
- int[] notificationIds = new int[size];
+ val notificationId = holder.notificationId
+ markNotificationIdAsFree(notificationId)
- for (int i = 0; i < size; i++) {
- NotificationHolder holder = activeNotifications.get(i);
- notificationIds[i] = holder.notificationId;
+ return if (additionalNotifications.isEmpty()) {
+ RemoveNotificationResult.cancelNotification(notificationId)
+ } else {
+ val newContent = additionalNotifications.removeFirst()
+ val replacement = createNotificationHolder(notificationId, newContent)
+ activeNotifications.addLast(replacement)
+ RemoveNotificationResult.createNotification(replacement)
}
-
- return notificationIds;
}
- public RemoveNotificationResult removeNotificationForMessage(MessageReference messageReference) {
- NotificationHolder holder = getNotificationHolderForMessage(messageReference);
- if (holder == null) {
- return RemoveNotificationResult.unknownNotification();
- }
-
- activeNotifications.remove(holder);
+ private fun getNotificationHolderForMessage(messageReference: MessageReference): NotificationHolder? {
+ return activeNotifications.firstOrNull { it.content.messageReference == messageReference }
+ }
- int notificationId = holder.notificationId;
- markNotificationIdAsFree(notificationId);
+ fun getAllMessageReferences(): ArrayList {
+ val newSize = activeNotifications.size + additionalNotifications.size
+ val messageReferences = ArrayList(newSize)
- if (!additionalNotifications.isEmpty()) {
- NotificationContent newContent = additionalNotifications.removeFirst();
- NotificationHolder replacement = createNotificationHolder(notificationId, newContent);
- activeNotifications.addLast(replacement);
- return RemoveNotificationResult.createNotification(replacement);
+ for (holder in activeNotifications) {
+ messageReferences.add(holder.content.messageReference)
}
- return RemoveNotificationResult.cancelNotification(notificationId);
- }
-
- private NotificationHolder getNotificationHolderForMessage(MessageReference messageReference) {
- for (NotificationHolder holder : activeNotifications) {
- if (messageReference.equals(holder.content.messageReference)) {
- return holder;
- }
+ for (content in additionalNotifications) {
+ messageReferences.add(content.messageReference)
}
- return null;
- }
-
- public Account getAccount() {
- return account;
+ return messageReferences
}
- public int getUnreadMessageCount() {
- return unreadMessageCount + getNewMessagesCount();
- }
-
- public void setUnreadMessageCount(int unreadMessageCount) {
- this.unreadMessageCount = unreadMessageCount;
- }
-
- public ArrayList getAllMessageReferences() {
- int newSize = activeNotifications.size() + additionalNotifications.size();
- ArrayList messageReferences = new ArrayList<>(newSize);
-
- for (NotificationHolder holder : activeNotifications) {
- messageReferences.add(holder.content.messageReference);
- }
-
- for (NotificationContent content : additionalNotifications) {
- messageReferences.add(content.messageReference);
- }
+ companion object {
+ // Note: As of Jellybean, phone notifications show a maximum of 5 lines, while tablet notifications show 7 lines.
+ const val MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION = 5
- return messageReferences;
+ // Note: This class assumes MAX_NUMBER_OF_STACKED_NOTIFICATIONS >= MAX_NUMBER_OF_MESSAGES_FOR_SUMMARY_NOTIFICATION
+ const val MAX_NUMBER_OF_STACKED_NOTIFICATIONS = 8
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt
index 7d95f50feb..14c150cd27 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationGroupKeys.kt
@@ -1,14 +1,12 @@
-package com.fsck.k9.notification;
+package com.fsck.k9.notification
+import com.fsck.k9.Account
-import com.fsck.k9.Account;
+object NotificationGroupKeys {
+ private const val NOTIFICATION_GROUP_KEY_PREFIX = "newMailNotifications-"
-
-public class NotificationGroupKeys {
- private static final String NOTIFICATION_GROUP_KEY_PREFIX = "newMailNotifications-";
-
-
- public static String getGroupKey(Account account) {
- return NOTIFICATION_GROUP_KEY_PREFIX + account.getAccountNumber();
+ @JvmStatic
+ fun getGroupKey(account: Account): String {
+ return NOTIFICATION_GROUP_KEY_PREFIX + account.accountNumber
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt
index b1acf555fb..d60dfb635a 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationHolder.kt
@@ -1,13 +1,6 @@
-package com.fsck.k9.notification;
+package com.fsck.k9.notification
-
-class NotificationHolder {
- public final int notificationId;
- public final NotificationContent content;
-
-
- public NotificationHolder(int notificationId, NotificationContent content) {
- this.notificationId = notificationId;
- this.content = content;
- }
-}
+internal class NotificationHolder(
+ val notificationId: Int,
+ val content: NotificationContent
+)
diff --git a/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt b/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt
index e74d7de2f3..fd0c5d2cba 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/NotificationIds.kt
@@ -1,61 +1,62 @@
-package com.fsck.k9.notification;
-
-
-import com.fsck.k9.Account;
-
-
-class NotificationIds {
- public static final int PUSH_NOTIFICATION_ID = 1;
- private static final int NUMBER_OF_GENERAL_NOTIFICATIONS = 1;
-
- private static final int OFFSET_SEND_FAILED_NOTIFICATION = 0;
- private static final int OFFSET_CERTIFICATE_ERROR_INCOMING = 1;
- private static final int OFFSET_CERTIFICATE_ERROR_OUTGOING = 2;
- private static final int OFFSET_AUTHENTICATION_ERROR_INCOMING = 3;
- private static final int OFFSET_AUTHENTICATION_ERROR_OUTGOING = 4;
- private static final int OFFSET_FETCHING_MAIL = 5;
- private static final int OFFSET_NEW_MAIL_SUMMARY = 6;
-
- private static final int OFFSET_NEW_MAIL_STACKED = 7;
-
- private static final int NUMBER_OF_DEVICE_NOTIFICATIONS = 7;
- private static final int NUMBER_OF_STACKED_NOTIFICATIONS = NotificationData.MAX_NUMBER_OF_STACKED_NOTIFICATIONS;
- private static final int NUMBER_OF_NOTIFICATIONS_PER_ACCOUNT = NUMBER_OF_DEVICE_NOTIFICATIONS +
- NUMBER_OF_STACKED_NOTIFICATIONS;
-
-
- public static int getNewMailSummaryNotificationId(Account account) {
- return getBaseNotificationId(account) + OFFSET_NEW_MAIL_SUMMARY;
+package com.fsck.k9.notification
+
+import com.fsck.k9.Account
+
+internal object NotificationIds {
+ const val PUSH_NOTIFICATION_ID = 1
+
+ private const val NUMBER_OF_GENERAL_NOTIFICATIONS = 1
+ private const val OFFSET_SEND_FAILED_NOTIFICATION = 0
+ private const val OFFSET_CERTIFICATE_ERROR_INCOMING = 1
+ private const val OFFSET_CERTIFICATE_ERROR_OUTGOING = 2
+ private const val OFFSET_AUTHENTICATION_ERROR_INCOMING = 3
+ private const val OFFSET_AUTHENTICATION_ERROR_OUTGOING = 4
+ private const val OFFSET_FETCHING_MAIL = 5
+ private const val OFFSET_NEW_MAIL_SUMMARY = 6
+ private const val OFFSET_NEW_MAIL_STACKED = 7
+ private const val NUMBER_OF_DEVICE_NOTIFICATIONS = 7
+ private const val NUMBER_OF_STACKED_NOTIFICATIONS = NotificationData.MAX_NUMBER_OF_STACKED_NOTIFICATIONS
+ private const val NUMBER_OF_NOTIFICATIONS_PER_ACCOUNT =
+ NUMBER_OF_DEVICE_NOTIFICATIONS + NUMBER_OF_STACKED_NOTIFICATIONS
+
+ @JvmStatic
+ fun getNewMailSummaryNotificationId(account: Account): Int {
+ return getBaseNotificationId(account) + OFFSET_NEW_MAIL_SUMMARY
}
- public static int getNewMailStackedNotificationId(Account account, int index) {
- if (index < 0 || index >= NUMBER_OF_STACKED_NOTIFICATIONS) {
- throw new IndexOutOfBoundsException("Invalid value: " + index);
- }
+ @JvmStatic
+ fun getNewMailStackedNotificationId(account: Account, index: Int): Int {
+ require(index in 0 until NUMBER_OF_STACKED_NOTIFICATIONS) { "Invalid index: $index" }
- return getBaseNotificationId(account) + OFFSET_NEW_MAIL_STACKED + index;
+ return getBaseNotificationId(account) + OFFSET_NEW_MAIL_STACKED + index
}
- public static int getFetchingMailNotificationId(Account account) {
- return getBaseNotificationId(account) + OFFSET_FETCHING_MAIL;
+ @JvmStatic
+ fun getFetchingMailNotificationId(account: Account): Int {
+ return getBaseNotificationId(account) + OFFSET_FETCHING_MAIL
}
- public static int getSendFailedNotificationId(Account account) {
- return getBaseNotificationId(account) + OFFSET_SEND_FAILED_NOTIFICATION;
+ @JvmStatic
+ fun getSendFailedNotificationId(account: Account): Int {
+ return getBaseNotificationId(account) + OFFSET_SEND_FAILED_NOTIFICATION
}
- public static int getCertificateErrorNotificationId(Account account, boolean incoming) {
- int offset = incoming ? OFFSET_CERTIFICATE_ERROR_INCOMING : OFFSET_CERTIFICATE_ERROR_OUTGOING;
- return getBaseNotificationId(account) + offset;
+ @JvmStatic
+ fun getCertificateErrorNotificationId(account: Account, incoming: Boolean): Int {
+ val offset = if (incoming) OFFSET_CERTIFICATE_ERROR_INCOMING else OFFSET_CERTIFICATE_ERROR_OUTGOING
+
+ return getBaseNotificationId(account) + offset
}
- public static int getAuthenticationErrorNotificationId(Account account, boolean incoming) {
- int offset = incoming ? OFFSET_AUTHENTICATION_ERROR_INCOMING : OFFSET_AUTHENTICATION_ERROR_OUTGOING;
- return getBaseNotificationId(account) + offset;
+ @JvmStatic
+ fun getAuthenticationErrorNotificationId(account: Account, incoming: Boolean): Int {
+ val offset = if (incoming) OFFSET_AUTHENTICATION_ERROR_INCOMING else OFFSET_AUTHENTICATION_ERROR_OUTGOING
+
+ return getBaseNotificationId(account) + offset
}
- private static int getBaseNotificationId(Account account) {
+ private fun getBaseNotificationId(account: Account): Int {
return 1 /* skip notification ID 0 */ + NUMBER_OF_GENERAL_NOTIFICATIONS +
- account.getAccountNumber() * NUMBER_OF_NOTIFICATIONS_PER_ACCOUNT;
+ account.accountNumber * NUMBER_OF_NOTIFICATIONS_PER_ACCOUNT
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt b/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt
index 7b57b0442c..36e3134da8 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/RemoveNotificationResult.kt
@@ -1,54 +1,45 @@
-package com.fsck.k9.notification;
-
-
-class RemoveNotificationResult {
- private final NotificationHolder notificationHolder;
- private final int notificationId;
- private final boolean unknownNotification;
-
-
- private RemoveNotificationResult(NotificationHolder notificationHolder, int notificationId,
- boolean unknownNotification) {
- this.notificationHolder = notificationHolder;
- this.notificationId = notificationId;
- this.unknownNotification = unknownNotification;
- }
-
- public static RemoveNotificationResult createNotification(NotificationHolder notificationHolder) {
- return new RemoveNotificationResult(notificationHolder, notificationHolder.notificationId, false);
- }
-
- public static RemoveNotificationResult cancelNotification(int notificationId) {
- return new RemoveNotificationResult(null, notificationId, false);
- }
-
- public static RemoveNotificationResult unknownNotification() {
- return new RemoveNotificationResult(null, 0, true);
- }
-
- public boolean shouldCreateNotification() {
- return notificationHolder != null;
- }
-
- public int getNotificationId() {
- if (isUnknownNotification()) {
- throw new IllegalStateException("getNotificationId() can only be called when " +
- "isUnknownNotification() returns false");
+package com.fsck.k9.notification
+
+internal class RemoveNotificationResult private constructor(
+ private val holder: NotificationHolder?,
+ notificationId: Int,
+ val isUnknownNotification: Boolean
+) {
+ val notificationId: Int = notificationId
+ get() {
+ check(!isUnknownNotification) { "isUnknownNotification == true" }
+ return field
}
- return notificationId;
- }
-
- public boolean isUnknownNotification() {
- return unknownNotification;
- }
+ @get:JvmName("shouldCreateNotification")
+ val shouldCreateNotification: Boolean
+ get() = holder != null
+
+ val notificationHolder: NotificationHolder
+ get() = holder ?: error("shouldCreateNotification == false")
+
+ companion object {
+ @JvmStatic
+ fun createNotification(notificationHolder: NotificationHolder): RemoveNotificationResult {
+ return RemoveNotificationResult(
+ holder = notificationHolder,
+ notificationId = notificationHolder.notificationId,
+ isUnknownNotification = false
+ )
+ }
- public NotificationHolder getNotificationHolder() {
- if (!shouldCreateNotification()) {
- throw new IllegalStateException("getNotificationHolder() can only be called when " +
- "shouldCreateNotification() returns true");
+ @JvmStatic
+ fun cancelNotification(notificationId: Int): RemoveNotificationResult {
+ return RemoveNotificationResult(
+ holder = null,
+ notificationId = notificationId,
+ isUnknownNotification = false
+ )
}
- return notificationHolder;
+ @JvmStatic
+ fun unknownNotification(): RemoveNotificationResult {
+ return RemoveNotificationResult(holder = null, notificationId = 0, isUnknownNotification = true)
+ }
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt
index 2bb63cd5e9..176704aa1b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/SendFailedNotifications.kt
@@ -1,64 +1,54 @@
-package com.fsck.k9.notification;
-
-
-import android.app.PendingIntent;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.BigTextStyle;
-import androidx.core.app.NotificationManagerCompat;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.helper.ExceptionHelper;
-
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_BLINK_FAST;
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR;
-
-
-class SendFailedNotifications {
- private final NotificationHelper notificationHelper;
- private final NotificationActionCreator actionBuilder;
- private final NotificationResourceProvider resourceProvider;
-
-
- public SendFailedNotifications(NotificationHelper notificationHelper, NotificationActionCreator actionBuilder,
- NotificationResourceProvider resourceProvider) {
- this.notificationHelper = notificationHelper;
- this.actionBuilder = actionBuilder;
- this.resourceProvider = resourceProvider;
+package com.fsck.k9.notification
+
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.fsck.k9.Account
+import com.fsck.k9.helper.ExceptionHelper
+
+internal class SendFailedNotifications(
+ private val notificationHelper: NotificationHelper,
+ private val actionBuilder: NotificationActionCreator,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun showSendFailedNotification(account: Account, exception: Exception) {
+ val title = resourceProvider.sendFailedTitle()
+ val text = ExceptionHelper.getRootCauseMessage(exception)
+
+ val notificationId = NotificationIds.getSendFailedNotificationId(account)
+ val folderListPendingIntent = actionBuilder.createViewFolderListPendingIntent(
+ account, notificationId
+ )
+
+ val notificationBuilder = notificationHelper
+ .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
+ .setSmallIcon(resourceProvider.iconWarning)
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(folderListPendingIntent)
+ .setStyle(NotificationCompat.BigTextStyle().bigText(text))
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_ERROR)
+
+ notificationHelper.configureNotification(
+ builder = notificationBuilder,
+ ringtone = null,
+ vibrationPattern = null,
+ ledColor = NotificationHelper.NOTIFICATION_LED_FAILURE_COLOR,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
+ ringAndVibrate = true
+ )
+
+ notificationManager.notify(notificationId, notificationBuilder.build())
}
- public void showSendFailedNotification(Account account, Exception exception) {
- String title = resourceProvider.sendFailedTitle();
- String text = ExceptionHelper.getRootCauseMessage(exception);
-
- int notificationId = NotificationIds.getSendFailedNotificationId(account);
- PendingIntent folderListPendingIntent = actionBuilder.createViewFolderListPendingIntent(
- account, notificationId);
-
- NotificationCompat.Builder builder = notificationHelper
- .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
- .setSmallIcon(resourceProvider.getIconWarning())
- .setWhen(System.currentTimeMillis())
- .setAutoCancel(true)
- .setTicker(title)
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(folderListPendingIntent)
- .setStyle(new BigTextStyle().bigText(text))
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCategory(NotificationCompat.CATEGORY_ERROR);
-
- notificationHelper.configureNotification(builder, null, null, NOTIFICATION_LED_FAILURE_COLOR,
- NOTIFICATION_LED_BLINK_FAST, true);
-
- getNotificationManager().notify(notificationId, builder.build());
+ fun clearSendFailedNotification(account: Account) {
+ val notificationId = NotificationIds.getSendFailedNotificationId(account)
+ notificationManager.cancel(notificationId)
}
- public void clearSendFailedNotification(Account account) {
- int notificationId = NotificationIds.getSendFailedNotificationId(account);
- getNotificationManager().cancel(notificationId);
- }
-
- private NotificationManagerCompat getNotificationManager() {
- return notificationHelper.getNotificationManager();
- }
+ private val notificationManager: NotificationManagerCompat
+ get() = notificationHelper.getNotificationManager()
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt
index 16a5888203..2224981b3b 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/SyncNotifications.kt
@@ -1,108 +1,104 @@
-package com.fsck.k9.notification;
-
-
-import android.app.PendingIntent;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationManagerCompat;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.mailstore.LocalFolder;
-
-import static com.fsck.k9.notification.NotificationHelper.NOTIFICATION_LED_BLINK_FAST;
-
-
-class SyncNotifications {
- private static final boolean NOTIFICATION_LED_WHILE_SYNCING = false;
-
-
- private final NotificationHelper notificationHelper;
- private final NotificationActionCreator actionBuilder;
- private final NotificationResourceProvider resourceProvider;
-
-
- public SyncNotifications(NotificationHelper notificationHelper, NotificationActionCreator actionBuilder,
- NotificationResourceProvider resourceProvider) {
- this.notificationHelper = notificationHelper;
- this.actionBuilder = actionBuilder;
- this.resourceProvider = resourceProvider;
- }
-
- public void showSendingNotification(Account account) {
- String accountName = notificationHelper.getAccountName(account);
- String title = resourceProvider.sendingMailTitle();
- String tickerText = resourceProvider.sendingMailBody(accountName);
-
- int notificationId = NotificationIds.getFetchingMailNotificationId(account);
- long outboxFolderId = account.getOutboxFolderId();
- PendingIntent showMessageListPendingIntent = actionBuilder.createViewFolderPendingIntent(
- account, outboxFolderId, notificationId);
-
- NotificationCompat.Builder builder = notificationHelper.createNotificationBuilder(account,
- NotificationChannelManager.ChannelType.MISCELLANEOUS)
- .setSmallIcon(resourceProvider.getIconSendingMail())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setTicker(tickerText)
- .setContentTitle(title)
- .setContentText(accountName)
- .setContentIntent(showMessageListPendingIntent)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+package com.fsck.k9.notification
+
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.fsck.k9.Account
+import com.fsck.k9.mailstore.LocalFolder
+
+private const val NOTIFICATION_LED_WHILE_SYNCING = false
+
+internal class SyncNotifications(
+ private val notificationHelper: NotificationHelper,
+ private val actionBuilder: NotificationActionCreator,
+ private val resourceProvider: NotificationResourceProvider
+) {
+ fun showSendingNotification(account: Account) {
+ val accountName = notificationHelper.getAccountName(account)
+ val title = resourceProvider.sendingMailTitle()
+ val tickerText = resourceProvider.sendingMailBody(accountName)
+
+ val notificationId = NotificationIds.getFetchingMailNotificationId(account)
+ val outboxFolderId = account.outboxFolderId ?: error("Outbox folder not configured")
+ val showMessageListPendingIntent = actionBuilder.createViewFolderPendingIntent(
+ account, outboxFolderId, notificationId
+ )
+
+ val notificationBuilder = notificationHelper
+ .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
+ .setSmallIcon(resourceProvider.iconSendingMail)
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setTicker(tickerText)
+ .setContentTitle(title)
+ .setContentText(accountName)
+ .setContentIntent(showMessageListPendingIntent)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (NOTIFICATION_LED_WHILE_SYNCING) {
- notificationHelper.configureNotification(builder, null, null,
- account.getNotificationSetting().getLedColor(),
- NOTIFICATION_LED_BLINK_FAST, true);
+ notificationHelper.configureNotification(
+ builder = notificationBuilder,
+ ringtone = null,
+ vibrationPattern = null,
+ ledColor = account.notificationSetting.ledColor,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
+ ringAndVibrate = true
+ )
}
- getNotificationManager().notify(notificationId, builder.build());
+ notificationManager.notify(notificationId, notificationBuilder.build())
}
- public void clearSendingNotification(Account account) {
- int notificationId = NotificationIds.getFetchingMailNotificationId(account);
- getNotificationManager().cancel(notificationId);
+ fun clearSendingNotification(account: Account) {
+ val notificationId = NotificationIds.getFetchingMailNotificationId(account)
+ notificationManager.cancel(notificationId)
}
- public void showFetchingMailNotification(Account account, LocalFolder folder) {
- String accountName = account.getDescription();
- long folderId = folder.getDatabaseId();
- String folderName = folder.getName();
-
- String tickerText = resourceProvider.checkingMailTicker(accountName, folderName);
- String title = resourceProvider.checkingMailTitle();
- //TODO: Use format string from resources
- String text = accountName + resourceProvider.checkingMailSeparator() + folderName;
-
- int notificationId = NotificationIds.getFetchingMailNotificationId(account);
- PendingIntent showMessageListPendingIntent = actionBuilder.createViewFolderPendingIntent(
- account, folderId, notificationId);
-
- NotificationCompat.Builder builder = notificationHelper.createNotificationBuilder(account,
- NotificationChannelManager.ChannelType.MISCELLANEOUS)
- .setSmallIcon(resourceProvider.getIconCheckingMail())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setTicker(tickerText)
- .setContentTitle(title)
- .setContentText(text)
- .setContentIntent(showMessageListPendingIntent)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCategory(NotificationCompat.CATEGORY_SERVICE);
+ fun showFetchingMailNotification(account: Account, folder: LocalFolder) {
+ val accountName = account.description
+ val folderId = folder.databaseId
+ val folderName = folder.name
+ val tickerText = resourceProvider.checkingMailTicker(accountName, folderName)
+ val title = resourceProvider.checkingMailTitle()
+
+ // TODO: Use format string from resources
+ val text = accountName + resourceProvider.checkingMailSeparator() + folderName
+
+ val notificationId = NotificationIds.getFetchingMailNotificationId(account)
+ val showMessageListPendingIntent = actionBuilder.createViewFolderPendingIntent(
+ account, folderId, notificationId
+ )
+
+ val notificationBuilder = notificationHelper
+ .createNotificationBuilder(account, NotificationChannelManager.ChannelType.MISCELLANEOUS)
+ .setSmallIcon(resourceProvider.iconCheckingMail)
+ .setWhen(System.currentTimeMillis())
+ .setOngoing(true)
+ .setTicker(tickerText)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setContentIntent(showMessageListPendingIntent)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_SERVICE)
if (NOTIFICATION_LED_WHILE_SYNCING) {
- notificationHelper.configureNotification(builder, null, null,
- account.getNotificationSetting().getLedColor(),
- NOTIFICATION_LED_BLINK_FAST, true);
+ notificationHelper.configureNotification(
+ builder = notificationBuilder,
+ ringtone = null,
+ vibrationPattern = null,
+ ledColor = account.notificationSetting.ledColor,
+ ledSpeed = NotificationHelper.NOTIFICATION_LED_BLINK_FAST,
+ ringAndVibrate = true
+ )
}
- getNotificationManager().notify(notificationId, builder.build());
+ notificationManager.notify(notificationId, notificationBuilder.build())
}
- public void clearFetchingMailNotification(Account account) {
- int notificationId = NotificationIds.getFetchingMailNotificationId(account);
- getNotificationManager().cancel(notificationId);
+ fun clearFetchingMailNotification(account: Account) {
+ val notificationId = NotificationIds.getFetchingMailNotificationId(account)
+ notificationManager.cancel(notificationId)
}
- private NotificationManagerCompat getNotificationManager() {
- return notificationHelper.getNotificationManager();
- }
+ private val notificationManager: NotificationManagerCompat
+ get() = notificationHelper.getNotificationManager()
}
diff --git a/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt b/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt
index bfcd81e002..45f74df895 100644
--- a/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt
+++ b/app/core/src/main/java/com/fsck/k9/notification/WearNotifications.kt
@@ -1,254 +1,241 @@
-package com.fsck.k9.notification;
+package com.fsck.k9.notification
+import android.app.Notification
+import androidx.core.app.NotificationCompat
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.controller.MessagingController
+import com.fsck.k9.notification.NotificationIds.getNewMailSummaryNotificationId
-import java.util.ArrayList;
+internal open class WearNotifications(
+ notificationHelper: NotificationHelper,
+ actionCreator: NotificationActionCreator,
+ resourceProvider: NotificationResourceProvider
+) : BaseNotifications(notificationHelper, actionCreator, resourceProvider) {
-import android.app.Notification;
-import android.app.PendingIntent;
-import androidx.core.app.NotificationCompat;
-import androidx.core.app.NotificationCompat.Builder;
-import androidx.core.app.NotificationCompat.WearableExtender;
+ fun buildStackedNotification(account: Account, holder: NotificationHolder): Notification {
+ val notificationId = holder.notificationId
+ val content = holder.content
+ val builder = createBigTextStyleNotification(account, holder, notificationId)
+ builder.setNotificationSilent()
-import com.fsck.k9.Account;
-import com.fsck.k9.K9;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.controller.MessagingController;
+ val deletePendingIntent = actionCreator.createDismissMessagePendingIntent(
+ context, content.messageReference, holder.notificationId
+ )
+ builder.setDeleteIntent(deletePendingIntent)
+ addActions(builder, account, holder)
-class WearNotifications extends BaseNotifications {
-
- public WearNotifications(NotificationHelper notificationHelper, NotificationActionCreator actionCreator,
- NotificationResourceProvider resourceProvider) {
- super(notificationHelper, actionCreator, resourceProvider);
- }
-
- public Notification buildStackedNotification(Account account, NotificationHolder holder) {
- int notificationId = holder.notificationId;
- NotificationContent content = holder.content;
- NotificationCompat.Builder builder = createBigTextStyleNotification(account, holder, notificationId);
- builder.setNotificationSilent();
-
- PendingIntent deletePendingIntent = actionCreator.createDismissMessagePendingIntent(
- context, content.messageReference, holder.notificationId);
- builder.setDeleteIntent(deletePendingIntent);
-
- addActions(builder, account, holder);
-
- return builder.build();
+ return builder.build()
}
+ fun addSummaryActions(builder: NotificationCompat.Builder, notificationData: NotificationData) {
+ val wearableExtender = NotificationCompat.WearableExtender()
- public void addSummaryActions(Builder builder, NotificationData notificationData) {
- NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender();
-
- addMarkAllAsReadAction(wearableExtender, notificationData);
+ addMarkAllAsReadAction(wearableExtender, notificationData)
if (isDeleteActionAvailableForWear()) {
- addDeleteAllAction(wearableExtender, notificationData);
+ addDeleteAllAction(wearableExtender, notificationData)
}
- Account account = notificationData.getAccount();
- if (isArchiveActionAvailableForWear(account)) {
- addArchiveAllAction(wearableExtender, notificationData);
+ if (isArchiveActionAvailableForWear(notificationData.account)) {
+ addArchiveAllAction(wearableExtender, notificationData)
}
- builder.extend(wearableExtender);
+ builder.extend(wearableExtender)
}
- private void addMarkAllAsReadAction(WearableExtender wearableExtender, NotificationData notificationData) {
- int icon = resourceProvider.getWearIconMarkAsRead();
- String title = resourceProvider.actionMarkAllAsRead();
+ private fun addMarkAllAsReadAction(
+ wearableExtender: NotificationCompat.WearableExtender,
+ notificationData: NotificationData
+ ) {
+ val icon = resourceProvider.wearIconMarkAsRead
+ val title = resourceProvider.actionMarkAllAsRead()
+ val account = notificationData.account
+ val messageReferences = notificationData.getAllMessageReferences()
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val action = actionCreator.createMarkAllAsReadPendingIntent(account, messageReferences, notificationId)
+ val markAsReadAction = NotificationCompat.Action.Builder(icon, title, action).build()
- Account account = notificationData.getAccount();
- ArrayList messageReferences = notificationData.getAllMessageReferences();
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent action = actionCreator.createMarkAllAsReadPendingIntent(
- account, messageReferences, notificationId);
-
- NotificationCompat.Action markAsReadAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(markAsReadAction);
+ wearableExtender.addAction(markAsReadAction)
}
- private void addDeleteAllAction(WearableExtender wearableExtender, NotificationData notificationData) {
- int icon = resourceProvider.getWearIconDelete();
- String title = resourceProvider.actionDeleteAll();
-
- Account account = notificationData.getAccount();
- ArrayList messageReferences = notificationData.getAllMessageReferences();
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent action = actionCreator.createDeleteAllPendingIntent(account, messageReferences, notificationId);
+ private fun addDeleteAllAction(
+ wearableExtender: NotificationCompat.WearableExtender,
+ notificationData: NotificationData
+ ) {
+ val icon = resourceProvider.wearIconDelete
+ val title = resourceProvider.actionDeleteAll()
+ val account = notificationData.account
+ val messageReferences = notificationData.getAllMessageReferences()
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val action = actionCreator.createDeleteAllPendingIntent(account, messageReferences, notificationId)
+ val deleteAction = NotificationCompat.Action.Builder(icon, title, action).build()
- NotificationCompat.Action deleteAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(deleteAction);
+ wearableExtender.addAction(deleteAction)
}
- private void addArchiveAllAction(WearableExtender wearableExtender, NotificationData notificationData) {
- int icon = resourceProvider.getWearIconArchive();
- String title = resourceProvider.actionArchiveAll();
+ private fun addArchiveAllAction(
+ wearableExtender: NotificationCompat.WearableExtender,
+ notificationData: NotificationData
+ ) {
+ val icon = resourceProvider.wearIconArchive
+ val title = resourceProvider.actionArchiveAll()
+ val account = notificationData.account
+ val messageReferences = notificationData.getAllMessageReferences()
+ val notificationId = getNewMailSummaryNotificationId(account)
+ val action = actionCreator.createArchiveAllPendingIntent(account, messageReferences, notificationId)
+ val archiveAction = NotificationCompat.Action.Builder(icon, title, action).build()
- Account account = notificationData.getAccount();
- ArrayList messageReferences = notificationData.getAllMessageReferences();
- int notificationId = NotificationIds.getNewMailSummaryNotificationId(account);
- PendingIntent action = actionCreator.createArchiveAllPendingIntent(account, messageReferences, notificationId);
-
- NotificationCompat.Action archiveAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(archiveAction);
+ wearableExtender.addAction(archiveAction)
}
- private void addActions(Builder builder, Account account, NotificationHolder holder) {
- addDeviceActions(builder, holder);
- addWearActions(builder, account, holder);
+ private fun addActions(builder: NotificationCompat.Builder, account: Account, holder: NotificationHolder) {
+ addDeviceActions(builder, holder)
+ addWearActions(builder, account, holder)
}
- private void addDeviceActions(Builder builder, NotificationHolder holder) {
- addDeviceReplyAction(builder, holder);
- addDeviceMarkAsReadAction(builder, holder);
- addDeviceDeleteAction(builder, holder);
+ private fun addDeviceActions(builder: NotificationCompat.Builder, holder: NotificationHolder) {
+ addDeviceReplyAction(builder, holder)
+ addDeviceMarkAsReadAction(builder, holder)
+ addDeviceDeleteAction(builder, holder)
}
- private void addDeviceReplyAction(Builder builder, NotificationHolder holder) {
- int icon = resourceProvider.getIconReply();
- String title = resourceProvider.actionReply();
-
- NotificationContent content = holder.content;
- MessageReference messageReference = content.messageReference;
- PendingIntent replyToMessagePendingIntent =
- actionCreator.createReplyPendingIntent(messageReference, holder.notificationId);
+ private fun addDeviceReplyAction(builder: NotificationCompat.Builder, holder: NotificationHolder) {
+ val icon = resourceProvider.iconReply
+ val title = resourceProvider.actionReply()
+ val content = holder.content
+ val messageReference = content.messageReference
+ val replyToMessagePendingIntent =
+ actionCreator.createReplyPendingIntent(messageReference, holder.notificationId)
- builder.addAction(icon, title, replyToMessagePendingIntent);
+ builder.addAction(icon, title, replyToMessagePendingIntent)
}
- private void addDeviceMarkAsReadAction(Builder builder, NotificationHolder holder) {
- int icon = resourceProvider.getIconMarkAsRead();
- String title = resourceProvider.actionMarkAsRead();
-
- NotificationContent content = holder.content;
- int notificationId = holder.notificationId;
- MessageReference messageReference = content.messageReference;
- PendingIntent action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId);
+ private fun addDeviceMarkAsReadAction(builder: NotificationCompat.Builder, holder: NotificationHolder) {
+ val icon = resourceProvider.iconMarkAsRead
+ val title = resourceProvider.actionMarkAsRead()
+ val content = holder.content
+ val notificationId = holder.notificationId
+ val messageReference = content.messageReference
+ val action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId)
- builder.addAction(icon, title, action);
+ builder.addAction(icon, title, action)
}
- private void addDeviceDeleteAction(Builder builder, NotificationHolder holder) {
+ private fun addDeviceDeleteAction(builder: NotificationCompat.Builder, holder: NotificationHolder) {
if (!isDeleteActionEnabled()) {
- return;
+ return
}
- int icon = resourceProvider.getIconDelete();
- String title = resourceProvider.actionDelete();
+ val icon = resourceProvider.iconDelete
+ val title = resourceProvider.actionDelete()
+ val content = holder.content
+ val notificationId = holder.notificationId
+ val messageReference = content.messageReference
+ val action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId)
- NotificationContent content = holder.content;
- int notificationId = holder.notificationId;
- MessageReference messageReference = content.messageReference;
- PendingIntent action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId);
-
- builder.addAction(icon, title, action);
+ builder.addAction(icon, title, action)
}
- private void addWearActions(Builder builder, Account account, NotificationHolder holder) {
- NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender();
+ private fun addWearActions(builder: NotificationCompat.Builder, account: Account, holder: NotificationHolder) {
+ val wearableExtender = NotificationCompat.WearableExtender()
- addReplyAction(wearableExtender, holder);
- addMarkAsReadAction(wearableExtender, holder);
+ addReplyAction(wearableExtender, holder)
+ addMarkAsReadAction(wearableExtender, holder)
if (isDeleteActionAvailableForWear()) {
- addDeleteAction(wearableExtender, holder);
+ addDeleteAction(wearableExtender, holder)
}
if (isArchiveActionAvailableForWear(account)) {
- addArchiveAction(wearableExtender, holder);
+ addArchiveAction(wearableExtender, holder)
}
if (isSpamActionAvailableForWear(account)) {
- addMarkAsSpamAction(wearableExtender, holder);
+ addMarkAsSpamAction(wearableExtender, holder)
}
- builder.extend(wearableExtender);
+ builder.extend(wearableExtender)
}
- private void addReplyAction(WearableExtender wearableExtender, NotificationHolder holder) {
- int icon = resourceProvider.getWearIconReplyAll();
- String title = resourceProvider.actionReply();
-
- MessageReference messageReference = holder.content.messageReference;
- int notificationId = holder.notificationId;
- PendingIntent action = actionCreator.createReplyPendingIntent(messageReference, notificationId);
+ private fun addReplyAction(wearableExtender: NotificationCompat.WearableExtender, holder: NotificationHolder) {
+ val icon = resourceProvider.wearIconReplyAll
+ val title = resourceProvider.actionReply()
+ val messageReference = holder.content.messageReference
+ val notificationId = holder.notificationId
+ val action = actionCreator.createReplyPendingIntent(messageReference, notificationId)
+ val replyAction = NotificationCompat.Action.Builder(icon, title, action).build()
- NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(replyAction);
+ wearableExtender.addAction(replyAction)
}
- private void addMarkAsReadAction(WearableExtender wearableExtender, NotificationHolder holder) {
- int icon = resourceProvider.getWearIconMarkAsRead();
- String title = resourceProvider.actionMarkAsRead();
+ private fun addMarkAsReadAction(wearableExtender: NotificationCompat.WearableExtender, holder: NotificationHolder) {
+ val icon = resourceProvider.wearIconMarkAsRead
+ val title = resourceProvider.actionMarkAsRead()
+ val messageReference = holder.content.messageReference
+ val notificationId = holder.notificationId
+ val action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId)
+ val markAsReadAction = NotificationCompat.Action.Builder(icon, title, action).build()
- MessageReference messageReference = holder.content.messageReference;
- int notificationId = holder.notificationId;
- PendingIntent action = actionCreator.createMarkMessageAsReadPendingIntent(messageReference, notificationId);
-
- NotificationCompat.Action markAsReadAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(markAsReadAction);
+ wearableExtender.addAction(markAsReadAction)
}
- private void addDeleteAction(WearableExtender wearableExtender, NotificationHolder holder) {
- int icon = resourceProvider.getWearIconDelete();
- String title = resourceProvider.actionDelete();
-
- MessageReference messageReference = holder.content.messageReference;
- int notificationId = holder.notificationId;
- PendingIntent action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId);
+ private fun addDeleteAction(wearableExtender: NotificationCompat.WearableExtender, holder: NotificationHolder) {
+ val icon = resourceProvider.wearIconDelete
+ val title = resourceProvider.actionDelete()
+ val messageReference = holder.content.messageReference
+ val notificationId = holder.notificationId
+ val action = actionCreator.createDeleteMessagePendingIntent(messageReference, notificationId)
+ val deleteAction = NotificationCompat.Action.Builder(icon, title, action).build()
- NotificationCompat.Action deleteAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(deleteAction);
+ wearableExtender.addAction(deleteAction)
}
- private void addArchiveAction(WearableExtender wearableExtender, NotificationHolder holder) {
- int icon = resourceProvider.getWearIconArchive();
- String title = resourceProvider.actionArchive();
+ private fun addArchiveAction(wearableExtender: NotificationCompat.WearableExtender, holder: NotificationHolder) {
+ val icon = resourceProvider.wearIconArchive
+ val title = resourceProvider.actionArchive()
+ val messageReference = holder.content.messageReference
+ val notificationId = holder.notificationId
+ val action = actionCreator.createArchiveMessagePendingIntent(messageReference, notificationId)
+ val archiveAction = NotificationCompat.Action.Builder(icon, title, action).build()
- MessageReference messageReference = holder.content.messageReference;
- int notificationId = holder.notificationId;
- PendingIntent action = actionCreator.createArchiveMessagePendingIntent(messageReference, notificationId);
-
- NotificationCompat.Action archiveAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(archiveAction);
+ wearableExtender.addAction(archiveAction)
}
- private void addMarkAsSpamAction(WearableExtender wearableExtender, NotificationHolder holder) {
- int icon = resourceProvider.getWearIconMarkAsSpam();
- String title = resourceProvider.actionMarkAsSpam();
-
- MessageReference messageReference = holder.content.messageReference;
- int notificationId = holder.notificationId;
- PendingIntent action = actionCreator.createMarkMessageAsSpamPendingIntent(messageReference, notificationId);
+ private fun addMarkAsSpamAction(wearableExtender: NotificationCompat.WearableExtender, holder: NotificationHolder) {
+ val icon = resourceProvider.wearIconMarkAsSpam
+ val title = resourceProvider.actionMarkAsSpam()
+ val messageReference = holder.content.messageReference
+ val notificationId = holder.notificationId
+ val action = actionCreator.createMarkMessageAsSpamPendingIntent(messageReference, notificationId)
+ val spamAction = NotificationCompat.Action.Builder(icon, title, action).build()
- NotificationCompat.Action spamAction = new NotificationCompat.Action.Builder(icon, title, action).build();
- wearableExtender.addAction(spamAction);
+ wearableExtender.addAction(spamAction)
}
- private boolean isDeleteActionAvailableForWear() {
- return isDeleteActionEnabled() && !K9.isConfirmDeleteFromNotification();
+ private fun isDeleteActionAvailableForWear(): Boolean {
+ return isDeleteActionEnabled() && !K9.isConfirmDeleteFromNotification
}
- private boolean isArchiveActionAvailableForWear(Account account) {
- return isMovePossible(account, account.getArchiveFolderId());
+ private fun isArchiveActionAvailableForWear(account: Account): Boolean {
+ return isMovePossible(account, account.archiveFolderId)
}
- private boolean isSpamActionAvailableForWear(Account account) {
- return !K9.isConfirmSpam() && isMovePossible(account, account.getSpamFolderId());
+ private fun isSpamActionAvailableForWear(account: Account): Boolean {
+ return !K9.isConfirmSpam && isMovePossible(account, account.spamFolderId)
}
- private boolean isMovePossible(Account account, Long destinationFolderId) {
+ private fun isMovePossible(account: Account, destinationFolderId: Long?): Boolean {
if (destinationFolderId == null) {
- return false;
+ return false
}
- MessagingController controller = createMessagingController();
- return controller.isMoveCapable(account);
+ val controller = createMessagingController()
+ return controller.isMoveCapable(account)
}
- MessagingController createMessagingController() {
- return MessagingController.getInstance(context);
+ protected open fun createMessagingController(): MessagingController {
+ return MessagingController.getInstance(context)
}
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/AddNotificationResultTest.java b/app/core/src/test/java/com/fsck/k9/notification/AddNotificationResultTest.java
index 3dbc35b559..b97decf3d6 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/AddNotificationResultTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/AddNotificationResultTest.java
@@ -1,6 +1,7 @@
package com.fsck.k9.notification;
+import com.fsck.k9.controller.MessageReference;
import org.junit.Before;
import org.junit.Test;
@@ -18,7 +19,10 @@ public class AddNotificationResultTest {
@Before
public void setUp() throws Exception {
- notificationHolder = new NotificationHolder(NOTIFICATION_ID, null);
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ NotificationContent notificationContent = new NotificationContent(messageReference, "irrelevant", "irrelevant",
+ "irrelevant", "irrelevant", false);
+ notificationHolder = new NotificationHolder(NOTIFICATION_ID, notificationContent);
}
@Test
diff --git a/app/core/src/test/java/com/fsck/k9/notification/AuthenticationErrorNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/AuthenticationErrorNotificationsTest.java
index 558b6983f5..af4966d45f 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/AuthenticationErrorNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/AuthenticationErrorNotificationsTest.java
@@ -141,7 +141,7 @@ public class AuthenticationErrorNotificationsTest extends RobolectricTest {
}
@Override
- PendingIntent createContentIntent(Account account, boolean incoming) {
+ protected PendingIntent createContentIntent(Account account, boolean incoming) {
return contentIntent;
}
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/BaseNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/BaseNotificationsTest.java
index 59624902ff..b1d2d2931b 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/BaseNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/BaseNotificationsTest.java
@@ -7,6 +7,7 @@ import androidx.core.app.NotificationCompat.Builder;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.K9.NotificationQuickDelete;
+import com.fsck.k9.controller.MessageReference;
import com.fsck.k9.testing.MockHelper;
import org.junit.Before;
import org.junit.Test;
@@ -97,7 +98,8 @@ public class BaseNotificationsTest {
}
private NotificationHolder createNotificationHolder(int notificationId) {
- NotificationContent content = new NotificationContent(null, SENDER, SUBJECT, NOTIFICATION_PREVIEW,
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ NotificationContent content = new NotificationContent(messageReference, SENDER, SUBJECT, NOTIFICATION_PREVIEW,
NOTIFICATION_SUMMARY, false);
return new NotificationHolder(notificationId, content);
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/CertificateErrorNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/CertificateErrorNotificationsTest.java
index c739b9395f..948951e79e 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/CertificateErrorNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/CertificateErrorNotificationsTest.java
@@ -142,7 +142,7 @@ public class CertificateErrorNotificationsTest extends RobolectricTest {
}
@Override
- PendingIntent createContentIntent(Account account, boolean incoming) {
+ protected PendingIntent createContentIntent(Account account, boolean incoming) {
return contentIntent;
}
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/DeviceNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/DeviceNotificationsTest.java
index f0f0fb185e..4993bb63d8 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/DeviceNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/DeviceNotificationsTest.java
@@ -17,6 +17,7 @@ import com.fsck.k9.K9.NotificationHideSubject;
import com.fsck.k9.K9.NotificationQuickDelete;
import com.fsck.k9.NotificationSetting;
import com.fsck.k9.RobolectricTest;
+import com.fsck.k9.controller.MessageReference;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -197,8 +198,11 @@ public class DeviceNotificationsTest extends RobolectricTest {
when(notificationData.getNewMessagesCount()).thenReturn(NEW_MESSAGE_COUNT);
when(notificationData.getAccount()).thenReturn(account);
- NotificationContent content = new NotificationContent(null, SENDER, SUBJECT, PREVIEW, SUMMARY, false);
- NotificationContent content2 = new NotificationContent(null, SENDER_2, SUBJECT_2, PREVIEW_2, SUMMARY_2, true);
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ NotificationContent content =
+ new NotificationContent(messageReference, SENDER, SUBJECT, PREVIEW, SUMMARY, false);
+ NotificationContent content2 =
+ new NotificationContent(messageReference, SENDER_2, SUBJECT_2, PREVIEW_2, SUMMARY_2, true);
List contents = Arrays.asList(content, content2);
when(notificationData.getContentForSummaryNotification()).thenReturn(contents);
diff --git a/app/core/src/test/java/com/fsck/k9/notification/LockScreenNotificationTest.java b/app/core/src/test/java/com/fsck/k9/notification/LockScreenNotificationTest.java
index 8de5dc4c6d..902f348fe7 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/LockScreenNotificationTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/LockScreenNotificationTest.java
@@ -11,6 +11,7 @@ import androidx.core.app.NotificationCompat.Builder;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.K9.LockScreenNotificationVisibility;
+import com.fsck.k9.controller.MessageReference;
import com.fsck.k9.testing.MockHelper;
import com.fsck.k9.RobolectricTest;
import org.junit.Before;
@@ -182,6 +183,7 @@ public class LockScreenNotificationTest extends RobolectricTest {
}
private NotificationContent createNotificationContent(String sender) {
- return new NotificationContent(null, sender, null, null, null, false);
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ return new NotificationContent(messageReference, sender, "irrelevant", "irrelevant", "irrelevant", false);
}
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/NewMailNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/NewMailNotificationsTest.java
index ed0a1d6a07..1858f88c8d 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/NewMailNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/NewMailNotificationsTest.java
@@ -285,7 +285,8 @@ public class NewMailNotificationsTest extends K9RobolectricTest {
}
private NotificationContent createNotificationContent() {
- return new NotificationContent(null, null, null, null, null, false);
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ return new NotificationContent(messageReference, "irrelevant", "irrelevant", "irrelevant", "irrelevant", false);
}
private NotificationHolder createNotificationHolder(NotificationContent content, int index) {
@@ -370,7 +371,7 @@ public class NewMailNotificationsTest extends K9RobolectricTest {
}
@Override
- NotificationData createNotificationData(Account account, int unreadMessageCount) {
+ protected NotificationData createNotificationData(Account account, int unreadMessageCount) {
return notificationData;
}
}
diff --git a/app/core/src/test/java/com/fsck/k9/notification/NotificationContentCreatorTest.java b/app/core/src/test/java/com/fsck/k9/notification/NotificationContentCreatorTest.java
index eeb1b230d5..e9c6f66300 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/NotificationContentCreatorTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/NotificationContentCreatorTest.java
@@ -53,12 +53,12 @@ public class NotificationContentCreatorTest extends RobolectricTest {
public void createFromMessage_withRegularMessage() throws Exception {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals(messageReference, content.messageReference);
- assertEquals(SENDER_NAME, content.sender);
- assertEquals(SUBJECT, content.subject);
- assertEquals(SUBJECT + "\n" + PREVIEW, content.preview.toString());
- assertEquals(SENDER_NAME + " " + SUBJECT, content.summary.toString());
- assertEquals(false, content.starred);
+ assertEquals(messageReference, content.getMessageReference());
+ assertEquals(SENDER_NAME, content.getSender());
+ assertEquals(SUBJECT, content.getSubject());
+ assertEquals(SUBJECT + "\n" + PREVIEW, content.getPreview().toString());
+ assertEquals(SENDER_NAME + " " + SUBJECT, content.getSummary().toString());
+ assertEquals(false, content.isStarred());
}
@Test
@@ -68,9 +68,9 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
String noSubject = "(No subject)";
- assertEquals(noSubject, content.subject);
- assertEquals(PREVIEW, content.preview.toString());
- assertEquals(SENDER_NAME + " " + noSubject, content.summary.toString());
+ assertEquals(noSubject, content.getSubject());
+ assertEquals(PREVIEW, content.getPreview().toString());
+ assertEquals(SENDER_NAME + " " + noSubject, content.getSummary().toString());
}
@Test
@@ -80,8 +80,8 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals(SUBJECT, content.subject);
- assertEquals(SUBJECT, content.preview.toString());
+ assertEquals(SUBJECT, content.getSubject());
+ assertEquals(SUBJECT, content.getPreview().toString());
}
@Test
@@ -91,8 +91,8 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals(SUBJECT, content.subject);
- assertEquals(SUBJECT, content.preview.toString());
+ assertEquals(SUBJECT, content.getSubject());
+ assertEquals(SUBJECT, content.getPreview().toString());
}
@Test
@@ -103,8 +103,8 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
String encrypted = "*Encrypted*";
- assertEquals(SUBJECT, content.subject);
- assertEquals(SUBJECT + "\n" + encrypted, content.preview.toString());
+ assertEquals(SUBJECT, content.getSubject());
+ assertEquals(SUBJECT + "\n" + encrypted, content.getPreview().toString());
}
@Test
@@ -113,8 +113,8 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals("No sender", content.sender);
- assertEquals(SUBJECT, content.summary.toString());
+ assertEquals("No sender", content.getSender());
+ assertEquals(SUBJECT, content.getSummary().toString());
}
@Test
@@ -124,8 +124,8 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
String insteadOfSender = "To:Bob";
- assertEquals(insteadOfSender, content.sender);
- assertEquals(insteadOfSender + " " + SUBJECT, content.summary.toString());
+ assertEquals(insteadOfSender, content.getSender());
+ assertEquals(insteadOfSender + " " + SUBJECT, content.getSummary().toString());
}
@Test
@@ -134,7 +134,7 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals(true, content.starred);
+ assertEquals(true, content.isStarred());
}
@Test
@@ -146,10 +146,10 @@ public class NotificationContentCreatorTest extends RobolectricTest {
NotificationContent content = contentCreator.createFromMessage(account, message);
- assertEquals("No sender", content.sender);
- assertEquals("(No subject)", content.subject);
- assertEquals("(No subject)", content.preview.toString());
- assertEquals("(No subject)", content.summary.toString());
+ assertEquals("No sender", content.getSender());
+ assertEquals("(No subject)", content.getSubject());
+ assertEquals("(No subject)", content.getPreview().toString());
+ assertEquals("(No subject)", content.getSummary().toString());
}
private NotificationContentCreator createNotificationContentCreator() {
diff --git a/app/core/src/test/java/com/fsck/k9/notification/NotificationDataTest.java b/app/core/src/test/java/com/fsck/k9/notification/NotificationDataTest.java
index 9fc5456eb1..dba257686c 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/NotificationDataTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/NotificationDataTest.java
@@ -31,7 +31,7 @@ public class NotificationDataTest extends RobolectricTest {
@Before
public void setUp() throws Exception {
account = createFakeAccount();
- notificationData = new NotificationData(account);
+ notificationData = new NotificationData(account, 0);
}
@Test
@@ -43,8 +43,8 @@ public class NotificationDataTest extends RobolectricTest {
assertFalse(result.shouldCancelNotification());
NotificationHolder holder = result.getNotificationHolder();
assertNotNull(holder);
- assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 0), holder.notificationId);
- assertEquals(content, holder.content);
+ assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 0), holder.getNotificationId());
+ assertEquals(content, holder.getContent());
}
@Test
@@ -69,7 +69,7 @@ public class NotificationDataTest extends RobolectricTest {
NotificationContent content = createNotificationContent("1");
notificationData.addNotificationContent(content);
- RemoveNotificationResult result = notificationData.removeNotificationForMessage(content.messageReference);
+ RemoveNotificationResult result = notificationData.removeNotificationForMessage(content.getMessageReference());
assertFalse(result.isUnknownNotification());
assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 0), result.getNotificationId());
@@ -92,15 +92,15 @@ public class NotificationDataTest extends RobolectricTest {
notificationData.addNotificationContent(latestContent);
RemoveNotificationResult result =
- notificationData.removeNotificationForMessage(latestContent.messageReference);
+ notificationData.removeNotificationForMessage(latestContent.getMessageReference());
assertFalse(result.isUnknownNotification());
assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 1), result.getNotificationId());
assertTrue(result.shouldCreateNotification());
NotificationHolder holder = result.getNotificationHolder();
assertNotNull(holder);
- assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 1), holder.notificationId);
- assertEquals(content, holder.content);
+ assertEquals(NotificationIds.getNewMailStackedNotificationId(account, 1), holder.getNotificationId());
+ assertEquals(content, holder.getContent());
}
@Test
@@ -108,7 +108,7 @@ public class NotificationDataTest extends RobolectricTest {
for (int i = 1; i <= NotificationData.MAX_NUMBER_OF_STACKED_NOTIFICATIONS + 1; i++) {
NotificationContent content = createNotificationContent("" + i);
notificationData.addNotificationContent(content);
- notificationData.removeNotificationForMessage(content.messageReference);
+ notificationData.removeNotificationForMessage(content.getMessageReference());
}
}
@@ -127,7 +127,7 @@ public class NotificationDataTest extends RobolectricTest {
@Test
public void testUnreadMessagesCount() throws Exception {
- notificationData.setUnreadMessageCount(42);
+ notificationData = new NotificationData(account, 42);
assertEquals(42, notificationData.getUnreadMessageCount());
NotificationContent content = createNotificationContent("1");
diff --git a/app/core/src/test/java/com/fsck/k9/notification/RemoveNotificationResultTest.java b/app/core/src/test/java/com/fsck/k9/notification/RemoveNotificationResultTest.java
index 1a90b0594c..e2061ef659 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/RemoveNotificationResultTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/RemoveNotificationResultTest.java
@@ -1,6 +1,7 @@
package com.fsck.k9.notification;
+import com.fsck.k9.controller.MessageReference;
import org.junit.Before;
import org.junit.Test;
@@ -18,7 +19,10 @@ public class RemoveNotificationResultTest {
@Before
public void setUp() throws Exception {
- notificationHolder = new NotificationHolder(NOTIFICATION_ID, null);
+ MessageReference messageReference = new MessageReference("irrelevant", 1, "irrelevant", null);
+ NotificationContent notificationContent = new NotificationContent(messageReference, "irrelevant", "irrelevant",
+ "irrelevant", "irrelevant", false);
+ notificationHolder = new NotificationHolder(NOTIFICATION_ID, notificationContent);
}
@Test
diff --git a/app/core/src/test/java/com/fsck/k9/notification/WearNotificationsTest.java b/app/core/src/test/java/com/fsck/k9/notification/WearNotificationsTest.java
index ea830f9b3e..6b3ce870f7 100644
--- a/app/core/src/test/java/com/fsck/k9/notification/WearNotificationsTest.java
+++ b/app/core/src/test/java/com/fsck/k9/notification/WearNotificationsTest.java
@@ -254,7 +254,7 @@ public class WearNotificationsTest extends RobolectricTest {
}
private NotificationContent createNotificationContent(MessageReference messageReference) {
- return new NotificationContent(messageReference, null, null, null, null, false);
+ return new NotificationContent(messageReference, "irrelevant", "irrelevant", "irrelevant", "irrelevant", false);
}
private NotificationHolder createNotificationHolder(int notificationId, NotificationContent content) {
@@ -355,7 +355,7 @@ public class WearNotificationsTest extends RobolectricTest {
}
@Override
- MessagingController createMessagingController() {
+ protected MessagingController createMessagingController() {
return messagingController;
}
}
diff --git a/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt b/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
index 8773ca22af..5042e397b6 100644
--- a/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
+++ b/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
@@ -1,232 +1,235 @@
-package com.fsck.k9.notification;
-
-
-import java.util.List;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.DI;
-import com.fsck.k9.K9;
-import com.fsck.k9.activity.MessageList;
-import com.fsck.k9.ui.notification.DeleteConfirmationActivity;
-import com.fsck.k9.activity.compose.MessageActions;
-import com.fsck.k9.activity.setup.AccountSetupIncoming;
-import com.fsck.k9.activity.setup.AccountSetupOutgoing;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.search.AccountSearchConditions;
-import com.fsck.k9.search.LocalSearch;
-import com.fsck.k9.ui.messagelist.DefaultFolderProvider;
-
+package com.fsck.k9.notification
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.activity.MessageList
+import com.fsck.k9.activity.compose.MessageActions
+import com.fsck.k9.activity.setup.AccountSetupIncoming
+import com.fsck.k9.activity.setup.AccountSetupOutgoing
+import com.fsck.k9.controller.MessageReference
+import com.fsck.k9.search.LocalSearch
+import com.fsck.k9.ui.messagelist.DefaultFolderProvider
+import com.fsck.k9.ui.notification.DeleteConfirmationActivity
/**
- * This class contains methods to create the {@link PendingIntent}s for the actions of our notifications.
- *
- * Note:
- * We need to take special care to ensure the {@code PendingIntent}s are unique as defined in the documentation of
- * {@link PendingIntent}. Otherwise selecting a notification action might perform the action on the wrong message.
- *
- * We use the notification ID as {@code requestCode} argument to ensure each notification/action pair gets a unique
- * {@code PendingIntent}.
+ * This class contains methods to create the [PendingIntent]s for the actions of our notifications.
+ *
+ * **Note:**
+ * We need to take special care to ensure the `PendingIntent`s are unique as defined in the documentation of
+ * [PendingIntent]. Otherwise selecting a notification action might perform the action on the wrong message.
+ *
+ * We use the notification ID as `requestCode` argument to ensure each notification/action pair gets a unique
+ * `PendingIntent`.
*/
-class K9NotificationActionCreator implements NotificationActionCreator {
- private final Context context;
- private final DefaultFolderProvider defaultFolderProvider = DI.get(DefaultFolderProvider.class);
-
-
- public K9NotificationActionCreator(Context context) {
- this.context = context;
- }
-
- @Override
- public PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = createMessageViewIntent(messageReference);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- @Override
- public PendingIntent createViewFolderPendingIntent(Account account, long folderId, int notificationId) {
- Intent intent = createMessageListIntent(account, folderId);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- @Override
- public PendingIntent createViewMessagesPendingIntent(Account account, List messageReferences,
- int notificationId) {
-
- Long folderServerId = getFolderIdOfAllMessages(messageReferences);
-
- Intent intent;
- if (folderServerId == null) {
- intent = createMessageListIntent(account);
+internal class K9NotificationActionCreator(
+ private val context: Context,
+ private val defaultFolderProvider: DefaultFolderProvider
+) : NotificationActionCreator {
+
+ override fun createViewMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = createMessageViewIntent(messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
+
+ override fun createViewFolderPendingIntent(account: Account, folderId: Long, notificationId: Int): PendingIntent {
+ val intent = createMessageListIntent(account, folderId)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
+
+ override fun createViewMessagesPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val folderServerId = getFolderIdOfAllMessages(messageReferences)
+ val intent = if (folderServerId != null) {
+ createMessageListIntent(account, folderServerId)
} else {
- intent = createMessageListIntent(account, folderServerId);
+ createMessageListIntent(account)
}
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createViewFolderListPendingIntent(Account account, int notificationId) {
- Intent intent = createMessageListIntent(account);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createViewFolderListPendingIntent(account: Account, notificationId: Int): PendingIntent {
+ val intent = createMessageListIntent(account)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId) {
- Intent intent = NotificationActionService.createDismissAllMessagesIntent(context, account);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createDismissAllMessagesPendingIntent(account: Account, notificationId: Int): PendingIntent {
+ val intent = NotificationActionService.createDismissAllMessagesIntent(context, account)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
- int notificationId) {
-
- Intent intent = NotificationActionService.createDismissMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createDismissMessagePendingIntent(
+ context: Context,
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createDismissMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = MessageActions.getActionReplyIntent(context, messageReference);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createReplyPendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent {
+ val intent = MessageActions.getActionReplyIntent(context, messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkMessageAsReadPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkAllAsReadPendingIntent(Account account, List messageReferences,
- int notificationId) {
- String accountUuid = account.getUuid();
- Intent intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkAllAsReadPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val accountUuid = account.uuid
+ val intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent getEditIncomingServerSettingsIntent(Account account) {
- Intent intent = AccountSetupIncoming.intentActionEditIncomingSettings(context, account);
-
- return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun getEditIncomingServerSettingsIntent(account: Account): PendingIntent {
+ val intent = AccountSetupIncoming.intentActionEditIncomingSettings(context, account)
+ return PendingIntent.getActivity(context, account.accountNumber, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent getEditOutgoingServerSettingsIntent(Account account) {
- Intent intent = AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account);
-
- return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun getEditOutgoingServerSettingsIntent(account: Account): PendingIntent {
+ val intent = AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account)
+ return PendingIntent.getActivity(context, account.accountNumber, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId) {
- if (K9.isConfirmDeleteFromNotification()) {
- return createDeleteConfirmationPendingIntent(messageReference, notificationId);
+ override fun createDeleteMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ return if (K9.isConfirmDeleteFromNotification) {
+ createDeleteConfirmationPendingIntent(messageReference, notificationId)
} else {
- return createDeleteServicePendingIntent(messageReference, notificationId);
+ createDeleteServicePendingIntent(messageReference, notificationId)
}
}
- private PendingIntent createDeleteServicePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createDeleteMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun createDeleteServicePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createDeleteMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- private PendingIntent createDeleteConfirmationPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = DeleteConfirmationActivity.getIntent(context, messageReference);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun createDeleteConfirmationPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = DeleteConfirmationActivity.getIntent(context, messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDeleteAllPendingIntent(Account account, List messageReferences,
- int notificationId) {
- if (K9.isConfirmDeleteFromNotification()) {
- return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId);
+ override fun createDeleteAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ return if (K9.isConfirmDeleteFromNotification) {
+ getDeleteAllConfirmationPendingIntent(messageReferences, notificationId)
} else {
- return getDeleteAllServicePendingIntent(account, messageReferences, notificationId);
+ getDeleteAllServicePendingIntent(account, messageReferences, notificationId)
}
}
- private PendingIntent getDeleteAllConfirmationPendingIntent(List messageReferences,
- int notificationId) {
- Intent intent = DeleteConfirmationActivity.getIntent(context, messageReferences);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ private fun getDeleteAllConfirmationPendingIntent(
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = DeleteConfirmationActivity.getIntent(context, messageReferences)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT)
}
- private PendingIntent getDeleteAllServicePendingIntent(Account account, List messageReferences,
- int notificationId) {
- String accountUuid = account.getUuid();
- Intent intent = NotificationActionService.createDeleteAllMessagesIntent(
- context, accountUuid, messageReferences);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun getDeleteAllServicePendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val accountUuid = account.uuid
+ val intent = NotificationActionService.createDeleteAllMessagesIntent(context, accountUuid, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createArchiveMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createArchiveMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createArchiveMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createArchiveAllPendingIntent(Account account, List messageReferences,
- int notificationId) {
- Intent intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences);
+ override fun createArchiveAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkMessageAsSpamPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference);
+ private fun createMessageListIntent(account: Account): Intent {
+ val folderId = defaultFolderProvider.getDefaultFolder(account)
+ val search = LocalSearch().apply {
+ addAllowedFolder(folderId)
+ addAccountUuid(account.uuid)
+ }
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return MessageList.intentDisplaySearch(
+ context = context,
+ search = search,
+ noThreading = false,
+ newTask = true,
+ clearTop = true
+ )
}
- private Intent createMessageListIntent(Account account) {
- long folderId = defaultFolderProvider.getDefaultFolder(account);
- LocalSearch search = new LocalSearch();
- search.addAllowedFolder(folderId);
- search.addAccountUuid(account.getUuid());
- return MessageList.intentDisplaySearch(context, search, false, true, true);
- }
+ private fun createMessageListIntent(account: Account, folderId: Long): Intent {
+ val search = LocalSearch().apply {
+ addAllowedFolder(folderId)
+ addAccountUuid(account.uuid)
+ }
- private Intent createMessageListIntent(Account account, long folderId) {
- LocalSearch search = new LocalSearch();
- search.addAllowedFolder(folderId);
- search.addAccountUuid(account.getUuid());
- return MessageList.intentDisplaySearch(context, search, false, true, true);
+ return MessageList.intentDisplaySearch(
+ context = context,
+ search = search,
+ noThreading = false,
+ newTask = true,
+ clearTop = true
+ )
}
- private Intent createMessageViewIntent(MessageReference message) {
- return MessageList.actionDisplayMessageIntent(context, message);
+ private fun createMessageViewIntent(message: MessageReference): Intent {
+ return MessageList.actionDisplayMessageIntent(context, message)
}
- private Long getFolderIdOfAllMessages(List messageReferences) {
- MessageReference firstMessage = messageReferences.get(0);
- long folderId = firstMessage.getFolderId();
-
- for (MessageReference messageReference : messageReferences) {
- if (folderId != messageReference.getFolderId()) {
- return null;
- }
- }
+ private fun getFolderIdOfAllMessages(messageReferences: List): Long? {
+ val firstMessage = messageReferences.first()
+ val folderId = firstMessage.folderId
- return folderId;
+ return if (messageReferences.all { it.folderId == folderId }) folderId else null
}
}
diff --git a/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/KoinModule.kt b/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/KoinModule.kt
index ce46fad315..ac5ee21308 100644
--- a/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/KoinModule.kt
+++ b/app/k9mail-jmap/src/main/java/com/fsck/k9/notification/KoinModule.kt
@@ -3,7 +3,7 @@ package com.fsck.k9.notification
import org.koin.dsl.module
val notificationModule = module {
- single { K9NotificationActionCreator(get()) }
+ single { K9NotificationActionCreator(context = get(), defaultFolderProvider = get()) }
single { K9NotificationResourceProvider(get()) }
single { K9NotificationStrategy(get()) }
}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt b/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
index f0d8b471c8..5042e397b6 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/notification/K9NotificationActionCreator.kt
@@ -1,232 +1,235 @@
-package com.fsck.k9.notification;
-
-
-import java.util.List;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.DI;
-import com.fsck.k9.K9;
-import com.fsck.k9.activity.MessageList;
-import com.fsck.k9.controller.MessageReference;
-import com.fsck.k9.ui.notification.DeleteConfirmationActivity;
-import com.fsck.k9.activity.compose.MessageActions;
-import com.fsck.k9.activity.setup.AccountSetupIncoming;
-import com.fsck.k9.activity.setup.AccountSetupOutgoing;
-import com.fsck.k9.search.AccountSearchConditions;
-import com.fsck.k9.search.LocalSearch;
-import com.fsck.k9.ui.messagelist.DefaultFolderProvider;
-
+package com.fsck.k9.notification
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import com.fsck.k9.Account
+import com.fsck.k9.K9
+import com.fsck.k9.activity.MessageList
+import com.fsck.k9.activity.compose.MessageActions
+import com.fsck.k9.activity.setup.AccountSetupIncoming
+import com.fsck.k9.activity.setup.AccountSetupOutgoing
+import com.fsck.k9.controller.MessageReference
+import com.fsck.k9.search.LocalSearch
+import com.fsck.k9.ui.messagelist.DefaultFolderProvider
+import com.fsck.k9.ui.notification.DeleteConfirmationActivity
/**
- * This class contains methods to create the {@link PendingIntent}s for the actions of our notifications.
- *
- * Note:
- * We need to take special care to ensure the {@code PendingIntent}s are unique as defined in the documentation of
- * {@link PendingIntent}. Otherwise selecting a notification action might perform the action on the wrong message.
- *
- * We use the notification ID as {@code requestCode} argument to ensure each notification/action pair gets a unique
- * {@code PendingIntent}.
+ * This class contains methods to create the [PendingIntent]s for the actions of our notifications.
+ *
+ * **Note:**
+ * We need to take special care to ensure the `PendingIntent`s are unique as defined in the documentation of
+ * [PendingIntent]. Otherwise selecting a notification action might perform the action on the wrong message.
+ *
+ * We use the notification ID as `requestCode` argument to ensure each notification/action pair gets a unique
+ * `PendingIntent`.
*/
-class K9NotificationActionCreator implements NotificationActionCreator {
- private final Context context;
- private final DefaultFolderProvider defaultFolderProvider = DI.get(DefaultFolderProvider.class);
-
-
- public K9NotificationActionCreator(Context context) {
- this.context = context;
- }
-
- @Override
- public PendingIntent createViewMessagePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = createMessageViewIntent(messageReference);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- @Override
- public PendingIntent createViewFolderPendingIntent(Account account, long folderId, int notificationId) {
- Intent intent = createMessageListIntent(account, folderId);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- @Override
- public PendingIntent createViewMessagesPendingIntent(Account account, List messageReferences,
- int notificationId) {
-
- Long folderServerId = getFolderIdOfAllMessages(messageReferences);
-
- Intent intent;
- if (folderServerId == null) {
- intent = createMessageListIntent(account);
+internal class K9NotificationActionCreator(
+ private val context: Context,
+ private val defaultFolderProvider: DefaultFolderProvider
+) : NotificationActionCreator {
+
+ override fun createViewMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = createMessageViewIntent(messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
+
+ override fun createViewFolderPendingIntent(account: Account, folderId: Long, notificationId: Int): PendingIntent {
+ val intent = createMessageListIntent(account, folderId)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
+
+ override fun createViewMessagesPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val folderServerId = getFolderIdOfAllMessages(messageReferences)
+ val intent = if (folderServerId != null) {
+ createMessageListIntent(account, folderServerId)
} else {
- intent = createMessageListIntent(account, folderServerId);
+ createMessageListIntent(account)
}
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createViewFolderListPendingIntent(Account account, int notificationId) {
- Intent intent = createMessageListIntent(account);
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createViewFolderListPendingIntent(account: Account, notificationId: Int): PendingIntent {
+ val intent = createMessageListIntent(account)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDismissAllMessagesPendingIntent(Account account, int notificationId) {
- Intent intent = NotificationActionService.createDismissAllMessagesIntent(context, account);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createDismissAllMessagesPendingIntent(account: Account, notificationId: Int): PendingIntent {
+ val intent = NotificationActionService.createDismissAllMessagesIntent(context, account)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDismissMessagePendingIntent(Context context, MessageReference messageReference,
- int notificationId) {
-
- Intent intent = NotificationActionService.createDismissMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createDismissMessagePendingIntent(
+ context: Context,
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createDismissMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createReplyPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = MessageActions.getActionReplyIntent(context, messageReference);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createReplyPendingIntent(messageReference: MessageReference, notificationId: Int): PendingIntent {
+ val intent = MessageActions.getActionReplyIntent(context, messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkMessageAsReadPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkMessageAsReadPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createMarkMessageAsReadIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkAllAsReadPendingIntent(Account account, List messageReferences,
- int notificationId) {
- String accountUuid = account.getUuid();
- Intent intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkAllAsReadPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val accountUuid = account.uuid
+ val intent = NotificationActionService.createMarkAllAsReadIntent(context, accountUuid, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent getEditIncomingServerSettingsIntent(Account account) {
- Intent intent = AccountSetupIncoming.intentActionEditIncomingSettings(context, account);
-
- return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun getEditIncomingServerSettingsIntent(account: Account): PendingIntent {
+ val intent = AccountSetupIncoming.intentActionEditIncomingSettings(context, account)
+ return PendingIntent.getActivity(context, account.accountNumber, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent getEditOutgoingServerSettingsIntent(Account account) {
- Intent intent = AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account);
-
- return PendingIntent.getActivity(context, account.getAccountNumber(), intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun getEditOutgoingServerSettingsIntent(account: Account): PendingIntent {
+ val intent = AccountSetupOutgoing.intentActionEditOutgoingSettings(context, account)
+ return PendingIntent.getActivity(context, account.accountNumber, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDeleteMessagePendingIntent(MessageReference messageReference, int notificationId) {
- if (K9.isConfirmDeleteFromNotification()) {
- return createDeleteConfirmationPendingIntent(messageReference, notificationId);
+ override fun createDeleteMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ return if (K9.isConfirmDeleteFromNotification) {
+ createDeleteConfirmationPendingIntent(messageReference, notificationId)
} else {
- return createDeleteServicePendingIntent(messageReference, notificationId);
+ createDeleteServicePendingIntent(messageReference, notificationId)
}
}
- private PendingIntent createDeleteServicePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createDeleteMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun createDeleteServicePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createDeleteMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- private PendingIntent createDeleteConfirmationPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = DeleteConfirmationActivity.getIntent(context, messageReference);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun createDeleteConfirmationPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = DeleteConfirmationActivity.getIntent(context, messageReference)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createDeleteAllPendingIntent(Account account, List messageReferences,
- int notificationId) {
- if (K9.isConfirmDeleteFromNotification()) {
- return getDeleteAllConfirmationPendingIntent(messageReferences, notificationId);
+ override fun createDeleteAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ return if (K9.isConfirmDeleteFromNotification) {
+ getDeleteAllConfirmationPendingIntent(messageReferences, notificationId)
} else {
- return getDeleteAllServicePendingIntent(account, messageReferences, notificationId);
+ getDeleteAllServicePendingIntent(account, messageReferences, notificationId)
}
}
- private PendingIntent getDeleteAllConfirmationPendingIntent(List messageReferences,
- int notificationId) {
- Intent intent = DeleteConfirmationActivity.getIntent(context, messageReferences);
-
- return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ private fun getDeleteAllConfirmationPendingIntent(
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = DeleteConfirmationActivity.getIntent(context, messageReferences)
+ return PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT)
}
- private PendingIntent getDeleteAllServicePendingIntent(Account account, List messageReferences,
- int notificationId) {
- String accountUuid = account.getUuid();
- Intent intent = NotificationActionService.createDeleteAllMessagesIntent(
- context, accountUuid, messageReferences);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ private fun getDeleteAllServicePendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val accountUuid = account.uuid
+ val intent = NotificationActionService.createDeleteAllMessagesIntent(context, accountUuid, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createArchiveMessagePendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createArchiveMessageIntent(context, messageReference);
-
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createArchiveMessagePendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createArchiveMessageIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createArchiveAllPendingIntent(Account account, List messageReferences,
- int notificationId) {
- Intent intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences);
+ override fun createArchiveAllPendingIntent(
+ account: Account,
+ messageReferences: List,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createArchiveAllIntent(context, account, messageReferences)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+ }
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ override fun createMarkMessageAsSpamPendingIntent(
+ messageReference: MessageReference,
+ notificationId: Int
+ ): PendingIntent {
+ val intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference)
+ return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
- @Override
- public PendingIntent createMarkMessageAsSpamPendingIntent(MessageReference messageReference, int notificationId) {
- Intent intent = NotificationActionService.createMarkMessageAsSpamIntent(context, messageReference);
+ private fun createMessageListIntent(account: Account): Intent {
+ val folderId = defaultFolderProvider.getDefaultFolder(account)
+ val search = LocalSearch().apply {
+ addAllowedFolder(folderId)
+ addAccountUuid(account.uuid)
+ }
- return PendingIntent.getService(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return MessageList.intentDisplaySearch(
+ context = context,
+ search = search,
+ noThreading = false,
+ newTask = true,
+ clearTop = true
+ )
}
- private Intent createMessageListIntent(Account account) {
- long folderId = defaultFolderProvider.getDefaultFolder(account);
- LocalSearch search = new LocalSearch();
- search.addAllowedFolder(folderId);
- search.addAccountUuid(account.getUuid());
- return MessageList.intentDisplaySearch(context, search, false, true, true);
- }
+ private fun createMessageListIntent(account: Account, folderId: Long): Intent {
+ val search = LocalSearch().apply {
+ addAllowedFolder(folderId)
+ addAccountUuid(account.uuid)
+ }
- private Intent createMessageListIntent(Account account, long folderId) {
- LocalSearch search = new LocalSearch();
- search.addAllowedFolder(folderId);
- search.addAccountUuid(account.getUuid());
- return MessageList.intentDisplaySearch(context, search, false, true, true);
+ return MessageList.intentDisplaySearch(
+ context = context,
+ search = search,
+ noThreading = false,
+ newTask = true,
+ clearTop = true
+ )
}
- private Intent createMessageViewIntent(MessageReference message) {
- return MessageList.actionDisplayMessageIntent(context, message);
+ private fun createMessageViewIntent(message: MessageReference): Intent {
+ return MessageList.actionDisplayMessageIntent(context, message)
}
- private Long getFolderIdOfAllMessages(List messageReferences) {
- MessageReference firstMessage = messageReferences.get(0);
- long folderId = firstMessage.getFolderId();
-
- for (MessageReference messageReference : messageReferences) {
- if (folderId != messageReference.getFolderId()) {
- return null;
- }
- }
+ private fun getFolderIdOfAllMessages(messageReferences: List): Long? {
+ val firstMessage = messageReferences.first()
+ val folderId = firstMessage.folderId
- return folderId;
+ return if (messageReferences.all { it.folderId == folderId }) folderId else null
}
}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/notification/KoinModule.kt b/app/k9mail/src/main/java/com/fsck/k9/notification/KoinModule.kt
index ce46fad315..ac5ee21308 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/notification/KoinModule.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/notification/KoinModule.kt
@@ -3,7 +3,7 @@ package com.fsck.k9.notification
import org.koin.dsl.module
val notificationModule = module {
- single { K9NotificationActionCreator(get()) }
+ single { K9NotificationActionCreator(context = get(), defaultFolderProvider = get()) }
single { K9NotificationResourceProvider(get()) }
single { K9NotificationStrategy(get()) }
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/notification/DeleteConfirmationActivity.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/notification/DeleteConfirmationActivity.kt
index 9101760df4..380dd48303 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/notification/DeleteConfirmationActivity.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/notification/DeleteConfirmationActivity.kt
@@ -99,12 +99,10 @@ class DeleteConfirmationActivity : K9Activity(ThemeType.DIALOG), ConfirmationDia
private const val DIALOG_ID = 1
private const val DIALOG_TAG = "dialog"
- @JvmStatic
fun getIntent(context: Context, messageReference: MessageReference): Intent {
return getIntent(context, listOf(messageReference))
}
- @JvmStatic
fun getIntent(context: Context, messageReferences: List): Intent {
val accountUuid = messageReferences[0].accountUuid
val messageReferenceStrings = MessageReferenceHelper.toMessageReferenceStringList(messageReferences)
--
GitLab
From 6084321bdee575e00a30aa03ea5f4e4810785d4c Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 26 Aug 2021 17:44:20 +0200
Subject: [PATCH 071/285] Update Kotlin to 1.5.30
Replace calls to deprecated stdlib functions
---
.../message/extractors/BasicPartInfoExtractor.kt | 5 ++---
.../java/com/fsck/k9/message/html/UriMatcher.kt | 11 +++++------
.../fsck/k9/preferences/ServerTypeConverter.kt | 4 +---
.../k9/storage/messages/SaveMessageOperations.kt | 3 +--
.../storage/messages/ThreadMessageOperations.kt | 3 +--
.../java/com/fsck/k9/account/AccountCreator.kt | 4 ++--
.../fsck/k9/contacts/ContactLetterExtractor.kt | 3 +--
.../com/fsck/k9/fragment/MessageListFragment.kt | 2 +-
.../k9/ui/choosefolder/ChooseFolderActivity.kt | 4 ++--
.../k9/ui/managefolders/ManageFoldersFragment.kt | 4 ++--
build.gradle | 4 ++--
.../src/main/java/com/fsck/k9/mail/MimeType.kt | 6 ++----
.../main/java/com/fsck/k9/mail/ServerSettings.kt | 4 +---
.../main/java/com/fsck/k9/mail/helper/Utf8.kt | 8 ++++----
.../fsck/k9/mail/internet/FormatFlowedHelper.kt | 6 ++----
.../fsck/k9/mail/internet/MessageIdGenerator.kt | 3 +--
.../com/fsck/k9/mail/internet/MimeExtensions.kt | 6 +++---
.../fsck/k9/mail/internet/MimeHeaderChecker.kt | 2 +-
.../fsck/k9/mail/internet/MimeHeaderParser.kt | 9 ++++-----
.../k9/mail/internet/MimeParameterDecoder.kt | 3 +--
.../k9/mail/internet/MimeParameterEncoder.kt | 6 +++---
.../fsck/k9/mail/store/imap/RealImapFolder.kt | 16 ++++++++--------
.../java/com/fsck/k9/mail/MessageBuilderDsl.kt | 2 +-
23 files changed, 51 insertions(+), 67 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/message/extractors/BasicPartInfoExtractor.kt b/app/core/src/main/java/com/fsck/k9/message/extractors/BasicPartInfoExtractor.kt
index b571abece8..6992a87a4a 100644
--- a/app/core/src/main/java/com/fsck/k9/message/extractors/BasicPartInfoExtractor.kt
+++ b/app/core/src/main/java/com/fsck/k9/message/extractors/BasicPartInfoExtractor.kt
@@ -4,7 +4,6 @@ import com.fsck.k9.mail.Part
import com.fsck.k9.mail.internet.MimeParameterDecoder
import com.fsck.k9.mail.internet.MimeUtility
import com.fsck.k9.mail.internet.MimeValue
-import java.util.Locale
private const val FALLBACK_NAME = "noname"
@@ -38,11 +37,11 @@ class BasicPartInfoExtractor {
private fun String.toMimeValue(): MimeValue = MimeParameterDecoder.decode(this)
- private fun MimeValue.getParameter(name: String): String? = parameters[name.toLowerCase(Locale.ROOT)]
+ private fun MimeValue.getParameter(name: String): String? = parameters[name.lowercase()]
private fun String.getParameter(name: String): String? {
val mimeValue = MimeParameterDecoder.decode(this)
- return mimeValue.parameters[name.toLowerCase(Locale.ROOT)]
+ return mimeValue.parameters[name.lowercase()]
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt b/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
index ee5b44344d..5dea02560e 100644
--- a/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
+++ b/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
@@ -1,9 +1,8 @@
package com.fsck.k9.message.html
-import java.util.Locale
-
object UriMatcher {
- private val SUPPORTED_URIS = { httpUriParser: HttpUriParser ->
+ private val SUPPORTED_URIS = run {
+ val httpUriParser = HttpUriParser()
mapOf(
"ethereum:" to EthereumUriParser(),
"bitcoin:" to BitcoinUriParser(),
@@ -11,7 +10,7 @@ object UriMatcher {
"https:" to httpUriParser,
"rtsp:" to httpUriParser
)
- }.invoke(HttpUriParser())
+ }
private const val SCHEME_SEPARATORS = "\\s(\\n<"
private const val ALLOWED_SEPARATORS_PATTERN = "(?:^|[$SCHEME_SEPARATORS])"
@@ -23,8 +22,8 @@ object UriMatcher {
fun findUris(text: CharSequence): List {
return URI_SCHEME.findAll(text).map { matchResult ->
val matchGroup = matchResult.groups[1]!!
- val startIndex = matchGroup.range.start
- val scheme = matchGroup.value.toLowerCase(Locale.ROOT)
+ val startIndex = matchGroup.range.first
+ val scheme = matchGroup.value.lowercase()
val parser = SUPPORTED_URIS[scheme] ?: throw AssertionError("Scheme not found: $scheme")
parser.parseUri(text, startIndex)
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/ServerTypeConverter.kt b/app/core/src/main/java/com/fsck/k9/preferences/ServerTypeConverter.kt
index d1bedc6c80..9d64def8b3 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/ServerTypeConverter.kt
+++ b/app/core/src/main/java/com/fsck/k9/preferences/ServerTypeConverter.kt
@@ -1,10 +1,8 @@
package com.fsck.k9.preferences
-import java.util.Locale
-
object ServerTypeConverter {
@JvmStatic
- fun toServerSettingsType(exportType: String): String = exportType.toLowerCase(Locale.ROOT)
+ fun toServerSettingsType(exportType: String): String = exportType.lowercase()
@JvmStatic
fun fromServerSettingsType(serverSettingsType: String): String = when (serverSettingsType) {
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/SaveMessageOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/SaveMessageOperations.kt
index 701e6f3329..49080c0507 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/SaveMessageOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/SaveMessageOperations.kt
@@ -28,7 +28,6 @@ import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
-import java.util.Locale
import java.util.Stack
import java.util.UUID
import org.apache.commons.io.IOUtils
@@ -355,7 +354,7 @@ internal class SaveMessageOperations(
private fun getTransferEncoding(part: Part): String {
val contentTransferEncoding = part.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING).firstOrNull()
- return contentTransferEncoding?.toLowerCase(Locale.ROOT) ?: MimeUtil.ENC_7BIT
+ return contentTransferEncoding?.lowercase() ?: MimeUtil.ENC_7BIT
}
private fun addChildrenToStack(stack: Stack, part: Part, parentId: Long) {
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/ThreadMessageOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/ThreadMessageOperations.kt
index 324841efdb..52544b1f4b 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/ThreadMessageOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/ThreadMessageOperations.kt
@@ -5,7 +5,6 @@ import android.database.sqlite.SQLiteDatabase
import com.fsck.k9.helper.Utility
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.message.MessageHeaderParser
-import java.util.Locale
internal class ThreadMessageOperations {
@@ -37,7 +36,7 @@ internal class ThreadMessageOperations {
var referencesHeader: String? = null
if (headerBytes != null) {
MessageHeaderParser.parse(headerBytes.inputStream()) { name, value ->
- when (name.toLowerCase(Locale.ROOT)) {
+ when (name.lowercase()) {
"in-reply-to" -> inReplyToHeader = value
"references" -> referencesHeader = value
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountCreator.kt b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountCreator.kt
index c3a29d12e8..7c1e18ecde 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountCreator.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/account/AccountCreator.kt
@@ -60,10 +60,10 @@ class AccountCreator(private val preferences: Preferences, private val resources
return accountColors.random()
}
- return availableColors.shuffled().minBy { color ->
+ return availableColors.shuffled().minOf { color ->
val index = DEFAULT_COLORS.indexOf(color)
if (index != -1) index else DEFAULT_COLORS.size
- }!!
+ }
}
companion object {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/contacts/ContactLetterExtractor.kt b/app/ui/legacy/src/main/java/com/fsck/k9/contacts/ContactLetterExtractor.kt
index 0664a5eb00..3b387a678a 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/contacts/ContactLetterExtractor.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/contacts/ContactLetterExtractor.kt
@@ -1,14 +1,13 @@
package com.fsck.k9.contacts
import com.fsck.k9.mail.Address
-import java.util.Locale
class ContactLetterExtractor {
fun extractContactLetter(address: Address): String {
val displayName = address.personal ?: address.address
val matchResult = EXTRACT_LETTER_PATTERN.find(displayName)
- return matchResult?.value?.toUpperCase(Locale.ROOT) ?: FALLBACK_CONTACT_LETTER
+ return matchResult?.value?.uppercase() ?: FALLBACK_CONTACT_LETTER
}
companion object {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
index 112f834c73..dbe6aefa11 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/fragment/MessageListFragment.kt
@@ -1503,7 +1503,7 @@ class MessageListFragment :
selectedCount = adapter.messages
.asSequence()
.filter { it.uniqueId in selected }
- .sumBy { it.threadCount.coerceAtLeast(1) }
+ .sumOf { it.threadCount.coerceAtLeast(1) }
}
fun remoteSearchFinished() {
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderActivity.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderActivity.kt
index 74640c9fc7..ff099351fd 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderActivity.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderActivity.kt
@@ -202,9 +202,9 @@ class ChooseFolderActivity : K9Activity() {
if (constraint.isNullOrEmpty()) return true
val locale = Locale.getDefault()
- val displayName = item.displayName.toLowerCase(locale)
+ val displayName = item.displayName.lowercase(locale)
return constraint.splitToSequence(" ")
- .map { it.toLowerCase(locale) }
+ .map { it.lowercase(locale) }
.any { it in displayName }
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
index 03c60cc188..2607a868df 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersFragment.kt
@@ -144,10 +144,10 @@ class ManageFoldersFragment : Fragment() {
if (constraint.isNullOrEmpty()) return true
val locale = Locale.getDefault()
- val displayName = item.displayName.toLowerCase(locale)
+ val displayName = item.displayName.lowercase(locale)
return constraint.splitToSequence(" ")
.filter { it.isNotEmpty() }
- .map { it.toLowerCase(locale) }
+ .map { it.lowercase(locale) }
.any { it in displayName }
}
diff --git a/build.gradle b/build.gradle
index 58ea34278d..97eafaf169 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,8 +11,8 @@ buildscript {
]
versions = [
- 'kotlin': '1.4.32',
- 'kotlinCoroutines': '1.4.3',
+ 'kotlin': '1.5.30',
+ 'kotlinCoroutines': '1.5.1',
'androidxAppCompat': '1.2.0',
'androidxRecyclerView': '1.1.0',
'androidxLifecycle': '2.3.1',
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/MimeType.kt b/mail/common/src/main/java/com/fsck/k9/mail/MimeType.kt
index 48d9e61bb1..33122ad0f6 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/MimeType.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/MimeType.kt
@@ -1,7 +1,5 @@
package com.fsck.k9.mail
-import java.util.Locale
-
class MimeType private constructor(
val type: String,
val subtype: String
@@ -27,8 +25,8 @@ class MimeType private constructor(
fun String.toMimeType(): MimeType {
val matchResult = requireNotNull(MIME_TYPE.matchEntire(this)) { "Invalid MIME type: $this" }
- val type = matchResult.groupValues[1].toLowerCase(Locale.ROOT)
- val subtype = matchResult.groupValues[2].toLowerCase(Locale.ROOT)
+ val type = matchResult.groupValues[1].lowercase()
+ val subtype = matchResult.groupValues[2].lowercase()
return MimeType(type, subtype)
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
index d51ad9045c..6c3576560e 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
@@ -1,7 +1,5 @@
package com.fsck.k9.mail
-import java.util.Locale
-
/**
* Container for incoming or outgoing server settings
*/
@@ -22,7 +20,7 @@ data class ServerSettings @JvmOverloads constructor(
}
init {
- require(type == type.toLowerCase(Locale.ROOT)) { "type must be all lower case" }
+ require(type == type.lowercase()) { "type must be all lower case" }
}
fun newPassword(newPassword: String?): ServerSettings {
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/helper/Utf8.kt b/mail/common/src/main/java/com/fsck/k9/mail/helper/Utf8.kt
index 9a79beb6d3..a8c20dc673 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/helper/Utf8.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/helper/Utf8.kt
@@ -29,7 +29,7 @@ inline fun String.encodeUtf8(beginIndex: Int = 0, endIndex: Int = length, crossi
// Transcode a UTF-16 Java String to UTF-8 bytes.
var i = beginIndex
while (i < endIndex) {
- val c = this[i].toInt()
+ val c = this[i].code
if (c < 0x80) {
// Emit a 7-bit character with 1 byte.
@@ -49,9 +49,9 @@ inline fun String.encodeUtf8(beginIndex: Int = 0, endIndex: Int = length, crossi
} else {
// c is a surrogate. Make sure it is a high surrogate and that its successor is a low surrogate.
// If not, the UTF-16 is invalid, in which case we emit a replacement character.
- val low = if (i + 1 < endIndex) this[i + 1].toInt() else 0
+ val low = if (i + 1 < endIndex) this[i + 1].code else 0
if (c > 0xdbff || low < 0xdc00 || low > 0xdfff) {
- writeByte('?'.toByte())
+ writeByte('?'.code.toByte())
i++
continue
}
@@ -104,7 +104,7 @@ inline fun Int.encodeUtf8(crossinline writeByte: (Byte) -> Unit) {
writeByte((codePoint and 0x3f or 0x80).toByte()) // 10xxxxxx
} else if (codePoint in 0xd800..0xdfff) {
// codePoint is a surrogate. Emit a replacement character
- writeByte('?'.toByte())
+ writeByte('?'.code.toByte())
} else {
// Emit a 21-bit character with 4 bytes.
writeByte((codePoint shr 18 or 0xf0).toByte()) // 11110xxx
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
index 248600afb1..65efd9c394 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/FormatFlowedHelper.kt
@@ -1,7 +1,5 @@
package com.fsck.k9.mail.internet
-import java.util.Locale
-
internal object FormatFlowedHelper {
private const val TEXT_PLAIN = "text/plain"
private const val HEADER_PARAM_FORMAT = "format"
@@ -16,10 +14,10 @@ internal object FormatFlowedHelper {
val mimeValue = MimeParameterDecoder.decode(contentTypeHeaderValue)
if (!MimeUtility.isSameMimeType(TEXT_PLAIN, mimeValue.value)) return negativeResult()
- val formatParameter = mimeValue.parameters[HEADER_PARAM_FORMAT]?.toLowerCase(Locale.ROOT)
+ val formatParameter = mimeValue.parameters[HEADER_PARAM_FORMAT]?.lowercase()
if (formatParameter != HEADER_FORMAT_FLOWED) return negativeResult()
- val delSpParameter = mimeValue.parameters[HEADER_PARAM_DELSP]?.toLowerCase(Locale.ROOT)
+ val delSpParameter = mimeValue.parameters[HEADER_PARAM_DELSP]?.lowercase()
return FormatFlowedResult(isFormatFlowed = true, isDelSp = delSpParameter == HEADER_DELSP_YES)
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageIdGenerator.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageIdGenerator.kt
index ae24eb0ac5..286a6431fd 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageIdGenerator.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MessageIdGenerator.kt
@@ -2,7 +2,6 @@ package com.fsck.k9.mail.internet
import com.fsck.k9.mail.Address
import com.fsck.k9.mail.Message
-import java.util.Locale
import java.util.UUID
class MessageIdGenerator(private val uuidGenerator: UuidGenerator) {
@@ -29,6 +28,6 @@ interface UuidGenerator {
class K9UuidGenerator : UuidGenerator {
override fun randomUuid(): String {
// We use upper case here to match Apple Mail Message-ID format (for privacy)
- return UUID.randomUUID().toString().toUpperCase(Locale.ROOT)
+ return UUID.randomUUID().toString().uppercase()
}
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeExtensions.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeExtensions.kt
index 3bbe438a45..093a57cbfa 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeExtensions.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeExtensions.kt
@@ -34,7 +34,7 @@ internal fun Char.isTSpecial() = this in TSPECIALS
internal fun Char.isTokenChar() = isVChar() && !isTSpecial()
// RFC 5234: VCHAR = %x21-7E
-internal fun Char.isVChar() = toInt() in 33..126
+internal fun Char.isVChar() = code in 33..126
// RFC 5234: WSP = SP / HTAB
internal fun Char.isWsp() = this == SPACE || this == HTAB
@@ -45,7 +45,7 @@ internal fun Char.isWspOrCrlf() = this == SPACE || this == HTAB || this == CR ||
internal fun Char.isAttributeChar() = isVChar() && this != '*' && this != '\'' && this != '%' && !isTSpecial()
// RFC 5322: ctext = %d33-39 / %d42-91 / %d93-126
-internal fun Char.isCText() = toInt().let { it in 33..39 || it in 42..91 || it in 93..126 }
+internal fun Char.isCText() = code.let { it in 33..39 || it in 42..91 || it in 93..126 }
// RFC 5234: DIGIT = %x30-39 ; 0-9
internal fun Char.isDIGIT() = this in '0'..'9'
@@ -59,4 +59,4 @@ internal fun Char.isAText() = isALPHA() || isDIGIT() || this in ATEXT_SPECIAL
// RFC 5322: Printable US-ASCII characters not including "[", "]", or "\"
// dtext = %d33-90 / %d94-126 / obs-dtext
-internal fun Char.isDText() = toInt().let { it in 33..90 || it in 94..126 }
+internal fun Char.isDText() = code.let { it in 33..90 || it in 94..126 }
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderChecker.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderChecker.kt
index 4bed540914..09fdeef432 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderChecker.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderChecker.kt
@@ -56,7 +56,7 @@ private class UnstructuredHeaderChecker(val input: String, initialLineLength: In
skipVCharAndWsp()
}
else -> {
- throw MimeHeaderParserException("Unexpected character (${char.toInt()})", currentIndex)
+ throw MimeHeaderParserException("Unexpected character (${char.code})", currentIndex)
}
}
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderParser.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderParser.kt
index 94fa5d1608..f013b87b8e 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderParser.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeHeaderParser.kt
@@ -38,7 +38,7 @@ class MimeHeaderParser(private val input: String) {
val c = read()
when {
c == '%' -> output.writeByte(readPercentEncoded())
- c.isAttributeChar() -> output.writeByte(c.toInt())
+ c.isAttributeChar() -> output.writeByte(c.code)
else -> return
}
}
@@ -52,8 +52,7 @@ class MimeHeaderParser(private val input: String) {
}
private fun readHexDigit(): Int {
- val character = read()
- return when (character) {
+ return when (val character = read()) {
in '0'..'9' -> character - '0'
in 'a'..'f' -> character - 'a' + 10
in 'A'..'F' -> character - 'A' + 10
@@ -112,7 +111,7 @@ class MimeHeaderParser(private val input: String) {
if (!endReached() && peek() == character) {
currentIndex++
} else {
- throw MimeHeaderParserException("Expected '$character' (${character.toInt()})", currentIndex)
+ throw MimeHeaderParserException("Expected '$character' (${character.code})", currentIndex)
}
}
@@ -149,7 +148,7 @@ class MimeHeaderParser(private val input: String) {
else -> {
currentIndex--
throw MimeHeaderParserException(
- "Unexpected '$character' (${character.toInt()}) in comment",
+ "Unexpected '$character' (${character.code}) in comment",
errorIndex = currentIndex
)
}
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterDecoder.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterDecoder.kt
index da7e8152e4..7dcf29a6d6 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterDecoder.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterDecoder.kt
@@ -2,7 +2,6 @@ package com.fsck.k9.mail.internet
import java.nio.charset.Charset
import java.nio.charset.IllegalCharsetNameException
-import java.util.Locale
import okio.Buffer
private typealias Parameters = Map
@@ -69,7 +68,7 @@ object MimeParameterDecoder {
do {
parser.expect(SEMICOLON)
- val parameterName = parser.readToken().toLowerCase(Locale.ROOT)
+ val parameterName = parser.readToken().lowercase()
parser.skipCFWS()
parser.expect(EQUALS_SIGN)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterEncoder.kt b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterEncoder.kt
index c761235192..b4023de0f4 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterEncoder.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/internet/MimeParameterEncoder.kt
@@ -120,7 +120,7 @@ object MimeParameterEncoder {
private fun String.rfc2231Encoded() = buildString {
this@rfc2231Encoded.encodeUtf8 { byte ->
- val c = byte.toChar()
+ val c = byte.toInt().toChar()
if (c.isAttributeChar()) {
append(c)
} else {
@@ -133,7 +133,7 @@ object MimeParameterEncoder {
private fun String.rfc2231EncodedLength(): Int {
var length = 0
encodeUtf8 { byte ->
- length += if (byte.toChar().isAttributeChar()) 1 else 3
+ length += if (byte.toInt().toChar().isAttributeChar()) 1 else 3
}
return length
}
@@ -186,7 +186,7 @@ object MimeParameterEncoder {
}
// RFC 5322: qtext = %d33 / %d35-91 / %d93-126 / obs-qtext
- private fun Char.isQText() = when (toInt()) {
+ private fun Char.isQText() = when (code) {
33 -> true
in 35..91 -> true
in 93..126 -> true
diff --git a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
index 1e4f5a7e0c..959240f39c 100644
--- a/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
+++ b/mail/protocols/imap/src/main/java/com/fsck/k9/mail/store/imap/RealImapFolder.kt
@@ -332,7 +332,7 @@ internal class RealImapFolder(
val command = String.format(Locale.US, "SEARCH 1:* %s", criteria)
val responses = executeSimpleCommand(command)
- return responses.sumBy { response ->
+ return responses.sumOf { response ->
if (ImapResponseParser.equalsIgnoreCase(response[0], "SEARCH")) {
response.size - 1
} else {
@@ -366,7 +366,7 @@ internal class RealImapFolder(
}
private fun extractHighestUid(searchResponse: SearchResponse): Long {
- return searchResponse.numbers.max() ?: -1L
+ return searchResponse.numbers.maxOrNull() ?: -1L
}
override fun getMessage(uid: String): ImapMessage {
@@ -841,7 +841,7 @@ internal class RealImapFolder(
// We've got to the end of the children of the part, so now we can find out what type it is and
// bail out.
val subType = bs.getString(i)
- mp.setSubType(subType.toLowerCase(Locale.US))
+ mp.setSubType(subType.lowercase())
break
}
}
@@ -866,7 +866,7 @@ internal class RealImapFolder(
*/
val type = bs.getString(0)
val subType = bs.getString(1)
- val mimeType = "$type/$subType".toLowerCase(Locale.US)
+ val mimeType = "$type/$subType".lowercase()
var bodyParams: ImapList? = null
if (bs[2] is ImapList) {
@@ -913,14 +913,14 @@ internal class RealImapFolder(
val contentDisposition = StringBuilder()
if (bodyDisposition != null && !bodyDisposition.isEmpty()) {
if (!"NIL".equals(bodyDisposition.getString(0), ignoreCase = true)) {
- contentDisposition.append(bodyDisposition.getString(0).toLowerCase(Locale.US))
+ contentDisposition.append(bodyDisposition.getString(0).lowercase())
}
if (bodyDisposition.size > 1 && bodyDisposition[1] is ImapList) {
val bodyDispositionParams = bodyDisposition.getList(1)
// If there is body disposition information we can pull some more information
// about the attachment out.
for (i in bodyDispositionParams.indices step 2) {
- val paramName = bodyDispositionParams.getString(i).toLowerCase(Locale.US)
+ val paramName = bodyDispositionParams.getString(i).lowercase()
val paramValue = bodyDispositionParams.getString(i + 1)
contentDisposition.append(String.format(";\r\n %s=\"%s\"", paramName, paramValue))
}
@@ -988,8 +988,8 @@ internal class RealImapFolder(
if (response.isContinuationRequested) {
val eolOut = EOLConvertingOutputStream(connection!!.outputStream)
message.writeTo(eolOut)
- eolOut.write('\r'.toInt())
- eolOut.write('\n'.toInt())
+ eolOut.write('\r'.code)
+ eolOut.write('\n'.code)
eolOut.flush()
}
} while (response.tag == null)
diff --git a/mail/testing/src/main/java/com/fsck/k9/mail/MessageBuilderDsl.kt b/mail/testing/src/main/java/com/fsck/k9/mail/MessageBuilderDsl.kt
index dc4c2174fb..0e27b69e56 100644
--- a/mail/testing/src/main/java/com/fsck/k9/mail/MessageBuilderDsl.kt
+++ b/mail/testing/src/main/java/com/fsck/k9/mail/MessageBuilderDsl.kt
@@ -36,7 +36,7 @@ class PartBuilder(private val part: Part) {
require(!gotBodyBlock) { "Only one body block allowed" }
gotBodyBlock = true
- val body = BinaryMemoryBody(ByteArray(size) { 'A'.toByte() }, encoding)
+ val body = BinaryMemoryBody(ByteArray(size) { 'A'.code.toByte() }, encoding)
MimeMessageHelper.setBody(part, body)
}
--
GitLab
From f2f8e4d0f35f7ca34d96fa7096cdac97a72278ad Mon Sep 17 00:00:00 2001
From: cketti
Date: Thu, 26 Aug 2021 22:28:36 +0200
Subject: [PATCH 072/285] Remove FolderRepositoryManager
Instead we use one FolderRepository instance and pass Account as parameter to individual functions.
---
.../controller/push/AccountPushController.kt | 7 ++-
.../push/AccountPushControllerFactory.kt | 6 +--
.../com/fsck/k9/controller/push/KoinModule.kt | 2 +-
...pandFolderBackendFoldersRefreshListener.kt | 4 +-
.../com/fsck/k9/mailstore/FolderRepository.kt | 51 +++++++++----------
.../k9/mailstore/FolderRepositoryManager.kt | 13 -----
.../k9/mailstore/K9BackendStorageFactory.kt | 3 +-
.../java/com/fsck/k9/mailstore/KoinModule.kt | 4 +-
.../fsck/k9/mailstore/SpecialFolderUpdater.kt | 18 +++----
.../k9/preferences/FolderSettingsProvider.kt | 7 ++-
.../com/fsck/k9/preferences/KoinModule.kt | 4 +-
.../fsck/k9/preferences/SettingsExporter.kt | 6 +--
.../k9/preferences/SettingsExporterTest.kt | 6 +--
.../fsck/k9/backends/WebDavBackendFactory.kt | 7 ++-
.../fsck/k9/backends/WebDavBackendFactory.kt | 7 ++-
.../com/fsck/k9/widget/unread/KoinModule.kt | 4 +-
.../widget/unread/UnreadWidgetDataProvider.kt | 7 ++-
.../widget/unread/UnreadWidgetMigrations.kt | 7 ++-
.../unread/UnreadWidgetDataProviderTest.kt | 14 ++---
.../ui/choosefolder/ChooseFolderViewModel.kt | 2 +-
.../com/fsck/k9/ui/folders/FoldersLiveData.kt | 14 ++---
.../k9/ui/folders/FoldersLiveDataFactory.kt | 7 ++-
.../fsck/k9/ui/folders/FoldersViewModel.kt | 2 +-
.../managefolders/FolderSettingsDataStore.kt | 4 +-
.../managefolders/FolderSettingsViewModel.kt | 12 ++---
.../fsck/k9/ui/managefolders/KoinModule.kt | 2 +-
.../managefolders/ManageFoldersViewModel.kt | 2 +-
.../account/AccountSettingsViewModel.kt | 13 ++---
28 files changed, 102 insertions(+), 133 deletions(-)
delete mode 100644 app/core/src/main/java/com/fsck/k9/mailstore/FolderRepositoryManager.kt
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
index 8627700844..c735c20bc6 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushController.kt
@@ -7,7 +7,7 @@ import com.fsck.k9.backend.BackendManager
import com.fsck.k9.backend.api.BackendPusher
import com.fsck.k9.backend.api.BackendPusherCallback
import com.fsck.k9.controller.MessagingController
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -20,11 +20,10 @@ internal class AccountPushController(
private val backendManager: BackendManager,
private val messagingController: MessagingController,
private val preferences: Preferences,
- folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO,
private val account: Account
) {
- private val folderRepository = folderRepositoryManager.getFolderRepository(account)
private val coroutineScope = CoroutineScope(backgroundDispatcher)
@Volatile
@@ -76,7 +75,7 @@ internal class AccountPushController(
private fun startListeningForPushFolders() {
coroutineScope.launch {
- folderRepository.getPushFoldersFlow().collect { remoteFolders ->
+ folderRepository.getPushFoldersFlow(account).collect { remoteFolders ->
val folderServerIds = remoteFolders.map { it.serverId }
updatePushFolders(folderServerIds)
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
index 89ae3bef1b..7091496d69 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/AccountPushControllerFactory.kt
@@ -4,12 +4,12 @@ import com.fsck.k9.Account
import com.fsck.k9.Preferences
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.controller.MessagingController
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
internal class AccountPushControllerFactory(
private val backendManager: BackendManager,
private val messagingController: MessagingController,
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val preferences: Preferences
) {
fun create(account: Account): AccountPushController {
@@ -17,7 +17,7 @@ internal class AccountPushControllerFactory(
backendManager,
messagingController,
preferences,
- folderRepositoryManager,
+ folderRepository,
account = account
)
}
diff --git a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
index 7a7a6441c9..b8046a970d 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/controller/push/KoinModule.kt
@@ -10,7 +10,7 @@ internal val controllerPushModule = module {
AccountPushControllerFactory(
backendManager = get(),
messagingController = get(),
- folderRepositoryManager = get(),
+ folderRepository = get(),
preferences = get()
)
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/AutoExpandFolderBackendFoldersRefreshListener.kt b/app/core/src/main/java/com/fsck/k9/mailstore/AutoExpandFolderBackendFoldersRefreshListener.kt
index e7394c8b9a..a0d09d1328 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/AutoExpandFolderBackendFoldersRefreshListener.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/AutoExpandFolderBackendFoldersRefreshListener.kt
@@ -22,14 +22,14 @@ class AutoExpandFolderBackendFoldersRefreshListener(
}
private fun checkAutoExpandFolder() {
- val folderId = account.importedAutoExpandFolder?.let { folderRepository.getFolderId(it) }
+ val folderId = account.importedAutoExpandFolder?.let { folderRepository.getFolderId(account, it) }
if (folderId != null) {
account.autoExpandFolderId = folderId
return
}
account.autoExpandFolderId?.let { autoExpandFolderId ->
- if (!folderRepository.isFolderPresent(autoExpandFolderId)) {
+ if (!folderRepository.isFolderPresent(account, autoExpandFolderId)) {
account.autoExpandFolderId = null
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt b/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
index 5d0914437b..1998e83dc2 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt
@@ -23,7 +23,6 @@ import com.fsck.k9.mail.FolderType as RemoteFolderType
class FolderRepository(
private val messageStoreManager: MessageStoreManager,
private val accountManager: AccountManager,
- private val account: Account,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {
private val sortForDisplay =
@@ -33,7 +32,7 @@ class FolderRepository(
.thenByDescending { it.isInTopGroup }
.thenBy(String.CASE_INSENSITIVE_ORDER) { it.folder.name }
- fun getDisplayFolders(displayMode: FolderMode?): List {
+ fun getDisplayFolders(account: Account, displayMode: FolderMode?): List {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getDisplayFolders(
displayMode = displayMode ?: account.folderDisplayMode,
@@ -43,7 +42,7 @@ class FolderRepository(
folder = Folder(
id = folder.id,
name = folder.name,
- type = folderTypeOf(folder.id),
+ type = folderTypeOf(account, folder.id),
isLocalOnly = folder.isLocalOnly
),
isInTopGroup = folder.isInTopGroup,
@@ -53,26 +52,26 @@ class FolderRepository(
}.sortedWith(sortForDisplay)
}
- fun getFolder(folderId: Long): Folder? {
+ fun getFolder(account: Account, folderId: Long): Folder? {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolder(folderId) { folder ->
Folder(
id = folder.id,
name = folder.name,
- type = folderTypeOf(folder.id),
+ type = folderTypeOf(account, folder.id),
isLocalOnly = folder.isLocalOnly
)
}
}
- fun getFolderDetails(folderId: Long): FolderDetails? {
+ fun getFolderDetails(account: Account, folderId: Long): FolderDetails? {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolder(folderId) { folder ->
FolderDetails(
folder = Folder(
id = folder.id,
name = folder.name,
- type = folderTypeOf(folder.id),
+ type = folderTypeOf(account, folder.id),
isLocalOnly = folder.isLocalOnly
),
isInTopGroup = folder.isInTopGroup,
@@ -85,7 +84,7 @@ class FolderRepository(
}
}
- fun getRemoteFolders(): List {
+ fun getRemoteFolders(account: Account): List {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolders(excludeLocalOnly = true) { folder ->
RemoteFolder(
@@ -97,7 +96,7 @@ class FolderRepository(
}
}
- fun getRemoteFolderDetails(): List {
+ fun getRemoteFolderDetails(account: Account): List {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolders(excludeLocalOnly = true) { folder ->
RemoteFolderDetails(
@@ -117,21 +116,21 @@ class FolderRepository(
}
}
- fun getPushFoldersFlow(): Flow> {
+ fun getPushFoldersFlow(account: Account): Flow> {
return account.getFolderPushModeFlow()
.flatMapLatest { pushMode ->
- getPushFoldersFlow(pushMode)
+ getPushFoldersFlow(account, pushMode)
}
}
- private fun getPushFoldersFlow(folderMode: FolderMode): Flow> {
+ private fun getPushFoldersFlow(account: Account, folderMode: FolderMode): Flow> {
val messageStore = messageStoreManager.getMessageStore(account)
return callbackFlow {
- send(getPushFolders(folderMode))
+ send(getPushFolders(account, folderMode))
val listener = FolderSettingsChangedListener {
launch {
- send(getPushFolders(folderMode))
+ send(getPushFolders(account, folderMode))
}
}
messageStore.addFolderSettingsChangedListener(listener)
@@ -144,10 +143,10 @@ class FolderRepository(
.flowOn(ioDispatcher)
}
- private fun getPushFolders(folderMode: FolderMode): List {
+ private fun getPushFolders(account: Account, folderMode: FolderMode): List {
if (folderMode == FolderMode.NONE) return emptyList()
- return getRemoteFolderDetails()
+ return getRemoteFolderDetails(account)
.asSequence()
.filter { folderDetails ->
val pushClass = folderDetails.effectivePushClass
@@ -165,54 +164,54 @@ class FolderRepository(
.toList()
}
- fun getFolderServerId(folderId: Long): String? {
+ fun getFolderServerId(account: Account, folderId: Long): String? {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolder(folderId) { folder ->
folder.serverId
}
}
- fun getFolderId(folderServerId: String): Long? {
+ fun getFolderId(account: Account, folderServerId: String): Long? {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolderId(folderServerId)
}
- fun isFolderPresent(folderId: Long): Boolean {
+ fun isFolderPresent(account: Account, folderId: Long): Boolean {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolder(folderId) { true } ?: false
}
- fun updateFolderDetails(folderDetails: FolderDetails) {
+ fun updateFolderDetails(account: Account, folderDetails: FolderDetails) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.updateFolderSettings(folderDetails)
}
- fun setIncludeInUnifiedInbox(folderId: Long, includeInUnifiedInbox: Boolean) {
+ fun setIncludeInUnifiedInbox(account: Account, folderId: Long, includeInUnifiedInbox: Boolean) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.setIncludeInUnifiedInbox(folderId, includeInUnifiedInbox)
}
- fun setDisplayClass(folderId: Long, folderClass: FolderClass) {
+ fun setDisplayClass(account: Account, folderId: Long, folderClass: FolderClass) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.setDisplayClass(folderId, folderClass)
}
- fun setSyncClass(folderId: Long, folderClass: FolderClass) {
+ fun setSyncClass(account: Account, folderId: Long, folderClass: FolderClass) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.setSyncClass(folderId, folderClass)
}
- fun setPushClass(folderId: Long, folderClass: FolderClass) {
+ fun setPushClass(account: Account, folderId: Long, folderClass: FolderClass) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.setPushClass(folderId, folderClass)
}
- fun setNotificationClass(folderId: Long, folderClass: FolderClass) {
+ fun setNotificationClass(account: Account, folderId: Long, folderClass: FolderClass) {
val messageStore = messageStoreManager.getMessageStore(account)
messageStore.setNotificationClass(folderId, folderClass)
}
- private fun folderTypeOf(folderId: Long) = when (folderId) {
+ private fun folderTypeOf(account: Account, folderId: Long) = when (folderId) {
account.inboxFolderId -> FolderType.INBOX
account.outboxFolderId -> FolderType.OUTBOX
account.sentFolderId -> FolderType.SENT
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepositoryManager.kt b/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepositoryManager.kt
deleted file mode 100644
index 95bae73c20..0000000000
--- a/app/core/src/main/java/com/fsck/k9/mailstore/FolderRepositoryManager.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.fsck.k9.mailstore
-
-import com.fsck.k9.Account
-import com.fsck.k9.preferences.AccountManager
-
-class FolderRepositoryManager(
- private val messageStoreManager: MessageStoreManager,
- private val accountManager: AccountManager
-) {
- fun getFolderRepository(account: Account): FolderRepository {
- return FolderRepository(messageStoreManager, accountManager, account)
- }
-}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendStorageFactory.kt b/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendStorageFactory.kt
index ab42cf04a5..211c74a57c 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendStorageFactory.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/K9BackendStorageFactory.kt
@@ -5,13 +5,12 @@ import com.fsck.k9.Preferences
class K9BackendStorageFactory(
private val preferences: Preferences,
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val messageStoreManager: MessageStoreManager,
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy,
private val saveMessageDataCreator: SaveMessageDataCreator
) {
fun createBackendStorage(account: Account): K9BackendStorage {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
val messageStore = messageStoreManager.getMessageStore(account)
val folderSettingsProvider = FolderSettingsProvider(preferences, account)
val specialFolderUpdater = SpecialFolderUpdater(
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt
index 3a14fb1bd1..5f657ecaa4 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/KoinModule.kt
@@ -6,7 +6,7 @@ import com.fsck.k9.message.extractors.MessagePreviewCreator
import org.koin.dsl.module
val mailStoreModule = module {
- single { FolderRepositoryManager(messageStoreManager = get(), accountManager = get()) }
+ single { FolderRepository(messageStoreManager = get(), accountManager = get()) }
single { MessageViewInfoExtractorFactory(get(), get(), get()) }
single { StorageManager.getInstance(get()) }
single { SearchStatusManager() }
@@ -14,7 +14,7 @@ val mailStoreModule = module {
single {
K9BackendStorageFactory(
preferences = get(),
- folderRepositoryManager = get(),
+ folderRepository = get(),
messageStoreManager = get(),
specialFolderSelectionStrategy = get(),
saveMessageDataCreator = get()
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/SpecialFolderUpdater.kt b/app/core/src/main/java/com/fsck/k9/mailstore/SpecialFolderUpdater.kt
index 908699a8bb..e25f08c776 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/SpecialFolderUpdater.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/SpecialFolderUpdater.kt
@@ -18,7 +18,7 @@ class SpecialFolderUpdater(
private val account: Account
) {
fun updateSpecialFolders() {
- val folders = folderRepository.getRemoteFolders()
+ val folders = folderRepository.getRemoteFolders(account)
updateInbox(folders)
@@ -42,15 +42,15 @@ class SpecialFolderUpdater(
account.inboxFolderId = newInboxId
if (oldInboxId != null && folders.any { it.id == oldInboxId }) {
- folderRepository.setIncludeInUnifiedInbox(oldInboxId, false)
+ folderRepository.setIncludeInUnifiedInbox(account, oldInboxId, false)
}
if (newInboxId != null) {
- folderRepository.setIncludeInUnifiedInbox(newInboxId, true)
- folderRepository.setDisplayClass(newInboxId, FolderClass.FIRST_CLASS)
- folderRepository.setSyncClass(newInboxId, FolderClass.FIRST_CLASS)
- folderRepository.setPushClass(newInboxId, FolderClass.FIRST_CLASS)
- folderRepository.setNotificationClass(newInboxId, FolderClass.FIRST_CLASS)
+ folderRepository.setIncludeInUnifiedInbox(account, newInboxId, true)
+ folderRepository.setDisplayClass(account, newInboxId, FolderClass.FIRST_CLASS)
+ folderRepository.setSyncClass(account, newInboxId, FolderClass.FIRST_CLASS)
+ folderRepository.setPushClass(account, newInboxId, FolderClass.FIRST_CLASS)
+ folderRepository.setNotificationClass(account, newInboxId, FolderClass.FIRST_CLASS)
}
}
@@ -117,8 +117,8 @@ class SpecialFolderUpdater(
}
if (folderId != null) {
- folderRepository.setDisplayClass(folderId, FolderClass.FIRST_CLASS)
- folderRepository.setSyncClass(folderId, FolderClass.NO_CLASS)
+ folderRepository.setDisplayClass(account, folderId, FolderClass.FIRST_CLASS)
+ folderRepository.setSyncClass(account, folderId, FolderClass.NO_CLASS)
}
}
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/FolderSettingsProvider.kt b/app/core/src/main/java/com/fsck/k9/preferences/FolderSettingsProvider.kt
index 8485a0752f..559a4ceb06 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/FolderSettingsProvider.kt
+++ b/app/core/src/main/java/com/fsck/k9/preferences/FolderSettingsProvider.kt
@@ -2,13 +2,12 @@ package com.fsck.k9.preferences
import com.fsck.k9.Account
import com.fsck.k9.mail.FolderClass
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.mailstore.RemoteFolderDetails
-class FolderSettingsProvider(private val folderRepositoryManager: FolderRepositoryManager) {
+class FolderSettingsProvider(private val folderRepository: FolderRepository) {
fun getFolderSettings(account: Account): List {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
- return folderRepository.getRemoteFolderDetails()
+ return folderRepository.getRemoteFolderDetails(account)
.filterNot { it.containsOnlyDefaultValues() }
.map { it.toFolderSettings() }
}
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt b/app/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
index 29acdbdb2a..8d1ca4c88a 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
+++ b/app/core/src/main/java/com/fsck/k9/preferences/KoinModule.kt
@@ -11,10 +11,10 @@ val preferencesModule = module {
contentResolver = get(),
preferences = get(),
folderSettingsProvider = get(),
- folderRepositoryManager = get()
+ folderRepository = get()
)
}
- factory { FolderSettingsProvider(folderRepositoryManager = get()) }
+ factory { FolderSettingsProvider(folderRepository = get()) }
factory { get() }
single {
RealGeneralSettingsManager(
diff --git a/app/core/src/main/java/com/fsck/k9/preferences/SettingsExporter.kt b/app/core/src/main/java/com/fsck/k9/preferences/SettingsExporter.kt
index 8fcdb6063f..f8f09c264b 100644
--- a/app/core/src/main/java/com/fsck/k9/preferences/SettingsExporter.kt
+++ b/app/core/src/main/java/com/fsck/k9/preferences/SettingsExporter.kt
@@ -10,7 +10,6 @@ import com.fsck.k9.AccountPreferenceSerializer.Companion.IDENTITY_EMAIL_KEY
import com.fsck.k9.AccountPreferenceSerializer.Companion.IDENTITY_NAME_KEY
import com.fsck.k9.Preferences
import com.fsck.k9.mailstore.FolderRepository
-import com.fsck.k9.mailstore.FolderRepositoryManager
import com.fsck.k9.preferences.ServerTypeConverter.fromServerSettingsType
import com.fsck.k9.preferences.Settings.InvalidSettingValueException
import com.fsck.k9.preferences.Settings.SettingsDescription
@@ -24,7 +23,7 @@ class SettingsExporter(
private val contentResolver: ContentResolver,
private val preferences: Preferences,
private val folderSettingsProvider: FolderSettingsProvider,
- private val folderRepositoryManager: FolderRepositoryManager
+ private val folderRepository: FolderRepository
) {
@Throws(SettingsImportExportException::class)
fun exportToUri(includeGlobals: Boolean, accountUuids: Set, uri: Uri) {
@@ -211,7 +210,6 @@ class SettingsExporter(
}
}
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
writeFolderNameSettings(account, folderRepository, serializer)
serializer.endTag(null, SETTINGS_ELEMENT)
@@ -272,7 +270,7 @@ class SettingsExporter(
) {
fun writeFolderNameSetting(key: String, folderId: Long?, importedFolderServerId: String?) {
val folderServerId = folderId?.let {
- folderRepository.getFolderServerId(folderId)
+ folderRepository.getFolderServerId(account, folderId)
} ?: importedFolderServerId
if (folderServerId != null) {
diff --git a/app/core/src/test/java/com/fsck/k9/preferences/SettingsExporterTest.kt b/app/core/src/test/java/com/fsck/k9/preferences/SettingsExporterTest.kt
index d03f923d24..b92e017ba3 100644
--- a/app/core/src/test/java/com/fsck/k9/preferences/SettingsExporterTest.kt
+++ b/app/core/src/test/java/com/fsck/k9/preferences/SettingsExporterTest.kt
@@ -2,7 +2,7 @@ package com.fsck.k9.preferences
import com.fsck.k9.K9RobolectricTest
import com.fsck.k9.Preferences
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import java.io.ByteArrayOutputStream
import org.jdom2.Document
import org.jdom2.input.SAXBuilder
@@ -17,12 +17,12 @@ class SettingsExporterTest : K9RobolectricTest() {
private val contentResolver = RuntimeEnvironment.application.contentResolver
private val preferences: Preferences by inject()
private val folderSettingsProvider: FolderSettingsProvider by inject()
- private val folderRepositoryManager: FolderRepositoryManager by inject()
+ private val folderRepository: FolderRepository by inject()
private val settingsExporter = SettingsExporter(
contentResolver,
preferences,
folderSettingsProvider,
- folderRepositoryManager
+ folderRepository
)
@Test
diff --git a/app/k9mail-jmap/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt b/app/k9mail-jmap/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
index 574b92885f..0098b96e46 100644
--- a/app/k9mail-jmap/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
+++ b/app/k9mail-jmap/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
@@ -8,13 +8,13 @@ import com.fsck.k9.mail.ssl.TrustManagerFactory
import com.fsck.k9.mail.store.webdav.DraftsFolderProvider
import com.fsck.k9.mail.store.webdav.WebDavStore
import com.fsck.k9.mail.transport.WebDavTransport
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.mailstore.K9BackendStorageFactory
class WebDavBackendFactory(
private val backendStorageFactory: K9BackendStorageFactory,
private val trustManagerFactory: TrustManagerFactory,
- private val folderRepositoryManager: FolderRepositoryManager
+ private val folderRepository: FolderRepository
) : BackendFactory {
override fun createBackend(account: Account): Backend {
val accountName = account.displayName
@@ -27,10 +27,9 @@ class WebDavBackendFactory(
}
private fun createDraftsFolderProvider(account: Account): DraftsFolderProvider {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
return DraftsFolderProvider {
val draftsFolderId = account.draftsFolderId ?: error("No Drafts folder configured")
- folderRepository.getFolderServerId(draftsFolderId) ?: error("Couldn't find local Drafts folder")
+ folderRepository.getFolderServerId(account, draftsFolderId) ?: error("Couldn't find local Drafts folder")
}
}
}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt b/app/k9mail/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
index 574b92885f..0098b96e46 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/backends/WebDavBackendFactory.kt
@@ -8,13 +8,13 @@ import com.fsck.k9.mail.ssl.TrustManagerFactory
import com.fsck.k9.mail.store.webdav.DraftsFolderProvider
import com.fsck.k9.mail.store.webdav.WebDavStore
import com.fsck.k9.mail.transport.WebDavTransport
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.mailstore.K9BackendStorageFactory
class WebDavBackendFactory(
private val backendStorageFactory: K9BackendStorageFactory,
private val trustManagerFactory: TrustManagerFactory,
- private val folderRepositoryManager: FolderRepositoryManager
+ private val folderRepository: FolderRepository
) : BackendFactory {
override fun createBackend(account: Account): Backend {
val accountName = account.displayName
@@ -27,10 +27,9 @@ class WebDavBackendFactory(
}
private fun createDraftsFolderProvider(account: Account): DraftsFolderProvider {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
return DraftsFolderProvider {
val draftsFolderId = account.draftsFolderId ?: error("No Drafts folder configured")
- folderRepository.getFolderServerId(draftsFolderId) ?: error("Couldn't find local Drafts folder")
+ folderRepository.getFolderServerId(account, draftsFolderId) ?: error("Couldn't find local Drafts folder")
}
}
}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/KoinModule.kt b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/KoinModule.kt
index 1adad66c0f..1cae6a4fde 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/KoinModule.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/KoinModule.kt
@@ -10,11 +10,11 @@ val unreadWidgetModule = module {
preferences = get(),
messagingController = get(),
defaultFolderProvider = get(),
- folderRepositoryManager = get(),
+ folderRepository = get(),
folderNameFormatterFactory = get()
)
}
single { UnreadWidgetUpdater(context = get()) }
single { UnreadWidgetUpdateListener(unreadWidgetUpdater = get()) }
- single { UnreadWidgetMigrations(accountRepository = get(), folderRepositoryManager = get()) }
+ single { UnreadWidgetMigrations(accountRepository = get(), folderRepository = get()) }
}
diff --git a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetDataProvider.kt b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetDataProvider.kt
index 1de02427e0..b2b63a82e5 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetDataProvider.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetDataProvider.kt
@@ -7,7 +7,7 @@ import com.fsck.k9.Preferences
import com.fsck.k9.R
import com.fsck.k9.activity.MessageList
import com.fsck.k9.controller.MessagingController
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.search.LocalSearch
import com.fsck.k9.search.SearchAccount
import com.fsck.k9.ui.folders.FolderNameFormatterFactory
@@ -19,7 +19,7 @@ class UnreadWidgetDataProvider(
private val preferences: Preferences,
private val messagingController: MessagingController,
private val defaultFolderProvider: DefaultFolderProvider,
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val folderNameFormatterFactory: FolderNameFormatterFactory
) {
fun loadUnreadWidgetData(configuration: UnreadWidgetConfiguration): UnreadWidgetData? = with(configuration) {
@@ -78,8 +78,7 @@ class UnreadWidgetDataProvider(
}
private fun getFolderDisplayName(account: Account, folderId: Long): String {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
- val folder = folderRepository.getFolder(folderId)
+ val folder = folderRepository.getFolder(account, folderId)
return if (folder != null) {
val folderNameFormatter = folderNameFormatterFactory.create(context)
folderNameFormatter.displayName(folder)
diff --git a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetMigrations.kt b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetMigrations.kt
index d2b518dcf0..4221ccef74 100644
--- a/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetMigrations.kt
+++ b/app/k9mail/src/main/java/com/fsck/k9/widget/unread/UnreadWidgetMigrations.kt
@@ -3,13 +3,13 @@ package com.fsck.k9.widget.unread
import android.content.SharedPreferences
import androidx.core.content.edit
import com.fsck.k9.Preferences
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.widget.unread.UnreadWidgetRepository.Companion.PREFS_VERSION
import com.fsck.k9.widget.unread.UnreadWidgetRepository.Companion.PREF_VERSION_KEY
internal class UnreadWidgetMigrations(
private val accountRepository: Preferences,
- private val folderRepositoryManager: FolderRepositoryManager
+ private val folderRepository: FolderRepository
) {
fun upgradePreferences(preferences: SharedPreferences, version: Int) {
if (version < 2) rewriteFolderNameToFolderId(preferences)
@@ -33,8 +33,7 @@ internal class UnreadWidgetMigrations(
val folderServerId = preferences.getString("unread_widget.$widgetId.folder_name", null)
if (folderServerId != null) {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
- val folderId = folderRepository.getFolderId(folderServerId)
+ val folderId = folderRepository.getFolderId(account, folderServerId)
putString("unread_widget.$widgetId.folder_id", folderId?.toString())
}
diff --git a/app/k9mail/src/test/java/com/fsck/k9/widget/unread/UnreadWidgetDataProviderTest.kt b/app/k9mail/src/test/java/com/fsck/k9/widget/unread/UnreadWidgetDataProviderTest.kt
index d85224e262..e701181fb1 100644
--- a/app/k9mail/src/test/java/com/fsck/k9/widget/unread/UnreadWidgetDataProviderTest.kt
+++ b/app/k9mail/src/test/java/com/fsck/k9/widget/unread/UnreadWidgetDataProviderTest.kt
@@ -7,7 +7,6 @@ import com.fsck.k9.Preferences
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.mailstore.Folder
import com.fsck.k9.mailstore.FolderRepository
-import com.fsck.k9.mailstore.FolderRepositoryManager
import com.fsck.k9.mailstore.FolderType
import com.fsck.k9.search.SearchAccount
import com.fsck.k9.ui.folders.FolderNameFormatter
@@ -27,11 +26,11 @@ class UnreadWidgetDataProviderTest : AppRobolectricTest() {
val preferences = createPreferences()
val messagingController = createMessagingController()
val defaultFolderStrategy = createDefaultFolderStrategy()
- val folderRepositoryManager = createFolderRepositoryManager()
+ val folderRepository = createFolderRepository()
val folderNameFormatterFactory = createFolderNameFormatterFactory()
val provider = UnreadWidgetDataProvider(
context, preferences, messagingController, defaultFolderStrategy,
- folderRepositoryManager, folderNameFormatterFactory
+ folderRepository, folderNameFormatterFactory
)
@Test
@@ -102,16 +101,9 @@ class UnreadWidgetDataProviderTest : AppRobolectricTest() {
on { getDefaultFolder(account) } doReturn FOLDER_ID
}
- fun createFolderRepositoryManager(): FolderRepositoryManager {
- val folderRepository = createFolderRepository()
- return mock {
- on { getFolderRepository(account) } doReturn folderRepository
- }
- }
-
fun createFolderRepository(): FolderRepository {
return mock {
- on { getFolder(FOLDER_ID) } doReturn FOLDER
+ on { getFolder(account, FOLDER_ID) } doReturn FOLDER
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt
index 5e95c31fdc..d22748d200 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt
@@ -11,7 +11,7 @@ class ChooseFolderViewModel(private val foldersLiveDataFactory: FoldersLiveDataF
fun getFolders(account: Account, displayMode: FolderMode): FoldersLiveData {
val liveData = foldersLiveData
- if (liveData != null && liveData.accountUuid == account.uuid && liveData.displayMode == displayMode) {
+ if (liveData != null && liveData.account.uuid == account.uuid && liveData.displayMode == displayMode) {
return liveData
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveData.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveData.kt
index c1290de855..561b3951dc 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveData.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveData.kt
@@ -18,16 +18,13 @@ class FoldersLiveData(
private val folderRepository: FolderRepository,
private val messagingController: MessagingController,
private val preferences: Preferences,
- val accountUuid: String,
+ val account: Account,
val displayMode: FolderMode?
) : LiveData>() {
private val messagingListener = object : SimpleMessagingListener() {
- override fun folderStatusChanged(
- account: Account,
- folderId: Long
- ) {
- if (account?.uuid == accountUuid) {
+ override fun folderStatusChanged(account: Account, folderId: Long) {
+ if (account.uuid == this@FoldersLiveData.account.uuid) {
loadFoldersAsync()
}
}
@@ -39,7 +36,10 @@ class FoldersLiveData(
private fun loadFoldersAsync() {
GlobalScope.launch(Dispatchers.Main) {
- value = withContext(Dispatchers.IO) { folderRepository.getDisplayFolders(displayMode) }
+ val displayFolders = withContext(Dispatchers.IO) {
+ folderRepository.getDisplayFolders(account, displayMode)
+ }
+ value = displayFolders
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveDataFactory.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveDataFactory.kt
index 06a68f0dee..1c1e684206 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveDataFactory.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersLiveDataFactory.kt
@@ -4,15 +4,14 @@ import com.fsck.k9.Account
import com.fsck.k9.Account.FolderMode
import com.fsck.k9.Preferences
import com.fsck.k9.controller.MessagingController
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
class FoldersLiveDataFactory(
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val messagingController: MessagingController,
private val preferences: Preferences
) {
fun create(account: Account, displayMode: FolderMode? = null): FoldersLiveData {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
- return FoldersLiveData(folderRepository, messagingController, preferences, account.uuid, displayMode)
+ return FoldersLiveData(folderRepository, messagingController, preferences, account, displayMode)
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt
index 3df964660b..6216580d2f 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt
@@ -15,7 +15,7 @@ class FoldersViewModel(private val foldersLiveDataFactory: FoldersLiveDataFactor
}
fun loadFolders(account: Account) {
- if (currentFoldersLiveData?.accountUuid == account.uuid) return
+ if (currentFoldersLiveData?.account?.uuid == account.uuid) return
removeCurrentFoldersLiveData()
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsDataStore.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsDataStore.kt
index 1df1cb4540..4775b493a9 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsDataStore.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsDataStore.kt
@@ -1,6 +1,7 @@
package com.fsck.k9.ui.managefolders
import androidx.preference.PreferenceDataStore
+import com.fsck.k9.Account
import com.fsck.k9.mail.FolderClass
import com.fsck.k9.mailstore.FolderDetails
import com.fsck.k9.mailstore.FolderRepository
@@ -11,6 +12,7 @@ import kotlinx.coroutines.launch
class FolderSettingsDataStore(
private val folderRepository: FolderRepository,
+ private val account: Account,
private var folder: FolderDetails
) : PreferenceDataStore() {
private val saveScope = CoroutineScope(GlobalScope.coroutineContext + Dispatchers.IO)
@@ -64,7 +66,7 @@ class FolderSettingsDataStore(
private fun updateFolder(newFolder: FolderDetails) {
folder = newFolder
saveScope.launch {
- folderRepository.updateFolderDetails(newFolder)
+ folderRepository.updateFolderDetails(account, newFolder)
}
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsViewModel.kt
index 96b9b9135b..7c047ecaa0 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/FolderSettingsViewModel.kt
@@ -11,7 +11,6 @@ import com.fsck.k9.helper.SingleLiveEvent
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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
@@ -20,7 +19,7 @@ private const val NO_FOLDER_ID = 0L
class FolderSettingsViewModel(
private val preferences: Preferences,
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val messagingController: MessagingController
) : ViewModel() {
private val actionLiveData = SingleLiveEvent()
@@ -44,8 +43,7 @@ class FolderSettingsViewModel(
): LiveData {
return liveData(context = viewModelScope.coroutineContext) {
val account = loadAccount(accountUuid)
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
- val folderDetails = folderRepository.loadFolderDetails(folderId)
+ val folderDetails = folderRepository.loadFolderDetails(account, folderId)
if (folderDetails == null) {
Timber.w("Folder with ID $folderId not found")
emit(FolderNotFound)
@@ -57,7 +55,7 @@ class FolderSettingsViewModel(
val folderSettingsData = FolderSettingsData(
folder = folderDetails.folder,
- dataStore = FolderSettingsDataStore(folderRepository, folderDetails)
+ dataStore = FolderSettingsDataStore(folderRepository, account, folderDetails)
)
emit(folderSettingsData)
}
@@ -69,9 +67,9 @@ class FolderSettingsViewModel(
}
}
- private suspend fun FolderRepository.loadFolderDetails(folderId: Long): FolderDetails? {
+ private suspend fun FolderRepository.loadFolderDetails(account: Account, folderId: Long): FolderDetails? {
return withContext(Dispatchers.IO) {
- getFolderDetails(folderId)
+ getFolderDetails(account, folderId)
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/KoinModule.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/KoinModule.kt
index 7f9b1ca634..f80e24947f 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/KoinModule.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/KoinModule.kt
@@ -5,5 +5,5 @@ import org.koin.dsl.module
val manageFoldersUiModule = module {
viewModel { ManageFoldersViewModel(foldersLiveDataFactory = get()) }
- viewModel { FolderSettingsViewModel(preferences = get(), folderRepositoryManager = get(), messagingController = get()) }
+ viewModel { FolderSettingsViewModel(preferences = get(), folderRepository = get(), messagingController = get()) }
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt
index c938c48eb4..32ae36314c 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/managefolders/ManageFoldersViewModel.kt
@@ -10,7 +10,7 @@ class ManageFoldersViewModel(private val foldersLiveDataFactory: FoldersLiveData
fun getFolders(account: Account): FoldersLiveData {
val liveData = foldersLiveData
- if (liveData != null && liveData.accountUuid == account.uuid) {
+ if (liveData != null && liveData.account.uuid == account.uuid) {
return liveData
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsViewModel.kt b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsViewModel.kt
index b24c8d8356..8214b2615e 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsViewModel.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/ui/settings/account/AccountSettingsViewModel.kt
@@ -5,7 +5,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.fsck.k9.Account
import com.fsck.k9.Preferences
-import com.fsck.k9.mailstore.FolderRepositoryManager
+import com.fsck.k9.mailstore.FolderRepository
import com.fsck.k9.mailstore.FolderType
import com.fsck.k9.mailstore.RemoteFolder
import com.fsck.k9.mailstore.SpecialFolderSelectionStrategy
@@ -17,7 +17,7 @@ import kotlinx.coroutines.withContext
class AccountSettingsViewModel(
private val preferences: Preferences,
- private val folderRepositoryManager: FolderRepositoryManager,
+ private val folderRepository: FolderRepository,
private val specialFolderSelectionStrategy: SpecialFolderSelectionStrategy
) : ViewModel() {
val accounts = AccountsLiveData(preferences)
@@ -28,9 +28,10 @@ class AccountSettingsViewModel(
if (accountLiveData.value == null) {
GlobalScope.launch(Dispatchers.Main) {
- accountLiveData.value = withContext(Dispatchers.IO) {
+ val account = withContext(Dispatchers.IO) {
loadAccount(accountUuid)
}
+ accountLiveData.value = account
}
}
@@ -60,13 +61,13 @@ class AccountSettingsViewModel(
}
private fun loadFolders(account: Account) {
- val folderRepository = folderRepositoryManager.getFolderRepository(account)
GlobalScope.launch(Dispatchers.Main) {
- foldersLiveData.value = withContext(Dispatchers.IO) {
- val folders = folderRepository.getRemoteFolders()
+ val remoteFolderInfo = withContext(Dispatchers.IO) {
+ val folders = folderRepository.getRemoteFolders(account)
val automaticSpecialFolders = getAutomaticSpecialFolders(folders)
RemoteFolderInfo(folders, automaticSpecialFolders)
}
+ foldersLiveData.value = remoteFolderInfo
}
}
--
GitLab
From 32aefc2795aff0ba2a3ed6f4c80afc91b3a85008 Mon Sep 17 00:00:00 2001
From: cketti
Date: Sat, 28 Aug 2021 03:13:21 +0200
Subject: [PATCH 073/285] Fix ServerSettings.isMissingCredentials
We support SMTP without authentication and in that case set the username to the empty string :(
---
mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
index d51ad9045c..6107331e6b 100644
--- a/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
+++ b/mail/common/src/main/java/com/fsck/k9/mail/ServerSettings.kt
@@ -18,7 +18,7 @@ data class ServerSettings @JvmOverloads constructor(
) {
val isMissingCredentials: Boolean = when (authenticationType) {
AuthType.EXTERNAL -> clientCertificateAlias == null
- else -> password == null
+ else -> username.isNotBlank() && password == null
}
init {
--
GitLab
From f9a08fbc15a04e3ff9f9fa40b82fd90900abfd95 Mon Sep 17 00:00:00 2001
From: cketti
Date: Mon, 30 Aug 2021 19:50:27 +0200
Subject: [PATCH 074/285] Version 5.806
---
app/k9mail/build.gradle | 4 ++--
app/ui/legacy/src/main/res/raw/changelog_master.xml | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/app/k9mail/build.gradle b/app/k9mail/build.gradle
index c1995eef47..f062fc529a 100644
--- a/app/k9mail/build.gradle
+++ b/app/k9mail/build.gradle
@@ -46,8 +46,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
- versionCode 28005
- versionName '5.805'
+ versionCode 28006
+ versionName '5.806'
// Keep in sync with the resource string array 'supported_languages'
resConfigs "in", "br", "ca", "cs", "cy", "da", "de", "et", "en", "en_GB", "es", "eo", "eu", "fr", "gd", "gl",
diff --git a/app/ui/legacy/src/main/res/raw/changelog_master.xml b/app/ui/legacy/src/main/res/raw/changelog_master.xml
index 35c619742e..722a4984ae 100644
--- a/app/ui/legacy/src/main/res/raw/changelog_master.xml
+++ b/app/ui/legacy/src/main/res/raw/changelog_master.xml
@@ -5,6 +5,9 @@
Locale-specific versions are kept in res/raw-/changelog.xml.
-->
+
+ Fixed the check for missing outgoing server credentials, again… hopefully 🤞
+
Fixed the check for missing incoming/outgoing server credentials (introduced in K-9 Mail 5.804)
Changed the 'save attachment' icon (apparently floppy disks are no longer a thing)
--
GitLab
From 9a0c6843a759beeb00a0ef2a9d7cbcf86075e727 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 31 Aug 2021 03:13:14 +0200
Subject: [PATCH 075/285] Rename .java to .kt
---
.../compose/{RecipientMvpView.java => RecipientMvpView.kt} | 0
.../compose/{RecipientPresenter.java => RecipientPresenter.kt} | 0
.../{RecipientPresenterTest.java => RecipientPresenterTest.kt} | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/{RecipientMvpView.java => RecipientMvpView.kt} (100%)
rename app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/{RecipientPresenter.java => RecipientPresenter.kt} (100%)
rename app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/{RecipientPresenterTest.java => RecipientPresenterTest.kt} (100%)
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt
similarity index 100%
rename from app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.java
rename to app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.java b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt
similarity index 100%
rename from app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.java
rename to app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt
diff --git a/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.java b/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt
similarity index 100%
rename from app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.java
rename to app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt
--
GitLab
From 5793d2e68f3c8e6687dce904520d9897644a0b63 Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 31 Aug 2021 03:13:15 +0200
Subject: [PATCH 076/285] Convert RecipientPresenter to Kotlin
---
app/ui/legacy/build.gradle | 1 +
.../k9/activity/compose/RecipientMvpView.kt | 665 ++++------
.../k9/activity/compose/RecipientPresenter.kt | 1140 ++++++++---------
.../compose/RecipientPresenterTest.kt | 490 +++----
4 files changed, 1029 insertions(+), 1267 deletions(-)
diff --git a/app/ui/legacy/build.gradle b/app/ui/legacy/build.gradle
index af35825004..bb856b542e 100644
--- a/app/ui/legacy/build.gradle
+++ b/app/ui/legacy/build.gradle
@@ -58,6 +58,7 @@ dependencies {
testImplementation "org.robolectric:robolectric:${versions.robolectric}"
testImplementation "androidx.test:core:${versions.androidxTestCore}"
testImplementation "junit:junit:${versions.junit}"
+ testImplementation "org.jetbrains.kotlin:kotlin-test:${versions.kotlin}"
testImplementation "com.google.truth:truth:${versions.truth}"
testImplementation "org.mockito:mockito-core:${versions.mockito}"
testImplementation "org.mockito.kotlin:mockito-kotlin:${versions.mockitoKotlin}"
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt
index 049c0279bc..60f5b84f62 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientMvpView.kt
@@ -1,514 +1,387 @@
-package com.fsck.k9.activity.compose;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import android.app.PendingIntent;
-import androidx.loader.app.LoaderManager;
-import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
-import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
-import android.text.TextWatcher;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ViewAnimator;
-
-import com.fsck.k9.FontSizes;
-import com.fsck.k9.ui.R;
-import com.fsck.k9.activity.MessageCompose;
-import com.fsck.k9.mail.Address;
-import com.fsck.k9.mail.Message.RecipientType;
-import com.fsck.k9.view.RecipientSelectView;
-import com.fsck.k9.view.RecipientSelectView.Recipient;
-import com.fsck.k9.view.RecipientSelectView.TokenListener;
-import com.fsck.k9.view.ToolableViewAnimator;
-
-import static com.fsck.k9.FontSizes.FONT_10SP;
-import static com.fsck.k9.FontSizes.FONT_12SP;
-import static com.fsck.k9.FontSizes.FONT_16SP;
-import static com.fsck.k9.FontSizes.FONT_20SP;
-import static com.fsck.k9.FontSizes.FONT_DEFAULT;
-import static com.fsck.k9.FontSizes.LARGE;
-import static com.fsck.k9.FontSizes.MEDIUM;
-import static com.fsck.k9.FontSizes.SMALL;
-
-
-public class RecipientMvpView implements OnFocusChangeListener, OnClickListener {
- private static final int VIEW_INDEX_HIDDEN = -1;
-
- private static final int VIEW_INDEX_BCC_EXPANDER_VISIBLE = 0;
- private static final int VIEW_INDEX_BCC_EXPANDER_HIDDEN = 1;
-
- private static final FastOutLinearInInterpolator CRYPTO_ICON_OUT_ANIMATOR = new FastOutLinearInInterpolator();
- private static final int CRYPTO_ICON_OUT_DURATION = 195;
- private static final LinearOutSlowInInterpolator CRYPTO_ICON_IN_ANIMATOR = new LinearOutSlowInInterpolator();
- private static final int CRYPTO_ICON_IN_DURATION = 225;
-
- private final MessageCompose activity;
- private final View ccWrapper;
- private final View ccDivider;
- private final View bccWrapper;
- private final View bccDivider;
- private final RecipientSelectView toView;
- private final RecipientSelectView ccView;
- private final RecipientSelectView bccView;
- private final ToolableViewAnimator cryptoStatusView;
- private final ViewAnimator recipientExpanderContainer;
- private final ToolableViewAnimator cryptoSpecialModeIndicator;
- private final Set textWatchers = new HashSet<>();
- private RecipientPresenter presenter;
-
-
- public RecipientMvpView(MessageCompose activity) {
- this.activity = activity;
-
- toView = activity.findViewById(R.id.to);
- ccView = activity.findViewById(R.id.cc);
- bccView = activity.findViewById(R.id.bcc);
- ccWrapper = activity.findViewById(R.id.cc_wrapper);
- ccDivider = activity.findViewById(R.id.cc_divider);
- bccWrapper = activity.findViewById(R.id.bcc_wrapper);
- bccDivider = activity.findViewById(R.id.bcc_divider);
- recipientExpanderContainer = activity.findViewById(R.id.recipient_expander_container);
- cryptoStatusView = activity.findViewById(R.id.crypto_status);
- cryptoStatusView.setOnClickListener(this);
- cryptoSpecialModeIndicator = activity.findViewById(R.id.crypto_special_mode);
- cryptoSpecialModeIndicator.setOnClickListener(this);
-
- toView.setOnFocusChangeListener(this);
- ccView.setOnFocusChangeListener(this);
- bccView.setOnFocusChangeListener(this);
-
- View recipientExpander = activity.findViewById(R.id.recipient_expander);
- recipientExpander.setOnClickListener(this);
-
- View toLabel = activity.findViewById(R.id.to_label);
- View ccLabel = activity.findViewById(R.id.cc_label);
- View bccLabel = activity.findViewById(R.id.bcc_label);
- toLabel.setOnClickListener(this);
- ccLabel.setOnClickListener(this);
- bccLabel.setOnClickListener(this);
- }
-
- public void setPresenter(final RecipientPresenter presenter) {
- this.presenter = presenter;
-
- if (presenter == null) {
- toView.setTokenListener(null);
- ccView.setTokenListener(null);
- bccView.setTokenListener(null);
- return;
- }
+package com.fsck.k9.activity.compose
+
+import android.app.PendingIntent
+import android.text.TextWatcher
+import android.view.View
+import android.widget.TextView
+import android.widget.Toast
+import android.widget.ViewAnimator
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
+import androidx.interpolator.view.animation.FastOutLinearInInterpolator
+import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
+import androidx.loader.app.LoaderManager
+import com.fsck.k9.FontSizes
+import com.fsck.k9.activity.MessageCompose
+import com.fsck.k9.mail.Address
+import com.fsck.k9.mail.Message.RecipientType
+import com.fsck.k9.ui.R
+import com.fsck.k9.view.RecipientSelectView
+import com.fsck.k9.view.RecipientSelectView.Recipient
+import com.fsck.k9.view.ToolableViewAnimator
+import java.lang.AssertionError
- toView.setTokenListener(new TokenListener() {
- @Override
- public void onTokenAdded(Recipient recipient) {
- presenter.onToTokenAdded();
- }
+class RecipientMvpView(private val activity: MessageCompose) : View.OnFocusChangeListener, View.OnClickListener {
+ private val toView: RecipientSelectView = activity.findViewById(R.id.to)
+ private val ccView: RecipientSelectView = activity.findViewById(R.id.cc)
+ private val bccView: RecipientSelectView = activity.findViewById(R.id.bcc)
+ private val ccWrapper: View = activity.findViewById(R.id.cc_wrapper)
+ private val ccDivider: View = activity.findViewById(R.id.cc_divider)
+ private val bccWrapper: View = activity.findViewById(R.id.bcc_wrapper)
+ private val bccDivider: View = activity.findViewById(R.id.bcc_divider)
+ private val recipientExpanderContainer: ViewAnimator = activity.findViewById(R.id.recipient_expander_container)
+ private val cryptoStatusView: ToolableViewAnimator = activity.findViewById(R.id.crypto_status)
+ private val cryptoSpecialModeIndicator: ToolableViewAnimator = activity.findViewById(R.id.crypto_special_mode)
+ private val textWatchers: MutableSet = HashSet()
+ private lateinit var presenter: RecipientPresenter
- @Override
- public void onTokenRemoved(Recipient recipient) {
- presenter.onToTokenRemoved();
- }
+ init {
+ cryptoStatusView.setOnClickListener(this)
+ cryptoSpecialModeIndicator.setOnClickListener(this)
+ toView.onFocusChangeListener = this
+ ccView.onFocusChangeListener = this
+ bccView.onFocusChangeListener = this
- @Override
- public void onTokenChanged(Recipient recipient) {
- presenter.onToTokenChanged();
- }
+ activity.findViewById(R.id.recipient_expander).setOnClickListener(this)
+ activity.findViewById(R.id.to_label).setOnClickListener(this)
+ activity.findViewById(R.id.cc_label).setOnClickListener(this)
+ activity.findViewById(R.id.bcc_label).setOnClickListener(this)
+ }
- @Override
- public void onTokenIgnored(Recipient token) {
- // Do nothing
- }
- });
+ val isCcVisible: Boolean
+ get() = ccWrapper.isVisible
- ccView.setTokenListener(new TokenListener() {
- @Override
- public void onTokenAdded(Recipient recipient) {
- presenter.onCcTokenAdded();
- }
+ val isBccVisible: Boolean
+ get() = bccWrapper.isVisible
- @Override
- public void onTokenRemoved(Recipient recipient) {
- presenter.onCcTokenRemoved();
- }
+ val toAddresses: List
+ get() = toView.addresses.toList()
- @Override
- public void onTokenChanged(Recipient recipient) {
- presenter.onCcTokenChanged();
- }
+ val ccAddresses: List
+ get() = ccView.addresses.toList()
- @Override
- public void onTokenIgnored(Recipient token) {
- // Do nothing
- }
- });
+ val bccAddresses: List
+ get() = bccView.addresses.toList()
- bccView.setTokenListener(new TokenListener() {
- @Override
- public void onTokenAdded(Recipient recipient) {
- presenter.onBccTokenAdded();
- }
+ val toRecipients: List
+ get() = toView.objects
- @Override
- public void onTokenRemoved(Recipient recipient) {
- presenter.onBccTokenRemoved();
- }
+ val ccRecipients: List
+ get() = ccView.objects
- @Override
- public void onTokenChanged(Recipient recipient) {
- presenter.onBccTokenChanged();
- }
+ val bccRecipients: List
+ get() = bccView.objects
- @Override
- public void onTokenIgnored(Recipient token) {
- // Do nothing
- }
- });
- }
+ fun setPresenter(presenter: RecipientPresenter) {
+ this.presenter = presenter
+ toView.setTokenListener(object : RecipientSelectView.TokenListener {
+ override fun onTokenAdded(recipient: Recipient) = presenter.onToTokenAdded()
- public void addTextChangedListener(TextWatcher textWatcher) {
- textWatchers.add(textWatcher);
+ override fun onTokenRemoved(recipient: Recipient) = presenter.onToTokenRemoved()
- toView.addTextChangedListener(textWatcher);
- ccView.addTextChangedListener(textWatcher);
- bccView.addTextChangedListener(textWatcher);
+ override fun onTokenChanged(recipient: Recipient) = presenter.onToTokenChanged()
+
+ override fun onTokenIgnored(token: Recipient) = Unit
+ })
+
+ ccView.setTokenListener(object : RecipientSelectView.TokenListener {
+ override fun onTokenAdded(recipient: Recipient) = presenter.onCcTokenAdded()
+
+ override fun onTokenRemoved(recipient: Recipient) = presenter.onCcTokenRemoved()
+
+ override fun onTokenChanged(recipient: Recipient) = presenter.onCcTokenChanged()
+
+ override fun onTokenIgnored(token: Recipient) = Unit
+ })
+
+ bccView.setTokenListener(object : RecipientSelectView.TokenListener {
+ override fun onTokenAdded(recipient: Recipient) = presenter.onBccTokenAdded()
+
+ override fun onTokenRemoved(recipient: Recipient) = presenter.onBccTokenRemoved()
+
+ override fun onTokenChanged(recipient: Recipient) = presenter.onBccTokenChanged()
+
+ override fun onTokenIgnored(token: Recipient) = Unit
+ })
+ }
+
+ fun addTextChangedListener(textWatcher: TextWatcher) {
+ textWatchers.add(textWatcher)
+ toView.addTextChangedListener(textWatcher)
+ ccView.addTextChangedListener(textWatcher)
+ bccView.addTextChangedListener(textWatcher)
}
- private void removeAllTextChangedListeners(TextView view) {
- for (TextWatcher textWatcher : textWatchers) {
- view.removeTextChangedListener(textWatcher);
+ private fun removeAllTextChangedListeners(view: TextView) {
+ for (textWatcher in textWatchers) {
+ view.removeTextChangedListener(textWatcher)
}
}
- private void addAllTextChangedListeners(TextView view) {
- for (TextWatcher textWatcher : textWatchers) {
- view.addTextChangedListener(textWatcher);
+ private fun addAllTextChangedListeners(view: TextView) {
+ for (textWatcher in textWatchers) {
+ view.addTextChangedListener(textWatcher)
}
}
- public void setRecipientTokensShowCryptoEnabled(boolean isEnabled) {
- toView.setShowCryptoEnabled(isEnabled);
- ccView.setShowCryptoEnabled(isEnabled);
- bccView.setShowCryptoEnabled(isEnabled);
+ fun setRecipientTokensShowCryptoEnabled(isEnabled: Boolean) {
+ toView.setShowCryptoEnabled(isEnabled)
+ ccView.setShowCryptoEnabled(isEnabled)
+ bccView.setShowCryptoEnabled(isEnabled)
}
- public void setCryptoProvider(String openPgpProvider) {
+ fun setCryptoProvider(openPgpProvider: String?) {
// TODO move "show advanced" into settings, or somewhere?
- toView.setCryptoProvider(openPgpProvider, false);
- ccView.setCryptoProvider(openPgpProvider, false);
- bccView.setCryptoProvider(openPgpProvider, false);
+ toView.setCryptoProvider(openPgpProvider, false)
+ ccView.setCryptoProvider(openPgpProvider, false)
+ bccView.setCryptoProvider(openPgpProvider, false)
}
- public void requestFocusOnToField() {
- toView.requestFocus();
+ fun requestFocusOnToField() {
+ toView.requestFocus()
}
- public void requestFocusOnCcField() {
- ccView.requestFocus();
+ fun requestFocusOnCcField() {
+ ccView.requestFocus()
}
- public void requestFocusOnBccField() {
- bccView.requestFocus();
+ fun requestFocusOnBccField() {
+ bccView.requestFocus()
}
- public void setFontSizes(FontSizes fontSizes, int fontSize) {
- int tokenTextSize = getTokenTextSize(fontSize);
- toView.setTokenTextSize(tokenTextSize);
- ccView.setTokenTextSize(tokenTextSize);
- bccView.setTokenTextSize(tokenTextSize);
- fontSizes.setViewTextSize(toView, fontSize);
- fontSizes.setViewTextSize(ccView, fontSize);
- fontSizes.setViewTextSize(bccView, fontSize);
+ fun setFontSizes(fontSizes: FontSizes, fontSize: Int) {
+ val tokenTextSize = getTokenTextSize(fontSize)
+ toView.setTokenTextSize(tokenTextSize)
+ ccView.setTokenTextSize(tokenTextSize)
+ bccView.setTokenTextSize(tokenTextSize)
+ fontSizes.setViewTextSize(toView, fontSize)
+ fontSizes.setViewTextSize(ccView, fontSize)
+ fontSizes.setViewTextSize(bccView, fontSize)
}
- private int getTokenTextSize(int fontSize) {
- switch (fontSize) {
- case FONT_10SP: return FONT_10SP;
- case FONT_12SP: return FONT_12SP;
- case SMALL: return SMALL;
- case FONT_16SP: return 15;
- case MEDIUM: return FONT_16SP;
- case FONT_20SP: return MEDIUM;
- case LARGE: return FONT_20SP;
- default: return FONT_DEFAULT;
+ private fun getTokenTextSize(fontSize: Int): Int {
+ return when (fontSize) {
+ FontSizes.FONT_10SP -> FontSizes.FONT_10SP
+ FontSizes.FONT_12SP -> FontSizes.FONT_12SP
+ FontSizes.SMALL -> FontSizes.SMALL
+ FontSizes.FONT_16SP -> 15
+ FontSizes.MEDIUM -> FontSizes.FONT_16SP
+ FontSizes.FONT_20SP -> FontSizes.MEDIUM
+ FontSizes.LARGE -> FontSizes.FONT_20SP
+ else -> FontSizes.FONT_DEFAULT
}
}
- public void addRecipients(RecipientType recipientType, Recipient... recipients) {
- switch (recipientType) {
- case TO: {
- toView.addRecipients(recipients);
- break;
- }
- case CC: {
- ccView.addRecipients(recipients);
- break;
- }
- case BCC: {
- bccView.addRecipients(recipients);
- break;
- }
+ fun addRecipients(recipientType: RecipientType, vararg recipients: Recipient) {
+ when (recipientType) {
+ RecipientType.TO -> toView.addRecipients(*recipients)
+ RecipientType.CC -> ccView.addRecipients(*recipients)
+ RecipientType.BCC -> bccView.addRecipients(*recipients)
+ else -> throw AssertionError("Unsupported type: $recipientType")
}
}
- public void silentlyAddBccAddresses(Recipient... recipients) {
- removeAllTextChangedListeners(bccView);
+ fun silentlyAddBccAddresses(vararg recipients: Recipient) {
+ removeAllTextChangedListeners(bccView)
- bccView.addRecipients(recipients);
+ bccView.addRecipients(*recipients)
- addAllTextChangedListeners(bccView);
+ addAllTextChangedListeners(bccView)
}
- public void silentlyRemoveBccAddresses(Address[] addressesToRemove) {
- if (addressesToRemove.length == 0) {
- return;
- }
+ fun silentlyRemoveBccAddresses(addresses: Array) {
+ if (addresses.isEmpty()) return
- List bccRecipients = new ArrayList<>(getBccRecipients());
- for (Recipient recipient : bccRecipients) {
- removeAllTextChangedListeners(bccView);
+ val addressesToRemove = addresses.toSet()
+ for (recipient in bccRecipients.toList()) {
+ removeAllTextChangedListeners(bccView)
- for (Address address : addressesToRemove) {
- if (recipient.address.equals(address)) {
- bccView.removeObjectSync(recipient);
- }
+ if (recipient.address in addressesToRemove) {
+ bccView.removeObjectSync(recipient)
}
- addAllTextChangedListeners(bccView);
- }
- }
-
- public void setCcVisibility(boolean visible) {
- ccWrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
- ccDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
-
- public void setBccVisibility(boolean visible) {
- bccWrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
- bccDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
-
- public void setRecipientExpanderVisibility(boolean visible) {
- int childToDisplay = visible ? VIEW_INDEX_BCC_EXPANDER_VISIBLE : VIEW_INDEX_BCC_EXPANDER_HIDDEN;
- if (recipientExpanderContainer.getDisplayedChild() != childToDisplay) {
- recipientExpanderContainer.setDisplayedChild(childToDisplay);
+ addAllTextChangedListeners(bccView)
}
}
- public boolean isCcVisible() {
- return ccWrapper.getVisibility() == View.VISIBLE;
+ fun setCcVisibility(visible: Boolean) {
+ ccWrapper.isVisible = visible
+ ccDivider.isVisible = visible
}
- public boolean isBccVisible() {
- return bccWrapper.getVisibility() == View.VISIBLE;
+ fun setBccVisibility(visible: Boolean) {
+ bccWrapper.isVisible = visible
+ bccDivider.isVisible = visible
}
- public void showNoRecipientsError() {
- toView.setError(toView.getContext().getString(R.string.message_compose_error_no_recipients));
- }
-
- public List getToAddresses() {
- return Arrays.asList(toView.getAddresses());
- }
-
- public List getCcAddresses() {
- return Arrays.asList(ccView.getAddresses());
- }
-
- public List getBccAddresses() {
- return Arrays.asList(bccView.getAddresses());
- }
+ fun setRecipientExpanderVisibility(visible: Boolean) {
+ val childToDisplay = if (visible) VIEW_INDEX_BCC_EXPANDER_VISIBLE else VIEW_INDEX_BCC_EXPANDER_HIDDEN
- public List getToRecipients() {
- return toView.getObjects();
- }
-
- public List getCcRecipients() {
- return ccView.getObjects();
+ if (recipientExpanderContainer.displayedChild != childToDisplay) {
+ recipientExpanderContainer.displayedChild = childToDisplay
+ }
}
- public List getBccRecipients() {
- return bccView.getObjects();
+ fun showNoRecipientsError() {
+ toView.error = toView.context.getString(R.string.message_compose_error_no_recipients)
}
- public boolean recipientToHasUncompletedText() {
- return toView.hasUncompletedText();
+ fun recipientToHasUncompletedText(): Boolean {
+ return toView.hasUncompletedText()
}
- public boolean recipientCcHasUncompletedText() {
- return ccView.hasUncompletedText();
+ fun recipientCcHasUncompletedText(): Boolean {
+ return ccView.hasUncompletedText()
}
- public boolean recipientBccHasUncompletedText() {
- return bccView.hasUncompletedText();
+ fun recipientBccHasUncompletedText(): Boolean {
+ return bccView.hasUncompletedText()
}
- public boolean recipientToTryPerformCompletion() {
- return toView.tryPerformCompletion();
+ fun recipientToTryPerformCompletion(): Boolean {
+ return toView.tryPerformCompletion()
}
- public boolean recipientCcTryPerformCompletion() {
- return ccView.tryPerformCompletion();
+ fun recipientCcTryPerformCompletion(): Boolean {
+ return ccView.tryPerformCompletion()
}
- public boolean recipientBccTryPerformCompletion() {
- return bccView.tryPerformCompletion();
+ fun recipientBccTryPerformCompletion(): Boolean {
+ return bccView.tryPerformCompletion()
}
- public void showToUncompletedError() {
- toView.setError(toView.getContext().getString(R.string.compose_error_incomplete_recipient));
+ fun showToUncompletedError() {
+ toView.error = toView.context.getString(R.string.compose_error_incomplete_recipient)
}
- public void showCcUncompletedError() {
- ccView.setError(ccView.getContext().getString(R.string.compose_error_incomplete_recipient));
+ fun showCcUncompletedError() {
+ ccView.error = ccView.context.getString(R.string.compose_error_incomplete_recipient)
}
- public void showBccUncompletedError() {
- bccView.setError(bccView.getContext().getString(R.string.compose_error_incomplete_recipient));
+ fun showBccUncompletedError() {
+ bccView.error = bccView.context.getString(R.string.compose_error_incomplete_recipient)
}
- public void showCryptoSpecialMode(CryptoSpecialModeDisplayType cryptoSpecialModeDisplayType) {
- boolean shouldBeHidden = cryptoSpecialModeDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN;
+ fun showCryptoSpecialMode(cryptoSpecialModeDisplayType: CryptoSpecialModeDisplayType) {
+ val shouldBeHidden = cryptoSpecialModeDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN
if (shouldBeHidden) {
- cryptoSpecialModeIndicator.setVisibility(View.GONE);
- return;
+ cryptoSpecialModeIndicator.isGone = true
+ return
}
- cryptoSpecialModeIndicator.setVisibility(View.VISIBLE);
- cryptoSpecialModeIndicator.setDisplayedChildId(cryptoSpecialModeDisplayType.childIdToDisplay);
- activity.invalidateOptionsMenu();
+ cryptoSpecialModeIndicator.isVisible = true
+ cryptoSpecialModeIndicator.displayedChildId = cryptoSpecialModeDisplayType.childIdToDisplay
+
+ activity.invalidateOptionsMenu()
}
- public void showCryptoStatus(CryptoStatusDisplayType cryptoStatusDisplayType) {
- boolean shouldBeHidden = cryptoStatusDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN;
+ fun showCryptoStatus(cryptoStatusDisplayType: CryptoStatusDisplayType) {
+ val shouldBeHidden = cryptoStatusDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN
if (shouldBeHidden) {
cryptoStatusView.animate()
- .translationXBy(100.0f)
- .alpha(0.0f)
- .setDuration(CRYPTO_ICON_OUT_DURATION)
- .setInterpolator(CRYPTO_ICON_OUT_ANIMATOR)
- .start();
- return;
+ .translationXBy(100.0f)
+ .alpha(0.0f)
+ .setDuration(CRYPTO_ICON_OUT_DURATION.toLong())
+ .setInterpolator(CRYPTO_ICON_OUT_ANIMATOR)
+ .start()
+
+ return
}
- cryptoStatusView.setVisibility(View.VISIBLE);
- cryptoStatusView.setDisplayedChildId(cryptoStatusDisplayType.childIdToDisplay);
+ cryptoStatusView.isVisible = true
+ cryptoStatusView.displayedChildId = cryptoStatusDisplayType.childIdToDisplay
cryptoStatusView.animate()
- .translationX(0.0f)
- .alpha(1.0f)
- .setDuration(CRYPTO_ICON_IN_DURATION)
- .setInterpolator(CRYPTO_ICON_IN_ANIMATOR)
- .start();
- }
-
- public void showContactPicker(int requestCode) {
- activity.showContactPicker(requestCode);
+ .translationX(0.0f)
+ .alpha(1.0f)
+ .setDuration(CRYPTO_ICON_IN_DURATION.toLong())
+ .setInterpolator(CRYPTO_ICON_IN_ANIMATOR)
+ .start()
}
- public void showErrorIsSignOnly() {
- Toast.makeText(activity, R.string.error_sign_only_no_encryption, Toast.LENGTH_LONG).show();
+ fun showContactPicker(requestCode: Int) {
+ activity.showContactPicker(requestCode)
}
- public void showErrorContactNoAddress() {
- Toast.makeText(activity, R.string.error_contact_address_not_found, Toast.LENGTH_LONG).show();
+ fun showErrorIsSignOnly() {
+ Toast.makeText(activity, R.string.error_sign_only_no_encryption, Toast.LENGTH_LONG).show()
}
- public void showErrorOpenPgpRetrieveStatus() {
- Toast.makeText(activity, R.string.error_recipient_crypto_retrieve, Toast.LENGTH_LONG).show();
+ fun showErrorContactNoAddress() {
+ Toast.makeText(activity, R.string.error_contact_address_not_found, Toast.LENGTH_LONG).show()
}
- public void showErrorOpenPgpIncompatible() {
- Toast.makeText(activity, R.string.error_crypto_provider_incompatible, Toast.LENGTH_LONG).show();
+ fun showErrorOpenPgpIncompatible() {
+ Toast.makeText(activity, R.string.error_crypto_provider_incompatible, Toast.LENGTH_LONG).show()
}
- public void showErrorOpenPgpConnection() {
- Toast.makeText(activity, R.string.error_crypto_provider_connect, Toast.LENGTH_LONG).show();
+ fun showErrorOpenPgpConnection() {
+ Toast.makeText(activity, R.string.error_crypto_provider_connect, Toast.LENGTH_LONG).show()
}
- public void showErrorOpenPgpUserInteractionRequired() {
- Toast.makeText(activity, R.string.error_crypto_provider_ui_required, Toast.LENGTH_LONG).show();
+ fun showErrorOpenPgpUserInteractionRequired() {
+ Toast.makeText(activity, R.string.error_crypto_provider_ui_required, Toast.LENGTH_LONG).show()
}
- public void showErrorNoKeyConfigured() {
- Toast.makeText(activity, R.string.compose_error_no_key_configured, Toast.LENGTH_LONG).show();
+ fun showErrorNoKeyConfigured() {
+ Toast.makeText(activity, R.string.compose_error_no_key_configured, Toast.LENGTH_LONG).show()
}
- public void showErrorInlineAttach() {
- Toast.makeText(activity, R.string.error_crypto_inline_attach, Toast.LENGTH_LONG).show();
+ fun showErrorInlineAttach() {
+ Toast.makeText(activity, R.string.error_crypto_inline_attach, Toast.LENGTH_LONG).show()
}
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus) {
- return;
- }
+ override fun onFocusChange(view: View, hasFocus: Boolean) {
+ if (!hasFocus) return
- int id = view.getId();
- if (id == R.id.to) {
- presenter.onToFocused();
- } else if (id == R.id.cc) {
- presenter.onCcFocused();
- } else if (id == R.id.bcc) {
- presenter.onBccFocused();
+ when (view.id) {
+ R.id.to -> presenter.onToFocused()
+ R.id.cc -> presenter.onCcFocused()
+ R.id.bcc -> presenter.onBccFocused()
}
}
- @Override
- public void onClick(View view) {
- int id = view.getId();
- if (id == R.id.to_label) {
- presenter.onClickToLabel();
- } else if (id == R.id.cc_label) {
- presenter.onClickCcLabel();
- } else if (id == R.id.bcc_label) {
- presenter.onClickBccLabel();
- } else if (id == R.id.recipient_expander) {
- presenter.onClickRecipientExpander();
- } else if (id == R.id.crypto_status) {
- presenter.onClickCryptoStatus();
- } else if (id == R.id.crypto_special_mode) {
- presenter.onClickCryptoSpecialModeIndicator();
+ override fun onClick(view: View) {
+ when (view.id) {
+ R.id.to_label -> presenter.onClickToLabel()
+ R.id.cc_label -> presenter.onClickCcLabel()
+ R.id.bcc_label -> presenter.onClickBccLabel()
+ R.id.recipient_expander -> presenter.onClickRecipientExpander()
+ R.id.crypto_status -> presenter.onClickCryptoStatus()
+ R.id.crypto_special_mode -> presenter.onClickCryptoSpecialModeIndicator()
}
}
- public void showOpenPgpInlineDialog(boolean firstTime) {
- PgpInlineDialog dialog = PgpInlineDialog.newInstance(firstTime, R.id.crypto_special_mode);
- dialog.show(activity.getSupportFragmentManager(), "openpgp_inline");
+ fun showOpenPgpInlineDialog(firstTime: Boolean) {
+ val dialog = PgpInlineDialog.newInstance(firstTime, R.id.crypto_special_mode)
+ dialog.show(activity.supportFragmentManager, "openpgp_inline")
}
- public void showOpenPgpSignOnlyDialog(boolean firstTime) {
- PgpSignOnlyDialog dialog = PgpSignOnlyDialog.newInstance(firstTime, R.id.crypto_special_mode);
- dialog.show(activity.getSupportFragmentManager(), "openpgp_signonly");
+ fun showOpenPgpSignOnlyDialog(firstTime: Boolean) {
+ val dialog = PgpSignOnlyDialog.newInstance(firstTime, R.id.crypto_special_mode)
+ dialog.show(activity.supportFragmentManager, "openpgp_signonly")
}
- public void showOpenPgpEnabledErrorDialog(final boolean isGotItDialog) {
- PgpEnabledErrorDialog dialog = PgpEnabledErrorDialog.newInstance(isGotItDialog, R.id.crypto_status_anchor);
- dialog.show(activity.getSupportFragmentManager(), "openpgp_error");
+ fun showOpenPgpEnabledErrorDialog(isGotItDialog: Boolean) {
+ val dialog = PgpEnabledErrorDialog.newInstance(isGotItDialog, R.id.crypto_status_anchor)
+ dialog.show(activity.supportFragmentManager, "openpgp_error")
}
- public void showOpenPgpEncryptExplanationDialog() {
- PgpEncryptDescriptionDialog dialog = PgpEncryptDescriptionDialog.newInstance(R.id.crypto_status_anchor);
- dialog.show(activity.getSupportFragmentManager(), "openpgp_description");
+ fun showOpenPgpEncryptExplanationDialog() {
+ val dialog = PgpEncryptDescriptionDialog.newInstance(R.id.crypto_status_anchor)
+ dialog.show(activity.supportFragmentManager, "openpgp_description")
}
- public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int requestCode) {
- activity.launchUserInteractionPendingIntent(pendingIntent, requestCode);
+ fun launchUserInteractionPendingIntent(pendingIntent: PendingIntent?, requestCode: Int) {
+ activity.launchUserInteractionPendingIntent(pendingIntent, requestCode)
}
- public void setLoaderManager(LoaderManager loaderManager) {
- toView.setLoaderManager(loaderManager);
- ccView.setLoaderManager(loaderManager);
- bccView.setLoaderManager(loaderManager);
+ fun setLoaderManager(loaderManager: LoaderManager?) {
+ toView.setLoaderManager(loaderManager)
+ ccView.setLoaderManager(loaderManager)
+ bccView.setLoaderManager(loaderManager)
}
- public enum CryptoStatusDisplayType {
+ enum class CryptoStatusDisplayType(val childIdToDisplay: Int) {
UNCONFIGURED(VIEW_INDEX_HIDDEN),
UNINITIALIZED(VIEW_INDEX_HIDDEN),
SIGN_ONLY(R.id.crypto_status_disabled),
@@ -518,26 +391,24 @@ public class RecipientMvpView implements OnFocusChangeListener, OnClickListener
ENABLED_TRUSTED(R.id.crypto_status_trusted),
AVAILABLE(R.id.crypto_status_disabled),
ERROR(R.id.crypto_status_error);
-
-
- final int childIdToDisplay;
-
- CryptoStatusDisplayType(int childIdToDisplay) {
- this.childIdToDisplay = childIdToDisplay;
- }
}
- public enum CryptoSpecialModeDisplayType {
+ enum class CryptoSpecialModeDisplayType(val childIdToDisplay: Int) {
NONE(VIEW_INDEX_HIDDEN),
PGP_INLINE(R.id.crypto_special_inline),
SIGN_ONLY(R.id.crypto_special_sign_only),
SIGN_ONLY_PGP_INLINE(R.id.crypto_special_sign_only_inline);
+ }
+ companion object {
+ private const val VIEW_INDEX_HIDDEN = -1
+ private const val VIEW_INDEX_BCC_EXPANDER_VISIBLE = 0
+ private const val VIEW_INDEX_BCC_EXPANDER_HIDDEN = 1
- final int childIdToDisplay;
+ private val CRYPTO_ICON_OUT_ANIMATOR = FastOutLinearInInterpolator()
+ private const val CRYPTO_ICON_OUT_DURATION = 195
- CryptoSpecialModeDisplayType(int childIdToDisplay) {
- this.childIdToDisplay = childIdToDisplay;
- }
+ private val CRYPTO_ICON_IN_ANIMATOR = LinearOutSlowInInterpolator()
+ private const val CRYPTO_ICON_IN_DURATION = 225
}
}
diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt
index 7aaf4a8b3e..9b0e6d2ed3 100644
--- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt
+++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/compose/RecipientPresenter.kt
@@ -1,886 +1,770 @@
-package com.fsck.k9.activity.compose;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import android.Manifest;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import androidx.annotation.Nullable;
-import androidx.core.content.ContextCompat;
-import androidx.loader.app.LoaderManager;
-import android.view.Menu;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.Identity;
-import com.fsck.k9.K9;
-import com.fsck.k9.activity.compose.ComposeCryptoStatus.AttachErrorState;
-import com.fsck.k9.activity.compose.ComposeCryptoStatus.SendErrorState;
-import com.fsck.k9.activity.compose.RecipientMvpView.CryptoStatusDisplayType;
-import com.fsck.k9.autocrypt.AutocryptDraftStateHeader;
-import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser;
-import com.fsck.k9.helper.Contacts;
-import com.fsck.k9.helper.MailTo;
-import com.fsck.k9.helper.ReplyToParser;
-import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
-import com.fsck.k9.mail.Address;
-import com.fsck.k9.mail.Flag;
-import com.fsck.k9.mail.Message;
-import com.fsck.k9.mail.Message.RecipientType;
-import com.fsck.k9.message.AutocryptStatusInteractor;
-import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus;
-import com.fsck.k9.message.ComposePgpEnableByDefaultDecider;
-import com.fsck.k9.message.ComposePgpInlineDecider;
-import com.fsck.k9.message.MessageBuilder;
-import com.fsck.k9.message.PgpMessageBuilder;
-import com.fsck.k9.ui.R;
-import com.fsck.k9.view.RecipientSelectView.Recipient;
-import org.openintents.openpgp.OpenPgpApiManager;
-import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback;
-import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderError;
-import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState;
-import org.openintents.openpgp.util.OpenPgpApi;
-import timber.log.Timber;
-
-
-public class RecipientPresenter {
- private static final String STATE_KEY_CC_SHOWN = "state:ccShown";
- private static final String STATE_KEY_BCC_SHOWN = "state:bccShown";
- private static final String STATE_KEY_LAST_FOCUSED_TYPE = "state:lastFocusedType";
- private static final String STATE_KEY_CURRENT_CRYPTO_MODE = "state:currentCryptoMode";
- private static final String STATE_KEY_CRYPTO_ENABLE_PGP_INLINE = "state:cryptoEnablePgpInline";
-
- private static final int CONTACT_PICKER_TO = 1;
- private static final int CONTACT_PICKER_CC = 2;
- private static final int CONTACT_PICKER_BCC = 3;
- private static final int OPENPGP_USER_INTERACTION = 4;
- private static final int REQUEST_CODE_AUTOCRYPT = 5;
-
- private static final int PGP_DIALOG_DISPLAY_THRESHOLD = 2;
-
-
- // transient state, which is either obtained during construction and initialization, or cached
- private final Context context;
- private final RecipientMvpView recipientMvpView;
- private final ComposePgpEnableByDefaultDecider composePgpEnableByDefaultDecider;
- private final ComposePgpInlineDecider composePgpInlineDecider;
- private final AutocryptStatusInteractor autocryptStatusInteractor;
- private final OpenPgpApiManager openPgpApiManager;
- private final AutocryptDraftStateHeaderParser draftStateHeaderParser;
- private ReplyToParser replyToParser;
- private Account account;
- private Address[] alwaysBccAddresses;
- private Boolean hasContactPicker;
- @Nullable
- private ComposeCryptoStatus cachedCryptoStatus;
-
-
- // persistent state, saved during onSaveInstanceState
- private RecipientType lastFocusedType = RecipientType.TO;
- private CryptoMode currentCryptoMode = CryptoMode.NO_CHOICE;
- private boolean cryptoEnablePgpInline = false;
- private boolean isReplyToEncryptedMessage = false;
-
-
- public RecipientPresenter(Context context, LoaderManager loaderManager,
- OpenPgpApiManager openPgpApiManager, RecipientMvpView recipientMvpView, Account account,
- ComposePgpInlineDecider composePgpInlineDecider,
- ComposePgpEnableByDefaultDecider composePgpEnableByDefaultDecider,
- AutocryptStatusInteractor autocryptStatusInteractor,
- ReplyToParser replyToParser, AutocryptDraftStateHeaderParser draftStateHeaderParser) {
- this.recipientMvpView = recipientMvpView;
- this.context = context;
- this.autocryptStatusInteractor = autocryptStatusInteractor;
- this.composePgpInlineDecider = composePgpInlineDecider;
- this.composePgpEnableByDefaultDecider = composePgpEnableByDefaultDecider;
- this.replyToParser = replyToParser;
- this.openPgpApiManager = openPgpApiManager;
- this.draftStateHeaderParser = draftStateHeaderParser;
-
- recipientMvpView.setPresenter(this);
- recipientMvpView.setLoaderManager(loaderManager);
- onSwitchAccount(account);
- }
-
- public List getToAddresses() {
- return recipientMvpView.getToAddresses();
- }
-
- public List getCcAddresses() {
- return recipientMvpView.getCcAddresses();
- }
-
- public List getBccAddresses() {
- return recipientMvpView.getBccAddresses();
- }
-
- private List getAllRecipients() {
- ArrayList result = new ArrayList<>();
-
- result.addAll(recipientMvpView.getToRecipients());
- result.addAll(recipientMvpView.getCcRecipients());
- result.addAll(recipientMvpView.getBccRecipients());
-
- return result;
- }
-
- public boolean checkRecipientsOkForSending() {
- recipientMvpView.recipientToTryPerformCompletion();
- recipientMvpView.recipientCcTryPerformCompletion();
- recipientMvpView.recipientBccTryPerformCompletion();
+package com.fsck.k9.activity.compose
+
+import android.Manifest
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.AsyncTask
+import android.os.Bundle
+import android.view.Menu
+import androidx.core.content.ContextCompat
+import androidx.loader.app.LoaderManager
+import com.fsck.k9.Account
+import com.fsck.k9.Identity
+import com.fsck.k9.K9
+import com.fsck.k9.activity.compose.ComposeCryptoStatus.AttachErrorState
+import com.fsck.k9.activity.compose.ComposeCryptoStatus.SendErrorState
+import com.fsck.k9.autocrypt.AutocryptDraftStateHeader
+import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser
+import com.fsck.k9.helper.Contacts
+import com.fsck.k9.helper.MailTo
+import com.fsck.k9.helper.ReplyToParser
+import com.fsck.k9.mail.Address
+import com.fsck.k9.mail.Flag
+import com.fsck.k9.mail.Message
+import com.fsck.k9.mail.Message.RecipientType
+import com.fsck.k9.message.AutocryptStatusInteractor
+import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus
+import com.fsck.k9.message.ComposePgpEnableByDefaultDecider
+import com.fsck.k9.message.ComposePgpInlineDecider
+import com.fsck.k9.message.MessageBuilder
+import com.fsck.k9.message.PgpMessageBuilder
+import com.fsck.k9.ui.R
+import com.fsck.k9.view.RecipientSelectView.Recipient
+import org.openintents.openpgp.OpenPgpApiManager
+import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback
+import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderError
+import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState
+import timber.log.Timber
+
+private const val STATE_KEY_CC_SHOWN = "state:ccShown"
+private const val STATE_KEY_BCC_SHOWN = "state:bccShown"
+private const val STATE_KEY_LAST_FOCUSED_TYPE = "state:lastFocusedType"
+private const val STATE_KEY_CURRENT_CRYPTO_MODE = "state:currentCryptoMode"
+private const val STATE_KEY_CRYPTO_ENABLE_PGP_INLINE = "state:cryptoEnablePgpInline"
+
+private const val CONTACT_PICKER_TO = 1
+private const val CONTACT_PICKER_CC = 2
+private const val CONTACT_PICKER_BCC = 3
+private const val OPENPGP_USER_INTERACTION = 4
+private const val REQUEST_CODE_AUTOCRYPT = 5
+
+private const val PGP_DIALOG_DISPLAY_THRESHOLD = 2
+
+class RecipientPresenter(
+ private val context: Context,
+ loaderManager: LoaderManager,
+ private val openPgpApiManager: OpenPgpApiManager,
+ private val recipientMvpView: RecipientMvpView,
+ account: Account,
+ private val composePgpInlineDecider: ComposePgpInlineDecider,
+ private val composePgpEnableByDefaultDecider: ComposePgpEnableByDefaultDecider,
+ private val autocryptStatusInteractor: AutocryptStatusInteractor,
+ private val replyToParser: ReplyToParser,
+ private val draftStateHeaderParser: AutocryptDraftStateHeaderParser
+) {
+ private lateinit var account: Account
+ private var alwaysBccAddresses: Array? = null
+ private var hasContactPicker: Boolean? = null
+ private var isReplyToEncryptedMessage = false
+
+ private var lastFocusedType = RecipientType.TO
+ private var currentCryptoMode = CryptoMode.NO_CHOICE
+
+ var isForceTextMessageFormat = false
+ private set
+
+ var currentCachedCryptoStatus: ComposeCryptoStatus? = null
+ private set
+
+ val toAddresses: List
+ get() = recipientMvpView.toAddresses
+
+ val ccAddresses: List
+ get() = recipientMvpView.ccAddresses
+
+ val bccAddresses: List
+ get() = recipientMvpView.bccAddresses
+
+ private val allRecipients: List
+ get() = with(recipientMvpView) { toRecipients + ccRecipients + bccRecipients }
+
+ init {
+ recipientMvpView.setPresenter(this)
+ recipientMvpView.setLoaderManager(loaderManager)
+
+ onSwitchAccount(account)
+ }
+
+ fun checkRecipientsOkForSending(): Boolean {
+ recipientMvpView.recipientToTryPerformCompletion()
+ recipientMvpView.recipientCcTryPerformCompletion()
+ recipientMvpView.recipientBccTryPerformCompletion()
if (recipientMvpView.recipientToHasUncompletedText()) {
- recipientMvpView.showToUncompletedError();
- return true;
+ recipientMvpView.showToUncompletedError()
+ return true
}
if (recipientMvpView.recipientCcHasUncompletedText()) {
- recipientMvpView.showCcUncompletedError();
- return true;
+ recipientMvpView.showCcUncompletedError()
+ return true
}
if (recipientMvpView.recipientBccHasUncompletedText()) {
- recipientMvpView.showBccUncompletedError();
- return true;
+ recipientMvpView.showBccUncompletedError()
+ return true
}
- if (getToAddresses().isEmpty() && getCcAddresses().isEmpty() && getBccAddresses().isEmpty()) {
- recipientMvpView.showNoRecipientsError();
- return true;
+ if (toAddresses.isEmpty() && ccAddresses.isEmpty() && bccAddresses.isEmpty()) {
+ recipientMvpView.showNoRecipientsError()
+ return true
}
- return false;
+ return false
}
- public void initFromReplyToMessage(Message message, boolean isReplyAll) {
- ReplyToAddresses replyToAddresses = isReplyAll ?
- replyToParser.getRecipientsToReplyAllTo(message, account) :
- replyToParser.getRecipientsToReplyTo(message, account);
+ fun initFromReplyToMessage(message: Message?, isReplyAll: Boolean) {
+ val replyToAddresses = if (isReplyAll) {
+ replyToParser.getRecipientsToReplyAllTo(message, account)
+ } else {
+ replyToParser.getRecipientsToReplyTo(message, account)
+ }
- addToAddresses(replyToAddresses.to);
- addCcAddresses(replyToAddresses.cc);
+ addToAddresses(*replyToAddresses.to)
+ addCcAddresses(*replyToAddresses.cc)
- boolean shouldSendAsPgpInline = composePgpInlineDecider.shouldReplyInline(message);
+ val shouldSendAsPgpInline = composePgpInlineDecider.shouldReplyInline(message)
if (shouldSendAsPgpInline) {
- cryptoEnablePgpInline = true;
+ isForceTextMessageFormat = true
}
- isReplyToEncryptedMessage = composePgpEnableByDefaultDecider.shouldEncryptByDefault(message);
+ isReplyToEncryptedMessage = composePgpEnableByDefaultDecider.shouldEncryptByDefault(message)
}
- public void initFromTrustIdAction(String trustId) {
- addToAddresses(Address.parse(trustId));
- currentCryptoMode = CryptoMode.CHOICE_ENABLED;
+ fun initFromTrustIdAction(trustId: String?) {
+ addToAddresses(*Address.parse(trustId))
+ currentCryptoMode = CryptoMode.CHOICE_ENABLED
}
- public void initFromMailto(MailTo mailTo) {
- addToAddresses(mailTo.getTo());
- addCcAddresses(mailTo.getCc());
- addBccAddresses(mailTo.getBcc());
+ fun initFromMailto(mailTo: MailTo) {
+ addToAddresses(*mailTo.to)
+ addCcAddresses(*mailTo.cc)
+ addBccAddresses(*mailTo.bcc)
}
- public void initFromSendOrViewIntent(Intent intent) {
- String[] extraEmail = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
- String[] extraCc = intent.getStringArrayExtra(Intent.EXTRA_CC);
- String[] extraBcc = intent.getStringArrayExtra(Intent.EXTRA_BCC);
+ fun initFromSendOrViewIntent(intent: Intent) {
+ val toAddresses = intent.getStringArrayExtra(Intent.EXTRA_EMAIL)?.toAddressArray()
+ val ccAddresses = intent.getStringArrayExtra(Intent.EXTRA_CC)?.toAddressArray()
+ val bccAddresses = intent.getStringArrayExtra(Intent.EXTRA_BCC)?.toAddressArray()
- if (extraEmail != null) {
- addToAddresses(addressFromStringArray(extraEmail));
+ if (toAddresses != null) {
+ addToAddresses(*toAddresses)
}
- if (extraCc != null) {
- addCcAddresses(addressFromStringArray(extraCc));
+ if (ccAddresses != null) {
+ addCcAddresses(*ccAddresses)
}
- if (extraBcc != null) {
- addBccAddresses(addressFromStringArray(extraBcc));
+ if (bccAddresses != null) {
+ addBccAddresses(*bccAddresses)
}
}
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- recipientMvpView.setCcVisibility(savedInstanceState.getBoolean(STATE_KEY_CC_SHOWN));
- recipientMvpView.setBccVisibility(savedInstanceState.getBoolean(STATE_KEY_BCC_SHOWN));
- lastFocusedType = RecipientType.valueOf(savedInstanceState.getString(STATE_KEY_LAST_FOCUSED_TYPE));
- currentCryptoMode = CryptoMode.valueOf(savedInstanceState.getString(STATE_KEY_CURRENT_CRYPTO_MODE));
- cryptoEnablePgpInline = savedInstanceState.getBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE);
- updateRecipientExpanderVisibility();
+ fun onRestoreInstanceState(savedInstanceState: Bundle) {
+ recipientMvpView.setCcVisibility(savedInstanceState.getBoolean(STATE_KEY_CC_SHOWN))
+ recipientMvpView.setBccVisibility(savedInstanceState.getBoolean(STATE_KEY_BCC_SHOWN))
+ lastFocusedType = RecipientType.valueOf(savedInstanceState.getString(STATE_KEY_LAST_FOCUSED_TYPE)!!)
+ currentCryptoMode = CryptoMode.valueOf(savedInstanceState.getString(STATE_KEY_CURRENT_CRYPTO_MODE)!!)
+ isForceTextMessageFormat = savedInstanceState.getBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE)
+
+ updateRecipientExpanderVisibility()
}
- public void onSaveInstanceState(Bundle outState) {
- outState.putBoolean(STATE_KEY_CC_SHOWN, recipientMvpView.isCcVisible());
- outState.putBoolean(STATE_KEY_BCC_SHOWN, recipientMvpView.isBccVisible());
- outState.putString(STATE_KEY_LAST_FOCUSED_TYPE, lastFocusedType.toString());
- outState.putString(STATE_KEY_CURRENT_CRYPTO_MODE, currentCryptoMode.toString());
- outState.putBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE, cryptoEnablePgpInline);
+ fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(STATE_KEY_CC_SHOWN, recipientMvpView.isCcVisible)
+ outState.putBoolean(STATE_KEY_BCC_SHOWN, recipientMvpView.isBccVisible)
+ outState.putString(STATE_KEY_LAST_FOCUSED_TYPE, lastFocusedType.toString())
+ outState.putString(STATE_KEY_CURRENT_CRYPTO_MODE, currentCryptoMode.toString())
+ outState.putBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE, isForceTextMessageFormat)
}
- public void initFromDraftMessage(Message message) {
- initRecipientsFromDraftMessage(message);
+ fun initFromDraftMessage(message: Message) {
+ initRecipientsFromDraftMessage(message)
- String[] draftStateHeader = message.getHeader(AutocryptDraftStateHeader.AUTOCRYPT_DRAFT_STATE_HEADER);
- if (draftStateHeader.length == 1) {
- initEncryptionStateFromDraftStateHeader(draftStateHeader[0]);
+ val draftStateHeader = message.getHeader(AutocryptDraftStateHeader.AUTOCRYPT_DRAFT_STATE_HEADER)
+ if (draftStateHeader.size == 1) {
+ initEncryptionStateFromDraftStateHeader(draftStateHeader.first())
} else {
- initPgpInlineFromDraftMessage(message);
+ initPgpInlineFromDraftMessage(message)
}
}
- private void initEncryptionStateFromDraftStateHeader(String headerValue) {
- AutocryptDraftStateHeader autocryptDraftStateHeader =
- draftStateHeaderParser.parseAutocryptDraftStateHeader(headerValue);
+ private fun initEncryptionStateFromDraftStateHeader(headerValue: String) {
+ val autocryptDraftStateHeader = draftStateHeaderParser.parseAutocryptDraftStateHeader(headerValue)
if (autocryptDraftStateHeader != null) {
- initEncryptionStateFromDraftStateHeader(autocryptDraftStateHeader);
+ initEncryptionStateFromDraftStateHeader(autocryptDraftStateHeader)
}
}
- private void initRecipientsFromDraftMessage(Message message) {
- addToAddresses(message.getRecipients(RecipientType.TO));
-
- Address[] ccRecipients = message.getRecipients(RecipientType.CC);
- addCcAddresses(ccRecipients);
-
- Address[] bccRecipients = message.getRecipients(RecipientType.BCC);
- addBccAddresses(bccRecipients);
+ private fun initRecipientsFromDraftMessage(message: Message) {
+ addToAddresses(*message.getRecipients(RecipientType.TO))
+ addCcAddresses(*message.getRecipients(RecipientType.CC))
+ addBccAddresses(*message.getRecipients(RecipientType.BCC))
}
- private void initEncryptionStateFromDraftStateHeader(AutocryptDraftStateHeader draftState) {
- cryptoEnablePgpInline = draftState.isPgpInline();
- isReplyToEncryptedMessage = draftState.isReply();
- if (!draftState.isByChoice()) {
+ private fun initEncryptionStateFromDraftStateHeader(draftState: AutocryptDraftStateHeader) {
+ isForceTextMessageFormat = draftState.isPgpInline
+ isReplyToEncryptedMessage = draftState.isReply
+
+ if (!draftState.isByChoice) {
// TODO if it's not by choice, we're going with our defaults. should we do something here if those differ?
- return;
+ return
}
- if (draftState.isSignOnly()) {
- currentCryptoMode = CryptoMode.SIGN_ONLY;
- } else {
- currentCryptoMode = draftState.isEncrypt() ? CryptoMode.CHOICE_ENABLED : CryptoMode.CHOICE_DISABLED;
+ currentCryptoMode = when {
+ draftState.isSignOnly -> CryptoMode.SIGN_ONLY
+ draftState.isEncrypt -> CryptoMode.CHOICE_ENABLED
+ else -> CryptoMode.CHOICE_DISABLED
}
}
- private void initPgpInlineFromDraftMessage(Message message) {
- cryptoEnablePgpInline = message.isSet(Flag.X_DRAFT_OPENPGP_INLINE);
+ private fun initPgpInlineFromDraftMessage(message: Message) {
+ isForceTextMessageFormat = message.isSet(Flag.X_DRAFT_OPENPGP_INLINE)
}
- private void addToAddresses(Address... toAddresses) {
- addRecipientsFromAddresses(RecipientType.TO, toAddresses);
+ private fun addToAddresses(vararg toAddresses: Address) {
+ addRecipientsFromAddresses(RecipientType.TO, *toAddresses)
}
- private void addCcAddresses(Address... ccAddresses) {
- if (ccAddresses.length > 0) {
- addRecipientsFromAddresses(RecipientType.CC, ccAddresses);
- recipientMvpView.setCcVisibility(true);
- updateRecipientExpanderVisibility();
+ private fun addCcAddresses(vararg ccAddresses: Address) {
+ if (ccAddresses.isNotEmpty()) {
+ addRecipientsFromAddresses(RecipientType.CC, *ccAddresses)
+ recipientMvpView.setCcVisibility(true)
+ updateRecipientExpanderVisibility()
}
}
- public void addBccAddresses(Address... bccRecipients) {
- if (bccRecipients.length > 0) {
- addRecipientsFromAddresses(RecipientType.BCC, bccRecipients);
- recipientMvpView.setBccVisibility(true);
- updateRecipientExpanderVisibility();
+ private fun addBccAddresses(vararg bccRecipients: Address) {
+ if (bccRecipients.isNotEmpty()) {
+ addRecipientsFromAddresses(RecipientType.BCC, *bccRecipients)
+ recipientMvpView.setBccVisibility(true)
+ updateRecipientExpanderVisibility()
}
}
- public void addAlwaysBcc() {
- alwaysBccAddresses = Address.parse(account.getAlwaysBcc());
+ private fun addAlwaysBcc() {
+ val alwaysBccAddresses = Address.parse(account.alwaysBcc)
+ this.alwaysBccAddresses = alwaysBccAddresses
+ if (alwaysBccAddresses.isEmpty()) return
- new RecipientLoader(context, account.getOpenPgpProvider(), alwaysBccAddresses) {
- @Override
- public void deliverResult(List result) {
- Recipient[] recipientArray = result.toArray(new Recipient[result.size()]);
- recipientMvpView.silentlyAddBccAddresses(recipientArray);
+ object : RecipientLoader(context, account.openPgpProvider, *alwaysBccAddresses) {
+ override fun deliverResult(result: List?) {
+ val recipientArray = result!!.toTypedArray()
+ recipientMvpView.silentlyAddBccAddresses(*recipientArray)
- stopLoading();
- abandon();
+ stopLoading()
+ abandon()
}
- }.startLoading();
+ }.startLoading()
}
- private void removeAlwaysBcc() {
- if (alwaysBccAddresses != null) {
- recipientMvpView.silentlyRemoveBccAddresses(alwaysBccAddresses);
+ private fun removeAlwaysBcc() {
+ alwaysBccAddresses?.let { alwaysBccAddresses ->
+ recipientMvpView.silentlyRemoveBccAddresses(alwaysBccAddresses)
}
}
- public void onPrepareOptionsMenu(Menu menu) {
- ComposeCryptoStatus currentCryptoStatus = getCurrentCachedCryptoStatus();
- boolean isCryptoConfigured = currentCryptoStatus != null && currentCryptoStatus.isProviderStateOk();
- if (isCryptoConfigured) {
- boolean isEncrypting = currentCryptoStatus.isEncryptionEnabled();
- menu.findItem(R.id.openpgp_encrypt_enable).setVisible(!isEncrypting);
- menu.findItem(R.id.openpgp_encrypt_disable).setVisible(isEncrypting);
+ fun onPrepareOptionsMenu(menu: Menu) {
+ val currentCryptoStatus = currentCachedCryptoStatus
- boolean showSignOnly = !account.isOpenPgpHideSignOnly();
- boolean isSignOnly = currentCryptoStatus.isSignOnly();
- menu.findItem(R.id.openpgp_sign_only).setVisible(showSignOnly && !isSignOnly);
- menu.findItem(R.id.openpgp_sign_only_disable).setVisible(showSignOnly && isSignOnly);
+ if (currentCryptoStatus != null && currentCryptoStatus.isProviderStateOk()) {
+ val isEncrypting = currentCryptoStatus.isEncryptionEnabled
+ menu.findItem(R.id.openpgp_encrypt_enable).isVisible = !isEncrypting
+ menu.findItem(R.id.openpgp_encrypt_disable).isVisible = isEncrypting
- boolean pgpInlineModeEnabled = currentCryptoStatus.isPgpInlineModeEnabled();
- boolean showPgpInlineEnable = (isEncrypting || isSignOnly) && !pgpInlineModeEnabled;
- menu.findItem(R.id.openpgp_inline_enable).setVisible(showPgpInlineEnable);
- menu.findItem(R.id.openpgp_inline_disable).setVisible(pgpInlineModeEnabled);
+ val showSignOnly = !account.isOpenPgpHideSignOnly
+ val isSignOnly = currentCryptoStatus.isSignOnly
+ menu.findItem(R.id.openpgp_sign_only).isVisible = showSignOnly && !isSignOnly
+ menu.findItem(R.id.openpgp_sign_only_disable).isVisible = showSignOnly && isSignOnly
+
+ val pgpInlineModeEnabled = currentCryptoStatus.isPgpInlineModeEnabled
+ val showPgpInlineEnable = (isEncrypting || isSignOnly) && !pgpInlineModeEnabled
+ menu.findItem(R.id.openpgp_inline_enable).isVisible = showPgpInlineEnable
+ menu.findItem(R.id.openpgp_inline_disable).isVisible = pgpInlineModeEnabled
} else {
- menu.findItem(R.id.openpgp_inline_enable).setVisible(false);
- menu.findItem(R.id.openpgp_inline_disable).setVisible(false);
- menu.findItem(R.id.openpgp_encrypt_enable).setVisible(false);
- menu.findItem(R.id.openpgp_encrypt_disable).setVisible(false);
- menu.findItem(R.id.openpgp_sign_only).setVisible(false);
- menu.findItem(R.id.openpgp_sign_only_disable).setVisible(false);
+ menu.findItem(R.id.openpgp_inline_enable).isVisible = false
+ menu.findItem(R.id.openpgp_inline_disable).isVisible = false
+ menu.findItem(R.id.openpgp_encrypt_enable).isVisible = false
+ menu.findItem(R.id.openpgp_encrypt_disable).isVisible = false
+ menu.findItem(R.id.openpgp_sign_only).isVisible = false
+ menu.findItem(R.id.openpgp_sign_only_disable).isVisible = false
}
- menu.findItem(R.id.add_from_contacts).setVisible(hasContactPicker() && hasContactPermission());
+ menu.findItem(R.id.add_from_contacts).isVisible = hasContactPermission() && hasContactPicker()
}
- public void onSwitchAccount(Account account) {
- this.account = account;
+ fun onSwitchAccount(account: Account) {
+ this.account = account
- if (account.isAlwaysShowCcBcc()) {
- recipientMvpView.setCcVisibility(true);
- recipientMvpView.setBccVisibility(true);
- updateRecipientExpanderVisibility();
+ if (account.isAlwaysShowCcBcc) {
+ recipientMvpView.setCcVisibility(true)
+ recipientMvpView.setBccVisibility(true)
+ updateRecipientExpanderVisibility()
}
- removeAlwaysBcc();
- addAlwaysBcc();
+ removeAlwaysBcc()
+ addAlwaysBcc()
- String openPgpProvider = account.getOpenPgpProvider();
- recipientMvpView.setCryptoProvider(openPgpProvider);
- openPgpApiManager.setOpenPgpProvider(openPgpProvider, openPgpCallback);
+ val openPgpProvider = account.openPgpProvider
+ recipientMvpView.setCryptoProvider(openPgpProvider)
+ openPgpApiManager.setOpenPgpProvider(openPgpProvider, openPgpCallback)
}
- @SuppressWarnings("UnusedParameters")
- public void onSwitchIdentity(Identity identity) {
-
+ fun onSwitchIdentity(identity: Identity) {
// TODO decide what actually to do on identity switch?
- asyncUpdateCryptoStatus();
- /*
- if (mIdentityChanged) {
- mBccWrapper.setVisibility(View.VISIBLE);
- }
- mBccView.setText("");
- mBccView.addAddress(new Address(mAccount.getAlwaysBcc(), ""));
- */
-
- }
-
- private static Address[] addressFromStringArray(String[] addresses) {
- return addressFromStringArray(Arrays.asList(addresses));
+ asyncUpdateCryptoStatus()
}
- private static Address[] addressFromStringArray(List addresses) {
- ArrayList result = new ArrayList<>(addresses.size());
-
- for (String addressStr : addresses) {
- Collections.addAll(result, Address.parseUnencoded(addressStr));
- }
-
- return result.toArray(new Address[result.size()]);
+ fun onClickToLabel() {
+ recipientMvpView.requestFocusOnToField()
}
- void onClickToLabel() {
- recipientMvpView.requestFocusOnToField();
+ fun onClickCcLabel() {
+ recipientMvpView.requestFocusOnCcField()
}
- void onClickCcLabel() {
- recipientMvpView.requestFocusOnCcField();
+ fun onClickBccLabel() {
+ recipientMvpView.requestFocusOnBccField()
}
- void onClickBccLabel() {
- recipientMvpView.requestFocusOnBccField();
+ fun onClickRecipientExpander() {
+ recipientMvpView.setCcVisibility(true)
+ recipientMvpView.setBccVisibility(true)
+ updateRecipientExpanderVisibility()
}
- void onClickRecipientExpander() {
- recipientMvpView.setCcVisibility(true);
- recipientMvpView.setBccVisibility(true);
- updateRecipientExpanderVisibility();
- }
-
- private void hideEmptyExtendedRecipientFields() {
- if (recipientMvpView.getCcAddresses().isEmpty()) {
- recipientMvpView.setCcVisibility(false);
+ private fun hideEmptyExtendedRecipientFields() {
+ if (recipientMvpView.ccAddresses.isEmpty()) {
+ recipientMvpView.setCcVisibility(false)
if (lastFocusedType == RecipientType.CC) {
- lastFocusedType = RecipientType.TO;
+ lastFocusedType = RecipientType.TO
}
}
- if (recipientMvpView.getBccAddresses().isEmpty()) {
- recipientMvpView.setBccVisibility(false);
+
+ if (recipientMvpView.bccAddresses.isEmpty()) {
+ recipientMvpView.setBccVisibility(false)
if (lastFocusedType == RecipientType.BCC) {
- lastFocusedType = RecipientType.TO;
+ lastFocusedType = RecipientType.TO
}
}
- updateRecipientExpanderVisibility();
- }
- private void updateRecipientExpanderVisibility() {
- boolean notBothAreVisible = !(recipientMvpView.isCcVisible() && recipientMvpView.isBccVisible());
- recipientMvpView.setRecipientExpanderVisibility(notBothAreVisible);
+ updateRecipientExpanderVisibility()
}
- public void asyncUpdateCryptoStatus() {
- cachedCryptoStatus = null;
+ private fun updateRecipientExpanderVisibility() {
+ val notBothAreVisible = !(recipientMvpView.isCcVisible && recipientMvpView.isBccVisible)
+ recipientMvpView.setRecipientExpanderVisibility(notBothAreVisible)
+ }
- OpenPgpProviderState openPgpProviderState = openPgpApiManager.getOpenPgpProviderState();
+ fun asyncUpdateCryptoStatus() {
+ currentCachedCryptoStatus = null
- Long accountCryptoKey = account.getOpenPgpKey();
+ val openPgpProviderState = openPgpApiManager.openPgpProviderState
+ var accountCryptoKey: Long? = account.openPgpKey
if (accountCryptoKey == Account.NO_OPENPGP_KEY) {
- accountCryptoKey = null;
+ accountCryptoKey = null
}
- final ComposeCryptoStatus composeCryptoStatus = new ComposeCryptoStatus(
- openPgpProviderState,
- accountCryptoKey,
- getAllRecipients(),
- cryptoEnablePgpInline,
- account.getAutocryptPreferEncryptMutual(),
- isReplyToEncryptedMessage,
- account.isOpenPgpEncryptAllDrafts(),
- account.isOpenPgpEncryptSubject(),
- currentCryptoMode);
+ val composeCryptoStatus = ComposeCryptoStatus(
+ openPgpProviderState = openPgpProviderState,
+ openPgpKeyId = accountCryptoKey,
+ recipientAddresses = allRecipients,
+ isPgpInlineModeEnabled = isForceTextMessageFormat,
+ isSenderPreferEncryptMutual = account.autocryptPreferEncryptMutual,
+ isReplyToEncrypted = isReplyToEncryptedMessage,
+ isEncryptAllDrafts = account.isOpenPgpEncryptAllDrafts,
+ isEncryptSubject = account.isOpenPgpEncryptSubject,
+ cryptoMode = currentCryptoMode
+ )
if (openPgpProviderState != OpenPgpProviderState.OK) {
- cachedCryptoStatus = composeCryptoStatus;
- redrawCachedCryptoStatusIcon();
- return;
+ currentCachedCryptoStatus = composeCryptoStatus
+ redrawCachedCryptoStatusIcon()
+ return
}
- final String[] recipientAddresses = composeCryptoStatus.getRecipientAddressesAsArray();
-
- new AsyncTask() {
- @Override
- protected RecipientAutocryptStatus doInBackground(Void... voids) {
- OpenPgpApi openPgpApi = openPgpApiManager.getOpenPgpApi();
- if (openPgpApi == null) {
- return null;
- }
- return autocryptStatusInteractor.retrieveCryptoProviderRecipientStatus(openPgpApi, recipientAddresses);
+ val recipientAddresses = composeCryptoStatus.recipientAddressesAsArray
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void?): RecipientAutocryptStatus? {
+ val openPgpApi = openPgpApiManager.openPgpApi ?: return null
+ return autocryptStatusInteractor.retrieveCryptoProviderRecipientStatus(openPgpApi, recipientAddresses)
}
- @Override
- protected void onPostExecute(RecipientAutocryptStatus recipientAutocryptStatus) {
- if (recipientAutocryptStatus != null) {
- cachedCryptoStatus = composeCryptoStatus.withRecipientAutocryptStatus(recipientAutocryptStatus);
+ override fun onPostExecute(recipientAutocryptStatus: RecipientAutocryptStatus?) {
+ currentCachedCryptoStatus = if (recipientAutocryptStatus != null) {
+ composeCryptoStatus.withRecipientAutocryptStatus(recipientAutocryptStatus)
} else {
- cachedCryptoStatus = composeCryptoStatus;
+ composeCryptoStatus
}
- redrawCachedCryptoStatusIcon();
+ redrawCachedCryptoStatusIcon()
}
- }.execute();
- }
-
- private void redrawCachedCryptoStatusIcon() {
- if (cachedCryptoStatus == null) {
- throw new IllegalStateException("must have cached crypto status to redraw it!");
- }
-
- recipientMvpView.setRecipientTokensShowCryptoEnabled(cachedCryptoStatus.isEncryptionEnabled());
-
- CryptoStatusDisplayType cryptoStatusDisplayType = cachedCryptoStatus.getDisplayType();
- recipientMvpView.showCryptoStatus(cryptoStatusDisplayType);
- recipientMvpView.showCryptoSpecialMode(cachedCryptoStatus.getSpecialModeDisplayType());
+ }.execute()
}
- @Nullable
- public ComposeCryptoStatus getCurrentCachedCryptoStatus() {
- return cachedCryptoStatus;
- }
+ private fun redrawCachedCryptoStatusIcon() {
+ val cryptoStatus = checkNotNull(currentCachedCryptoStatus) { "must have cached crypto status to redraw it!" }
- public boolean isForceTextMessageFormat() {
- return cryptoEnablePgpInline;
+ recipientMvpView.setRecipientTokensShowCryptoEnabled(cryptoStatus.isEncryptionEnabled)
+ recipientMvpView.showCryptoStatus(cryptoStatus.displayType)
+ recipientMvpView.showCryptoSpecialMode(cryptoStatus.specialModeDisplayType)
}
- void onToTokenAdded() {
- asyncUpdateCryptoStatus();
+ fun onToTokenAdded() {
+ asyncUpdateCryptoStatus()
}
- void onToTokenRemoved() {
- asyncUpdateCryptoStatus();
+ fun onToTokenRemoved() {
+ asyncUpdateCryptoStatus()
}
- void onToTokenChanged() {
- asyncUpdateCryptoStatus();
+ fun onToTokenChanged() {
+ asyncUpdateCryptoStatus()
}
- void onCcTokenAdded() {
- asyncUpdateCryptoStatus();
+ fun onCcTokenAdded() {
+ asyncUpdateCryptoStatus()
}
- void onCcTokenRemoved() {
- asyncUpdateCryptoStatus();
+ fun onCcTokenRemoved() {
+ asyncUpdateCryptoStatus()
}
- void onCcTokenChanged() {
- asyncUpdateCryptoStatus();
+ fun onCcTokenChanged() {
+ asyncUpdateCryptoStatus()
}
- void onBccTokenAdded() {
- asyncUpdateCryptoStatus();
+ fun onBccTokenAdded() {
+ asyncUpdateCryptoStatus()
}
- void onBccTokenRemoved() {
- asyncUpdateCryptoStatus();
+ fun onBccTokenRemoved() {
+ asyncUpdateCryptoStatus()
}
- void onBccTokenChanged() {
- asyncUpdateCryptoStatus();
+ fun onBccTokenChanged() {
+ asyncUpdateCryptoStatus()
}
- public void onCryptoModeChanged(CryptoMode cryptoMode) {
- currentCryptoMode = cryptoMode;
- asyncUpdateCryptoStatus();
+ fun onCryptoModeChanged(cryptoMode: CryptoMode) {
+ currentCryptoMode = cryptoMode
+ asyncUpdateCryptoStatus()
}
- public void onCryptoPgpInlineChanged(boolean enablePgpInline) {
- cryptoEnablePgpInline = enablePgpInline;
- asyncUpdateCryptoStatus();
+ fun onCryptoPgpInlineChanged(enablePgpInline: Boolean) {
+ isForceTextMessageFormat = enablePgpInline
+ asyncUpdateCryptoStatus()
}
- private void addRecipientsFromAddresses(final RecipientType recipientType, final Address... addresses) {
- new RecipientLoader(context, account.getOpenPgpProvider(), addresses) {
- @Override
- public void deliverResult(List result) {
- Recipient[] recipientArray = result.toArray(new Recipient[result.size()]);
- recipientMvpView.addRecipients(recipientType, recipientArray);
+ private fun addRecipientsFromAddresses(recipientType: RecipientType, vararg addresses: Address) {
+ object : RecipientLoader(context, account.openPgpProvider, *addresses) {
+ override fun deliverResult(result: List?) {
+ val recipientArray = result!!.toTypedArray()
+ recipientMvpView.addRecipients(recipientType, *recipientArray)
- stopLoading();
- abandon();
+ stopLoading()
+ abandon()
}
- }.startLoading();
+ }.startLoading()
}
- private void addRecipientFromContactUri(final RecipientType recipientType, final Uri uri) {
- new RecipientLoader(context, account.getOpenPgpProvider(), uri, false) {
- @Override
- public void deliverResult(List result) {
+ private fun addRecipientFromContactUri(recipientType: RecipientType, uri: Uri?) {
+ object : RecipientLoader(context, account.openPgpProvider, uri, false) {
+ override fun deliverResult(result: List?) {
// TODO handle multiple available mail addresses for a contact?
- if (result.isEmpty()) {
- recipientMvpView.showErrorContactNoAddress();
- return;
+ if (result!!.isEmpty()) {
+ recipientMvpView.showErrorContactNoAddress()
+ return
}
- Recipient recipient = result.get(0);
- recipientMvpView.addRecipients(recipientType, recipient);
+ val recipient = result[0]
+ recipientMvpView.addRecipients(recipientType, recipient)
- stopLoading();
- abandon();
+ stopLoading()
+ abandon()
}
- }.startLoading();
+ }.startLoading()
}
- void onToFocused() {
- lastFocusedType = RecipientType.TO;
+ fun onToFocused() {
+ lastFocusedType = RecipientType.TO
}
- void onCcFocused() {
- lastFocusedType = RecipientType.CC;
+ fun onCcFocused() {
+ lastFocusedType = RecipientType.CC
}
- void onBccFocused() {
- lastFocusedType = RecipientType.BCC;
+ fun onBccFocused() {
+ lastFocusedType = RecipientType.BCC
}
- public void onMenuAddFromContacts() {
- int requestCode = recipientTypeToRequestCode(lastFocusedType);
- recipientMvpView.showContactPicker(requestCode);
+ fun onMenuAddFromContacts() {
+ val requestCode = lastFocusedType.toRequestCode()
+ recipientMvpView.showContactPicker(requestCode)
}
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case CONTACT_PICKER_TO:
- case CONTACT_PICKER_CC:
- case CONTACT_PICKER_BCC:
- if (resultCode != Activity.RESULT_OK || data == null) {
- return;
- }
- RecipientType recipientType = recipientTypeFromRequestCode(requestCode);
- addRecipientFromContactUri(recipientType, data.getData());
- break;
- case OPENPGP_USER_INTERACTION:
- openPgpApiManager.onUserInteractionResult();
- break;
- case REQUEST_CODE_AUTOCRYPT:
- asyncUpdateCryptoStatus();
- break;
- }
- }
-
- private static int recipientTypeToRequestCode(RecipientType type) {
- switch (type) {
- case TO: {
- return CONTACT_PICKER_TO;
- }
- case CC: {
- return CONTACT_PICKER_CC;
- }
- case BCC: {
- return CONTACT_PICKER_BCC;
- }
- }
-
- throw new AssertionError("Unhandled case: " + type);
- }
+ fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ when (requestCode) {
+ CONTACT_PICKER_TO, CONTACT_PICKER_CC, CONTACT_PICKER_BCC -> {
+ if (resultCode != Activity.RESULT_OK || data == null) return
- private static RecipientType recipientTypeFromRequestCode(int type) {
- switch (type) {
- case CONTACT_PICKER_TO: {
- return RecipientType.TO;
+ val recipientType = requestCode.toRecipientType()
+ addRecipientFromContactUri(recipientType, data.data)
}
- case CONTACT_PICKER_CC: {
- return RecipientType.CC;
+ OPENPGP_USER_INTERACTION -> {
+ openPgpApiManager.onUserInteractionResult()
}
- case CONTACT_PICKER_BCC: {
- return RecipientType.BCC;
+ REQUEST_CODE_AUTOCRYPT -> {
+ asyncUpdateCryptoStatus()
}
}
-
- throw new AssertionError("Unhandled case: " + type);
}
- public void onNonRecipientFieldFocused() {
- if (!account.isAlwaysShowCcBcc()) {
- hideEmptyExtendedRecipientFields();
+ fun onNonRecipientFieldFocused() {
+ if (!account.isAlwaysShowCcBcc) {
+ hideEmptyExtendedRecipientFields()
}
}
- void onClickCryptoStatus() {
- switch (openPgpApiManager.getOpenPgpProviderState()) {
- case UNCONFIGURED:
- Timber.e("click on crypto status while unconfigured - this should not really happen?!");
- return;
- case OK:
- toggleEncryptionState(false);
- return;
- case UI_REQUIRED:
+ fun onClickCryptoStatus() {
+ when (openPgpApiManager.openPgpProviderState) {
+ OpenPgpProviderState.UNCONFIGURED -> {
+ Timber.e("click on crypto status while unconfigured - this should not really happen?!")
+ }
+ OpenPgpProviderState.OK -> {
+ toggleEncryptionState(false)
+ }
+ OpenPgpProviderState.UI_REQUIRED -> {
// TODO show openpgp settings
- PendingIntent pendingIntent = openPgpApiManager.getUserInteractionPendingIntent();
- recipientMvpView.launchUserInteractionPendingIntent(pendingIntent, OPENPGP_USER_INTERACTION);
- break;
- case UNINITIALIZED:
- case ERROR:
- openPgpApiManager.refreshConnection();
+ val pendingIntent = openPgpApiManager.userInteractionPendingIntent
+ recipientMvpView.launchUserInteractionPendingIntent(pendingIntent, OPENPGP_USER_INTERACTION)
+ }
+ OpenPgpProviderState.UNINITIALIZED, OpenPgpProviderState.ERROR -> {
+ openPgpApiManager.refreshConnection()
+ }
}
}
- private void toggleEncryptionState(boolean showGotIt) {
- ComposeCryptoStatus currentCryptoStatus = getCurrentCachedCryptoStatus();
+ private fun toggleEncryptionState(showGotIt: Boolean) {
+ val currentCryptoStatus = currentCachedCryptoStatus
if (currentCryptoStatus == null) {
- Timber.e("click on crypto status while crypto status not available - should not really happen?!");
- return;
+ Timber.e("click on crypto status while crypto status not available - should not really happen?!")
+ return
}
- if (currentCryptoStatus.isEncryptionEnabled() && !currentCryptoStatus.allRecipientsCanEncrypt()) {
- recipientMvpView.showOpenPgpEnabledErrorDialog(false);
- return;
+ if (currentCryptoStatus.isEncryptionEnabled && !currentCryptoStatus.allRecipientsCanEncrypt()) {
+ recipientMvpView.showOpenPgpEnabledErrorDialog(false)
+ return
}
if (currentCryptoMode == CryptoMode.SIGN_ONLY) {
- recipientMvpView.showErrorIsSignOnly();
- return;
+ recipientMvpView.showErrorIsSignOnly()
+ return
}
- boolean isEncryptOnNoChoice = currentCryptoStatus.canEncryptAndIsMutualDefault() ||
- currentCryptoStatus.isReplyToEncrypted();
+ val isEncryptOnNoChoice = currentCryptoStatus.canEncryptAndIsMutualDefault() ||
+ currentCryptoStatus.isReplyToEncrypted
+
if (currentCryptoMode == CryptoMode.NO_CHOICE) {
if (currentCryptoStatus.hasAutocryptPendingIntent()) {
recipientMvpView.launchUserInteractionPendingIntent(
- currentCryptoStatus.getAutocryptPendingIntent(), REQUEST_CODE_AUTOCRYPT);
+ currentCryptoStatus.autocryptPendingIntent, REQUEST_CODE_AUTOCRYPT
+ )
} else if (isEncryptOnNoChoice) {
// TODO warning dialog if we override, especially from reply!
- onCryptoModeChanged(CryptoMode.CHOICE_DISABLED);
+ onCryptoModeChanged(CryptoMode.CHOICE_DISABLED)
} else {
- onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
+ onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
if (showGotIt) {
- recipientMvpView.showOpenPgpEncryptExplanationDialog();
+ recipientMvpView.showOpenPgpEncryptExplanationDialog()
}
}
} else if (currentCryptoMode == CryptoMode.CHOICE_DISABLED && !isEncryptOnNoChoice) {
- onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
+ onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
} else {
- onCryptoModeChanged(CryptoMode.NO_CHOICE);
+ onCryptoModeChanged(CryptoMode.NO_CHOICE)
}
}
/**
- * Does the device actually have a Contacts application suitable for
- * picking a contact. As hard as it is to believe, some vendors ship
- * without it.
- *
- * @return True, if the device supports picking contacts. False, otherwise.
+ * Does the device actually have a Contacts application suitable for picking a contact.
+ * As hard as it is to believe, some vendors ship without it.
*/
- private boolean hasContactPicker() {
- if (hasContactPicker == null) {
- Contacts contacts = Contacts.getInstance(context);
-
- PackageManager packageManager = context.getPackageManager();
- List resolveInfoList = packageManager.queryIntentActivities(contacts.contactPickerIntent(), 0);
- hasContactPicker = !resolveInfoList.isEmpty();
- }
+ private fun hasContactPicker(): Boolean {
+ return hasContactPicker ?: isContactPickerAvailable().also { hasContactPicker = it }
+ }
- return hasContactPicker;
+ private fun isContactPickerAvailable(): Boolean {
+ val contacts = Contacts.getInstance(context)
+ val resolveInfoList = context.packageManager.queryIntentActivities(contacts.contactPickerIntent(), 0)
+ return resolveInfoList.isNotEmpty()
}
- private boolean hasContactPermission() {
- return ContextCompat.checkSelfPermission(context,
- Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
+ private fun hasContactPermission(): Boolean {
+ val permissionState = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
+ return permissionState == PackageManager.PERMISSION_GRANTED
}
- public void showPgpSendError(SendErrorState sendErrorState) {
- switch (sendErrorState) {
- case ENABLED_ERROR:
- recipientMvpView.showOpenPgpEnabledErrorDialog(false);
- break;
- case PROVIDER_ERROR:
- recipientMvpView.showErrorOpenPgpConnection();
- break;
- case KEY_CONFIG_ERROR:
- recipientMvpView.showErrorNoKeyConfigured();
- break;
- default:
- throw new AssertionError("not all error states handled, this is a bug!");
+ fun showPgpSendError(sendErrorState: SendErrorState) {
+ when (sendErrorState) {
+ SendErrorState.ENABLED_ERROR -> recipientMvpView.showOpenPgpEnabledErrorDialog(false)
+ SendErrorState.PROVIDER_ERROR -> recipientMvpView.showErrorOpenPgpConnection()
+ SendErrorState.KEY_CONFIG_ERROR -> recipientMvpView.showErrorNoKeyConfigured()
+ else -> throw AssertionError("not all error states handled, this is a bug!")
}
}
- void showPgpAttachError(AttachErrorState attachErrorState) {
- switch (attachErrorState) {
- case IS_INLINE:
- recipientMvpView.showErrorInlineAttach();
- break;
- default:
- throw new AssertionError("not all error states handled, this is a bug!");
+ fun showPgpAttachError(attachErrorState: AttachErrorState) {
+ when (attachErrorState) {
+ AttachErrorState.IS_INLINE -> recipientMvpView.showErrorInlineAttach()
+ else -> throw AssertionError("not all error states handled, this is a bug!")
}
}
- public void builderSetProperties(MessageBuilder messageBuilder) {
- if (messageBuilder instanceof PgpMessageBuilder) {
- throw new IllegalArgumentException("PpgMessageBuilder must be called with ComposeCryptoStatus argument!");
+ fun builderSetProperties(messageBuilder: MessageBuilder) {
+ require(messageBuilder !is PgpMessageBuilder) {
+ "PpgMessageBuilder must be called with ComposeCryptoStatus argument!"
}
- messageBuilder.setTo(getToAddresses());
- messageBuilder.setCc(getCcAddresses());
- messageBuilder.setBcc(getBccAddresses());
+ messageBuilder.setTo(toAddresses)
+ messageBuilder.setCc(ccAddresses)
+ messageBuilder.setBcc(bccAddresses)
}
- public void builderSetProperties(PgpMessageBuilder pgpMessageBuilder, ComposeCryptoStatus cryptoStatus) {
- pgpMessageBuilder.setTo(getToAddresses());
- pgpMessageBuilder.setCc(getCcAddresses());
- pgpMessageBuilder.setBcc(getBccAddresses());
-
- pgpMessageBuilder.setOpenPgpApi(openPgpApiManager.getOpenPgpApi());
- pgpMessageBuilder.setCryptoStatus(cryptoStatus);
+ fun builderSetProperties(pgpMessageBuilder: PgpMessageBuilder, cryptoStatus: ComposeCryptoStatus) {
+ pgpMessageBuilder.setTo(toAddresses)
+ pgpMessageBuilder.setCc(ccAddresses)
+ pgpMessageBuilder.setBcc(bccAddresses)
+ pgpMessageBuilder.setOpenPgpApi(openPgpApiManager.openPgpApi)
+ pgpMessageBuilder.setCryptoStatus(cryptoStatus)
}
- public void onMenuSetPgpInline(boolean enablePgpInline) {
- onCryptoPgpInlineChanged(enablePgpInline);
+ fun onMenuSetPgpInline(enablePgpInline: Boolean) {
+ onCryptoPgpInlineChanged(enablePgpInline)
+
if (enablePgpInline) {
- boolean shouldShowPgpInlineDialog = checkAndIncrementPgpInlineDialogCounter();
+ val shouldShowPgpInlineDialog = checkAndIncrementPgpInlineDialogCounter()
if (shouldShowPgpInlineDialog) {
- recipientMvpView.showOpenPgpInlineDialog(true);
+ recipientMvpView.showOpenPgpInlineDialog(true)
}
}
}
- public void onMenuSetSignOnly(boolean enableSignOnly) {
+ fun onMenuSetSignOnly(enableSignOnly: Boolean) {
if (enableSignOnly) {
- onCryptoModeChanged(CryptoMode.SIGN_ONLY);
- boolean shouldShowPgpSignOnlyDialog = checkAndIncrementPgpSignOnlyDialogCounter();
+ onCryptoModeChanged(CryptoMode.SIGN_ONLY)
+
+ val shouldShowPgpSignOnlyDialog = checkAndIncrementPgpSignOnlyDialogCounter()
if (shouldShowPgpSignOnlyDialog) {
- recipientMvpView.showOpenPgpSignOnlyDialog(true);
+ recipientMvpView.showOpenPgpSignOnlyDialog(true)
}
} else {
- onCryptoModeChanged(CryptoMode.NO_CHOICE);
+ onCryptoModeChanged(CryptoMode.NO_CHOICE)
}
}
- public void onMenuToggleEncryption() {
- toggleEncryptionState(true);
+ fun onMenuToggleEncryption() {
+ toggleEncryptionState(true)
}
- public void onCryptoPgpClickDisable() {
- onCryptoModeChanged(CryptoMode.CHOICE_DISABLED);
+ fun onCryptoPgpClickDisable() {
+ onCryptoModeChanged(CryptoMode.CHOICE_DISABLED)
}
- public void onCryptoPgpSignOnlyDisabled() {
- onCryptoPgpInlineChanged(false);
- onCryptoModeChanged(CryptoMode.NO_CHOICE);
+ fun onCryptoPgpSignOnlyDisabled() {
+ onCryptoPgpInlineChanged(false)
+ onCryptoModeChanged(CryptoMode.NO_CHOICE)
}
- private boolean checkAndIncrementPgpInlineDialogCounter() {
- int pgpInlineDialogCounter = K9.getPgpInlineDialogCounter();
+ private fun checkAndIncrementPgpInlineDialogCounter(): Boolean {
+ val pgpInlineDialogCounter = K9.pgpInlineDialogCounter
if (pgpInlineDialogCounter < PGP_DIALOG_DISPLAY_THRESHOLD) {
- K9.setPgpInlineDialogCounter(pgpInlineDialogCounter + 1);
- K9.saveSettingsAsync();
- return true;
+ K9.pgpInlineDialogCounter = pgpInlineDialogCounter + 1
+ K9.saveSettingsAsync()
+ return true
}
- return false;
+
+ return false
}
- private boolean checkAndIncrementPgpSignOnlyDialogCounter() {
- int pgpSignOnlyDialogCounter = K9.getPgpSignOnlyDialogCounter();
+ private fun checkAndIncrementPgpSignOnlyDialogCounter(): Boolean {
+ val pgpSignOnlyDialogCounter = K9.pgpSignOnlyDialogCounter
if (pgpSignOnlyDialogCounter < PGP_DIALOG_DISPLAY_THRESHOLD) {
- K9.setPgpSignOnlyDialogCounter(pgpSignOnlyDialogCounter + 1);
- K9.saveSettingsAsync();
- return true;
+ K9.pgpSignOnlyDialogCounter = pgpSignOnlyDialogCounter + 1
+ K9.saveSettingsAsync()
+ return true
}
- return false;
- }
- void onClickCryptoSpecialModeIndicator() {
- if (currentCryptoMode == CryptoMode.SIGN_ONLY) {
- recipientMvpView.showOpenPgpSignOnlyDialog(false);
- } else if (cryptoEnablePgpInline) {
- recipientMvpView.showOpenPgpInlineDialog(false);
- } else {
- throw new IllegalStateException("This icon should not be clickable while no special mode is active!");
- }
+ return false
}
- public boolean shouldSaveRemotely() {
- // TODO more appropriate logic?
- return cachedCryptoStatus == null || !cachedCryptoStatus.isEncryptionEnabled();
+ fun onClickCryptoSpecialModeIndicator() {
+ when {
+ currentCryptoMode == CryptoMode.SIGN_ONLY -> {
+ recipientMvpView.showOpenPgpSignOnlyDialog(false)
+ }
+ isForceTextMessageFormat -> {
+ recipientMvpView.showOpenPgpInlineDialog(false)
+ }
+ else -> {
+ error("This icon should not be clickable while no special mode is active!")
+ }
+ }
}
- private final OpenPgpApiManagerCallback openPgpCallback = new OpenPgpApiManagerCallback() {
- @Override
- public void onOpenPgpProviderStatusChanged() {
- if (openPgpApiManager.getOpenPgpProviderState() == OpenPgpProviderState.UI_REQUIRED) {
- recipientMvpView.showErrorOpenPgpUserInteractionRequired();
+ private val openPgpCallback = object : OpenPgpApiManagerCallback {
+ override fun onOpenPgpProviderStatusChanged() {
+ if (openPgpApiManager.openPgpProviderState == OpenPgpProviderState.UI_REQUIRED) {
+ recipientMvpView.showErrorOpenPgpUserInteractionRequired()
}
- asyncUpdateCryptoStatus();
- }
-
- @Override
- public void onOpenPgpProviderError(OpenPgpProviderError error) {
- switch (error) {
- case ConnectionLost:
- openPgpApiManager.refreshConnection();
- break;
- case VersionIncompatible:
- recipientMvpView.showErrorOpenPgpIncompatible();
- break;
- case ConnectionFailed:
- default:
- recipientMvpView.showErrorOpenPgpConnection();
- break;
+ asyncUpdateCryptoStatus()
+ }
+
+ override fun onOpenPgpProviderError(error: OpenPgpProviderError) {
+ when (error) {
+ OpenPgpProviderError.ConnectionLost -> openPgpApiManager.refreshConnection()
+ OpenPgpProviderError.VersionIncompatible -> recipientMvpView.showErrorOpenPgpIncompatible()
+ OpenPgpProviderError.ConnectionFailed -> recipientMvpView.showErrorOpenPgpConnection()
+ else -> recipientMvpView.showErrorOpenPgpConnection()
}
}
- };
+ }
+
+ private fun Array.toAddressArray(): Array {
+ return flatMap { addressString ->
+ Address.parseUnencoded(addressString).toList()
+ }.toTypedArray()
+ }
+
+ private fun RecipientType.toRequestCode(): Int = when (this) {
+ RecipientType.TO -> CONTACT_PICKER_TO
+ RecipientType.CC -> CONTACT_PICKER_CC
+ RecipientType.BCC -> CONTACT_PICKER_BCC
+ else -> throw AssertionError("Unhandled case: $this")
+ }
+
+ private fun Int.toRecipientType(): RecipientType = when (this) {
+ CONTACT_PICKER_TO -> RecipientType.TO
+ CONTACT_PICKER_CC -> RecipientType.CC
+ CONTACT_PICKER_BCC -> RecipientType.BCC
+ else -> throw AssertionError("Unhandled case: $this")
+ }
- public enum CryptoMode {
- SIGN_ONLY,
- NO_CHOICE,
- CHOICE_DISABLED,
- CHOICE_ENABLED,
+ enum class CryptoMode {
+ SIGN_ONLY, NO_CHOICE, CHOICE_DISABLED, CHOICE_ENABLED
}
}
diff --git a/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt b/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt
index d6b1c21560..853170cba7 100644
--- a/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt
+++ b/app/ui/legacy/src/test/java/com/fsck/k9/activity/compose/RecipientPresenterTest.kt
@@ -1,301 +1,307 @@
-package com.fsck.k9.activity.compose;
-
-
-import java.util.Arrays;
-import java.util.List;
-
-import android.content.Context;
-import androidx.loader.app.LoaderManager;
-
-import com.fsck.k9.Account;
-import com.fsck.k9.DI;
-import com.fsck.k9.K9RobolectricTest;
-import com.fsck.k9.activity.compose.RecipientMvpView.CryptoSpecialModeDisplayType;
-import com.fsck.k9.activity.compose.RecipientMvpView.CryptoStatusDisplayType;
-import com.fsck.k9.activity.compose.RecipientPresenter.CryptoMode;
-import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser;
-import com.fsck.k9.helper.ReplyToParser;
-import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
-import com.fsck.k9.mail.Address;
-import com.fsck.k9.mail.Message;
-import com.fsck.k9.mail.Message.RecipientType;
-import com.fsck.k9.message.AutocryptStatusInteractor;
-import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus;
-import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatusType;
-import com.fsck.k9.message.ComposePgpEnableByDefaultDecider;
-import com.fsck.k9.message.ComposePgpInlineDecider;
-import com.fsck.k9.view.RecipientSelectView.Recipient;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.openintents.openpgp.OpenPgpApiManager;
-import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback;
-import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState;
-import org.openintents.openpgp.util.OpenPgpApi;
-import org.robolectric.Robolectric;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.LooperMode;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-
-@SuppressWarnings("ConstantConditions")
-@LooperMode(LooperMode.Mode.LEGACY)
-public class RecipientPresenterTest extends K9RobolectricTest {
- private static final ReplyToAddresses TO_ADDRESSES = new ReplyToAddresses(Address.parse("to@example.org"));
- private static final List ALL_TO_ADDRESSES = Arrays.asList(Address.parse("allTo@example.org"));
- private static final List ALL_CC_ADDRESSES = Arrays.asList(Address.parse("allCc@example.org"));
- private static final String CRYPTO_PROVIDER = "crypto_provider";
- private static final long CRYPTO_KEY_ID = 123L;
-
-
- private RecipientPresenter recipientPresenter;
- private ReplyToParser replyToParser;
- private ComposePgpInlineDecider composePgpInlineDecider;
- private ComposePgpEnableByDefaultDecider composePgpEnableByDefaultDecider;
- private Account account;
- private RecipientMvpView recipientMvpView;
- private AutocryptStatusInteractor autocryptStatusInteractor;
- private RecipientAutocryptStatus noRecipientsAutocryptResult;
- private OpenPgpApiManager openPgpApiManager;
- private OpenPgpApiManagerCallback openPgpApiManagerCallback;
+package com.fsck.k9.activity.compose
+
+import androidx.test.core.app.ApplicationProvider
+import com.fsck.k9.Account
+import com.fsck.k9.K9RobolectricTest
+import com.fsck.k9.activity.compose.RecipientMvpView.CryptoSpecialModeDisplayType
+import com.fsck.k9.activity.compose.RecipientMvpView.CryptoStatusDisplayType
+import com.fsck.k9.activity.compose.RecipientPresenter.CryptoMode
+import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser
+import com.fsck.k9.helper.ReplyToParser
+import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses
+import com.fsck.k9.mail.Address
+import com.fsck.k9.mail.Message
+import com.fsck.k9.mail.Message.RecipientType
+import com.fsck.k9.message.AutocryptStatusInteractor
+import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus
+import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatusType
+import com.fsck.k9.message.ComposePgpEnableByDefaultDecider
+import com.fsck.k9.message.ComposePgpInlineDecider
+import com.fsck.k9.view.RecipientSelectView.Recipient
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertNotNull
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.koin.test.inject
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stubbing
+import org.openintents.openpgp.OpenPgpApiManager
+import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback
+import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState
+import org.openintents.openpgp.util.OpenPgpApi
+import org.robolectric.Robolectric
+import org.robolectric.annotation.LooperMode
+
+private val TO_ADDRESS = Address("to@domain.example")
+private val CC_ADDRESS = Address("cc@domain.example")
+private const val CRYPTO_PROVIDER = "crypto_provider"
+private const val CRYPTO_KEY_ID = 123L
+@LooperMode(LooperMode.Mode.LEGACY)
+class RecipientPresenterTest : K9RobolectricTest() {
+ private val openPgpApiManager = mock {
+ on { openPgpProviderState } doReturn OpenPgpProviderState.UNCONFIGURED
+ on { setOpenPgpProvider(any(), any()) } doAnswer { invocation ->
+ openPgpApiManagerCallback = invocation.getArgument(1)
+ }
+ }
+ private val recipientMvpView = mock()
+ private val account = mock()
+ private val composePgpInlineDecider = mock()
+ private val composePgpEnableByDefaultDecider = mock()
+ private val autocryptStatusInteractor = mock()
+ private val replyToParser = mock()
+ private val autocryptDraftStateHeaderParser: AutocryptDraftStateHeaderParser by inject()
+ private lateinit var recipientPresenter: RecipientPresenter
+
+ private val noRecipientsAutocryptResult = RecipientAutocryptStatus(RecipientAutocryptStatusType.NO_RECIPIENTS, null)
+ private var openPgpApiManagerCallback: OpenPgpApiManagerCallback? = null
@Before
- public void setUp() throws Exception {
- Context context = RuntimeEnvironment.application;
- Robolectric.getBackgroundThreadScheduler().pause();
-
- recipientMvpView = mock(RecipientMvpView.class);
- openPgpApiManager = mock(OpenPgpApiManager.class);
- account = mock(Account.class);
- composePgpInlineDecider = mock(ComposePgpInlineDecider.class);
- composePgpEnableByDefaultDecider = mock(ComposePgpEnableByDefaultDecider.class);
- autocryptStatusInteractor = mock(AutocryptStatusInteractor.class);
- replyToParser = mock(ReplyToParser.class);
- LoaderManager loaderManager = mock(LoaderManager.class);
-
- when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.UNCONFIGURED);
-
- recipientPresenter = new RecipientPresenter(
- context, loaderManager, openPgpApiManager, recipientMvpView, account, composePgpInlineDecider,
- composePgpEnableByDefaultDecider, autocryptStatusInteractor, replyToParser,
- DI.get(AutocryptDraftStateHeaderParser.class)
- );
-
- ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass(OpenPgpApiManagerCallback.class);
- verify(openPgpApiManager).setOpenPgpProvider(isNull(String.class), callbackCaptor.capture());
- openPgpApiManagerCallback = callbackCaptor.getValue();
-
- noRecipientsAutocryptResult = new RecipientAutocryptStatus(RecipientAutocryptStatusType.NO_RECIPIENTS, null);
+ fun setUp() {
+ Robolectric.getBackgroundThreadScheduler().pause()
+
+ recipientPresenter = RecipientPresenter(
+ ApplicationProvider.getApplicationContext(),
+ mock(),
+ openPgpApiManager,
+ recipientMvpView,
+ account,
+ composePgpInlineDecider,
+ composePgpEnableByDefaultDecider,
+ autocryptStatusInteractor,
+ replyToParser,
+ autocryptDraftStateHeaderParser
+ )
}
@Test
@Ignore("It looks like the support version of AsyncTaskLoader handles background tasks differently")
- public void testInitFromReplyToMessage() throws Exception {
- Message message = mock(Message.class);
- when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
+ fun testInitFromReplyToMessage() {
+ val message = mock()
+ stubbing(replyToParser) {
+ on { getRecipientsToReplyTo(message, account) } doReturn ReplyToAddresses(arrayOf(TO_ADDRESS))
+ }
- recipientPresenter.initFromReplyToMessage(message, false);
- runBackgroundTask();
+ recipientPresenter.initFromReplyToMessage(message, false)
+ runBackgroundTask()
- Recipient toRecipient = new Recipient(TO_ADDRESSES.to[0]);
- verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(toRecipient));
+ verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(Recipient(TO_ADDRESS)))
}
@Test
@Ignore("It looks like the support version of AsyncTaskLoader handles background tasks differently")
- public void testInitFromReplyToAllMessage() throws Exception {
- Message message = mock(Message.class);
- when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
- ReplyToAddresses replyToAddresses = new ReplyToAddresses(ALL_TO_ADDRESSES, ALL_CC_ADDRESSES);
- when(replyToParser.getRecipientsToReplyAllTo(message, account)).thenReturn(replyToAddresses);
-
- recipientPresenter.initFromReplyToMessage(message, true);
- // one for To, one for Cc
- runBackgroundTask();
- runBackgroundTask();
-
- verify(recipientMvpView).addRecipients(eq(RecipientType.TO), any(Recipient.class));
- verify(recipientMvpView).addRecipients(eq(RecipientType.CC), any(Recipient.class));
+ fun testInitFromReplyToAllMessage() {
+ val message = mock()
+ val replyToAddresses = ReplyToAddresses(listOf(TO_ADDRESS), listOf(CC_ADDRESS))
+ stubbing(replyToParser) {
+ on { getRecipientsToReplyAllTo(message, account) } doReturn replyToAddresses
+ }
+
+ recipientPresenter.initFromReplyToMessage(message, true)
+ runBackgroundTask()
+ runBackgroundTask()
+
+ verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(Recipient(TO_ADDRESS)))
+ verify(recipientMvpView).addRecipients(eq(RecipientType.CC), eq(Recipient(CC_ADDRESS)))
}
@Test
- public void initFromReplyToMessage_shouldCallComposePgpInlineDecider() throws Exception {
- Message message = mock(Message.class);
- when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
+ fun initFromReplyToMessage_shouldCallComposePgpInlineDecider() {
+ val message = mock()
+ stubbing(replyToParser) {
+ on { getRecipientsToReplyTo(message, account) } doReturn ReplyToAddresses(arrayOf(TO_ADDRESS))
+ }
- recipientPresenter.initFromReplyToMessage(message, false);
+ recipientPresenter.initFromReplyToMessage(message, false)
- verify(composePgpInlineDecider).shouldReplyInline(message);
+ verify(composePgpInlineDecider).shouldReplyInline(message)
}
@Test
- public void getCurrentCryptoStatus_withoutCryptoProvider() throws Exception {
- when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.UNCONFIGURED);
- recipientPresenter.asyncUpdateCryptoStatus();
-
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.UNCONFIGURED, status.getDisplayType());
- assertEquals(CryptoSpecialModeDisplayType.NONE, status.getSpecialModeDisplayType());
- assertNull(status.getAttachErrorStateOrNull());
- assertFalse(status.isProviderStateOk());
- assertFalse(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withoutCryptoProvider() {
+ stubbing(openPgpApiManager) {
+ on { openPgpProviderState } doReturn OpenPgpProviderState.UNCONFIGURED
+ }
+
+ recipientPresenter.asyncUpdateCryptoStatus()
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNCONFIGURED)
+ assertThat(status.specialModeDisplayType).isEqualTo(CryptoSpecialModeDisplayType.NONE)
+ assertThat(status.attachErrorStateOrNull).isNull()
+ assertThat(status.isProviderStateOk()).isFalse()
+ assertThat(status.isOpenPgpConfigured).isFalse()
+ }
}
@Test
- public void getCurrentCryptoStatus_withCryptoProvider() throws Exception {
- setupCryptoProvider(noRecipientsAutocryptResult);
-
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withCryptoProvider() {
+ setupCryptoProvider(noRecipientsAutocryptResult)
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withOpportunistic() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withOpportunistic() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withOpportunistic__confirmed() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.AVAILABLE_CONFIRMED, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withOpportunistic__confirmed() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.AVAILABLE_CONFIRMED, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withOpportunistic__missingKeys() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.UNAVAILABLE, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withOpportunistic__missingKeys() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.UNAVAILABLE, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withOpportunistic__privateMissingKeys() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.UNAVAILABLE, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
- runBackgroundTask();
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.ENABLED_ERROR, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withOpportunistic__privateMissingKeys() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.UNAVAILABLE, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+ recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
+ runBackgroundTask()
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.ENABLED_ERROR)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withModeDisabled() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_DISABLED);
- runBackgroundTask();
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withModeDisabled() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+ recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_DISABLED)
+ runBackgroundTask()
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withModePrivate() throws Exception {
- RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
- RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
- setupCryptoProvider(recipientAutocryptStatus);
-
- recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
- runBackgroundTask();
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.ENABLED, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isOpenPgpConfigured());
+ fun getCurrentCryptoStatus_withModePrivate() {
+ val recipientAutocryptStatus = RecipientAutocryptStatus(
+ RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
+ )
+
+ setupCryptoProvider(recipientAutocryptStatus)
+ recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
+ runBackgroundTask()
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.ENABLED)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withModeSignOnly() throws Exception {
- setupCryptoProvider(noRecipientsAutocryptResult);
-
- recipientPresenter.onMenuSetSignOnly(true);
- runBackgroundTask();
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
-
- assertEquals(CryptoStatusDisplayType.SIGN_ONLY, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isSigningEnabled());
- assertTrue(status.isSignOnly());
+ fun getCurrentCryptoStatus_withModeSignOnly() {
+ setupCryptoProvider(noRecipientsAutocryptResult)
+
+ recipientPresenter.onMenuSetSignOnly(true)
+ runBackgroundTask()
+
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.SIGN_ONLY)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isOpenPgpConfigured).isTrue()
+ assertThat(status.isSignOnly).isTrue()
+ }
}
@Test
- public void getCurrentCryptoStatus_withModeInline() throws Exception {
- setupCryptoProvider(noRecipientsAutocryptResult);
+ fun getCurrentCryptoStatus_withModeInline() {
+ setupCryptoProvider(noRecipientsAutocryptResult)
- recipientPresenter.onMenuSetPgpInline(true);
- runBackgroundTask();
- ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
+ recipientPresenter.onMenuSetPgpInline(true)
+ runBackgroundTask()
- assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
- assertTrue(status.isProviderStateOk());
- assertTrue(status.isPgpInlineModeEnabled());
+ assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
+ assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
+ assertThat(status.isProviderStateOk()).isTrue()
+ assertThat(status.isPgpInlineModeEnabled).isTrue()
+ }
}
- private void runBackgroundTask() {
- boolean taskRun = Robolectric.getBackgroundThreadScheduler().runOneTask();
- assertTrue(taskRun);
+ private fun runBackgroundTask() {
+ assertThat(Robolectric.getBackgroundThreadScheduler().runOneTask()).isTrue()
}
- private void setupCryptoProvider(RecipientAutocryptStatus autocryptStatusResult) throws Exception {
- Account account = mock(Account.class);
- OpenPgpApi openPgpApi = mock(OpenPgpApi.class);
+ private fun setupCryptoProvider(autocryptStatusResult: RecipientAutocryptStatus) {
+ stubbing(account) {
+ on { openPgpProvider } doReturn CRYPTO_PROVIDER
+ on { isOpenPgpProviderConfigured } doReturn true
+ on { openPgpKey } doReturn CRYPTO_KEY_ID
+ }
+
+ recipientPresenter.onSwitchAccount(account)
+
+ val openPgpApiMock = mock()
- when(account.getOpenPgpProvider()).thenReturn(CRYPTO_PROVIDER);
- when(account.isOpenPgpProviderConfigured()).thenReturn(true);
- when(account.getOpenPgpKey()).thenReturn(CRYPTO_KEY_ID);
- recipientPresenter.onSwitchAccount(account);
+ stubbing(autocryptStatusInteractor) {
+ on { retrieveCryptoProviderRecipientStatus(eq(openPgpApiMock), any()) } doReturn autocryptStatusResult
+ }
- when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.OK);
- when(openPgpApiManager.getOpenPgpApi()).thenReturn(openPgpApi);
- when(autocryptStatusInteractor.retrieveCryptoProviderRecipientStatus(
- any(OpenPgpApi.class), any(String[].class))).thenReturn(autocryptStatusResult);
+ stubbing(openPgpApiManager) {
+ on { openPgpApi } doReturn openPgpApiMock
+ on { openPgpProviderState } doReturn OpenPgpProviderState.OK
+ }
- openPgpApiManagerCallback.onOpenPgpProviderStatusChanged();
- runBackgroundTask();
+ openPgpApiManagerCallback!!.onOpenPgpProviderStatusChanged()
+ runBackgroundTask()
}
}
--
GitLab
From 701b640da3a795c6d0d761516fac92d655dcb11c Mon Sep 17 00:00:00 2001
From: cketti
Date: Tue, 31 Aug 2021 18:33:46 +0200
Subject: [PATCH 077/285] Move LocalFolder.getMessageCount() to MessageStore
---
.../k9/controller/MessagingController.java | 22 +++++----------
.../com/fsck/k9/mailstore/LocalFolder.java | 28 -------------------
.../com/fsck/k9/mailstore/MessageStore.kt | 5 ++++
.../k9/storage/messages/K9MessageStore.kt | 4 +++
.../messages/RetrieveFolderOperations.kt | 11 ++++++++
.../messages/RetrieveFolderOperationsTest.kt | 27 ++++++++++++++++++
6 files changed, 54 insertions(+), 43 deletions(-)
diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
index a8deb617ad..0160b4dbf4 100644
--- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
+++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java
@@ -66,7 +66,6 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mailstore.FolderDetailsAccessor;
-import com.fsck.k9.mailstore.ListenableMessageStore;
import com.fsck.k9.mailstore.LocalFolder;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
@@ -1487,21 +1486,14 @@ public class MessagingController {
}
private boolean messagesPendingSend(final Account account) {
- try {
- LocalFolder localFolder = localStoreProvider.getInstance(account).getFolder(account.getOutboxFolderId());
- if (!localFolder.exists()) {
- return false;
- }
-
- localFolder.open();
-
- if (localFolder.getMessageCount() > 0) {
- return true;
- }
- } catch (Exception e) {
- Timber.e(e, "Exception while checking for unsent messages");
+ Long outboxFolderId = account.getOutboxFolderId();
+ if (outboxFolderId == null) {
+ Timber.w("Could not get Outbox folder ID from Account");
+ return false;
}
- return false;
+
+ MessageStore messageStore = messageStoreManager.getMessageStore(account);
+ return messageStore.getMessageCount(outboxFolderId) > 0;
}
/**
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
index 46a875eec2..01972b8a2d 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/LocalFolder.java
@@ -259,34 +259,6 @@ public class LocalFolder {
});
}
- public int getMessageCount() throws MessagingException {
- try {
- return this.localStore.getDatabase().execute(false, new DbCallback() {
- @Override
- public Integer doDbWork(final SQLiteDatabase db) throws WrappedException {
- try {
- open();
- } catch (MessagingException e) {
- throw new WrappedException(e);
- }
- Cursor cursor = null;
- try {
- cursor = db.rawQuery(
- "SELECT COUNT(id) FROM messages " +
- "WHERE empty = 0 AND deleted = 0 and folder_id = ?",
- new String[] { Long.toString(databaseId) });
- cursor.moveToFirst();
- return cursor.getInt(0); //messagecount
- } finally {
- Utility.closeQuietly(cursor);
- }
- }
- });
- } catch (WrappedException e) {
- throw (MessagingException) e.getCause();
- }
- }
-
public MessageCounts getMessageCounts() throws MessagingException {
return new MessageCounts(getUnreadMessageCount(), getStarredMessageCount());
}
diff --git a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
index 55e5ecb60f..6225792a9a 100644
--- a/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
+++ b/app/core/src/main/java/com/fsck/k9/mailstore/MessageStore.kt
@@ -176,6 +176,11 @@ interface MessageStore {
*/
fun getFolderId(folderServerId: String): Long?
+ /**
+ * Retrieve the number of messages in a folder.
+ */
+ fun getMessageCount(folderId: Long): Int
+
/**
* Update a folder's name and type.
*/
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
index 027ce8ed2f..a6ca1e13fb 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/K9MessageStore.kt
@@ -134,6 +134,10 @@ class K9MessageStore(
return retrieveFolderOperations.getFolderId(folderServerId)
}
+ override fun getMessageCount(folderId: Long): Int {
+ return retrieveFolderOperations.getMessageCount(folderId)
+ }
+
override fun getSize(): Long {
return databaseOperations.getSize()
}
diff --git a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
index c60bdaf348..08c5eaebf1 100644
--- a/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
+++ b/app/storage/src/main/java/com/fsck/k9/storage/messages/RetrieveFolderOperations.kt
@@ -130,6 +130,17 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa
}
}
}
+
+ fun getMessageCount(folderId: Long): Int {
+ return lockableDatabase.execute(false) { db ->
+ db.rawQuery(
+ "SELECT COUNT(id) FROM messages WHERE empty = 0 AND deleted = 0 AND folder_id = ?",
+ arrayOf(folderId.toString())
+ ).use { cursor ->
+ if (cursor.moveToFirst()) cursor.getInt(0) else 0
+ }
+ }
+ }
}
private class CursorFolderAccessor(val cursor: Cursor) : FolderDetailsAccessor {
diff --git a/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt b/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
index 7c4ac8f169..45b4739688 100644
--- a/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
+++ b/app/storage/src/test/java/com/fsck/k9/storage/messages/RetrieveFolderOperationsTest.kt
@@ -301,4 +301,31 @@ class RetrieveFolderOperationsTest : RobolectricTest() {
assertThat(result).isNull()
}
+
+ @Test
+ fun `get message count from empty folder`() {
+ val folderId = sqliteDatabase.createFolder()
+
+ val result = retrieveFolderOperations.getMessageCount(folderId)
+
+ assertThat(result).isEqualTo(0)
+ }
+
+ @Test
+ fun `get message count from non-existent folder`() {
+ val result = retrieveFolderOperations.getMessageCount(23)
+
+ assertThat(result).isEqualTo(0)
+ }
+
+ @Test
+ fun `get message count from non-empty folder`() {
+ val folderId = sqliteDatabase.createFolder()
+ sqliteDatabase.createMessage(folderId = folderId)
+ sqliteDatabase.createMessage(folderId = folderId)
+
+ val result = retrieveFolderOperations.getMessageCount(folderId)
+
+ assertThat(result).isEqualTo(2)
+ }
}
--
GitLab
From 140da14939d098dc0ec9a0fd3bdfe5e7619e83bc Mon Sep 17 00:00:00 2001
From: cketti