Merge branch 'main' into message-view-redesign

This commit is contained in:
cketti 2022-10-07 16:57:25 +02:00
commit 32f4b34e93
145 changed files with 1831 additions and 1245 deletions

View file

@ -21,6 +21,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.autodiscovery.providersxml'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.fsck.k9.autodiscovery.providersxml" />

View file

@ -43,6 +43,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.core'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.fsck.k9.core">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />

View file

@ -123,7 +123,7 @@ object K9 : EarlyInit {
val fontSizes = FontSizes()
@JvmStatic
var backgroundOps = BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC
var backgroundOps = BACKGROUND_OPS.ALWAYS
@JvmStatic
var isShowAnimations = true
@ -188,9 +188,6 @@ object K9 : EarlyInit {
@JvmStatic
var isUseVolumeKeysForNavigation = false
@JvmStatic
var isUseVolumeKeysForListNavigation = false
@JvmStatic
var isShowUnifiedInbox = true
@ -253,6 +250,12 @@ object K9 : EarlyInit {
@JvmStatic
var pgpSignOnlyDialogCounter: Int = 0
@JvmStatic
var swipeRightAction: SwipeAction = SwipeAction.ToggleSelection
@JvmStatic
var swipeLeftAction: SwipeAction = SwipeAction.ToggleRead
val isQuietTime: Boolean
get() {
if (!isQuietTimeEnabled) {
@ -298,7 +301,6 @@ object K9 : EarlyInit {
isSensitiveDebugLoggingEnabled = storage.getBoolean("enableSensitiveLogging", false)
isShowAnimations = storage.getBoolean("animations", true)
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)
@ -348,7 +350,7 @@ object K9 : EarlyInit {
isThreadedViewEnabled = storage.getBoolean("threadedView", true)
fontSizes.load(storage)
backgroundOps = storage.getEnum("backgroundOperations", BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC)
backgroundOps = storage.getEnum("backgroundOperations", BACKGROUND_OPS.ALWAYS)
isColorizeMissingContactPictures = storage.getBoolean("colorizeMissingContactPictures", true)
@ -362,6 +364,9 @@ object K9 : EarlyInit {
pgpSignOnlyDialogCounter = storage.getInt("pgpSignOnlyDialogCounter", 0)
k9Language = storage.getString("language", "")
swipeRightAction = storage.getEnum("swipeRightAction", SwipeAction.ToggleSelection)
swipeLeftAction = storage.getEnum("swipeLeftAction", SwipeAction.ToggleRead)
}
internal fun save(editor: StorageEditor) {
@ -370,7 +375,6 @@ object K9 : EarlyInit {
editor.putEnum("backgroundOperations", backgroundOps)
editor.putBoolean("animations", isShowAnimations)
editor.putBoolean("useVolumeKeysForNavigation", isUseVolumeKeysForNavigation)
editor.putBoolean("useVolumeKeysForListNavigation", isUseVolumeKeysForListNavigation)
editor.putBoolean("autofitWidth", isAutoFitWidth)
editor.putBoolean("quietTimeEnabled", isQuietTimeEnabled)
editor.putBoolean("notificationDuringQuietTimeEnabled", isNotificationDuringQuietTimeEnabled)
@ -422,6 +426,9 @@ object K9 : EarlyInit {
editor.putInt("pgpInlineDialogCounter", pgpInlineDialogCounter)
editor.putInt("pgpSignOnlyDialogCounter", pgpSignOnlyDialogCounter)
editor.putEnum("swipeRightAction", swipeRightAction)
editor.putEnum("swipeLeftAction", swipeLeftAction)
fontSizes.save(editor)
}

View file

@ -0,0 +1,12 @@
package com.fsck.k9
enum class SwipeAction {
None,
ToggleSelection,
ToggleRead,
ToggleStar,
Archive,
Delete,
Spam,
Move
}

View file

@ -58,6 +58,11 @@ class NotifierMessageStore(
notifyChange()
}
override fun setMoreMessages(folderId: Long, moreMessages: MoreMessages) {
messageStore.setMoreMessages(folderId, moreMessages)
notifyChange()
}
private fun notifyChange() {
localStore.notifyChange()
}

View file

@ -10,15 +10,16 @@ import java.util.Set;
import java.util.TreeMap;
import android.content.Context;
import android.graphics.Color;
import com.fsck.k9.Account;
import com.fsck.k9.Account.SortType;
import com.fsck.k9.DI;
import com.fsck.k9.FontSizes;
import com.fsck.k9.K9;
import com.fsck.k9.K9.BACKGROUND_OPS;
import com.fsck.k9.K9.NotificationQuickDelete;
import com.fsck.k9.K9.SplitViewMode;
import com.fsck.k9.SwipeAction;
import com.fsck.k9.core.R;
import com.fsck.k9.preferences.Settings.BooleanSetting;
import com.fsck.k9.preferences.Settings.ColorSetting;
@ -51,7 +52,8 @@ public class GeneralSettingsDescriptions {
new V(1, new BooleanSetting(false))
));
s.put("backgroundOperations", Settings.versions(
new V(1, new EnumSetting<>(K9.BACKGROUND_OPS.class, K9.BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC))
new V(1, new EnumSetting<>(K9.BACKGROUND_OPS.class, K9.BACKGROUND_OPS.WHEN_CHECKED_AUTO_SYNC)),
new V(83, new EnumSetting<>(K9.BACKGROUND_OPS.class, BACKGROUND_OPS.ALWAYS))
));
s.put("changeRegisteredNameColor", Settings.versions(
new V(1, new BooleanSetting(false))
@ -184,9 +186,6 @@ public class GeneralSettingsDescriptions {
new V(16, new LegacyThemeSetting(AppTheme.LIGHT)),
new V(24, new SubThemeSetting(SubTheme.USE_GLOBAL))
));
s.put("useVolumeKeysForListNavigation", Settings.versions(
new V(1, new BooleanSetting(false))
));
s.put("useVolumeKeysForNavigation", Settings.versions(
new V(1, new BooleanSetting(false))
));
@ -278,6 +277,12 @@ public class GeneralSettingsDescriptions {
s.put("showStarredCount", Settings.versions(
new V(75, new BooleanSetting(false))
));
s.put("swipeRightAction", Settings.versions(
new V(83, new EnumSetting<>(SwipeAction.class, SwipeAction.ToggleSelection))
));
s.put("swipeLeftAction", Settings.versions(
new V(83, new EnumSetting<>(SwipeAction.class, SwipeAction.ToggleRead))
));
SETTINGS = Collections.unmodifiableMap(s);

View file

@ -40,6 +40,9 @@ internal class RealGeneralSettingsManager(
}
override fun getSettingsFlow(): Flow<GeneralSettings> {
// Make sure to load settings now if they haven't been loaded already. This will also update settingsFlow.
getSettings()
return settingsFlow.distinctUntilChanged()
}

View file

@ -36,7 +36,7 @@ public class Settings {
*
* @see SettingsExporter
*/
public static final int VERSION = 81;
public static final int VERSION = 83;
static Map<String, Object> validate(int version, Map<String, TreeMap<Integer, SettingsDescription>> settings,
Map<String, String> importedSettings, boolean useDefaultValues) {

View file

@ -3,25 +3,31 @@
<!-- Must be kept in sync with arrays_drawer.xml/drawer_account_accent_color_dark_theme -->
<integer-array name="account_colors">
<item>0xFFFFB300</item> <!-- Amber 600 -->
<item>0xFFFB8C00</item> <!-- Orange 600 -->
<item>0xFFF4511E</item> <!-- Deep orange 600 -->
<item>0xFFE53935</item> <!-- Red 600 -->
<item>@color/material_amber_600</item>
<item>@color/material_orange_600</item>
<item>@color/material_deep_orange_600</item>
<item>@color/material_red_600</item>
<item>0xFFC0CA33</item> <!-- Lime 600 -->
<item>0xFF7CB342</item> <!-- Light green 600 -->
<item>0xFF388E3C</item> <!-- Green 700 -->
<item>0xFF00897B</item> <!-- Teal 600 -->
<item>@color/material_lime_600</item>
<item>@color/material_light_green_600</item>
<item>@color/material_green_700</item>
<item>@color/material_teal_600</item>
<item>0xFF00ACC1</item> <!-- Cyan 600 -->
<item>0xFF039BE5</item> <!-- Light blue 600 -->
<item>0xFF1976D2</item> <!-- Blue 700 -->
<item>0xFF3949AB</item> <!-- Indigo 600 -->
<item>@color/material_cyan_600</item>
<item>@color/material_light_blue_600</item>
<item>@color/material_blue_700</item>
<item>@color/material_indigo_600</item>
<item>0xFFE91E63</item> <!-- Pink 500 -->
<item>0xFF8E24AA</item> <!-- Purple 600 -->
<item>0xFF5E35B1</item> <!-- Deep purple 600 -->
<item>0xFF455A64</item> <!-- Blue gray 700 -->
<item>@color/material_pink_500</item>
<item>@color/material_purple_600</item>
<item>@color/material_deep_purple_600</item>
<item>@color/material_blue_gray_700</item>
</integer-array>
<integer-array name="default_account_colors">
<item>@color/material_blue_700</item>
<item>@color/material_pink_500</item>
<item>@color/material_amber_600</item>
</integer-array>
<string-array name="check_frequency_values" translatable="false">

View file

@ -3,25 +3,25 @@
<!-- Must be kept in sync with arrays_account_settings_values.xml/account_colors -->
<integer-array name="drawer_account_accent_color_dark_theme">
<item>0xFFFFB300</item> <!-- Amber 600 -->
<item>0xFFFF9800</item> <!-- Orange 500 -->
<item>0xFFFF7043</item> <!-- Deep orange 400 -->
<item>0xFFEF5350</item> <!-- Red 400 -->
<item>@color/material_amber_600</item>
<item>@color/material_orange_500</item>
<item>@color/material_deep_orange_400</item>
<item>@color/material_red_400</item>
<item>0xFFC0CA33</item> <!-- Lime 600 -->
<item>0xFF7CB342</item> <!-- Light green 600 -->
<item>0xFF4CAF50</item> <!-- Green 500 -->
<item>0xFF4DB6AC</item> <!-- Teal 300 -->
<item>@color/material_lime_600</item>
<item>@color/material_light_green_600</item>
<item>@color/material_green_500</item>
<item>@color/material_teal_300</item>
<item>0xFF00ACC1</item> <!-- Cyan 600 -->
<item>0xFF03A9F4</item> <!-- Light blue 500 -->
<item>0xFF42A5F5</item> <!-- Blue 400 -->
<item>0xFF9FA8DA</item> <!-- Indigo 200 -->
<item>@color/material_cyan_600</item>
<item>@color/material_light_blue_500</item>
<item>@color/material_blue_400</item>
<item>@color/material_indigo_200</item>
<item>0xFFF48FB1</item> <!-- Pink 200 -->
<item>0xFFCE93D8</item> <!-- Purple 200 -->
<item>0xFFB39DDB</item> <!-- Deep purple 200 -->
<item>0xFF90A4AE</item> <!-- Blue gray 300 -->
<item>@color/material_pink_200</item>
<item>@color/material_purple_200</item>
<item>@color/material_deep_purple_200</item>
<item>@color/material_blue_gray_300</item>
</integer-array>
</resources>

View file

@ -210,9 +210,15 @@
<item>spam</item>
</string-array>
<string-array name="volume_navigation_values" translatable="false">
<item>message</item>
<item>list</item>
<string-array name="swipe_action_values" translatable="false">
<item>none</item>
<item>toggle_selection</item>
<item>toggle_read</item>
<item>toggle_star</item>
<item>archive</item>
<item>delete</item>
<item>spam</item>
<item>move</item>
</string-array>
</resources>

View file

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="material_red_50">#FFEBEE</color>
<color name="material_red_100">#FFCDD2</color>
<color name="material_red_200">#EF9A9A</color>
<color name="material_red_300">#E57373</color>
<color name="material_red_400">#EF5350</color>
<color name="material_red_500">#F44336</color>
<color name="material_red_600">#E53935</color>
<color name="material_red_700">#D32F2F</color>
<color name="material_red_800">#C62828</color>
<color name="material_red_900">#B71C1C</color>
<color name="material_deep_purple_50">#EDE7F6</color>
<color name="material_deep_purple_100">#D1C4E9</color>
<color name="material_deep_purple_200">#B39DDB</color>
<color name="material_deep_purple_300">#9575CD</color>
<color name="material_deep_purple_400">#7E57C2</color>
<color name="material_deep_purple_500">#673AB7</color>
<color name="material_deep_purple_600">#5E35B1</color>
<color name="material_deep_purple_700">#512DA8</color>
<color name="material_deep_purple_800">#4527A0</color>
<color name="material_deep_purple_900">#311B92</color>
<color name="material_light_blue_50">#E1F5FE</color>
<color name="material_light_blue_100">#B3E5FC</color>
<color name="material_light_blue_200">#81D4FA</color>
<color name="material_light_blue_300">#4FC3F7</color>
<color name="material_light_blue_400">#29B6F6</color>
<color name="material_light_blue_500">#03A9F4</color>
<color name="material_light_blue_600">#039BE5</color>
<color name="material_light_blue_700">#0288D1</color>
<color name="material_light_blue_800">#0277BD</color>
<color name="material_light_blue_900">#01579B</color>
<color name="material_green_50">#E8F5E9</color>
<color name="material_green_100">#C8E6C9</color>
<color name="material_green_200">#A5D6A7</color>
<color name="material_green_300">#81C784</color>
<color name="material_green_400">#66BB6A</color>
<color name="material_green_500">#4CAF50</color>
<color name="material_green_600">#43A047</color>
<color name="material_green_700">#388E3C</color>
<color name="material_green_800">#2E7D32</color>
<color name="material_green_900">#1B5E20</color>
<color name="material_yellow_50">#FFFDE7</color>
<color name="material_yellow_100">#FFF9C4</color>
<color name="material_yellow_200">#FFF59D</color>
<color name="material_yellow_300">#FFF176</color>
<color name="material_yellow_400">#FFEE58</color>
<color name="material_yellow_500">#FFEB3B</color>
<color name="material_yellow_600">#FDD835</color>
<color name="material_yellow_700">#FBC02D</color>
<color name="material_yellow_800">#F9A825</color>
<color name="material_yellow_900">#F57F17</color>
<color name="material_deep_orange_50">#FBE9E7</color>
<color name="material_deep_orange_100">#FFCCBC</color>
<color name="material_deep_orange_200">#FFAB91</color>
<color name="material_deep_orange_300">#FF8A65</color>
<color name="material_deep_orange_400">#FF7043</color>
<color name="material_deep_orange_500">#FF5722</color>
<color name="material_deep_orange_600">#F4511E</color>
<color name="material_deep_orange_700">#E64A19</color>
<color name="material_deep_orange_800">#D84315</color>
<color name="material_deep_orange_900">#BF360C</color>
<color name="material_blue_gray_50">#ECEFF1</color>
<color name="material_blue_gray_100">#CFD8DC</color>
<color name="material_blue_gray_200">#B0BEC5</color>
<color name="material_blue_gray_300">#90A4AE</color>
<color name="material_blue_gray_400">#78909C</color>
<color name="material_blue_gray_500">#607D8B</color>
<color name="material_blue_gray_600">#546E7A</color>
<color name="material_blue_gray_700">#455A64</color>
<color name="material_blue_gray_800">#37474F</color>
<color name="material_blue_gray_900">#263238</color>
<color name="material_pink_50">#FCE4EC</color>
<color name="material_pink_100">#F8BBD0</color>
<color name="material_pink_200">#F48FB1</color>
<color name="material_pink_300">#F06292</color>
<color name="material_pink_400">#EC407A</color>
<color name="material_pink_500">#E91E63</color>
<color name="material_pink_600">#D81B60</color>
<color name="material_pink_700">#C2185B</color>
<color name="material_pink_800">#AD1457</color>
<color name="material_pink_900">#880E4F</color>
<color name="material_indigo_50">#E8EAF6</color>
<color name="material_indigo_100">#C5CAE9</color>
<color name="material_indigo_200">#9FA8DA</color>
<color name="material_indigo_300">#7986CB</color>
<color name="material_indigo_400">#5C6BC0</color>
<color name="material_indigo_500">#3F51B5</color>
<color name="material_indigo_600">#3949AB</color>
<color name="material_indigo_700">#303F9F</color>
<color name="material_indigo_800">#283593</color>
<color name="material_indigo_900">#1A237E</color>
<color name="material_cyan_50">#E0F7FA</color>
<color name="material_cyan_100">#B2EBF2</color>
<color name="material_cyan_200">#80DEEA</color>
<color name="material_cyan_300">#4DD0E1</color>
<color name="material_cyan_400">#26C6DA</color>
<color name="material_cyan_500">#00BCD4</color>
<color name="material_cyan_600">#00ACC1</color>
<color name="material_cyan_700">#0097A7</color>
<color name="material_cyan_800">#00838F</color>
<color name="material_cyan_900">#006064</color>
<color name="material_light_green_50">#F1F8E9</color>
<color name="material_light_green_100">#DCEDC8</color>
<color name="material_light_green_200">#C5E1A5</color>
<color name="material_light_green_300">#AED581</color>
<color name="material_light_green_400">#9CCC65</color>
<color name="material_light_green_500">#8BC34A</color>
<color name="material_light_green_600">#7CB342</color>
<color name="material_light_green_700">#689F38</color>
<color name="material_light_green_800">#558B2F</color>
<color name="material_light_green_900">#33691E</color>
<color name="material_amber_50">#FFF8E1</color>
<color name="material_amber_100">#FFECB3</color>
<color name="material_amber_200">#FFE082</color>
<color name="material_amber_300">#FFD54F</color>
<color name="material_amber_400">#FFCA28</color>
<color name="material_amber_500">#FFC107</color>
<color name="material_amber_600">#FFB300</color>
<color name="material_amber_700">#FFA000</color>
<color name="material_amber_800">#FF8F00</color>
<color name="material_amber_900">#FF6F00</color>
<color name="material_brown_50">#EFEBE9</color>
<color name="material_brown_100">#D7CCC8</color>
<color name="material_brown_200">#BCAAA4</color>
<color name="material_brown_300">#A1887F</color>
<color name="material_brown_400">#8D6E63</color>
<color name="material_brown_500">#795548</color>
<color name="material_brown_600">#6D4C41</color>
<color name="material_brown_700">#5D4037</color>
<color name="material_brown_800">#4E342E</color>
<color name="material_brown_900">#3E2723</color>
<color name="material_purple_50">#F3E5F5</color>
<color name="material_purple_100">#E1BEE7</color>
<color name="material_purple_200">#CE93D8</color>
<color name="material_purple_300">#BA68C8</color>
<color name="material_purple_400">#AB47BC</color>
<color name="material_purple_500">#9C27B0</color>
<color name="material_purple_600">#8E24AA</color>
<color name="material_purple_700">#7B1FA2</color>
<color name="material_purple_800">#6A1B9A</color>
<color name="material_purple_900">#4A148C</color>
<color name="material_blue_50">#E3F2FD</color>
<color name="material_blue_100">#BBDEFB</color>
<color name="material_blue_200">#90CAF9</color>
<color name="material_blue_300">#64B5F6</color>
<color name="material_blue_400">#42A5F5</color>
<color name="material_blue_500">#2196F3</color>
<color name="material_blue_600">#1E88E5</color>
<color name="material_blue_700">#1976D2</color>
<color name="material_blue_800">#1565C0</color>
<color name="material_blue_900">#0D47A1</color>
<color name="material_teal_50">#E0F2F1</color>
<color name="material_teal_100">#B2DFDB</color>
<color name="material_teal_200">#80CBC4</color>
<color name="material_teal_300">#4DB6AC</color>
<color name="material_teal_400">#26A69A</color>
<color name="material_teal_500">#009688</color>
<color name="material_teal_600">#00897B</color>
<color name="material_teal_700">#00796B</color>
<color name="material_teal_800">#00695C</color>
<color name="material_teal_900">#004D40</color>
<color name="material_lime_50">#F9FBE7</color>
<color name="material_lime_100">#F0F4C3</color>
<color name="material_lime_200">#E6EE9C</color>
<color name="material_lime_300">#DCE775</color>
<color name="material_lime_400">#D4E157</color>
<color name="material_lime_500">#CDDC39</color>
<color name="material_lime_600">#C0CA33</color>
<color name="material_lime_700">#AFB42B</color>
<color name="material_lime_800">#9E9D24</color>
<color name="material_lime_900">#827717</color>
<color name="material_orange_50">#FFF3E0</color>
<color name="material_orange_100">#FFE0B2</color>
<color name="material_orange_200">#FFCC80</color>
<color name="material_orange_300">#FFB74D</color>
<color name="material_orange_400">#FFA726</color>
<color name="material_orange_500">#FF9800</color>
<color name="material_orange_600">#FB8C00</color>
<color name="material_orange_700">#F57C00</color>
<color name="material_orange_800">#EF6C00</color>
<color name="material_orange_900">#E65100</color>
<color name="material_gray_50">#FAFAFA</color>
<color name="material_gray_100">#F5F5F5</color>
<color name="material_gray_200">#EEEEEE</color>
<color name="material_gray_300">#E0E0E0</color>
<color name="material_gray_400">#BDBDBD</color>
<color name="material_gray_500">#9E9E9E</color>
<color name="material_gray_600">#757575</color>
<color name="material_gray_700">#616161</color>
<color name="material_gray_800">#424242</color>
<color name="material_gray_900">#212121</color>
</resources>

View file

@ -9,6 +9,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.crypto.openpgp'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.fsck.k9.crypto.openpgp" />

View file

@ -41,6 +41,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools
@ -48,8 +50,8 @@ android {
applicationId "com.fsck.k9"
testApplicationId "com.fsck.k9.tests"
versionCode 33005
versionName '6.306-SNAPSHOT'
versionCode 33008
versionName '6.309-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",

View file

@ -2,8 +2,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto"
package="com.fsck.k9">
android:installLocation="auto">
<uses-feature
android:name="android.hardware.touchscreen"

View file

@ -1,5 +1,6 @@
package com.fsck.k9.external;
import java.util.Date;
import android.content.Context;
@ -7,13 +8,13 @@ import android.text.SpannableStringBuilder;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.R;
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.RecipientType;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.ui.R;
class MessageInfoHolder {
public Date compareDate;

View file

@ -1,7 +1,7 @@
package com.fsck.k9.notification
import android.content.Context
import com.fsck.k9.R
import com.fsck.k9.ui.R
class K9NotificationResourceProvider(private val context: Context) : NotificationResourceProvider {
override val iconWarning: Int = R.drawable.notification_icon_warning

View file

@ -1,8 +1,8 @@
package com.fsck.k9.resources
import android.content.Context
import com.fsck.k9.R
import com.fsck.k9.autocrypt.AutocryptStringProvider
import com.fsck.k9.ui.R
class K9AutocryptStringProvider(private val context: Context) : AutocryptStringProvider {
override fun transferMessageSubject(): String = context.getString(R.string.ac_transfer_msg_subject)

View file

@ -2,8 +2,8 @@ package com.fsck.k9.resources
import android.content.Context
import com.fsck.k9.CoreResourceProvider
import com.fsck.k9.R
import com.fsck.k9.notification.PushNotificationState
import com.fsck.k9.ui.R
class K9CoreResourceProvider(private val context: Context) : CoreResourceProvider {
override fun defaultSignature(): String = context.getString(R.string.default_signature)

View file

@ -147,7 +147,7 @@ public class MessageListRemoteViewFactory implements RemoteViewsService.RemoteVi
@Override
public RemoteViews getLoadingView() {
RemoteViews loadingView = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_loading);
loadingView.setTextViewText(R.id.loadingText, context.getString(R.string.mail_list_widget_loading));
loadingView.setTextViewText(R.id.loadingText, context.getString(com.fsck.k9.ui.R.string.mail_list_widget_loading));
loadingView.setViewVisibility(R.id.loadingText, View.VISIBLE);
return loadingView;
}

View file

@ -46,7 +46,7 @@ public class MessageListWidgetProvider extends AppWidgetProvider {
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.message_list_widget_layout);
views.setTextViewText(R.id.folder, context.getString(R.string.integrated_inbox_title));
views.setTextViewText(R.id.folder, context.getString(com.fsck.k9.ui.R.string.integrated_inbox_title));
Intent intent = new Intent(context, MessageListWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

View file

@ -6,6 +6,7 @@ import com.fsck.k9.R
import com.fsck.k9.ui.base.K9Activity
import com.fsck.k9.ui.fragmentTransaction
import timber.log.Timber
import com.fsck.k9.ui.R as UiR
/**
* Activity to select an account for the unread widget.
@ -15,7 +16,7 @@ class UnreadWidgetConfigurationActivity : K9Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setLayout(R.layout.activity_unread_widget_configuration)
setTitle(R.string.unread_widget_select_account)
setTitle(UiR.string.unread_widget_select_account)
var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
val extras = intent.extras

View file

@ -18,6 +18,7 @@ import com.fsck.k9.search.SearchAccount
import com.fsck.k9.ui.choosefolder.ChooseFolderActivity
import com.takisoft.preferencex.PreferenceFragmentCompat
import org.koin.android.ext.android.inject
import com.fsck.k9.ui.R as UiR
class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() {
private val preferences: Preferences by inject()
@ -48,7 +49,7 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() {
unreadFolderEnabled = findPreference(PREFERENCE_UNREAD_FOLDER_ENABLED)!!
unreadFolderEnabled.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ ->
unreadFolder.summary = getString(R.string.unread_widget_folder_summary)
unreadFolder.summary = getString(UiR.string.unread_widget_folder_summary)
selectedFolderId = null
selectedFolderDisplayName = null
true
@ -116,7 +117,7 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() {
selectedAccountUuid = accountUuid
selectedFolderId = null
selectedFolderDisplayName = null
unreadFolder.summary = getString(R.string.unread_widget_folder_summary)
unreadFolder.summary = getString(UiR.string.unread_widget_folder_summary)
if (SearchAccount.UNIFIED_INBOX == selectedAccountUuid) {
handleSearchAccount()
} else {
@ -126,7 +127,7 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() {
private fun handleSearchAccount() {
if (SearchAccount.UNIFIED_INBOX == selectedAccountUuid) {
unreadAccount.setSummary(R.string.unread_widget_unified_inbox_account_summary)
unreadAccount.setSummary(UiR.string.unread_widget_unified_inbox_account_summary)
}
unreadFolderEnabled.isEnabled = false
unreadFolderEnabled.isChecked = false
@ -168,10 +169,10 @@ class UnreadWidgetConfigurationFragment : PreferenceFragmentCompat() {
private fun validateWidget(): Boolean {
if (selectedAccountUuid == null) {
Toast.makeText(requireContext(), R.string.unread_widget_account_not_selected, Toast.LENGTH_LONG).show()
Toast.makeText(requireContext(), UiR.string.unread_widget_account_not_selected, Toast.LENGTH_LONG).show()
return false
} else if (unreadFolderEnabled.isChecked && selectedFolderId == null) {
Toast.makeText(requireContext(), R.string.unread_widget_folder_not_selected, Toast.LENGTH_LONG).show()
Toast.makeText(requireContext(), UiR.string.unread_widget_folder_not_selected, Toast.LENGTH_LONG).show()
return false
}
return true

View file

@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent
import com.fsck.k9.Account
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.FolderRepository
@ -13,6 +12,7 @@ import com.fsck.k9.search.SearchAccount
import com.fsck.k9.ui.folders.FolderNameFormatterFactory
import com.fsck.k9.ui.messagelist.DefaultFolderProvider
import timber.log.Timber
import com.fsck.k9.ui.R as UiR
class UnreadWidgetDataProvider(
private val context: Context,
@ -68,7 +68,7 @@ class UnreadWidgetDataProvider(
val accountName = account.displayName
val folderDisplayName = getFolderDisplayName(account, folderId)
val title = context.getString(R.string.unread_widget_title, accountName, folderDisplayName)
val title = context.getString(UiR.string.unread_widget_title, accountName, folderDisplayName)
val unreadCount = messagingController.getFolderUnreadMessageCount(account, folderId)

View file

@ -4,7 +4,7 @@
android:initialLayout="@layout/message_list_widget_layout"
android:minHeight="180dp"
android:minWidth="250dp"
android:minResizeWidth="180dp"
android:minResizeWidth="110dp"
android:minResizeHeight="110dp"
android:previewImage="@drawable/message_list_widget_preview"
android:resizeMode="horizontal|vertical"

View file

@ -24,6 +24,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.storage'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.fsck.k9.storage" />

View file

@ -70,30 +70,30 @@ internal class CopyMessageOperations(
private fun copyMessageParts(database: SQLiteDatabase, messageId: Long): Long {
return database.rawQuery(
"""
SELECT
message_parts.id,
message_parts.type,
message_parts.root,
message_parts.parent,
message_parts.seq,
message_parts.mime_type,
message_parts.decoded_body_size,
message_parts.display_name,
message_parts.header,
message_parts.encoding,
message_parts.charset,
message_parts.data_location,
message_parts.data,
message_parts.preamble,
message_parts.epilogue,
message_parts.boundary,
message_parts.content_id,
message_parts.server_extra
FROM messages
JOIN message_parts ON (message_parts.root = messages.message_part_id)
WHERE messages.id = ?
ORDER BY message_parts.seq
""".trimIndent(),
SELECT
message_parts.id,
message_parts.type,
message_parts.root,
message_parts.parent,
message_parts.seq,
message_parts.mime_type,
message_parts.decoded_body_size,
message_parts.display_name,
message_parts.header,
message_parts.encoding,
message_parts.charset,
message_parts.data_location,
message_parts.data,
message_parts.preamble,
message_parts.epilogue,
message_parts.boundary,
message_parts.content_id,
message_parts.server_extra
FROM messages
JOIN message_parts ON (message_parts.root = messages.message_part_id)
WHERE messages.id = ?
ORDER BY message_parts.seq
""",
arrayOf(messageId.toString())
).use { cursor ->
if (!cursor.moveToNext()) error("No message part found for message with ID $messageId")
@ -201,10 +201,8 @@ internal class CopyMessageOperations(
private fun copyFulltextEntry(database: SQLiteDatabase, newMessageId: Long, messageId: Long) {
database.execSQL(
"""
INSERT OR REPLACE INTO messages_fulltext (docid, fulltext)
SELECT ?, fulltext FROM messages_fulltext WHERE docid = ?
""".trimIndent(),
"INSERT OR REPLACE INTO messages_fulltext (docid, fulltext) " +
"SELECT ?, fulltext FROM messages_fulltext WHERE docid = ?",
arrayOf(newMessageId.toString(), messageId.toString())
)
}

View file

@ -19,16 +19,16 @@ internal class DeleteFolderOperations(
private fun SQLiteDatabase.deleteMessagePartFiles(folderServerId: String) {
rawQuery(
"""
SELECT message_parts.id
FROM folders
JOIN messages ON (messages.folder_id = folders.id)
JOIN message_parts ON (
message_parts.root = messages.message_part_id
AND
message_parts.data_location = $DATA_LOCATION_ON_DISK
)
WHERE folders.server_id = ?
""".trimIndent(),
SELECT message_parts.id
FROM folders
JOIN messages ON (messages.folder_id = folders.id)
JOIN message_parts ON (
message_parts.root = messages.message_part_id
AND
message_parts.data_location = $DATA_LOCATION_ON_DISK
)
WHERE folders.server_id = ?
""",
arrayOf(folderServerId)
).use { cursor ->
while (cursor.moveToNext()) {

View file

@ -38,12 +38,12 @@ internal class DeleteMessageOperations(
return lockableDatabase.execute(false) { database ->
database.rawQuery(
"""
SELECT messages.id, messages.message_part_id, COUNT(threads2.id)
FROM messages
LEFT JOIN threads threads1 ON (threads1.message_id = messages.id)
LEFT JOIN threads threads2 ON (threads2.parent = threads1.id)
WHERE folder_id = ? AND uid = ?
""".trimIndent(),
SELECT messages.id, messages.message_part_id, COUNT(threads2.id)
FROM messages
LEFT JOIN threads threads1 ON (threads1.message_id = messages.id)
LEFT JOIN threads threads2 ON (threads2.parent = threads1.id)
WHERE folder_id = ? AND uid = ?
""",
arrayOf(folderId.toString(), messageServerId)
).use { cursor ->
if (cursor.moveToFirst()) {
@ -128,12 +128,12 @@ internal class DeleteMessageOperations(
private fun SQLiteDatabase.getEmptyThreadParent(messageId: Long): Long? {
return rawQuery(
"""
SELECT messages.id
FROM threads threads1
JOIN threads threads2 ON (threads1.parent = threads2.id)
JOIN messages ON (threads2.message_id = messages.id AND messages.empty = 1)
WHERE threads1.message_id = ?
""".trimIndent(),
SELECT messages.id
FROM threads threads1
JOIN threads threads2 ON (threads1.parent = threads2.id)
JOIN messages ON (threads2.message_id = messages.id AND messages.empty = 1)
WHERE threads1.message_id = ?
""",
arrayOf(messageId.toString())
).use { cursor ->
if (cursor.moveToFirst() && !cursor.isNull(0)) {
@ -151,11 +151,11 @@ internal class DeleteMessageOperations(
private fun SQLiteDatabase.hasThreadChildren(messageId: Long): Boolean {
return rawQuery(
"""
SELECT COUNT(threads2.id)
FROM threads threads1
JOIN threads threads2 ON (threads2.parent = threads1.id)
WHERE threads1.message_id = ?
""".trimIndent(),
SELECT COUNT(threads2.id)
FROM threads threads1
JOIN threads threads2 ON (threads2.parent = threads1.id)
WHERE threads1.message_id = ?
""",
arrayOf(messageId.toString())
).use { cursor ->
cursor.moveToFirst() && !cursor.isNull(0) && cursor.getLong(0) > 0L

View file

@ -70,22 +70,22 @@ internal class RetrieveFolderOperations(private val lockableDatabase: LockableDa
val query =
"""
SELECT ${FOLDER_COLUMNS.joinToString()}, (
SELECT COUNT(messages.id)
FROM messages
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
""".trimIndent()
SELECT ${FOLDER_COLUMNS.joinToString()}, (
SELECT COUNT(messages.id)
FROM messages
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
"""
db.rawQuery(query, arrayOf(outboxFolderIdOrZero.toString())).use { cursor ->
val cursorFolderAccessor = CursorFolderAccessor(cursor)

View file

@ -20,32 +20,32 @@ internal class RetrieveMessageListOperations(private val lockableDatabase: Locka
return lockableDatabase.execute(false) { database ->
database.rawQuery(
"""
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
date,
internal_date,
subject,
preview_type,
preview,
read,
flagged,
answered,
forwarded,
attachment_count,
root
FROM messages
JOIN threads ON (threads.message_id = messages.id)
LEFT JOIN FOLDERS ON (folders.id = messages.folder_id)
WHERE
($selection)
AND empty = 0 AND deleted = 0
ORDER BY $sortOrder
""".trimIndent(),
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
date,
internal_date,
subject,
preview_type,
preview,
read,
flagged,
answered,
forwarded,
attachment_count,
root
FROM messages
JOIN threads ON (threads.message_id = messages.id)
LEFT JOIN FOLDERS ON (folders.id = messages.folder_id)
WHERE
($selection)
AND empty = 0 AND deleted = 0
ORDER BY $sortOrder
""",
selectionArgs,
).use { cursor ->
val cursorMessageAccessor = CursorMessageAccessor(cursor, includesThreadCount = false)
@ -72,60 +72,60 @@ internal class RetrieveMessageListOperations(private val lockableDatabase: Locka
return lockableDatabase.execute(false) { database ->
database.rawQuery(
"""
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
aggregated.date AS date,
aggregated.internal_date AS internal_date,
subject,
preview_type,
preview,
aggregated.read AS read,
aggregated.flagged AS flagged,
aggregated.answered AS answered,
aggregated.forwarded AS forwarded,
aggregated.attachment_count AS attachment_count,
root,
aggregated.thread_count AS thread_count
FROM (
SELECT
threads.root AS thread_root,
MAX(date) AS date,
MAX(internal_date) AS internal_date,
MIN(read) AS read,
MAX(flagged) AS flagged,
MIN(answered) AS answered,
MIN(forwarded) AS forwarded,
SUM(attachment_count) AS attachment_count,
COUNT(threads.root) AS thread_count
FROM messages
JOIN threads ON (threads.message_id = messages.id)
JOIN folders ON (folders.id = messages.folder_id)
WHERE
threads.root IN (
SELECT threads.root
FROM messages
JOIN threads ON (threads.message_id = messages.id)
WHERE messages.empty = 0 AND messages.deleted = 0
)
AND ($selection)
AND messages.empty = 0 AND messages.deleted = 0
GROUP BY threads.root
) aggregated
JOIN threads ON (threads.root = aggregated.thread_root)
JOIN messages ON (
messages.id = threads.message_id
AND messages.empty = 0 AND messages.deleted = 0
AND messages.date = aggregated.date
)
JOIN folders ON (folders.id = messages.folder_id)
GROUP BY threads.root
ORDER BY $orderBy
""".trimIndent(),
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
aggregated.date AS date,
aggregated.internal_date AS internal_date,
subject,
preview_type,
preview,
aggregated.read AS read,
aggregated.flagged AS flagged,
aggregated.answered AS answered,
aggregated.forwarded AS forwarded,
aggregated.attachment_count AS attachment_count,
root,
aggregated.thread_count AS thread_count
FROM (
SELECT
threads.root AS thread_root,
MAX(date) AS date,
MAX(internal_date) AS internal_date,
MIN(read) AS read,
MAX(flagged) AS flagged,
MIN(answered) AS answered,
MIN(forwarded) AS forwarded,
SUM(attachment_count) AS attachment_count,
COUNT(threads.root) AS thread_count
FROM messages
JOIN threads ON (threads.message_id = messages.id)
JOIN folders ON (folders.id = messages.folder_id)
WHERE
threads.root IN (
SELECT threads.root
FROM messages
JOIN threads ON (threads.message_id = messages.id)
WHERE messages.empty = 0 AND messages.deleted = 0
)
AND ($selection)
AND messages.empty = 0 AND messages.deleted = 0
GROUP BY threads.root
) aggregated
JOIN threads ON (threads.root = aggregated.thread_root)
JOIN messages ON (
messages.id = threads.message_id
AND messages.empty = 0 AND messages.deleted = 0
AND messages.date = aggregated.date
)
JOIN folders ON (folders.id = messages.folder_id)
GROUP BY threads.root
ORDER BY $orderBy
""",
selectionArgs,
).use { cursor ->
val cursorMessageAccessor = CursorMessageAccessor(cursor, includesThreadCount = true)
@ -145,32 +145,32 @@ internal class RetrieveMessageListOperations(private val lockableDatabase: Locka
return lockableDatabase.execute(false) { database ->
database.rawQuery(
"""
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
date,
internal_date,
subject,
preview_type,
preview,
read,
flagged,
answered,
forwarded,
attachment_count,
root
FROM threads
JOIN messages ON (messages.id = threads.message_id)
LEFT JOIN FOLDERS ON (folders.id = messages.folder_id)
WHERE
root = ?
AND empty = 0 AND deleted = 0
ORDER BY $sortOrder
""".trimIndent(),
SELECT
messages.id AS id,
uid,
folder_id,
sender_list,
to_list,
cc_list,
date,
internal_date,
subject,
preview_type,
preview,
read,
flagged,
answered,
forwarded,
attachment_count,
root
FROM threads
JOIN messages ON (messages.id = threads.message_id)
LEFT JOIN FOLDERS ON (folders.id = messages.folder_id)
WHERE
root = ?
AND empty = 0 AND deleted = 0
ORDER BY $sortOrder
""",
arrayOf(threadId.toString()),
).use { cursor ->
val cursorMessageAccessor = CursorMessageAccessor(cursor, includesThreadCount = false)

View file

@ -20,11 +20,11 @@ internal class ThreadMessageOperations {
fun getMessageThreadHeaders(database: SQLiteDatabase, messageId: Long): ThreadHeaders {
return database.rawQuery(
"""
SELECT messages.message_id, message_parts.header
FROM messages
LEFT JOIN message_parts ON (messages.message_part_id = message_parts.id)
WHERE messages.id = ?
""".trimIndent(),
SELECT messages.message_id, message_parts.header
FROM messages
LEFT JOIN message_parts ON (messages.message_part_id = message_parts.id)
WHERE messages.id = ?
""",
arrayOf(messageId.toString()),
).use { cursor ->
if (!cursor.moveToFirst()) error("Message not found: $messageId")
@ -157,14 +157,14 @@ internal class ThreadMessageOperations {
return db.rawQuery(
"""
SELECT t.id, t.message_id, t.root, t.parent
FROM messages m
LEFT JOIN threads t ON (t.message_id = m.id)
WHERE m.folder_id = ? AND m.message_id = ?
${if (onlyEmpty) "AND m.empty = 1 " else ""}
ORDER BY m.id
LIMIT 1
""".trimIndent(),
SELECT t.id, t.message_id, t.root, t.parent
FROM messages m
LEFT JOIN threads t ON (t.message_id = m.id)
WHERE m.folder_id = ? AND m.message_id = ?
${if (onlyEmpty) "AND m.empty = 1 " else ""}
ORDER BY m.id
LIMIT 1
""",
arrayOf(folderId.toString(), messageIdHeader)
).use { cursor ->
if (cursor.moveToFirst()) {

View file

@ -12,6 +12,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.testing'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.fsck.k9.testing" />

View file

@ -18,6 +18,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.ui.base'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fsck.k9.ui.base">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>

View file

@ -64,7 +64,7 @@ class ThemeManager(
.onEach {
updateAppTheme(it)
}
.launchIn(appCoroutineScope + Dispatchers.Main)
.launchIn(appCoroutineScope + Dispatchers.Main.immediate)
}
private fun updateAppTheme(appTheme: AppTheme) {

View file

@ -33,9 +33,7 @@ dependencies {
implementation "com.splitwise:tokenautocomplete:4.0.0-beta01"
implementation "de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0"
implementation 'com.mikepenz:materialdrawer:8.4.5'
implementation 'com.mikepenz:materialdrawer-iconics:8.4.5'
implementation 'com.mikepenz:fontawesome-typeface:5.9.0.0-kotlin@aar'
implementation 'com.github.ByteHamster:SearchPreference:v2.2.1'
implementation 'com.github.ByteHamster:SearchPreference:v2.3.0'
implementation "com.mikepenz:fastadapter:${versions.fastAdapter}"
implementation "com.mikepenz:fastadapter-extensions-drag:${versions.fastAdapter}"
implementation "com.mikepenz:fastadapter-extensions-utils:${versions.fastAdapter}"
@ -70,6 +68,8 @@ dependencies {
}
android {
namespace 'com.fsck.k9.ui'
compileSdkVersion buildConfig.compileSdk
buildToolsVersion buildConfig.buildTools

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fsck.k9.ui">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.VIBRATE" />

View file

@ -4,7 +4,6 @@ import com.fsck.k9.account.accountModule
import com.fsck.k9.activity.activityModule
import com.fsck.k9.autodiscovery.providersxml.autodiscoveryProvidersXmlModule
import com.fsck.k9.contacts.contactsModule
import com.fsck.k9.fragment.fragmentModule
import com.fsck.k9.ui.account.accountUiModule
import com.fsck.k9.ui.base.uiBaseModule
import com.fsck.k9.ui.changelog.changelogUiModule
@ -28,7 +27,6 @@ val uiModules = listOf(
messageListUiModule,
manageFoldersUiModule,
chooseFolderUiModule,
fragmentModule,
contactsModule,
accountModule,
autodiscoveryProvidersXmlModule,

View file

@ -3,10 +3,9 @@ package com.fsck.k9.account
import android.content.res.Resources
import com.fsck.k9.Account.DeletePolicy
import com.fsck.k9.Preferences
import com.fsck.k9.core.R
import com.fsck.k9.mail.ConnectionSecurity
import com.fsck.k9.preferences.Protocols
import com.fsck.k9.ui.R
import com.fsck.k9.ui.helper.MaterialColors
/**
* Deals with logic surrounding account creation.
@ -53,7 +52,7 @@ class AccountCreator(private val preferences: Preferences, private val resources
fun pickColor(): Int {
val accounts = preferences.accounts
val usedAccountColors = accounts.map { it.chipColor }
val usedAccountColors = accounts.map { it.chipColor }.toSet()
val accountColors = resources.getIntArray(R.array.account_colors).toList()
val availableColors = accountColors - usedAccountColors
@ -61,17 +60,10 @@ class AccountCreator(private val preferences: Preferences, private val resources
return accountColors.random()
}
val defaultAccountColors = resources.getIntArray(R.array.default_account_colors)
return availableColors.shuffled().minByOrNull { color ->
val index = DEFAULT_COLORS.indexOf(color)
if (index != -1) index else DEFAULT_COLORS.size
val index = defaultAccountColors.indexOf(color)
if (index != -1) index else defaultAccountColors.size
} ?: error("availableColors must not be empty")
}
companion object {
private val DEFAULT_COLORS = intArrayOf(
MaterialColors.BLUE_700,
MaterialColors.PINK_500,
MaterialColors.AMBER_600
)
}
}

View file

@ -1,13 +1,10 @@
package com.fsck.k9.activity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.fsck.k9.K9;
import com.fsck.k9.ui.base.K9Activity;
@ -15,45 +12,6 @@ public abstract class K9ListActivity extends K9Activity {
protected ListAdapter adapter;
protected ListView list;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Shortcuts that work no matter what is selected
if (K9.isUseVolumeKeysForListNavigation() &&
(keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
final ListView listView = getListView();
int currentPosition = listView.getSelectedItemPosition();
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode()) {
currentPosition = listView.getFirstVisiblePosition();
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && currentPosition > 0) {
listView.setSelection(currentPosition - 1);
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN &&
currentPosition < listView.getCount()) {
listView.setSelection(currentPosition + 1);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Swallow these events too to avoid the audible notification of a volume change
if (K9.isUseVolumeKeysForListNavigation() &&
(keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
protected ListView getListView() {
if (list == null) {
list = findViewById(android.R.id.list);

View file

@ -15,7 +15,6 @@ import android.view.MenuItem
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.ProgressBar
import android.widget.Toast
import androidx.appcompat.app.ActionBar
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
@ -35,8 +34,6 @@ import com.fsck.k9.account.BackgroundAccountRemover
import com.fsck.k9.activity.compose.MessageActions
import com.fsck.k9.controller.MessageReference
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.fragment.MessageListFragment
import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener
import com.fsck.k9.helper.Contacts
import com.fsck.k9.helper.ParcelableUtil
import com.fsck.k9.mailstore.SearchStatusManager
@ -55,6 +52,8 @@ import com.fsck.k9.ui.changelog.RecentChangesActivity
import com.fsck.k9.ui.changelog.RecentChangesViewModel
import com.fsck.k9.ui.managefolders.ManageFoldersActivity
import com.fsck.k9.ui.messagelist.DefaultFolderProvider
import com.fsck.k9.ui.messagelist.MessageListFragment
import com.fsck.k9.ui.messagelist.MessageListFragment.MessageListFragmentListener
import com.fsck.k9.ui.messageview.Direction
import com.fsck.k9.ui.messageview.MessageViewContainerFragment
import com.fsck.k9.ui.messageview.MessageViewContainerFragment.MessageViewContainerListener
@ -120,7 +119,7 @@ open class MessageList :
?: if (K9.isMessageViewShowNext) Direction.NEXT else Direction.PREVIOUS
}
private var messageListActivityAppearance: MessageListActivityAppearance? = null
private var messageListActivityConfig: MessageListActivityConfig? = null
/**
* `true` if the message list should be displayed as flat list (i.e. no threading)
@ -552,9 +551,9 @@ open class MessageList :
public override fun onResume() {
super.onResume()
if (messageListActivityAppearance == null) {
messageListActivityAppearance = MessageListActivityAppearance.create(generalSettingsManager)
} else if (messageListActivityAppearance != MessageListActivityAppearance.create(generalSettingsManager)) {
if (messageListActivityConfig == null) {
messageListActivityConfig = MessageListActivityConfig.create(generalSettingsManager)
} else if (messageListActivityConfig != MessageListActivityConfig.create(generalSettingsManager)) {
recreateCompat()
}
@ -591,7 +590,7 @@ open class MessageList :
messageViewOnly = savedInstanceState.getBoolean(STATE_MESSAGE_VIEW_ONLY)
messageListWasDisplayed = savedInstanceState.getBoolean(STATE_MESSAGE_LIST_WAS_DISPLAYED)
initialSearchViewIconified = savedInstanceState.getBoolean(STATE_SEARCH_VIEW_ICONIFIED)
initialSearchViewIconified = savedInstanceState.getBoolean(STATE_SEARCH_VIEW_ICONIFIED, true)
initialSearchViewQuery = savedInstanceState.getString(STATE_SEARCH_VIEW_QUERY)
}
@ -620,7 +619,10 @@ open class MessageList :
override fun onDrawerStateChanged(newState: Int) = Unit
override fun onDrawerOpened(drawerView: View) = Unit
override fun onDrawerOpened(drawerView: View) {
collapseSearchView()
messageListFragment?.finishActionMode()
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) = Unit
}
@ -762,9 +764,6 @@ open class MessageList :
) {
showPreviousMessage()
return true
} else if (displayMode != DisplayMode.MESSAGE_VIEW && K9.isUseVolumeKeysForListNavigation) {
messageListFragment!!.onMoveUp()
return true
}
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
@ -773,9 +772,6 @@ open class MessageList :
) {
showNextMessage()
return true
} else if (displayMode != DisplayMode.MESSAGE_VIEW && K9.isUseVolumeKeysForListNavigation) {
messageListFragment!!.onMoveDown()
return true
}
}
KeyEvent.KEYCODE_DEL -> {
@ -889,15 +885,6 @@ open class MessageList :
}
return true
}
'h' -> {
val toast = if (displayMode == DisplayMode.MESSAGE_LIST) {
Toast.makeText(this, R.string.message_list_help_key, Toast.LENGTH_LONG)
} else {
Toast.makeText(this, R.string.message_view_help_key, Toast.LENGTH_LONG)
}
toast.show()
return true
}
}
return false
@ -913,7 +900,7 @@ open class MessageList :
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
// Swallow these events too to avoid the audible notification of a volume change
if (K9.isUseVolumeKeysForListNavigation) {
if (K9.isUseVolumeKeysForNavigation) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
Timber.v("Swallowed key up.")
return true
@ -931,7 +918,6 @@ open class MessageList :
if (drawer!!.isOpen) {
drawer!!.close()
} else {
collapseSearchView()
drawer!!.open()
}
} else {
@ -979,8 +965,8 @@ open class MessageList :
}
})
searchView.isIconified = initialSearchViewIconified
searchView.setQuery(initialSearchViewQuery, false)
searchView.isIconified = initialSearchViewIconified
this.searchView = searchView
}
@ -1080,6 +1066,8 @@ open class MessageList :
}
private fun addMessageListFragment(fragment: MessageListFragment) {
messageListFragment?.isActive = false
supportFragmentManager.commit {
replace(R.id.message_list_container, fragment)
@ -1207,10 +1195,16 @@ open class MessageList :
}
private fun showLogicalNextMessage(): Boolean {
return when (lastDirection) {
val couldMoveInLastDirection = when (lastDirection) {
Direction.NEXT -> showNextMessage()
Direction.PREVIOUS -> showPreviousMessage()
}
return if (couldMoveInLastDirection) {
true
} else {
showNextMessage() || showPreviousMessage()
}
}
override fun setProgress(enable: Boolean) {

View file

@ -1,11 +1,12 @@
package com.fsck.k9.activity
import com.fsck.k9.K9
import com.fsck.k9.SwipeAction
import com.fsck.k9.preferences.AppTheme
import com.fsck.k9.preferences.GeneralSettingsManager
import com.fsck.k9.preferences.SubTheme
data class MessageListActivityAppearance(
data class MessageListActivityConfig(
val appTheme: AppTheme,
val isShowUnifiedInbox: Boolean,
val isShowMessageListStars: Boolean,
@ -31,13 +32,15 @@ data class MessageListActivityAppearance(
val fontSizeMessageViewAdditionalHeaders: Int,
val fontSizeMessageViewSubject: Int,
val fontSizeMessageViewDate: Int,
val fontSizeMessageViewContentAsPercent: Int
val fontSizeMessageViewContentAsPercent: Int,
val swipeRightAction: SwipeAction,
val swipeLeftAction: SwipeAction,
) {
companion object {
fun create(generalSettingsManager: GeneralSettingsManager): MessageListActivityAppearance {
fun create(generalSettingsManager: GeneralSettingsManager): MessageListActivityConfig {
val settings = generalSettingsManager.getSettings()
return MessageListActivityAppearance(
return MessageListActivityConfig(
appTheme = settings.appTheme,
isShowUnifiedInbox = K9.isShowUnifiedInbox,
isShowMessageListStars = K9.isShowMessageListStars,
@ -63,7 +66,9 @@ data class MessageListActivityAppearance(
fontSizeMessageViewAdditionalHeaders = K9.fontSizes.messageViewAdditionalHeaders,
fontSizeMessageViewSubject = K9.fontSizes.messageViewSubject,
fontSizeMessageViewDate = K9.fontSizes.messageViewDate,
fontSizeMessageViewContentAsPercent = K9.fontSizes.messageViewContentAsPercent
fontSizeMessageViewContentAsPercent = K9.fontSizes.messageViewContentAsPercent,
swipeRightAction = K9.swipeRightAction,
swipeLeftAction = K9.swipeLeftAction,
)
}
}

View file

@ -1,26 +1,28 @@
package com.fsck.k9.contacts
import android.content.Context
import android.util.TypedValue
import android.view.ContextThemeWrapper
import com.fsck.k9.K9
import com.fsck.k9.ui.R
import com.fsck.k9.ui.base.Theme
import com.fsck.k9.ui.base.ThemeManager
import com.fsck.k9.ui.getIntArray
import com.fsck.k9.ui.resolveColorAttribute
class ContactLetterBitmapConfig(context: Context, themeManager: ThemeManager) {
val hasDefaultBackgroundColor: Boolean = !K9.isColorizeMissingContactPictures
val useDarkTheme = themeManager.appTheme == Theme.DARK
val defaultBackgroundColor: Int
val backgroundColors: IntArray
init {
defaultBackgroundColor = if (hasDefaultBackgroundColor) {
val outValue = TypedValue()
val themedContext = ContextThemeWrapper(context, themeManager.appThemeResourceId)
themedContext.theme.resolveAttribute(R.attr.contactPictureFallbackDefaultBackgroundColor, outValue, true)
outValue.data
val themedContext = ContextThemeWrapper(context, themeManager.appThemeResourceId)
val theme = themedContext.theme
if (hasDefaultBackgroundColor) {
defaultBackgroundColor = theme.resolveColorAttribute(R.attr.contactPictureFallbackDefaultBackgroundColor)
backgroundColors = intArrayOf()
} else {
0
defaultBackgroundColor = 0
backgroundColors = theme.getIntArray(R.attr.contactPictureFallbackBackgroundColors)
}
}
}

View file

@ -5,7 +5,6 @@ import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import com.fsck.k9.mail.Address
import com.fsck.k9.ui.helper.MaterialColors
/**
* Draw a `Bitmap` containing the "contact letter" obtained by [ContactLetterExtractor].
@ -48,54 +47,12 @@ class ContactLetterBitmapCreator(
}
val hash = address.hashCode()
if (config.useDarkTheme) {
val colorIndex = (hash and Integer.MAX_VALUE) % BACKGROUND_COLORS_DARK.size
return BACKGROUND_COLORS_DARK[colorIndex]
} else {
val colorIndex = (hash and Integer.MAX_VALUE) % BACKGROUND_COLORS_LIGHT.size
return BACKGROUND_COLORS_LIGHT[colorIndex]
}
val backgroundColors = config.backgroundColors
val colorIndex = (hash and Integer.MAX_VALUE) % backgroundColors.size
return backgroundColors[colorIndex]
}
fun signatureOf(address: Address): String {
return calcUnknownContactColor(address).toString()
}
companion object {
private val BACKGROUND_COLORS_LIGHT = intArrayOf(
MaterialColors.RED_300,
MaterialColors.DEEP_PURPLE_300,
MaterialColors.LIGHT_BLUE_300,
MaterialColors.GREEN_300,
MaterialColors.DEEP_ORANGE_300,
MaterialColors.BLUE_GREY_300,
MaterialColors.PINK_300,
MaterialColors.INDIGO_300,
MaterialColors.CYAN_300,
MaterialColors.AMBER_400,
MaterialColors.BROWN_300,
MaterialColors.PURPLE_300,
MaterialColors.BLUE_300,
MaterialColors.TEAL_300,
MaterialColors.ORANGE_400
)
private val BACKGROUND_COLORS_DARK = intArrayOf(
MaterialColors.RED_600,
MaterialColors.DEEP_PURPLE_600,
MaterialColors.LIGHT_BLUE_600,
MaterialColors.GREEN_600,
MaterialColors.DEEP_ORANGE_600,
MaterialColors.BLUE_GREY_600,
MaterialColors.PINK_600,
MaterialColors.INDIGO_600,
MaterialColors.CYAN_600,
MaterialColors.AMBER_600,
MaterialColors.BROWN_600,
MaterialColors.PURPLE_600,
MaterialColors.BLUE_600,
MaterialColors.TEAL_600,
MaterialColors.ORANGE_600
)
}
}

View file

@ -1,7 +0,0 @@
package com.fsck.k9.fragment
import org.koin.dsl.module
val fragmentModule = module {
single { SortTypeToastProvider() }
}

View file

@ -56,6 +56,8 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf
import com.fsck.k9.core.R as CoreR
import com.mikepenz.materialdrawer.R as MaterialDrawerR
private const val UNREAD_SYMBOL = "\u2B24"
private const val STARRED_SYMBOL = "\u2605"
@ -466,8 +468,8 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
private fun getDarkThemeAccentColor(color: Int): Int {
val lightColors = resources.getIntArray(R.array.account_colors)
val darkColors = resources.getIntArray(R.array.drawer_account_accent_color_dark_theme)
val lightColors = resources.getIntArray(CoreR.array.account_colors)
val darkColors = resources.getIntArray(CoreR.array.drawer_account_accent_color_dark_theme)
val index = lightColors.indexOf(color)
return if (index == -1) color else darkColors[index]
}
@ -537,11 +539,11 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
private fun Context.obtainDrawerTextColor(): Int {
val styledAttributes = obtainStyledAttributes(
null,
R.styleable.MaterialDrawerSliderView,
R.attr.materialDrawerStyle,
R.style.Widget_MaterialDrawerStyle
MaterialDrawerR.styleable.MaterialDrawerSliderView,
MaterialDrawerR.attr.materialDrawerStyle,
MaterialDrawerR.style.Widget_MaterialDrawerStyle
)
val textColor = styledAttributes.getColor(R.styleable.MaterialDrawerSliderView_materialDrawerPrimaryText, 0)
val textColor = styledAttributes.getColor(MaterialDrawerR.styleable.MaterialDrawerSliderView_materialDrawerPrimaryText, 0)
styledAttributes.recycle()
return textColor

View file

@ -25,3 +25,14 @@ fun Theme.resolveDrawableAttribute(attrId: Int): Drawable {
return getDrawable(typedValue.resourceId)
}
fun Theme.getIntArray(attrId: Int): IntArray {
val typedValue = TypedValue()
val found = resolveAttribute(attrId, typedValue, true)
if (!found) {
throw IllegalStateException("Couldn't resolve attribute ($attrId)")
}
return resources.getIntArray(typedValue.resourceId)
}

View file

@ -2,24 +2,21 @@ package com.fsck.k9.ui.account
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import com.fsck.k9.ui.R
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome
import com.mikepenz.iconics.utils.backgroundColorInt
import com.mikepenz.iconics.utils.colorRes
import com.mikepenz.iconics.utils.paddingDp
import com.mikepenz.iconics.utils.sizeDp
/**
* Provides a [Drawable] for the account using the account's color as background color.
*/
class AccountFallbackImageProvider(private val context: Context) {
fun getDrawable(color: Int): Drawable {
return IconicsDrawable(context, FontAwesome.Icon.faw_user_alt).apply {
colorRes = R.color.material_drawer_profile_icon
backgroundColorInt = color
sizeDp = 56
paddingDp = 12
val drawable = ContextCompat.getDrawable(context, R.drawable.drawer_account_fallback)
?: error("Error loading drawable")
return drawable.mutate().apply {
colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.DST_OVER)
}
}
}

View file

@ -1,216 +0,0 @@
package com.fsck.k9.ui.helper
@Suppress("unused")
object MaterialColors {
/*
* Heavily modified version of https://gist.github.com/kalehv/bae765c756e94455ed88
*/
const val RED_50 = 0xFFFFEBEE.toInt()
const val RED_100 = 0xFFFFCDD2.toInt()
const val RED_200 = 0xFFEF9A9A.toInt()
const val RED_300 = 0xFFE57373.toInt()
const val RED_400 = 0xFFEF5350.toInt()
const val RED_500 = 0xFFF44336.toInt()
const val RED_600 = 0xFFE53935.toInt()
const val RED_700 = 0xFFD32F2F.toInt()
const val RED_800 = 0xFFC62828.toInt()
const val RED_900 = 0xFFB71C1C.toInt()
const val DEEP_PURPLE_50 = 0xFFEDE7F6.toInt()
const val DEEP_PURPLE_100 = 0xFFD1C4E9.toInt()
const val DEEP_PURPLE_200 = 0xFFB39DDB.toInt()
const val DEEP_PURPLE_300 = 0xFF9575CD.toInt()
const val DEEP_PURPLE_400 = 0xFF7E57C2.toInt()
const val DEEP_PURPLE_500 = 0xFF673AB7.toInt()
const val DEEP_PURPLE_600 = 0xFF5E35B1.toInt()
const val DEEP_PURPLE_700 = 0xFF512DA8.toInt()
const val DEEP_PURPLE_800 = 0xFF4527A0.toInt()
const val DEEP_PURPLE_900 = 0xFF311B92.toInt()
const val LIGHT_BLUE_50 = 0xFFE1F5FE.toInt()
const val LIGHT_BLUE_100 = 0xFFB3E5FC.toInt()
const val LIGHT_BLUE_200 = 0xFF81D4FA.toInt()
const val LIGHT_BLUE_300 = 0xFF4FC3F7.toInt()
const val LIGHT_BLUE_400 = 0xFF29B6F6.toInt()
const val LIGHT_BLUE_500 = 0xFF03A9F4.toInt()
const val LIGHT_BLUE_600 = 0xFF039BE5.toInt()
const val LIGHT_BLUE_700 = 0xFF0288D1.toInt()
const val LIGHT_BLUE_800 = 0xFF0277BD.toInt()
const val LIGHT_BLUE_900 = 0xFF01579B.toInt()
const val GREEN_50 = 0xFFE8F5E9.toInt()
const val GREEN_100 = 0xFFC8E6C9.toInt()
const val GREEN_200 = 0xFFA5D6A7.toInt()
const val GREEN_300 = 0xFF81C784.toInt()
const val GREEN_400 = 0xFF66BB6A.toInt()
const val GREEN_500 = 0xFF4CAF50.toInt()
const val GREEN_600 = 0xFF43A047.toInt()
const val GREEN_700 = 0xFF388E3C.toInt()
const val GREEN_800 = 0xFF2E7D32.toInt()
const val GREEN_900 = 0xFF1B5E20.toInt()
const val YELLOW_50 = 0xFFFFFDE7.toInt()
const val YELLOW_100 = 0xFFFFF9C4.toInt()
const val YELLOW_200 = 0xFFFFF59D.toInt()
const val YELLOW_300 = 0xFFFFF176.toInt()
const val YELLOW_400 = 0xFFFFEE58.toInt()
const val YELLOW_500 = 0xFFFFEB3B.toInt()
const val YELLOW_600 = 0xFFFDD835.toInt()
const val YELLOW_700 = 0xFFFBC02D.toInt()
const val YELLOW_800 = 0xFFF9A825.toInt()
const val YELLOW_900 = 0xFFF57F17.toInt()
const val DEEP_ORANGE_50 = 0xFFFBE9E7.toInt()
const val DEEP_ORANGE_100 = 0xFFFFCCBC.toInt()
const val DEEP_ORANGE_200 = 0xFFFFAB91.toInt()
const val DEEP_ORANGE_300 = 0xFFFF8A65.toInt()
const val DEEP_ORANGE_400 = 0xFFFF7043.toInt()
const val DEEP_ORANGE_500 = 0xFFFF5722.toInt()
const val DEEP_ORANGE_600 = 0xFFF4511E.toInt()
const val DEEP_ORANGE_700 = 0xFFE64A19.toInt()
const val DEEP_ORANGE_800 = 0xFFD84315.toInt()
const val DEEP_ORANGE_900 = 0xFFBF360C.toInt()
const val BLUE_GREY_50 = 0xFFECEFF1.toInt()
const val BLUE_GREY_100 = 0xFFCFD8DC.toInt()
const val BLUE_GREY_200 = 0xFFB0BEC5.toInt()
const val BLUE_GREY_300 = 0xFF90A4AE.toInt()
const val BLUE_GREY_400 = 0xFF78909C.toInt()
const val BLUE_GREY_500 = 0xFF607D8B.toInt()
const val BLUE_GREY_600 = 0xFF546E7A.toInt()
const val BLUE_GREY_700 = 0xFF455A64.toInt()
const val BLUE_GREY_800 = 0xFF37474F.toInt()
const val BLUE_GREY_900 = 0xFF263238.toInt()
const val PINK_50 = 0xFFFCE4EC.toInt()
const val PINK_100 = 0xFFF8BBD0.toInt()
const val PINK_200 = 0xFFF48FB1.toInt()
const val PINK_300 = 0xFFF06292.toInt()
const val PINK_400 = 0xFFEC407A.toInt()
const val PINK_500 = 0xFFE91E63.toInt()
const val PINK_600 = 0xFFD81B60.toInt()
const val PINK_700 = 0xFFC2185B.toInt()
const val PINK_800 = 0xFFAD1457.toInt()
const val PINK_900 = 0xFF880E4F.toInt()
const val INDIGO_50 = 0xFFE8EAF6.toInt()
const val INDIGO_100 = 0xFFC5CAE9.toInt()
const val INDIGO_200 = 0xFF9FA8DA.toInt()
const val INDIGO_300 = 0xFF7986CB.toInt()
const val INDIGO_400 = 0xFF5C6BC0.toInt()
const val INDIGO_500 = 0xFF3F51B5.toInt()
const val INDIGO_600 = 0xFF3949AB.toInt()
const val INDIGO_700 = 0xFF303F9F.toInt()
const val INDIGO_800 = 0xFF283593.toInt()
const val INDIGO_900 = 0xFF1A237E.toInt()
const val CYAN_50 = 0xFFE0F7FA.toInt()
const val CYAN_100 = 0xFFB2EBF2.toInt()
const val CYAN_200 = 0xFF80DEEA.toInt()
const val CYAN_300 = 0xFF4DD0E1.toInt()
const val CYAN_400 = 0xFF26C6DA.toInt()
const val CYAN_500 = 0xFF00BCD4.toInt()
const val CYAN_600 = 0xFF00ACC1.toInt()
const val CYAN_700 = 0xFF0097A7.toInt()
const val CYAN_800 = 0xFF00838F.toInt()
const val CYAN_900 = 0xFF006064.toInt()
const val LIGHT_GREEN_50 = 0xFFF1F8E9.toInt()
const val LIGHT_GREEN_100 = 0xFFDCEDC8.toInt()
const val LIGHT_GREEN_200 = 0xFFC5E1A5.toInt()
const val LIGHT_GREEN_300 = 0xFFAED581.toInt()
const val LIGHT_GREEN_400 = 0xFF9CCC65.toInt()
const val LIGHT_GREEN_500 = 0xFF8BC34A.toInt()
const val LIGHT_GREEN_600 = 0xFF7CB342.toInt()
const val LIGHT_GREEN_700 = 0xFF689F38.toInt()
const val LIGHT_GREEN_800 = 0xFF558B2F.toInt()
const val LIGHT_GREEN_900 = 0xFF33691E.toInt()
const val AMBER_50 = 0xFFFFF8E1.toInt()
const val AMBER_100 = 0xFFFFECB3.toInt()
const val AMBER_200 = 0xFFFFE082.toInt()
const val AMBER_300 = 0xFFFFD54F.toInt()
const val AMBER_400 = 0xFFFFCA28.toInt()
const val AMBER_500 = 0xFFFFC107.toInt()
const val AMBER_600 = 0xFFFFB300.toInt()
const val AMBER_700 = 0xFFFFA000.toInt()
const val AMBER_800 = 0xFFFF8F00.toInt()
const val AMBER_900 = 0xFFFF6F00.toInt()
const val BROWN_50 = 0xFFEFEBE9.toInt()
const val BROWN_100 = 0xFFD7CCC8.toInt()
const val BROWN_200 = 0xFFBCAAA4.toInt()
const val BROWN_300 = 0xFFA1887F.toInt()
const val BROWN_400 = 0xFF8D6E63.toInt()
const val BROWN_500 = 0xFF795548.toInt()
const val BROWN_600 = 0xFF6D4C41.toInt()
const val BROWN_700 = 0xFF5D4037.toInt()
const val BROWN_800 = 0xFF4E342E.toInt()
const val BROWN_900 = 0xFF3E2723.toInt()
const val PURPLE_50 = 0xFFF3E5F5.toInt()
const val PURPLE_100 = 0xFFE1BEE7.toInt()
const val PURPLE_200 = 0xFFCE93D8.toInt()
const val PURPLE_300 = 0xFFBA68C8.toInt()
const val PURPLE_400 = 0xFFAB47BC.toInt()
const val PURPLE_500 = 0xFF9C27B0.toInt()
const val PURPLE_600 = 0xFF8E24AA.toInt()
const val PURPLE_700 = 0xFF7B1FA2.toInt()
const val PURPLE_800 = 0xFF6A1B9A.toInt()
const val PURPLE_900 = 0xFF4A148C.toInt()
const val BLUE_50 = 0xFFE3F2FD.toInt()
const val BLUE_100 = 0xFFBBDEFB.toInt()
const val BLUE_200 = 0xFF90CAF9.toInt()
const val BLUE_300 = 0xFF64B5F6.toInt()
const val BLUE_400 = 0xFF42A5F5.toInt()
const val BLUE_500 = 0xFF2196F3.toInt()
const val BLUE_600 = 0xFF1E88E5.toInt()
const val BLUE_700 = 0xFF1976D2.toInt()
const val BLUE_800 = 0xFF1565C0.toInt()
const val BLUE_900 = 0xFF0D47A1.toInt()
const val TEAL_50 = 0xFFE0F2F1.toInt()
const val TEAL_100 = 0xFFB2DFDB.toInt()
const val TEAL_200 = 0xFF80CBC4.toInt()
const val TEAL_300 = 0xFF4DB6AC.toInt()
const val TEAL_400 = 0xFF26A69A.toInt()
const val TEAL_500 = 0xFF009688.toInt()
const val TEAL_600 = 0xFF00897B.toInt()
const val TEAL_700 = 0xFF00796B.toInt()
const val TEAL_800 = 0xFF00695C.toInt()
const val TEAL_900 = 0xFF004D40.toInt()
const val LIME_50 = 0xFFF9FBE7.toInt()
const val LIME_100 = 0xFFF0F4C3.toInt()
const val LIME_200 = 0xFFE6EE9C.toInt()
const val LIME_300 = 0xFFDCE775.toInt()
const val LIME_400 = 0xFFD4E157.toInt()
const val LIME_500 = 0xFFCDDC39.toInt()
const val LIME_600 = 0xFFC0CA33.toInt()
const val LIME_700 = 0xFFAFB42B.toInt()
const val LIME_800 = 0xFF9E9D24.toInt()
const val LIME_900 = 0xFF827717.toInt()
const val ORANGE_50 = 0xFFFFF3E0.toInt()
const val ORANGE_100 = 0xFFFFE0B2.toInt()
const val ORANGE_200 = 0xFFFFCC80.toInt()
const val ORANGE_300 = 0xFFFFB74D.toInt()
const val ORANGE_400 = 0xFFFFA726.toInt()
const val ORANGE_500 = 0xFFFF9800.toInt()
const val ORANGE_600 = 0xFFFB8C00.toInt()
const val ORANGE_700 = 0xFFF57C00.toInt()
const val ORANGE_800 = 0xFFEF6C00.toInt()
const val ORANGE_900 = 0xFFE65100.toInt()
const val GREY_50 = 0xFFFAFAFA.toInt()
const val GREY_100 = 0xFFF5F5F5.toInt()
const val GREY_200 = 0xFFEEEEEE.toInt()
const val GREY_300 = 0xFFE0E0E0.toInt()
const val GREY_400 = 0xFFBDBDBD.toInt()
const val GREY_500 = 0xFF9E9E9E.toInt()
const val GREY_600 = 0xFF757575.toInt()
const val GREY_700 = 0xFF616161.toInt()
const val GREY_800 = 0xFF424242.toInt()
const val GREY_900 = 0xFF212121.toInt()
}

View file

@ -17,4 +17,5 @@ val messageListUiModule = module {
factory {
MessageListLiveDataFactory(messageListLoader = get(), preferences = get(), messageListRepository = get())
}
single { SortTypeToastProvider() }
}

View file

@ -1,9 +1,8 @@
package com.fsck.k9.fragment
package com.fsck.k9.ui.messagelist
import android.content.Context
import android.annotation.SuppressLint
import android.content.res.Resources
import android.content.res.Resources.Theme
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.text.Spannable
@ -14,26 +13,31 @@ import android.text.style.StyleSpan
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
import com.fsck.k9.FontSizes
import com.fsck.k9.contacts.ContactPictureLoader
import com.fsck.k9.controller.MessageReference
import com.fsck.k9.mail.Address
import com.fsck.k9.ui.R
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
import com.fsck.k9.ui.messagelist.MessageListAppearance
import com.fsck.k9.ui.messagelist.MessageListItem
import com.fsck.k9.ui.resolveColorAttribute
import com.fsck.k9.ui.resolveDrawableAttribute
import kotlin.math.max
private const val FOOTER_ID = 1L
private const val TYPE_MESSAGE = 0
private const val TYPE_FOOTER = 1
class MessageListAdapter internal constructor(
private val context: Context,
theme: Theme,
private val res: Resources,
private val layoutInflater: LayoutInflater,
@ -41,7 +45,7 @@ class MessageListAdapter internal constructor(
private val listItemListener: MessageListItemActionListener,
private val appearance: MessageListAppearance,
private val relativeDateTimeFormatter: RelativeDateTimeFormatter
) : BaseAdapter() {
) : RecyclerView.Adapter<MessageListViewHolder>() {
private val forwardedIcon: Drawable = theme.resolveDrawableAttribute(R.attr.messageListForwarded)
private val answeredIcon: Drawable = theme.resolveDrawableAttribute(R.attr.messageListAnswered)
@ -49,11 +53,15 @@ class MessageListAdapter internal constructor(
private val previewTextColor: Int = theme.resolveColorAttribute(R.attr.messageListPreviewTextColor)
private val activeItemBackgroundColor: Int = theme.resolveColorAttribute(R.attr.messageListActiveItemBackgroundColor)
private val selectedItemBackgroundColor: Int = theme.resolveColorAttribute(R.attr.messageListSelectedBackgroundColor)
private val regularItemBackgroundColor: Int = theme.resolveColorAttribute(R.attr.messageListRegularItemBackgroundColor)
private val readItemBackgroundColor: Int = theme.resolveColorAttribute(R.attr.messageListReadItemBackgroundColor)
private val unreadItemBackgroundColor: Int = theme.resolveColorAttribute(R.attr.messageListUnreadItemBackgroundColor)
var messages: List<MessageListItem> = emptyList()
@SuppressLint("NotifyDataSetChanged")
set(value) {
val oldMessageList = field
field = value
messagesMap = value.associateBy { it.uniqueId }
@ -62,18 +70,57 @@ class MessageListAdapter internal constructor(
selected = selected.intersect(uniqueIds)
}
notifyDataSetChanged()
if (oldMessageList.isEmpty()) {
// While loading, only the footer view is showing. If we used DiffUtil, the footer view would be used as
// anchor element and the updated list would be scrolled all the way down.
notifyDataSetChanged()
} else {
val diffResult = DiffUtil.calculateDiff(
MessageListDiffCallback(oldMessageList = oldMessageList, newMessageList = value)
)
diffResult.dispatchUpdatesTo(this)
}
}
private var messagesMap = emptyMap<Long, MessageListItem>()
var activeMessage: MessageReference? = null
set(value) {
if (value == field) return
val oldPosition = getPosition(field)
val newPosition = getPosition(value)
field = value
oldPosition?.let { position -> notifyItemChanged(position) }
newPosition?.let { position -> notifyItemChanged(position) }
}
var selected: Set<Long> = emptySet()
private set(value) {
if (value == field) return
// Selection removed
field.asSequence()
.filter { uniqueId -> uniqueId !in value }
.mapNotNull { uniqueId -> messagesMap[uniqueId] }
.mapNotNull { messageListItem -> getPosition(messageListItem) }
.forEach { position ->
notifyItemChanged(position)
}
// Selection added
value.asSequence()
.filter { uniqueId -> uniqueId !in field }
.mapNotNull { uniqueId -> messagesMap[uniqueId] }
.mapNotNull { messageListItem -> getPosition(messageListItem) }
.forEach { position ->
notifyItemChanged(position)
}
field = value
selectedCount = calculateSelectionCount()
notifyDataSetChanged()
}
val selectedMessages: List<MessageListItem>
@ -85,6 +132,34 @@ class MessageListAdapter internal constructor(
var selectedCount: Int = 0
private set
var footerText: String? = null
set(value) {
if (field == value) return
val hadFooterText = field != null
val previousFooterPosition = footerPosition
field = value
if (hadFooterText) {
if (value == null) {
notifyItemRemoved(previousFooterPosition)
} else {
notifyItemChanged(footerPosition)
}
} else {
notifyItemInserted(footerPosition)
}
}
private val hasFooter: Boolean
get() = footerText != null
private val lastMessagePosition: Int
get() = messages.lastIndex
private val footerPosition: Int
get() = if (hasFooter) lastMessagePosition + 1 else NO_POSITION
private inline val subjectViewFontSize: Int
get() = if (appearance.senderAboveSubject) {
appearance.fontSizes.messageListSender
@ -92,35 +167,60 @@ class MessageListAdapter internal constructor(
appearance.fontSizes.messageListSubject
}
private val messageClickedListener = OnClickListener { view: View ->
val messageListItem = getItemFromView(view)
listItemListener.onMessageClicked(messageListItem)
}
private val messageLongClickedListener = OnLongClickListener { view: View ->
val messageListItem = getItemFromView(view)
listItemListener.onToggleMessageSelection(messageListItem)
true
}
private val footerClickListener = OnClickListener {
listItemListener.onFooterClicked()
}
private val flagClickListener = OnClickListener { view: View ->
val messageViewHolder = view.tag as MessageViewHolder
val messageListItem = getItemById(messageViewHolder.uniqueId)
val messageListItem = getItemFromView(view)
listItemListener.onToggleMessageFlag(messageListItem)
}
private val contactPictureClickListener = OnClickListener { view: View ->
val parentView = view.parent.parent as View
val messageViewHolder = parentView.tag as MessageViewHolder
val messageListItem = getItemById(messageViewHolder.uniqueId)
val messageListItem = getItemFromView(parentView)
listItemListener.onToggleMessageSelection(messageListItem)
}
init {
setHasStableIds(true)
}
private fun recipientSigil(toMe: Boolean, ccMe: Boolean) = when {
toMe -> res.getString(R.string.messagelist_sent_to_me_sigil) + " "
ccMe -> res.getString(R.string.messagelist_sent_cc_me_sigil) + " "
else -> ""
}
override fun hasStableIds(): Boolean = true
override fun getItemCount(): Int = messages.size + if (hasFooter) 1 else 0
override fun getCount(): Int = messages.size
override fun getItemId(position: Int): Long {
return if (position <= lastMessagePosition) {
messages[position].uniqueId
} else {
FOOTER_ID
}
}
override fun getItemId(position: Int): Long = messages[position].uniqueId
override fun getItemViewType(position: Int): Int {
return if (position <= lastMessagePosition) TYPE_MESSAGE else TYPE_FOOTER
}
override fun getItem(position: Int): MessageListItem = messages[position]
private fun getItem(position: Int): MessageListItem = messages[position]
private fun getItemById(uniqueId: Long): MessageListItem {
return messagesMap[uniqueId]!!
fun getItemById(uniqueId: Long): MessageListItem? {
return messagesMap[uniqueId]
}
fun getItem(messageReference: MessageReference): MessageListItem? {
@ -135,16 +235,26 @@ class MessageListAdapter internal constructor(
return messages.indexOf(messageListItem).takeIf { it != -1 }
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val message = getItem(position)
val view: View = convertView ?: newView(parent)
bindView(view, context, message)
private fun getPosition(messageReference: MessageReference?): Int? {
if (messageReference == null) return null
return view
return messages.indexOfFirst {
messageReference.equals(it.account.uuid, it.folderId, it.messageUid)
}.takeIf { it != -1 }
}
private fun newView(parent: ViewGroup?): View {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageListViewHolder {
return when (viewType) {
TYPE_MESSAGE -> createMessageViewHolder(parent)
TYPE_FOOTER -> createFooterViewHolder(parent)
else -> error("Unsupported type: $viewType")
}
}
private fun createMessageViewHolder(parent: ViewGroup?): MessageViewHolder {
val view = layoutInflater.inflate(R.layout.message_list_item, parent, false)
view.setOnClickListener(messageClickedListener)
view.setOnLongClickListener(messageLongClickedListener)
val holder = MessageViewHolder(view)
@ -168,14 +278,33 @@ class MessageListAdapter internal constructor(
view.tag = holder
return view
return holder
}
private fun bindView(view: View, context: Context, message: MessageListItem) {
val isSelected = selected.contains(message.uniqueId)
val isActive = isActiveMessage(message)
private fun createFooterViewHolder(parent: ViewGroup): MessageListViewHolder {
val view = layoutInflater.inflate(R.layout.message_list_item_footer, parent, false)
view.setOnClickListener(footerClickListener)
return FooterViewHolder(view)
}
val holder = view.tag as MessageViewHolder
override fun onBindViewHolder(holder: MessageListViewHolder, position: Int) {
when (val viewType = getItemViewType(position)) {
TYPE_MESSAGE -> {
val messageListItem = getItem(position)
bindMessageViewHolder(holder as MessageViewHolder, messageListItem)
}
TYPE_FOOTER -> {
bindFooterViewHolder(holder as FooterViewHolder)
}
else -> {
error("Unsupported type: $viewType")
}
}
}
private fun bindMessageViewHolder(holder: MessageViewHolder, messageListItem: MessageListItem) {
val isSelected = selected.contains(messageListItem.uniqueId)
val isActive = isActiveMessage(messageListItem)
if (appearance.showContactPicture) {
if (isSelected) {
@ -187,7 +316,7 @@ class MessageListAdapter internal constructor(
}
}
with(message) {
with(messageListItem) {
val maybeBoldTypeface = if (isRead) Typeface.NORMAL else Typeface.BOLD
val displayDate = relativeDateTimeFormatter.formatDate(messageDate)
val displayThreadCount = if (appearance.showingThreadedList) threadCount else 0
@ -206,7 +335,7 @@ class MessageListAdapter internal constructor(
if (appearance.showContactPicture && holder.contactPicture.isVisible) {
setContactPicture(holder.contactPicture, displayAddress)
}
setBackgroundColor(view, isSelected, isRead, isActive)
setBackgroundColor(holder.itemView, isSelected, isRead, isActive)
updateWithThreadCount(holder, displayThreadCount)
val beforePreviewText = if (appearance.senderAboveSubject) subject else displayName
val sigil = recipientSigil(toMe, ccMe)
@ -240,6 +369,10 @@ class MessageListAdapter internal constructor(
}
}
private fun bindFooterViewHolder(holder: FooterViewHolder) {
holder.text.text = footerText
}
private fun formatPreviewText(
preview: TextView,
beforePreviewText: CharSequence,
@ -304,7 +437,7 @@ class MessageListAdapter internal constructor(
selected -> selectedItemBackgroundColor
backGroundAsReadIndicator && read -> readItemBackgroundColor
backGroundAsReadIndicator && !read -> unreadItemBackgroundColor
else -> Color.TRANSPARENT
else -> regularItemBackgroundColor
}
view.setBackgroundColor(backgroundColor)
@ -388,9 +521,33 @@ class MessageListAdapter internal constructor(
.filter { it.uniqueId in selected }
.sumOf { it.threadCount.coerceAtLeast(1) }
}
private fun getItemFromView(view: View): MessageListItem {
val messageViewHolder = view.tag as MessageViewHolder
return getItemById(messageViewHolder.uniqueId) ?: error("Couldn't find MessageListItem by View")
}
}
private class MessageListDiffCallback(
private val oldMessageList: List<MessageListItem>,
private val newMessageList: List<MessageListItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldMessageList.size
override fun getNewListSize(): Int = newMessageList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldMessageList[oldItemPosition].uniqueId == newMessageList[newItemPosition].uniqueId
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldMessageList[oldItemPosition] == newMessageList[newItemPosition]
}
}
interface MessageListItemActionListener {
fun onMessageClicked(messageListItem: MessageListItem)
fun onToggleMessageSelection(item: MessageListItem)
fun onToggleMessageFlag(item: MessageListItem)
fun onFooterClicked()
}

View file

@ -1,4 +1,4 @@
package com.fsck.k9.fragment
package com.fsck.k9.ui.messagelist
import android.app.Activity
import android.app.SearchManager
@ -6,20 +6,19 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener
import android.widget.AdapterView.OnItemLongClickListener
import android.widget.ListView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.view.ActionMode
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.fsck.k9.Account
import com.fsck.k9.Account.Expunge
@ -27,14 +26,15 @@ import com.fsck.k9.Account.SortType
import com.fsck.k9.Clock
import com.fsck.k9.K9
import com.fsck.k9.Preferences
import com.fsck.k9.SwipeAction
import com.fsck.k9.activity.FolderInfoHolder
import com.fsck.k9.activity.Search
import com.fsck.k9.activity.misc.ContactPicture
import com.fsck.k9.controller.MessageReference
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.controller.SimpleMessagingListener
import com.fsck.k9.fragment.ConfirmationDialogFragment
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener.Companion.MAX_PROGRESS
import com.fsck.k9.helper.Utility
import com.fsck.k9.helper.mapToSet
import com.fsck.k9.mail.Flag
@ -47,12 +47,7 @@ import com.fsck.k9.ui.choosefolder.ChooseFolderActivity
import com.fsck.k9.ui.folders.FolderNameFormatter
import com.fsck.k9.ui.folders.FolderNameFormatterFactory
import com.fsck.k9.ui.helper.RelativeDateTimeFormatter
import com.fsck.k9.ui.messagelist.MessageListAppearance
import com.fsck.k9.ui.messagelist.MessageListConfig
import com.fsck.k9.ui.messagelist.MessageListInfo
import com.fsck.k9.ui.messagelist.MessageListItem
import com.fsck.k9.ui.messagelist.MessageListViewModel
import com.fsck.k9.ui.messagelist.MessageSortOverride
import com.fsck.k9.ui.messagelist.MessageListFragment.MessageListFragmentListener.Companion.MAX_PROGRESS
import java.util.concurrent.Future
import net.jcip.annotations.GuardedBy
import org.koin.android.ext.android.inject
@ -60,11 +55,10 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber
private const val MAXIMUM_MESSAGE_SORT_OVERRIDES = 3
private const val MINIMUM_CLICK_INTERVAL = 200L
class MessageListFragment :
Fragment(),
OnItemClickListener,
OnItemLongClickListener,
ConfirmationDialogFragmentListener,
MessageListItemActionListener {
@ -82,12 +76,9 @@ class MessageListFragment :
private lateinit var fragmentListener: MessageListFragmentListener
private lateinit var listView: ListView
private lateinit var recyclerView: RecyclerView
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var adapter: MessageListAdapter
private var footerView: View? = null
private var savedListState: Parcelable? = null
private lateinit var accountUuids: Array<String>
private var account: Account? = null
@ -111,6 +102,7 @@ class MessageListFragment :
private var isThreadDisplay = false
private var activeMessage: MessageReference? = null
private var rememberedSelected: Set<Long>? = null
private var lastMessageClick = 0L
lateinit var localSearch: LocalSearch
private set
@ -118,6 +110,7 @@ class MessageListFragment :
private set
private var isSingleFolderMode = false
private var isRemoteSearch = false
private var initialMessageListLoad = true
private val isUnifiedInbox: Boolean
get() = localSearch.id == SearchAccount.UNIFIED_INBOX
@ -176,7 +169,6 @@ class MessageListFragment :
activeMessages = savedInstanceState.getStringArray(STATE_ACTIVE_MESSAGES)?.map { MessageReference.parse(it)!! }
restoreSelectedMessages(savedInstanceState)
isRemoteSearch = savedInstanceState.getBoolean(STATE_REMOTE_SEARCH_PERFORMED)
savedListState = savedInstanceState.getParcelable(STATE_MESSAGE_LIST)
val messageReferenceString = savedInstanceState.getString(STATE_ACTIVE_MESSAGE)
activeMessage = MessageReference.parse(messageReferenceString)
}
@ -186,7 +178,7 @@ class MessageListFragment :
}
fun restoreListState(savedListState: Parcelable) {
listView.onRestoreInstanceState(savedListState)
recyclerView.layoutManager?.onRestoreInstanceState(savedListState)
}
private fun decodeArguments(): MessageListFragment? {
@ -226,7 +218,7 @@ class MessageListFragment :
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.message_list_fragment, container, false).apply {
initializeSwipeRefreshLayout(this)
initializeListView(this)
initializeRecyclerView(this)
}
}
@ -243,17 +235,13 @@ class MessageListFragment :
swipeRefreshLayout.isEnabled = false
}
private fun initializeListView(view: View) {
listView = view.findViewById(R.id.message_list)
with(listView) {
scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
isLongClickable = true
isFastScrollEnabled = true
isVerticalFadingEdgeEnabled = false
isScrollingCacheEnabled = false
onItemClickListener = this@MessageListFragment
onItemLongClickListener = this@MessageListFragment
}
private fun initializeRecyclerView(view: View) {
recyclerView = view.findViewById(R.id.message_list)
val itemDecoration = MessageListItemDecoration(requireContext())
recyclerView.addItemDecoration(itemDecoration)
recyclerView.itemAnimator = MessageListItemAnimator()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -267,9 +255,10 @@ class MessageListFragment :
}
private fun initializeMessageList() {
val theme = requireActivity().theme
adapter = MessageListAdapter(
context = requireContext(),
theme = requireActivity().theme,
theme = theme,
res = resources,
layoutInflater = layoutInflater,
contactsPictureLoader = ContactPicture.getContactPictureLoader(),
@ -280,12 +269,20 @@ class MessageListFragment :
adapter.activeMessage = activeMessage
if (isSingleFolderMode) {
listView.addFooterView(getFooterView(listView))
updateFooter(null)
}
recyclerView.adapter = adapter
listView.adapter = adapter
val itemTouchHelper = ItemTouchHelper(
MessageListSwipeCallback(
resources,
resourceProvider = SwipeResourceProvider(theme),
swipeActionSupportProvider,
swipeRightAction = K9.swipeRightAction,
swipeLeftAction = K9.swipeLeftAction,
adapter,
swipeListener
)
)
itemTouchHelper.attachToRecyclerView(recyclerView)
}
private fun initializeSortSettings() {
@ -318,10 +315,9 @@ class MessageListFragment :
currentFolder?.let {
if (it.databaseId == folderId) {
it.loading = loading
updateFooterText()
}
}
updateFooterView()
}
fun updateTitle() {
@ -375,16 +371,7 @@ class MessageListFragment :
fragmentListener.setMessageListProgressEnabled(progress)
}
override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
if (view === footerView) {
handleFooterClick()
} else {
val messageListItem = adapter.getItem(position)
handleListItemClick(messageListItem)
}
}
private fun handleFooterClick() {
override fun onFooterClicked() {
val currentFolder = this.currentFolder ?: return
if (currentFolder.moreMessages && !localSearch.isManualSearch) {
@ -403,7 +390,7 @@ class MessageListFragment :
} else {
extraSearchResults = null
loadSearchResults = additionalSearchResults
updateFooter(null)
updateFooterText(null)
}
messagingController.loadSearchResults(
@ -415,10 +402,20 @@ class MessageListFragment :
}
}
private fun handleListItemClick(messageListItem: MessageListItem) {
override fun onMessageClicked(messageListItem: MessageListItem) {
if (!isActive) {
// Ignore click events that are delivered after the Fragment is no longer active. This could happen when
// the user taps two messages at almost the same time and the first tap opens a new MessageListFragment.
return
}
val clickTime = SystemClock.elapsedRealtime()
if (clickTime - lastMessageClick < MINIMUM_CLICK_INTERVAL) return
if (adapter.selectedCount > 0) {
toggleMessageSelect(messageListItem)
} else {
lastMessageClick = clickTime
if (showingThreadedList && messageListItem.threadCount > 1) {
fragmentListener.showThread(messageListItem.account, messageListItem.threadRoot)
} else {
@ -427,28 +424,17 @@ class MessageListFragment :
}
}
override fun onItemLongClick(parent: AdapterView<*>?, view: View, position: Int, id: Long): Boolean {
if (view === footerView) return false
val messageListItem = adapter.getItem(position)
toggleMessageSelect(messageListItem)
return true
}
override fun onDestroyView() {
if (isNewMessagesView && !requireActivity().isChangingConfigurations) {
messagingController.clearNewMessages(account)
}
savedListState = listView.onSaveInstanceState()
super.onDestroyView()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
saveListState(outState)
outState.putLongArray(STATE_SELECTED_MESSAGES, adapter.selected.toLongArray())
outState.putBoolean(STATE_REMOTE_SEARCH_PERFORMED, isRemoteSearch)
outState.putStringArray(
@ -460,15 +446,6 @@ class MessageListFragment :
}
}
private fun saveListState(outState: Bundle) {
if (savedListState != null) {
// The previously saved state was never restored, so just use that.
outState.putParcelable(STATE_MESSAGE_LIST, savedListState)
} else {
outState.putParcelable(STATE_MESSAGE_LIST, listView.onSaveInstanceState())
}
}
private val messageListAppearance: MessageListAppearance
get() = MessageListAppearance(
fontSizes = K9.fontSizes,
@ -792,26 +769,15 @@ class MessageListFragment :
messagingController.sendPendingMessages(account, null)
}
private fun getFooterView(parent: ViewGroup?): View? {
return footerView ?: createFooterView(parent).also { footerView = it }
}
private fun createFooterView(parent: ViewGroup?): View {
return layoutInflater.inflate(R.layout.message_list_item_footer, parent, false).apply {
tag = FooterViewHolder(this)
}
}
private fun updateFooterView() {
private fun updateFooterText() {
val currentFolder = this.currentFolder
val account = this.account
if (localSearch.isManualSearch || currentFolder == null || account == null) {
updateFooter(null)
return
}
val footerText = if (currentFolder.loading) {
val footerText = if (initialMessageListLoad) {
null
} else if (localSearch.isManualSearch || currentFolder == null || account == null) {
null
} else if (currentFolder.loading) {
getString(R.string.status_loading_more)
} else if (!currentFolder.moreMessages) {
null
@ -821,24 +787,11 @@ class MessageListFragment :
getString(R.string.load_more_messages_fmt, account.displayCount)
}
updateFooter(footerText)
updateFooterText(footerText)
}
fun updateFooter(text: String?) {
val footerView = this.footerView ?: return
val shouldHideFooter = text == null
if (shouldHideFooter) {
listView.removeFooterView(footerView)
} else {
val isFooterViewAddedToListView = listView.footerViewsCount > 0
if (!isFooterViewAddedToListView) {
listView.addFooterView(footerView)
}
}
val holder = footerView.tag as FooterViewHolder
holder.main.text = text
fun updateFooterText(text: String?) {
adapter.footerText = text
}
private fun selectAll() {
@ -1195,28 +1148,6 @@ class MessageListFragment :
super.onStop()
}
fun onMoveUp() {
var currentPosition = listView.selectedItemPosition
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode) {
currentPosition = listView.firstVisiblePosition
}
if (currentPosition > 0) {
listView.setSelection(currentPosition - 1)
}
}
fun onMoveDown() {
var currentPosition = listView.selectedItemPosition
if (currentPosition == AdapterView.INVALID_POSITION || listView.isInTouchMode) {
currentPosition = listView.firstVisiblePosition
}
if (currentPosition < listView.count) {
listView.setSelection(currentPosition + 1)
}
}
fun openMessage(messageReference: MessageReference) {
fragmentListener.openMessage(messageReference)
}
@ -1230,8 +1161,9 @@ class MessageListFragment :
private val selectedMessageListItem: MessageListItem?
get() {
val position = listView.selectedItemPosition
return if (position !in 0 until adapter.count) null else adapter.getItem(position)
val focusedView = recyclerView.focusedChild ?: return null
val viewHolder = recyclerView.findContainingViewHolder(focusedView) as? MessageViewHolder ?: return null
return adapter.getItemById(viewHolder.uniqueId)
}
private val selectedMessages: List<MessageReference>
@ -1368,16 +1300,13 @@ class MessageListFragment :
resetActionMode()
computeBatchDirection()
if (savedListState != null) {
handler.restoreListPosition(savedListState)
savedListState = null
}
invalidateMenu()
initialMessageListLoad = false
currentFolder?.let { currentFolder ->
currentFolder.moreMessages = messageListInfo.hasMoreMessages
updateFooterView()
updateFooterText()
}
}
@ -1402,6 +1331,10 @@ class MessageListFragment :
actionMode?.invalidate()
}
fun finishActionMode() {
actionMode?.finish()
}
fun remoteSearchFinished() {
remoteSearchFuture = null
}
@ -1419,7 +1352,6 @@ class MessageListFragment :
// Redraw list immediately
if (::adapter.isInitialized) {
adapter.activeMessage = activeMessage
adapter.notifyDataSetChanged()
if (messageReference != null) {
scrollToMessage(messageReference)
@ -1462,8 +1394,11 @@ class MessageListFragment :
val messageListItem = adapter.getItem(messageReference) ?: return
val position = adapter.getPosition(messageListItem) ?: return
if (position <= listView.firstVisiblePosition || position >= listView.lastVisiblePosition) {
listView.smoothScrollToPosition(position)
val linearLayoutManager = recyclerView.layoutManager as LinearLayoutManager
val firstVisiblePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
val lastVisiblePosition = linearLayoutManager.findLastCompletelyVisibleItemPosition()
if (position !in firstVisiblePosition..lastVisiblePosition) {
recyclerView.smoothScrollToPosition(position)
}
}
@ -1497,6 +1432,58 @@ class MessageListFragment :
private val isPullToRefreshAllowed: Boolean
get() = isRemoteSearchAllowed || isCheckMailAllowed
private val swipeListener = MessageListSwipeListener { item, action ->
when (action) {
SwipeAction.None -> Unit
SwipeAction.ToggleSelection -> {
toggleMessageSelect(item)
}
SwipeAction.ToggleRead -> {
setFlag(item, Flag.SEEN, !item.isRead)
}
SwipeAction.ToggleStar -> {
setFlag(item, Flag.FLAGGED, !item.isStarred)
}
SwipeAction.Archive -> {
onArchive(item.messageReference)
}
SwipeAction.Delete -> {
if (K9.isConfirmDelete) {
notifyItemChanged(item)
}
onDelete(listOf(item.messageReference))
}
SwipeAction.Spam -> {
if (K9.isConfirmSpam) {
notifyItemChanged(item)
}
onSpam(listOf(item.messageReference))
}
SwipeAction.Move -> {
notifyItemChanged(item)
onMove(item.messageReference)
}
}
}
private fun notifyItemChanged(item: MessageListItem) {
val position = adapter.getPosition(item) ?: return
adapter.notifyItemChanged(position)
}
private val swipeActionSupportProvider = SwipeActionSupportProvider { item, action ->
when (action) {
SwipeAction.None -> false
SwipeAction.ToggleSelection -> true
SwipeAction.ToggleRead -> !isOutbox
SwipeAction.ToggleStar -> !isOutbox
SwipeAction.Archive -> !isOutbox && item.account.hasArchiveFolder()
SwipeAction.Delete -> true
SwipeAction.Move -> !isOutbox && messagingController.isMoveCapable(item.account)
SwipeAction.Spam -> !isOutbox && item.account.hasSpamFolder() && item.folderId != item.account.spamFolderId
}
}
internal inner class MessageListActivityListener : SimpleMessagingListener() {
private val lock = Any()
@ -1839,10 +1826,6 @@ class MessageListFragment :
}
}
internal class FooterViewHolder(view: View) {
val main: TextView = view.findViewById(R.id.main_text)
}
private enum class FolderOperation {
COPY, MOVE
}
@ -1876,7 +1859,6 @@ class MessageListFragment :
private const val STATE_ACTIVE_MESSAGES = "activeMessages"
private const val STATE_ACTIVE_MESSAGE = "activeMessage"
private const val STATE_REMOTE_SEARCH_PERFORMED = "remoteSearchPerformed"
private const val STATE_MESSAGE_LIST = "listState"
fun newInstance(search: LocalSearch, isThreadDisplay: Boolean, threadedList: Boolean): MessageListFragment {
return MessageListFragment().apply {

View file

@ -1,4 +1,4 @@
package com.fsck.k9.fragment;
package com.fsck.k9.ui.messagelist;
import java.lang.ref.WeakReference;
@ -57,7 +57,7 @@ public class MessageListHandler extends Handler {
public void run() {
MessageListFragment fragment = mFragment.get();
if (fragment != null) {
fragment.updateFooter(message);
fragment.updateFooterText(message);
}
}
});

View file

@ -0,0 +1,17 @@
package com.fsck.k9.ui.messagelist
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.RecyclerView.ViewHolder
class MessageListItemAnimator : DefaultItemAnimator() {
init {
supportsChangeAnimations = false
changeDuration = 120
}
override fun canReuseUpdatedViewHolder(viewHolder: ViewHolder, payloads: MutableList<Any>): Boolean {
// ItemTouchHelper expects swiped views to be removed from the view hierarchy. So we don't reuse views that are
// marked as having been swiped.
return !viewHolder.wasSwiped && super.canReuseUpdatedViewHolder(viewHolder, payloads)
}
}

View file

@ -0,0 +1,52 @@
package com.fsck.k9.ui.messagelist
import android.content.Context
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import androidx.core.graphics.withSave
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import com.fsck.k9.ui.resolveDrawableAttribute
import kotlin.math.roundToInt
/**
* An [ItemDecoration] that uses the alpha and visibility values of a view when drawing the divider.
*
* Based on [androidx.recyclerview.widget.DividerItemDecoration].
*/
class MessageListItemDecoration(context: Context) : ItemDecoration() {
private val divider: Drawable = context.theme.resolveDrawableAttribute(android.R.attr.listDivider)
private val bounds = Rect()
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null) return
canvas.withSave {
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
if (!child.isVisible) {
continue
}
parent.getDecoratedBoundsWithMargins(child, bounds)
val left = 0
val right = parent.width
val bottom = bounds.bottom + child.translationY.roundToInt()
val top = bottom - divider.intrinsicHeight
divider.setBounds(left, top, right, bottom)
divider.alpha = (child.alpha * 255).toInt()
divider.draw(canvas)
}
}
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
outRect.set(0, 0, 0, divider.intrinsicHeight)
}
}

View file

@ -0,0 +1,172 @@
package com.fsck.k9.ui.messagelist
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Paint
import android.view.View
import androidx.core.graphics.withSave
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.fsck.k9.SwipeAction
import com.fsck.k9.ui.R
import kotlin.math.abs
class MessageListSwipeCallback(
resources: Resources,
private val resourceProvider: SwipeResourceProvider,
private val swipeActionSupportProvider: SwipeActionSupportProvider,
private val swipeRightAction: SwipeAction,
private val swipeLeftAction: SwipeAction,
private val adapter: MessageListAdapter,
private val listener: MessageListSwipeListener
) : ItemTouchHelper.Callback() {
private val iconPadding = resources.getDimension(R.dimen.messageListSwipeIconPadding).toInt()
private val swipeThreshold = resources.getDimension(R.dimen.messageListSwipeThreshold)
private val backgroundColorPaint = Paint()
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: ViewHolder): Int {
if (viewHolder !is MessageViewHolder) return 0
val item = adapter.getItemById(viewHolder.uniqueId) ?: return 0
var swipeFlags = 0
if (swipeActionSupportProvider.isActionSupported(item, swipeRightAction)) {
swipeFlags = swipeFlags or ItemTouchHelper.RIGHT
}
if (swipeActionSupportProvider.isActionSupported(item, swipeLeftAction)) {
swipeFlags = swipeFlags or ItemTouchHelper.LEFT
}
return makeMovementFlags(0, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: ViewHolder,
target: ViewHolder
): Boolean {
throw UnsupportedOperationException("not implemented")
}
override fun onSwiped(viewHolder: ViewHolder, direction: Int) {
val holder = viewHolder as MessageViewHolder
val item = adapter.getItemById(holder.uniqueId) ?: error("Couldn't find MessageListItem")
// ItemTouchHelper expects swiped views to be removed from the view hierarchy. We mark this ViewHolder so that
// MessageListItemAnimator knows not to reuse it during an animation.
viewHolder.markAsSwiped(true)
when (direction) {
ItemTouchHelper.RIGHT -> listener.onSwipeAction(item, swipeRightAction)
ItemTouchHelper.LEFT -> listener.onSwipeAction(item, swipeLeftAction)
else -> error("Unsupported direction: $direction")
}
}
override fun clearView(recyclerView: RecyclerView, viewHolder: ViewHolder) {
super.clearView(recyclerView, viewHolder)
viewHolder.markAsSwiped(false)
}
override fun getSwipeThreshold(viewHolder: ViewHolder): Float {
return swipeThreshold / viewHolder.itemView.width
}
override fun onChildDraw(
canvas: Canvas,
recyclerView: RecyclerView,
viewHolder: ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
canvas.withSave {
val view = viewHolder.itemView
val holder = viewHolder as MessageViewHolder
val item = adapter.getItemById(holder.uniqueId) ?: return@withSave
val swipeThreshold = recyclerView.width * getSwipeThreshold(holder)
val swipeThresholdReached = abs(dX) > swipeThreshold
if (swipeThresholdReached) {
val action = if (dX > 0) swipeRightAction else swipeLeftAction
val backgroundColor = resourceProvider.getBackgroundColor(item, action)
drawBackground(view, backgroundColor)
} else {
val backgroundColor = resourceProvider.getBackgroundColor(item, SwipeAction.None)
drawBackground(view, backgroundColor)
}
// Stop drawing the icon when the view has been animated all the way off the screen by ItemTouchHelper.
// We do this so the icon doesn't switch state when RecyclerView's ItemAnimator animates the view back after
// a toggle action (mark as read/unread, add/remove star) was used.
if (isCurrentlyActive || abs(dX).toInt() < view.width) {
drawIcon(dX, view, item, swipeThresholdReached)
}
}
super.onChildDraw(canvas, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
private fun Canvas.drawBackground(view: View, color: Int) {
backgroundColorPaint.color = color
drawRect(
view.left.toFloat(),
view.top.toFloat(),
view.right.toFloat(),
view.bottom.toFloat(),
backgroundColorPaint
)
}
private fun Canvas.drawIcon(dX: Float, view: View, item: MessageListItem, swipeThresholdReached: Boolean) {
if (dX > 0) {
drawSwipeRightIcon(view, item, swipeThresholdReached)
} else {
drawSwipeLeftIcon(view, item, swipeThresholdReached)
}
}
private fun Canvas.drawSwipeRightIcon(view: View, item: MessageListItem, swipeThresholdReached: Boolean) {
resourceProvider.getIcon(item, swipeRightAction)?.let { icon ->
val iconLeft = iconPadding
val iconTop = view.top + ((view.height - icon.intrinsicHeight) / 2)
val iconRight = iconLeft + icon.intrinsicWidth
val iconBottom = iconTop + icon.intrinsicHeight
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
icon.setTint(resourceProvider.getIconTint(item, swipeRightAction, swipeThresholdReached))
icon.draw(this)
}
}
private fun Canvas.drawSwipeLeftIcon(view: View, item: MessageListItem, swipeThresholdReached: Boolean) {
resourceProvider.getIcon(item, swipeLeftAction)?.let { icon ->
val iconRight = view.right - iconPadding
val iconLeft = iconRight - icon.intrinsicWidth
val iconTop = view.top + ((view.height - icon.intrinsicHeight) / 2)
val iconBottom = iconTop + icon.intrinsicHeight
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
icon.setTint(resourceProvider.getIconTint(item, swipeLeftAction, swipeThresholdReached))
icon.draw(this)
}
}
}
fun interface SwipeActionSupportProvider {
fun isActionSupported(item: MessageListItem, action: SwipeAction): Boolean
}
fun interface MessageListSwipeListener {
fun onSwipeAction(item: MessageListItem, action: SwipeAction)
}
private fun ViewHolder.markAsSwiped(value: Boolean) {
itemView.setTag(R.id.message_list_swipe_tag, if (value) true else null)
}
val ViewHolder.wasSwiped
get() = itemView.getTag(R.id.message_list_swipe_tag) == true

View file

@ -1,12 +1,15 @@
package com.fsck.k9.fragment
package com.fsck.k9.ui.messagelist
import android.view.View
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.fsck.k9.ui.R
class MessageViewHolder(view: View) {
sealed class MessageListViewHolder(view: View) : ViewHolder(view)
class MessageViewHolder(view: View) : MessageListViewHolder(view) {
var uniqueId: Long = -1L
val selected: View = view.findViewById(R.id.selected)
@ -20,3 +23,7 @@ class MessageViewHolder(view: View) {
val attachment: ImageView = view.findViewById(R.id.attachment)
val status: ImageView = view.findViewById(R.id.status)
}
class FooterViewHolder(view: View) : MessageListViewHolder(view) {
val text: TextView = view.findViewById(R.id.main_text)
}

View file

@ -1,4 +1,4 @@
package com.fsck.k9.fragment;
package com.fsck.k9.ui.messagelist;
import java.util.List;

View file

@ -1,4 +1,4 @@
package com.fsck.k9.fragment
package com.fsck.k9.ui.messagelist
import com.fsck.k9.Account.SortType
import com.fsck.k9.Account.SortType.SORT_ARRIVAL

View file

@ -0,0 +1,72 @@
package com.fsck.k9.ui.messagelist
import android.content.res.Resources.Theme
import android.graphics.drawable.Drawable
import androidx.annotation.AttrRes
import com.fsck.k9.SwipeAction
import com.fsck.k9.ui.R
import com.fsck.k9.ui.resolveColorAttribute
import com.fsck.k9.ui.resolveDrawableAttribute
class SwipeResourceProvider(val theme: Theme) {
private val iconTint = theme.resolveColorAttribute(R.attr.messageListSwipeIconTint)
private val selectIcon = theme.loadDrawable(R.attr.messageListSwipeSelectIcon)
private val markAsReadIcon = theme.loadDrawable(R.attr.messageListSwipeMarkAsReadIcon)
private val markAsUnreadIcon = theme.loadDrawable(R.attr.messageListSwipeMarkAsUnreadIcon)
private val addStarIcon = theme.loadDrawable(R.attr.messageListSwipeAddStarIcon)
private val removeStarIcon = theme.loadDrawable(R.attr.messageListSwipeRemoveStarIcon)
private val archiveIcon = theme.loadDrawable(R.attr.messageListSwipeArchiveIcon)
private val deleteIcon = theme.loadDrawable(R.attr.messageListSwipeDeleteIcon)
private val spamIcon = theme.loadDrawable(R.attr.messageListSwipeSpamIcon)
private val moveIcon = theme.loadDrawable(R.attr.messageListSwipeMoveIcon)
private val noActionColor = theme.resolveColorAttribute(R.attr.messageListSwipeDisabledBackgroundColor)
private val selectColor = theme.resolveColorAttribute(R.attr.messageListSwipeSelectBackgroundColor)
private val markAsReadColor = theme.resolveColorAttribute(R.attr.messageListSwipeMarkAsReadBackgroundColor)
private val markAsUnreadColor = theme.resolveColorAttribute(R.attr.messageListSwipeMarkAsUnreadBackgroundColor)
private val addStarColor = theme.resolveColorAttribute(R.attr.messageListSwipeAddStarBackgroundColor)
private val removeStarColor = theme.resolveColorAttribute(R.attr.messageListSwipeRemoveStarBackgroundColor)
private val archiveColor = theme.resolveColorAttribute(R.attr.messageListSwipeArchiveBackgroundColor)
private val deleteColor = theme.resolveColorAttribute(R.attr.messageListSwipeDeleteBackgroundColor)
private val spamColor = theme.resolveColorAttribute(R.attr.messageListSwipeSpamBackgroundColor)
private val moveColor = theme.resolveColorAttribute(R.attr.messageListSwipeMoveBackgroundColor)
fun getIconTint(item: MessageListItem, action: SwipeAction, swipeThresholdReached: Boolean): Int {
return if (swipeThresholdReached) {
iconTint
} else {
getBackgroundColor(item, action)
}
}
fun getIcon(item: MessageListItem, action: SwipeAction): Drawable? {
return when (action) {
SwipeAction.None -> null
SwipeAction.ToggleSelection -> selectIcon
SwipeAction.ToggleRead -> if (item.isRead) markAsUnreadIcon else markAsReadIcon
SwipeAction.ToggleStar -> if (item.isStarred) removeStarIcon else addStarIcon
SwipeAction.Archive -> archiveIcon
SwipeAction.Delete -> deleteIcon
SwipeAction.Spam -> spamIcon
SwipeAction.Move -> moveIcon
}
}
fun getBackgroundColor(item: MessageListItem, action: SwipeAction): Int {
return when (action) {
SwipeAction.None -> noActionColor
SwipeAction.ToggleSelection -> selectColor
SwipeAction.ToggleRead -> if (item.isRead) markAsUnreadColor else markAsReadColor
SwipeAction.ToggleStar -> if (item.isStarred) removeStarColor else addStarColor
SwipeAction.Archive -> archiveColor
SwipeAction.Delete -> deleteColor
SwipeAction.Spam -> spamColor
SwipeAction.Move -> moveColor
}
}
}
private fun Theme.loadDrawable(@AttrRes attributeId: Int): Drawable {
return resolveDrawableAttribute(attributeId).mutate()
}

View file

@ -110,8 +110,8 @@ public class OpenPgpAppSelectDialog extends K9Activity {
Context context = getActivity();
OpenPgpProviderEntry noneEntry = new OpenPgpProviderEntry(null,
context.getString(R.string.openpgp_list_preference_none),
getResources().getDrawable(R.drawable.ic_action_cancel_launchersize_light));
context.getString(org.openintents.openpgp.R.string.openpgp_list_preference_none),
getResources().getDrawable(org.openintents.openpgp.R.drawable.ic_action_cancel_launchersize_light));
openPgpProviderList.add(noneEntry);
// search for OpenPGP providers...
@ -144,8 +144,9 @@ public class OpenPgpAppSelectDialog extends K9Activity {
Drawable icon = resolveInfo.activityInfo.loadIcon(context.getPackageManager());
String marketName = String.valueOf(resolveInfo.activityInfo.applicationInfo
.loadLabel(context.getPackageManager()));
String simpleName = String.format(context.getString(R.string
.openpgp_install_openkeychain_via), marketName);
String simpleName = String.format(
context.getString(org.openintents.openpgp.R.string.openpgp_install_openkeychain_via),
marketName);
openPgpProviderList.add(new OpenPgpProviderEntry(OPENKEYCHAIN_PACKAGE, simpleName,
icon, marketIntent));
}

View file

@ -2,6 +2,7 @@ package com.fsck.k9.ui.settings.general
import androidx.preference.PreferenceDataStore
import com.fsck.k9.K9
import com.fsck.k9.SwipeAction
import com.fsck.k9.job.K9JobManager
import com.fsck.k9.preferences.AppTheme
import com.fsck.k9.preferences.GeneralSettingsManager
@ -41,6 +42,7 @@ class GeneralSettingsDataStore(
"privacy_hide_timezone" -> K9.isHideTimeZone
"debug_logging" -> K9.isDebugLoggingEnabled
"sensitive_logging" -> K9.isSensitiveDebugLoggingEnabled
"volume_navigation" -> K9.isUseVolumeKeysForNavigation
else -> defValue
}
}
@ -70,6 +72,7 @@ class GeneralSettingsDataStore(
"privacy_hide_timezone" -> K9.isHideTimeZone = value
"debug_logging" -> K9.isDebugLoggingEnabled = value
"sensitive_logging" -> K9.isSensitiveDebugLoggingEnabled = value
"volume_navigation" -> K9.isUseVolumeKeysForNavigation = value
else -> return
}
@ -123,6 +126,8 @@ class GeneralSettingsDataStore(
"message_view_date_font" -> K9.fontSizes.messageViewDate.toString()
"message_view_additional_headers_font" -> K9.fontSizes.messageViewAdditionalHeaders.toString()
"message_compose_input_font" -> K9.fontSizes.messageComposeInput.toString()
"swipe_action_right" -> swipeActionToString(K9.swipeRightAction)
"swipe_action_left" -> swipeActionToString(K9.swipeLeftAction)
else -> defValue
}
}
@ -162,6 +167,8 @@ class GeneralSettingsDataStore(
"message_view_date_font" -> K9.fontSizes.messageViewDate = value.toInt()
"message_view_additional_headers_font" -> K9.fontSizes.messageViewAdditionalHeaders = value.toInt()
"message_compose_input_font" -> K9.fontSizes.messageComposeInput = value.toInt()
"swipe_action_right" -> K9.swipeRightAction = stringToSwipeAction(value)
"swipe_action_left" -> K9.swipeLeftAction = stringToSwipeAction(value)
else -> return
}
@ -189,12 +196,6 @@ class GeneralSettingsDataStore(
if (K9.isMessageViewSpamActionVisible) add("spam")
}
}
"volume_navigation" -> {
mutableSetOf<String>().apply {
if (K9.isUseVolumeKeysForNavigation) add("message")
if (K9.isUseVolumeKeysForListNavigation) add("list")
}
}
else -> defValues
}
}
@ -217,10 +218,6 @@ class GeneralSettingsDataStore(
K9.isMessageViewCopyActionVisible = "copy" in checkedValues
K9.isMessageViewSpamActionVisible = "spam" in checkedValues
}
"volume_navigation" -> {
K9.isUseVolumeKeysForNavigation = "message" in checkedValues
K9.isUseVolumeKeysForListNavigation = "list" in checkedValues
}
else -> return
}
@ -288,4 +285,27 @@ class GeneralSettingsDataStore(
jobManager.scheduleAllMailJobs()
}
}
private fun swipeActionToString(action: SwipeAction) = when (action) {
SwipeAction.None -> "none"
SwipeAction.ToggleSelection -> "toggle_selection"
SwipeAction.ToggleRead -> "toggle_read"
SwipeAction.ToggleStar -> "toggle_star"
SwipeAction.Archive -> "archive"
SwipeAction.Delete -> "delete"
SwipeAction.Spam -> "spam"
SwipeAction.Move -> "move"
}
private fun stringToSwipeAction(action: String) = when (action) {
"none" -> SwipeAction.None
"toggle_selection" -> SwipeAction.ToggleSelection
"toggle_read" -> SwipeAction.ToggleRead
"toggle_star" -> SwipeAction.ToggleStar
"archive" -> SwipeAction.Archive
"delete" -> SwipeAction.Delete
"spam" -> SwipeAction.Spam
"move" -> SwipeAction.Move
else -> throw AssertionError()
}
}

View file

@ -14,6 +14,7 @@ import com.google.android.material.snackbar.Snackbar
import com.takisoft.preferencex.PreferenceFragmentCompat
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import com.fsck.k9.core.R as CoreR
class GeneralSettingsFragment : PreferenceFragmentCompat() {
private val viewModel: GeneralSettingsViewModel by viewModel()
@ -74,7 +75,7 @@ class GeneralSettingsFragment : PreferenceFragmentCompat() {
(findPreference(PREFERENCE_THEME) as? ListPreference)?.apply {
if (Build.VERSION.SDK_INT < 28) {
setEntries(R.array.theme_entries_legacy)
setEntryValues(R.array.theme_values_legacy)
setEntryValues(CoreR.array.theme_values_legacy)
}
}
}

View file

@ -5,7 +5,7 @@ import android.content.Context
import android.util.AttributeSet
import androidx.core.content.res.TypedArrayUtils
import androidx.preference.ListPreference
import com.fsck.k9.ui.R
import com.fsck.k9.core.R
class LanguagePreference
@JvmOverloads

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:viewportWidth="28"
android:viewportHeight="28">
<path
android:fillColor="@android:color/white"
android:pathData="M14,14c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM14,16c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM14,18v-3h-4v-4h4L14,8l5,5 -5,5z" />
</vector>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_selected="true"
android:drawable="@color/message_list_item_footer_background" />
<item android:state_selected="true"
android:drawable="@android:color/transparent" />
<item android:state_pressed="true" android:state_selected="false"
android:drawable="@android:color/transparent" />
<item android:state_selected="false"
android:drawable="@android:color/transparent"
/>
</selector>

View file

@ -1,18 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.fsck.k9.fragment.MessageListFragment">
tools:context=".messagelist.MessageListFragment">
<ListView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/message_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5"
android:scrollbars="vertical"
android:scrollbarStyle="insideOverlay"
android:fadingEdge="none"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/message_list_item"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View file

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
tools:layout_height="?android:attr/listPreferredItemHeight"

View file

@ -4,7 +4,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:background="@drawable/message_list_item_footer_background"
android:background="?attr/messageListRegularItemBackgroundColor"
android:foreground="?attr/selectableItemBackground"
android:gravity="center"
android:orientation="horizontal">
<TextView

View file

@ -5,6 +5,26 @@
Locale-specific versions are kept in res/raw-<locale qualifier>/changelog.xml.
-->
<changelog>
<release version="6.308" versioncode="33008" date="2022-10-06">
<change>Added swipe actions to the message list screen</change>
<change>Changed the minimum size of the message list widget to 2x2 cells</change>
<change>Fixed a bug where the app would start using the light theme before switching to the dark theme resulting in a brief flash of white</change>
<change>More minor bug fixes and improvements</change>
<change>Updated translations</change>
</release>
<release version="6.307" versioncode="33007" date="2022-09-26">
<change>Fixed the message list background color in the dark theme</change>
<change>Fixed a small display issue where "Load up to X more" could have been displayed when it shouldn't have been</change>
<change>Updated translations</change>
</release>
<release version="6.306" versioncode="33006" date="2022-09-23">
<change>Added a monochromatic app icon for Android 13</change>
<change>Changed the UI component used for the message list; now changes to the list will be animated</change>
<change>Removed the volume key navigation for list views because it doesn't play nice with the above change</change>
<change>Fixed a bug that lead to the search input field being focused on app start on some devices</change>
<change>Restored the previous behavior of "show next message after delete"</change>
<change>A lot of internal changes and some minor performance improvements</change>
</release>
<release version="6.305" versioncode="33005" date="2022-09-17">
<change>Fixed a bug that could lead to a crash when opening the message list</change>
</release>

View file

@ -567,7 +567,6 @@
<string name="account_setup_push_limit_500">500 مجلد</string>
<string name="account_setup_push_limit_1000">1000 مجلد</string>
<string name="animations_title">الحركة</string>
<string name="volume_navigation_title">التصفح عبر أزرار التحكم في الصوت</string>
<string name="integrated_inbox_title">البريد الوارد الموحَّد</string>
<string name="integrated_inbox_detail">كل الرسائل في مجلدات موحَّدة</string>
<string name="folder_settings_include_in_integrated_inbox_label">التوحيد</string>

View file

@ -579,8 +579,6 @@ K-9 Mail - шматфункцыянальны свабодны паштовы к
<string name="account_setup_failed_dlg_invalid_certificate_title">Нераспазнаны сертыфікат</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Ухваліць</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Адхіліць</string>
<string name="message_view_help_key">Del (ці D) - Выдаліць\nR - Адказаць\nA - Адказаць усім\nC - Стварыць\nF - Пераслаць\nM - Перамясціць\nV - Адправіць у архіў\nY - Скапіяваць\nZ - Пазначыць (не)прачытаным\nG - Адзначыць\nO - Тып сартавання\nI - Парадак сартавання\nQ - Вярнуцца да каталогаў\nS - Абраць / Адкінуць выбар\nJ альбо P - Папярэдні ліст\nK альбо N - Наступны ліст</string>
<string name="message_list_help_key">Del (ці D) - Выдаліць\nC - Стварыць\nF - Пераслаць\nM - Перамясціць\nV - Адправіць у архіў\nY - Скапіяваць\nZ - Пазначыць (не)прачытаным\nG - Адзначыць\nO - Тып сартавання\nI - Парадак сартавання\nQ - Вярнуцца да каталогаў\nS - Абраць / Адкінуць выбар</string>
<string name="folder_list_filter_hint">Пошук каталога</string>
<string name="folder_list_display_mode_label">Паказваць каталогі…</string>
<string name="folder_list_display_mode_all">Усе каталогі</string>
@ -628,9 +626,6 @@ K-9 Mail - шматфункцыянальны свабодны паштовы к
<string name="account_setup_push_limit_1000">1000 каталогаў</string>
<string name="animations_title">Анімацыя</string>
<string name="animations_summary">Анімацыя інтэрфейсу</string>
<string name="volume_navigation_title">Навігацыя клавішамі гучнасці</string>
<string name="volume_navigation_message">У лісце</string>
<string name="volume_navigation_list">У спісе</string>
<string name="show_unified_inbox_title">Агульная скрыня ўваходных лістоў для ўсіх акаўнтаў</string>
<string name="integrated_inbox_title">Усе атрыманыя</string>
<string name="integrated_inbox_detail">Усе лісты са ўсіх каталогаў</string>

View file

@ -576,8 +576,6 @@ K-9 Mail е мощен, безплатен имейл клиент за Андр
<string name="account_setup_failed_dlg_invalid_certificate_title">Неразпознат сертификат</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Приеми ключа</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Отхвърли ключа</string>
<string name="message_view_help_key">Del (or D) - Изтриване\nR - Отговор\nA - Отговор на всички\nC - Създаване\nF - Препращане\nM - Премесване\nV - Архивиране\nY - Копиране\nZ - Отбелязване като (не)прочетно\nG - Звезда\nO - Сортиране\nI - Приоритет на сортиране\nQ - Обратно към папките\nS - Отбелязване/премахване на отбелязване\nJ или P - Предно съобщение\nK или N - Следващо съобщение</string>
<string name="message_list_help_key">Del (or D) - Изтриване\nC - Създаване\nM - Премесване\nV - Архивиране\nC - Копиране\nZ - Отбелязване като (не)прочетно\nG - Звезда\nO - Сортиране\nI - Приоритет на сортиране\nQ - Обратно към папките\nS - Отбелязване/премахване на отбелязване</string>
<string name="folder_list_filter_hint">Името на папката съдържа</string>
<string name="folder_list_display_mode_label">Покажи папките…</string>
<string name="folder_list_display_mode_all">Всички папки</string>
@ -625,9 +623,6 @@ K-9 Mail е мощен, безплатен имейл клиент за Андр
<string name="account_setup_push_limit_1000">1000 папки</string>
<string name="animations_title">Анимация</string>
<string name="animations_summary">Изплозване на ярки виулани ефекти</string>
<string name="volume_navigation_title">Навигация с клавиш за звука</string>
<string name="volume_navigation_message">В преглед на съобщението</string>
<string name="volume_navigation_list">В списъка със съобщения</string>
<string name="show_unified_inbox_title">Покажи унифицирана папка Входящи</string>
<string name="integrated_inbox_title">Обща входяща кутия</string>
<string name="integrated_inbox_detail">Всички съобщения в общата входяща кутия</string>

View file

@ -550,8 +550,6 @@ Danevellit beugoù, kenlabourit war keweriusterioù nevez ha savit goulennoù wa
<string name="account_setup_failed_dlg_invalid_certificate_title">Testeni dianav</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Asantiñ an alchwez</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Nach an alchwez</string>
<string name="message_view_help_key">Del (pe D) - Dilemel\nR - Respont\nA - Respont dan holl\nC - Skridaozañ\nF - Treuzkas\nM - Dilechiañ\nV - Diellaouiñ\nY - Eilañ\nZ - Merkañ evel (An)lennet\nG - Steredenniñ\nO - Doare urzhiañ\nI - Tu an urzh\nQ - Distreiñ dan teuliadoù\nS - (Di)ziuzañ\nJ or P - Kemennadenn gent\nK pe N - Kemennadenn da heul</string>
<string name="message_list_help_key">Del (pe D) - Dilemel\nC - Skridaozañ\nM - Dilechiañ\nV - Diellaouiñ\nY - Eilañ\nZ - Merkañ evel (An)Lennet\nG - Steredenniñ\nO - Doare urzhiañ\nI - Tu an urzhiañ\nQ - Distreiñ dan teuliadoù\nS - (Di)ziuzañ</string>
<string name="folder_list_filter_hint">Anv an teuliad a endalch</string>
<string name="folder_list_display_mode_label">Diskouez an teuliadoù</string>
<string name="folder_list_display_mode_all">An holl deuliadoù</string>
@ -597,9 +595,6 @@ Danevellit beugoù, kenlabourit war keweriusterioù nevez ha savit goulennoù wa
<string name="account_setup_push_limit_1000">1000 teuliad</string>
<string name="animations_title">Bliverezh</string>
<string name="animations_summary">Ober gant efedoù gwel gaudy</string>
<string name="volume_navigation_title">Merdeiñ dre afelloù an ampled</string>
<string name="volume_navigation_message">Er gwel kemennadenn</string>
<string name="volume_navigation_list">Er gwel roll</string>
<string name="integrated_inbox_title">Boest degemer unanet</string>
<string name="integrated_inbox_detail">Holl gemennadennoù an teuliadoù unanet</string>
<string name="folder_settings_include_in_integrated_inbox_label">Unanañ</string>

View file

@ -633,8 +633,6 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
<string name="account_setup_failed_dlg_invalid_certificate_title">Certificat no reconegut</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accepta la clau</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Rebutja la clau</string>
<string name="message_view_help_key">Del (o D) - Elimina\nR - Respon\nA - Respon a tothom\nC - Escriu\nF - Reenvia\nM - Mou\nV - Arxiva\nY - Copia\nZ - Marca com a (no) llegit\nG - Estel\nO - Per tipus\nI - Per ordre\nQ - Torna a les carpetes\nS - Selecciona / desmarca\nJ o P - Missatge anterior n\K o N - Missatge següent</string>
<string name="message_list_help_key">Del (o D) - Elimina\nC - Escriu\nM - Mou\nV - Arxiva\nY - Copia\nZ - Marca com a (no) llegit\nG - Estel\nO - Tipus de classificació\nI - Ordre de classificació\nQ - Torna a les carpetes\nS - Selecciona / desmarca</string>
<string name="folder_list_filter_hint">El nom de carpeta conté</string>
<string name="folder_list_display_mode_label">Carpetes…</string>
<string name="folder_list_display_mode_all">Mostra totes les carpetes</string>
@ -682,9 +680,7 @@ Si us plau, envieu informes d\'errors, contribuïu-hi amb noves millores i feu p
<string name="account_setup_push_limit_1000">1000 carpetes</string>
<string name="animations_title">Animació</string>
<string name="animations_summary">Utilitza efectes visuals cridaners</string>
<string name="volume_navigation_title">Navegació amb botons de volum</string>
<string name="volume_navigation_message">Vista del missatge</string>
<string name="volume_navigation_list">A la vista de llistes</string>
<string name="volume_navigation_title">Navegació amb la tecla de volum a la vista de missatges</string>
<string name="show_unified_inbox_title">Mostra la safata d\'entrada unificada</string>
<string name="show_starred_count_title">Mostra el recompte de destacats.</string>
<string name="integrated_inbox_title">Bústia unificada</string>

View file

@ -95,7 +95,7 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
<string name="single_message_options_action">Odeslat…</string>
<string name="refile_action">Přesměrovat…</string>
<string name="done_action">Hotovo</string>
<string name="discard_action">Zrušit</string>
<string name="discard_action">Zahodit</string>
<string name="save_draft_action">Uložit jako koncept</string>
<string name="check_mail_action">Zkontrolovat poštu</string>
<string name="send_messages_action">Odeslat zprávy</string>
@ -637,8 +637,6 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
<string name="account_setup_failed_dlg_invalid_certificate_title">Nerozpoznaný certifikát</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Přijmout klíč</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Odmítnout klíč</string>
<string name="message_view_help_key">Delete (nebo D) Smazat\nR Odpovědět\nA Odpovědět všem\nC Vytvořit\nF Přeposlat\nM Přesunout\nV - Archivovat\nY Kopírovat\nZ Označit (Ne)přečtené\nG Hvězdička\nO Uspořádat podle typu\nI Uspořádat podle pořadí\nQ Zpět ke složkám\nS Označit/odznačit\nJ nebo P Předešlá zpráva\nK nebo N Další zpráva</string>
<string name="message_list_help_key">Delete (nebo D) Smazat\nC Vytvořit\nM Přesunout\nV Archivovat\nY Zkopírovat\nZ Označit jako (ne)přečtené\nG Označit hvězdičkou\nO Typ řazení\nI Pořadí řazení\nQ Návrat na složky\nS Označit / zrušit označení</string>
<string name="folder_list_filter_hint">Název složky obsahuje</string>
<string name="folder_list_display_mode_label">Zobrazit složky…</string>
<string name="folder_list_display_mode_all">Všechny složky</string>
@ -686,9 +684,6 @@ Hlášení o chyb, úpravy pro nové funkce a dotazy zadávejte prostřednictví
<string name="account_setup_push_limit_1000">1000 složek</string>
<string name="animations_title">Animace</string>
<string name="animations_summary">Používat okázalé vizuální efekty</string>
<string name="volume_navigation_title">Navigace tlačítky hlasitosti</string>
<string name="volume_navigation_message">Zobrazení zpráv</string>
<string name="volume_navigation_list">Různá zobrazení seznamů</string>
<string name="show_unified_inbox_title">Ukázat sjednocený pohled na doručenou poštu</string>
<string name="show_starred_count_title">Zobrazit počet označených hvězdičkou</string>
<string name="integrated_inbox_title">Integrovaná doručená pošta</string>

View file

@ -12,7 +12,10 @@
<string name="app_license">Trwydded Apache, Fersiwn 2.0</string>
<string name="about_project_title">Prosiect Cod Agored</string>
<string name="about_website_title">Gwefan</string>
<string name="user_manual_title">Llawlyfr defnyddiwr</string>
<string name="get_help_title">Cael cymorth</string>
<string name="user_forum_title">Fforwm defnyddiwyr</string>
<string name="about_fediverse_title">Fediverse</string>
<string name="about_twitter_title">Twitter</string>
<string name="about_libraries">Llyfrgelloedd</string>
<string name="license">Trwydded</string>
@ -71,7 +74,7 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="choose_account_title">Dewis cyfrif</string>
<string name="choose_folder_title">Dewis ffolder</string>
<string name="choose_folder_move_title">Symud i...</string>
<string name="choose_folder_copy_title">Copïo i...</string>
<string name="choose_folder_copy_title">Copïo i</string>
<string name="actionbar_selected"><xliff:g id="selection_count">%d</xliff:g> wedi\'i dewis</string>
<string name="next_action">Nesaf</string>
<string name="previous_action">Blaenorol</string>
@ -171,7 +174,9 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="notification_authentication_error_title">Methwyd a dilysu</string>
<string name="notification_authentication_error_text">Methodd y dilysiad ar gyfer <xliff:g id="account">%s</xliff:g>. Diweddara dy osodiadau gweinydd.</string>
<!--Title of an error notification that is displayed when creating a notification for a new message has failed-->
<string name="notification_notify_error_title">Gwall hysbysiad</string>
<!--Body of an error notification that is displayed when creating a notification for a new message has failed-->
<string name="notification_notify_error_text">Bu gwall wrth geisio creu hysbysiad system am neges newydd. Mae\'n debyg mai\'r rheswm yw bod sain hysbysiad ar goll.\n\nTapia i agor gosodiadau hysbysiadau.</string>
<string name="notification_bg_sync_ticker">Yn gwirio am negeseuon: <xliff:g id="account">%1$s</xliff:g>:<xliff:g id="folder">%2$s</xliff:g></string>
<string name="notification_bg_sync_title">Yn gwirio am negeseuon</string>
<string name="notification_bg_send_ticker">Yn anfon negeseuon: <xliff:g id="account">%s</xliff:g></string>
@ -196,7 +201,7 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="debug_enable_sensitive_logging_summary">Gall dangos cyfrineiriau mewn logiau.</string>
<string name="debug_export_logs_title">Allforio logiau</string>
<string name="debug_export_logs_success">Allforiwyd yn llwyddiannus. Gall logiau gynnwys gwybodaeth sensitif. Byddwch yn ofalus gyda phwy rydych yn eu rhannu.</string>
<string name="debug_export_logs_failure">Methwyd yr allforio.</string>
<string name="debug_export_logs_failure">Methodd yr allforio.</string>
<string name="message_list_load_more_messages_action">Llwytho rhagor o negeseuon</string>
<string name="message_to_fmt">At:<xliff:g id="counterParty">%s</xliff:g></string>
<string name="message_compose_subject_hint">Pwnc</string>
@ -397,6 +402,7 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="account_setup_failed_dlg_server_message_fmt">Methwyd cysylltu gyda\'r gweinydd.\n(<xliff:g id="error">%s</xliff:g>)</string>
<string name="account_setup_failed_dlg_oauth_flow_canceled">Diddymwyd awdurdodi</string>
<string name="account_setup_failed_dlg_oauth_flow_failed">Methodd awdurdodi gyda\'r gwall hwn: <xliff:g id="error">%s</xliff:g></string>
<string name="account_setup_failed_dlg_oauth_not_supported">Ni chefnogir OAuth 2.0 ar hyn o bryd gyda\'r darparydd hwn.</string>
<string name="account_setup_failed_dlg_browser_not_found">Methodd yr ap hwn ddod o hyd i borwr i\'w ddefnyddio i roi mynediad at dy gyfrif.</string>
<string name="account_setup_failed_dlg_edit_details_action">Golygu manylion</string>
<string name="account_setup_failed_dlg_continue_action">Parhau</string>
@ -538,6 +544,7 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="folder_settings_folder_push_mode_normal">Dim Rhenc</string>
<string name="folder_settings_folder_push_mode_first_class">Rhenc 1af</string>
<string name="folder_settings_folder_push_mode_second_class">2ail renc</string>
<string name="folder_settings_folder_push_mode_inherited">Fel rhenc gwirio</string>
<string name="folder_settings_folder_notify_mode_label">Rhenc hysbysiadau\'r ffolder</string>
<string name="folder_settings_folder_notify_mode_normal">Dim rhenc</string>
<string name="folder_settings_folder_notify_mode_first_class">Rhenc 1af</string>
@ -631,8 +638,6 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="account_setup_failed_dlg_invalid_certificate_title">Tystysgrif Ddiarth</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Derbyn Allwedd</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Gwrthod Allwedd</string>
<string name="message_view_help_key">Del (neu D) - Dileu\nR - Ateb\nA - Ateb i bawb\nC - Cyfansoddi\nF - Anfon ymlaen\nM - Symud\nV - Archifo\nY - Copïo\nZ - Nodi heb/wedi ei darllen\nG - Serennu\nO - Math o drefn\nI - Trefn sortio\nQ - Nôl i\'r ffolderi\nS - Dewis/dad-ddewis\nJ neu P - Neges flaenorol\nK neu N - Neges nesaf</string>
<string name="message_list_help_key">Del (neu D) - Dileu\nC - Cyfansoddi\nM - Symud\nV - Archive\nY - Copy\nZ -Nodi wedi/heb ei darllen\nG - Serennu\nO - Math o drefn\nI - Trefn\nQ - Nôl i\'r ffolderi\nS - Dewis/dad-ddewis</string>
<string name="folder_list_filter_hint">Enw ffolder yn cynnwys</string>
<string name="folder_list_display_mode_label">Dangos ffolderi…</string>
<string name="folder_list_display_mode_all">Pob ffolder</string>
@ -680,10 +685,9 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="account_setup_push_limit_1000">1000 o ffolderi</string>
<string name="animations_title">Animeiddiad</string>
<string name="animations_summary">Defnyddio effeithiau gweledol dros ben llestri</string>
<string name="volume_navigation_title">Pori gyda\'r botymau sain</string>
<string name="volume_navigation_message">Wrth edrych ar neges</string>
<string name="volume_navigation_list">Wrth edrych ar restr</string>
<string name="volume_navigation_title">Llywio gyda botymau sain ym modd golwg neges</string>
<string name="show_unified_inbox_title">Dangos mewnflwch unedig</string>
<string name="show_starred_count_title">Dangos cyfrif serennog</string>
<string name="integrated_inbox_title">Mewnflwch Unedig</string>
<string name="integrated_inbox_detail">Holl negeseuon pob cyfrif mewn un ffolder unedig</string>
<string name="folder_settings_include_in_integrated_inbox_label">Uno</string>
@ -766,7 +770,7 @@ Plîs rho wybod am unrhyw wallau, syniadau am nodweddion newydd, neu ofyn cwesti
<string name="messagelist_sent_cc_me_sigil"></string>
<string name="settings_list_backup_category">Copi wrth gefn</string>
<string name="settings_list_miscellaneous_category">Amrywiol</string>
<string name="settings_export_title">Archwilio gosodiadau</string>
<string name="settings_export_title">Allforio gosodiadau</string>
<string name="settings_export_button">Allforio</string>
<string name="settings_export_share_button">Rhannu</string>
<string name="settings_export_progress_text">Yn allforio gosodiadau…</string>
@ -1039,10 +1043,16 @@ Mae\'n bosib i ti gadw\'r neges hon a\'i ddefnyddio wrth gefn fel dy allwedd gyf
<string name="permission_contacts_rationale_title">Caniatáu mynediad at gysylltiadau</string>
<string name="permission_contacts_rationale_message">Er mwyn medru awgrymu cysylltiadau a dangos lluniau ac enwau cysylltiadau, mae ar yr ap angen mynediad at dy gysylltiadau.</string>
<string name="generic_loading_error">Bu gwall wrth lwytho\'r data</string>
<string name="push_notification_state_initializing">Yn ymgychwyn…</string>
<string name="push_notification_state_listening">Yn aros am negeseuon e-bost newydd</string>
<string name="push_notification_state_wait_background_sync">Yn cysgu nes bod cysoni yn y cefndir wedi\'i ganiatáu</string>
<string name="push_notification_state_wait_network">Yn cysgu nes bod rhwydwaith ar gael</string>
<string name="push_notification_info">Tapiwch i ddysgu rhagor.</string>
<string name="push_info_title">Gwybodaeth gwthio</string>
<string name="push_info_notification_explanation_text">Pan yn defnyddio Gwthio, mae K-9 Mail yn cadw cysylltiad â\'r gweinydd ebost. Mae ar Android angen dangos hysbysiad parhaus tra bod yr ap yn weithredol yn y cefndir. %s</string>
<string name="push_info_configure_notification_text">Fodd bynnag, mae Android hefyd yn eich galluogi i guddio\'r hysbysiad.</string>
<string name="push_info_learn_more_text">Dysgu rhagor</string>
<string name="push_info_configure_notification_action">Ffurfweddu hysbysiad</string>
<string name="push_info_disable_push_text">Os nad wyt angen hysbysiadau ar unwaith am negeseuon newydd, analluoga Gwthio a defnyddio Gwirio. Mae Gwirio yn edrych am negeseuon newydd ar gyfnodau rheolaidd heb fod angen yr hysbysiad parhaus.</string>
<string name="push_info_disable_push_action">Analluogi Gwthio</string>
</resources>

View file

@ -605,8 +605,6 @@ Rapporter venligst fejl, forslag til nye funktioner eller stil spørgsmål på:
<string name="account_setup_failed_dlg_invalid_certificate_title">Ukendt certificat</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Acceptér nøgle</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Afvis nøgle</string>
<string name="message_view_help_key">Del (or D) - Slet\nR - Svar\nA - Svar alle\nC - Skriv besked\nF - Videresend\nM - Flyt\nV - Arkiver\nY - Kopier\nZ - Marker (U)læst\nG - Stjernemarker\nO - Sorteringstype\nI - Sortering\nQ - Tilbage til Mapper\nS - Marker/afmarker\nJ or P - Forrige meddelelse\nK or N - Næste Meddelelse</string>
<string name="message_list_help_key">Del (or D) - Slet\nC - Skriv besked\nM - Flyt\nV - Arkiver\nY - Kopier\nZ - Marker (U)læst\nG - Stjernemarker\nO - Sorteringstype\nI - Sorteringsorden\nQ - Tilbage til mapper\nS - Marker/afmaker</string>
<string name="folder_list_filter_hint">Mappenavn indeholder</string>
<string name="folder_list_display_mode_label">Mapper</string>
<string name="folder_list_display_mode_all">Vis alle mapper</string>
@ -654,9 +652,6 @@ Rapporter venligst fejl, forslag til nye funktioner eller stil spørgsmål på:
<string name="account_setup_push_limit_1000">1000 mapper</string>
<string name="animations_title">Animation</string>
<string name="animations_summary">Anvend visuelle effekter</string>
<string name="volume_navigation_title">Volume-knap navigation</string>
<string name="volume_navigation_message">Mail-visning</string>
<string name="volume_navigation_list">Diverse listevisninger</string>
<string name="show_unified_inbox_title">Vis Fælles Indbakke</string>
<string name="integrated_inbox_title">Fælles indbakke</string>
<string name="integrated_inbox_detail">Alle mails i fælles mapper</string>

View file

@ -633,8 +633,6 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
<string name="account_setup_failed_dlg_invalid_certificate_title">Ungültiges Zertifikat</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Zertifikat akzeptieren</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Zertifikat ablehnen</string>
<string name="message_view_help_key">Entf (oder D) - Löschen\nR - Antworten\nA - Allen Antworten\nC - Verfassen\nF - Weiterleiten\nM - Verschieben\nV - Archivieren\nY - Kopieren\nZ - Als (un)gelesen markieren\nG - Wichtig\nO - Sortiertyp\nI - Sortierreihenfolge\nQ - Zurück zu den Ordnern\nS - Auswählen/Abwählen\nJ oder P - Vorherige Nachricht\nK oder N - Nächste Nachricht</string>
<string name="message_list_help_key">Entf (oder D) - Löschen\nC - Verfassen\nM - Verschieben\nV - Archivieren\nY - Kopieren\nZ - Als (un)gelesen markieren\nG - Wichtig\nO - Sortiertyp\nI - Sortierreihenfolge\nQ - Zurück zu den Ordnern\nS - Auswählen/Abwählen</string>
<string name="folder_list_filter_hint">Ordnername enthält</string>
<string name="folder_list_display_mode_label">Ordner</string>
<string name="folder_list_display_mode_all">Alle Ordner anzeigen</string>
@ -682,9 +680,7 @@ Bitte senden Sie Fehlerberichte, Ideen für neue Funktionen und stellen Sie Frag
<string name="account_setup_push_limit_1000">1000 Ordner</string>
<string name="animations_title">Animationen</string>
<string name="animations_summary">Aufwendige visuelle Effekte benutzen</string>
<string name="volume_navigation_title">Lauter/Leiser-Navigation</string>
<string name="volume_navigation_message">Nachrichtenansicht</string>
<string name="volume_navigation_list">Diverse Listenansichten</string>
<string name="volume_navigation_title">Navigation per Lautstärketasten in der Nachrichtenansicht</string>
<string name="show_unified_inbox_title">Gemeinsamen Posteingang anzeigen</string>
<string name="show_starred_count_title">Anzahl der Sterne anzeigen</string>
<string name="integrated_inbox_title">Gemeinsamer Posteingang</string>

View file

@ -9,10 +9,12 @@
<!--Used in the about dialog-->
<string name="app_authors">The K-9 Dog Walkers</string>
<string name="source_code">Πηγαίος κώδικας</string>
<string name="app_license">Άδεια χρήσης Apache, έκδοση 2.0.</string>
<string name="about_project_title">Έργο Ανοιχτού Κώδικα</string>
<string name="app_license">Άδεια χρήσης Apache, έκδοση 2.0</string>
<string name="about_project_title">Έργο ανοικτού κώδικα</string>
<string name="about_website_title">Ιστότοπος</string>
<string name="user_forum_title">Χώρος συζητήσεων χρηστών</string>
<string name="user_manual_title">Οδηγός χρήστη</string>
<string name="get_help_title">Λήψη βοήθειας</string>
<string name="user_forum_title">Φόρουμ χρηστών</string>
<string name="about_fediverse_title">Fediverse</string>
<string name="about_twitter_title">Twitter</string>
<string name="about_libraries">Βιβλιοθήκες</string>
@ -71,12 +73,14 @@
<string name="compose_title_forward_as_attachment">Προώθηση ως συνημμένο</string>
<string name="choose_account_title">Επιλογή Λογαριασμού</string>
<string name="choose_folder_title">Επιλογή φακέλου</string>
<string name="choose_folder_move_title">Μετακίνηση σε…</string>
<string name="choose_folder_copy_title">Αντιγραφή σε…</string>
<string name="actionbar_selected"><xliff:g id="selection_count">%d</xliff:g> επιλέχθηκαν</string>
<string name="next_action">Επόμενο</string>
<string name="previous_action">Προηγούμενο</string>
<!--Used to confirm acceptance of dialog boxes, warnings, errors, etc.-->
<string name="okay_action">OK</string>
<string name="cancel_action">Άκυρο</string>
<string name="cancel_action">Ακύρωση</string>
<string name="send_action">Αποστολή</string>
<string name="empty_subject">Το θέμα είναι κενό, πατήστε επανάληψη για αποστολή</string>
<string name="reply_action">Απάντηση</string>
@ -103,17 +107,19 @@
<string name="search_action">Αναζήτηση</string>
<string name="search_everywhere_action">Αναζήτηση παντού</string>
<string name="search_results">Αποτελέσματα αναζήτησης</string>
<string name="new_messages_title">Νέα μηνύματα</string>
<string name="preferences_action">Ρυθμίσεις</string>
<string name="folders_action">Διαχείριση φακέλων</string>
<string name="account_settings_action">Ρυθμίσεις λογαριασμού</string>
<string name="remove_account_action">Διαγραφή λογαριασμού</string>
<string name="mark_as_read_action">Σήμανση ως αναγνωσμένου</string>
<string name="send_alternate_action">Διανομή</string>
<string name="send_alternate_action">Κοινοποίηση</string>
<string name="send_alternate_chooser_title">Επιλογή αποστολέα</string>
<string name="flag_action">Προσθήκη αστεριού</string>
<string name="unflag_action">Αφαίρεση αστεριού</string>
<string name="copy_action">Αντιγραφή</string>
<string name="show_headers_action">Προβολή επικεφαλίδων</string>
<string name="unsubscribe_action">Κατάργηση συνδρομής</string>
<string name="show_headers_action">Προβολή κεφαλίδων</string>
<plurals name="copy_address_to_clipboard">
<item quantity="one">Η διεύθυνση αντιγράφηκε στο πρόχειρο</item>
<item quantity="other">Οι διευθύνσεις αντιγράφηκαν στο πρόχειρο </item>
@ -126,19 +132,19 @@
<string name="read_receipt_enabled">Θα ζητηθεί απόδειξη ανάγνωσης</string>
<string name="read_receipt_disabled">Δε θα ζητηθεί αποδεικτικό ανάγνωσης</string>
<string name="add_attachment_action">Προσθήκη συνημμένου</string>
<string name="empty_trash_action">Άδειασμα σκουπιδιών</string>
<string name="empty_trash_action">Άδειασμα απορριμμάτων</string>
<string name="expunge_action">Εξάλειψη</string>
<string name="about_action">Περί</string>
<string name="about_action">Πληροφορίες</string>
<string name="prefs_title">Ρυθμίσεις</string>
<!--Shown in place of the subject when a message has no subject. Showing this in parentheses is customary.-->
<string name="general_no_subject">(Χωρίς θέμα)</string>
<string name="general_no_sender">Χωρίς αποστολέα</string>
<string name="status_loading_more">Φόρτωση μηνυμάτων\u2026</string>
<string name="status_network_error">Σφάλμα σύνδεσης</string>
<string name="status_invalid_id_error">Δε βρέθηκε το μήνυμα</string>
<string name="status_loading_error">Σφάλμα φόρτωση μηνύματος</string>
<string name="load_more_messages_fmt">Φόρτωση
έως <xliff:g id="messages_to_load">%d</xliff:g> περισσότερων</string>
<string name="status_invalid_id_error">Δεν βρέθηκε το μήνυμα</string>
<string name="status_loading_error">Σφάλμα φόρτωσης μηνύματος</string>
<string name="load_more_messages_fmt">Φόρτωση έως
<xliff:g id="messages_to_load">%d</xliff:g> περισσότερων</string>
<string name="size_format_gigabytes">%.1f GB</string>
<string name="size_format_megabytes">%.1f MB</string>
<string name="size_format_kilobytes">%.1f kB</string>
@ -151,19 +157,22 @@
<string name="notification_new_one_account_fmt"><xliff:g id="unread_message_count">%1$d</xliff:g> μη αναγνωσμένα (<xliff:g id="account">%2$s</xliff:g>)</string>
<string name="notification_additional_messages">+ <xliff:g id="additional_messages">%1$d</xliff:g> περισσότερα για <xliff:g id="account">%2$s</xliff:g></string>
<string name="notification_action_reply">Απάντηση</string>
<string name="notification_action_mark_as_read">Ανάγνωση</string>
<string name="notification_action_mark_all_as_read">Σήμανση όλων των αναγνωσμένων</string>
<string name="notification_action_mark_as_read">Σήμανση ως αναγνωσμένο</string>
<string name="notification_action_mark_all_as_read">Σήμανση όλων ως αναγνωσμένων</string>
<string name="notification_action_delete">Διαγραφή</string>
<string name="notification_action_delete_all">Διαγραφή όλων</string>
<string name="notification_action_archive">Αρχειοθήκη</string>
<string name="notification_action_archive">Αρχειοθέτηση</string>
<string name="notification_action_archive_all">Αρχειοθέτηση όλων</string>
<string name="notification_action_spam">Ανεπιθύμητα</string>
<string name="notification_certificate_error_public">Σφάλμα πιστοποιητικού</string>
<string name="notification_certificate_error_title">Σφάλμα πιστοποιητικού για <xliff:g id="account">%s</xliff:g></string>
<string name="notification_certificate_error_text">Ελέγξτε τις ρυθμίσεις του εξυπηρετητή</string>
<string name="notification_certificate_error_text">Ελέγξτε τις ρυθμίσεις του διακομιστή σας</string>
<string name="notification_authentication_error_title">Αποτυχία πιστοποίησης</string>
<string name="notification_authentication_error_text">Αποτυχία πιστοποίησης <xliff:g id="account">%s</xliff:g>. Ενημερώστε τις ρυθμίσεις του εξυπηρετητή σας.</string>
<!--Title of an error notification that is displayed when creating a notification for a new message has failed-->
<string name="notification_notify_error_title">Σφάλμα ειδοποίησης</string>
<!--Body of an error notification that is displayed when creating a notification for a new message has failed-->
<string name="notification_notify_error_text">Σφάλμα στην προσπάθεια δημιουργίας ειδοποίησης συστήματος για νέο μήνυμα. Η ατία είναι μάλλον λείπει ο ήχος της ειδοπίησης.\n\nΠατήστε για να ανοίξετε τις ρυθμίσεων των ειδοποιήσεων.</string>
<string name="notification_bg_sync_ticker">Έλεγχος μηνύματος: <xliff:g id="account">%1$s</xliff:g>:<xliff:g id="folder">%2$s</xliff:g></string>
<string name="notification_bg_sync_title">Έλεγχος μηνύματος</string>
<string name="notification_bg_send_ticker">Αποστολή μηνύματος: <xliff:g id="account">%s</xliff:g></string>
@ -186,6 +195,9 @@
<string name="debug_enable_debug_logging_summary">Καταγραφή πρόσθετων διαγνωστικών πληροφοριών</string>
<string name="debug_enable_sensitive_logging_title">Καταγραφή ευαίσθητων πληροφοριών</string>
<string name="debug_enable_sensitive_logging_summary">Συνθηματικά μπορεί να εμφανιστούν στις καταγραφές.</string>
<string name="debug_export_logs_title">Καταγραφές εξαγωγών</string>
<string name="debug_export_logs_success">Επιτυχής εξαγωγή. Οι καταγραφές ίσως περιέχουν ευαίσθητες πληροφορίες. Προσέχετε σε ποιον/ποια τις στέλνετε.</string>
<string name="debug_export_logs_failure">Αποτυχία εξαγωγής</string>
<string name="message_list_load_more_messages_action">Φόρτωση περισσότερων μηνυμάτων</string>
<string name="message_to_fmt">Προς:<xliff:g id="counterParty">%s</xliff:g></string>
<string name="message_compose_subject_hint">Θέμα</string>
@ -197,11 +209,11 @@
<string name="message_compose_quote_header_from">Από:</string>
<string name="message_compose_quote_header_to">Προς:</string>
<string name="message_compose_quote_header_cc">Κοιν:</string>
<string name="message_compose_reply_header_fmt"><xliff:g id="sender">%s</xliff:g> έγραψε:</string>
<string name="message_compose_reply_header_fmt">Ο/Η <xliff:g id="sender">%s</xliff:g> έγραψε:</string>
<string name="message_compose_reply_header_fmt_with_date">Στις <xliff:g id="sent_date">%1$s</xliff:g>, ο<xliff:g id="sender">%2$s</xliff:g> έγραψε:</string>
<string name="message_compose_error_no_recipients">Πρέπει να συμπεριλάβετε τουλάχιστον έναν παραλήπτη.</string>
<string name="message_compose_error_no_recipients">Πρέπει να προσθέσετε τουλάχιστον έναν παραλήπτη.</string>
<string name="compose_error_incomplete_recipient">Το πεδίο παραλήπτη περιέχει ελλιπή στοιχεία!</string>
<string name="error_contact_address_not_found">Δε βρέθηκαν διευθύνσεις ηλεκτρονικού ταχυδρομείου.</string>
<string name="error_contact_address_not_found">Δεν βρέθηκαν διευθύνσεις ηλεκτρονικού ταχυδρομείου.</string>
<string name="message_compose_attachments_skipped_toast">Μερικά συνημμένα δεν μπορούν να προωθηθούν γιατί δεν έχουν ληφθεί.</string>
<string name="message_compose_attachments_forward_toast">Το μήνυμα δεν μπορεί να προωθηθεί επειδή μερικά συνημμένα δεν έχουν ληφθεί.</string>
<string name="message_compose_show_quoted_text_action">Συμπερίληψη του παραθετιμένου μηνύματος</string>
@ -211,19 +223,19 @@
<string name="message_view_from_format">Από: <xliff:g id="name">%1$s</xliff:g> &lt;<xliff:g id="email">%2$s</xliff:g>&gt;</string>
<string name="message_to_label">Προς:</string>
<string name="message_view_cc_label">Κοιν:</string>
<string name="message_view_bcc_label">Κρυφή Κοιν:</string>
<string name="message_view_bcc_label">Κρυφή κοιν:</string>
<string name="message_view_status_attachment_not_saved">Αδυναμία αποθήκευσης συνημμένου.</string>
<string name="message_view_show_pictures_action">Προβολή εικόνων</string>
<string name="message_view_show_pictures_action">Εμφάνιση εικόνων</string>
<string name="message_view_no_viewer">Δεν υπάρχει πρόγραμμα προβολής για <xliff:g id="mimetype">%s</xliff:g>.</string>
<string name="message_view_download_remainder">Λήψη πλήρους μηνύματος</string>
<string name="message_view_sender_label">μέσω %1$s</string>
<string name="from_same_sender">Από τον ίδιο αποστολέα</string>
<string name="search_from_format">Από <xliff:g id="sender">%s</xliff:g></string>
<string name="message_discarded_toast">Το μήνυμα αγνοήθηκε.</string>
<string name="message_saved_toast">Το μήνυμα αποθηκεύτηκε στα πρόχειρα.</string>
<string name="global_settings_flag_label">Προβολή αστεριών</string>
<string name="message_discarded_toast">Το μήνυμα απορρίφθηκε</string>
<string name="message_saved_toast">Το μήνυμα αποθηκεύτηκε ως πρόχειρο</string>
<string name="global_settings_flag_label">Εμφάνιση αστεριών</string>
<string name="global_settings_flag_summary">Τα αστέρια υποδηλώνουν σημαντικά μηνύματα</string>
<string name="global_settings_preview_lines_label">Προεπισκόπηση μηνυμάτων</string>
<string name="global_settings_preview_lines_label">Γραμμές προεπισκόπησης</string>
<string name="global_settings_show_correspondent_names_label">Εμφάνιση ονομάτων επιστολογράφων</string>
<string name="global_settings_show_correspondent_names_summary">Εμφάνιση των ονομάτων των επιστολογράφων αντί των διευθύνσεων ηλεκτρονικού ταχυδρομείου</string>
<string name="global_settings_sender_above_subject_label">Αποστολέας πάνω από το θέμα</string>
@ -232,14 +244,15 @@
<string name="global_settings_show_contact_name_summary">Χρήση ονομάτων επιστολογράφων από Επαφές όταν είναι διαθέσιμο</string>
<string name="global_settings_registered_name_color_label">Χρωματισμός Επαφών</string>
<string name="global_settings_registered_name_color_changed">Να χρωματίζονται τα ονόματα στη λίστα επαφών</string>
<string name="general_settings_contact_name_color_label">Χρώμα ονόματος επαφής</string>
<string name="global_settings_messageview_fixedwidth_label">Γραμματοσειρά σταθερού πλάτους</string>
<string name="global_settings_messageview_fixedwidth_summary">Να χρησιμοποιείται γραμματοσειρά σταθερού πλάτους όταν προβάλλονται μηνύματα απλού κειμένου</string>
<string name="global_settings_messageview_autofit_width_label">Αυτόματη προσαρμογή</string>
<string name="global_settings_messageview_autofit_width_summary">Ρύθμιση μεγέθους μηνύματος για να χωρά στην οθόνη</string>
<string name="global_settings_messageview_return_to_list_label">Επιστροφή στη λίστα</string>
<string name="global_settings_messageview_return_to_list_summary">Επιστροφή στη λίστα μηνυμάτων μετά τη διαγραφή ενός μηνύματος</string>
<string name="global_settings_messageview_show_next_label">Προβολή επόμενου</string>
<string name="global_settings_messageview_show_next_summary">Προβολή επόμενου μηνύματος μετά τη διαγραφή ενός μηνύματος</string>
<string name="global_settings_messageview_show_next_label">Εμφάνιση επόμενου μηνύματος μετά τη διαγραφή</string>
<string name="global_settings_messageview_show_next_summary">Εμφάνιση επόμενου μηνύματος μετά τη διαγραφή ενός μηνύματος</string>
<string name="global_settings_confirm_actions_title">Επιβεβαίωση ενεργειών</string>
<string name="global_settings_confirm_actions_summary">Προβολή διαλόγου όποτε εκτελούνται επιλεγμένες ενέργειες</string>
<string name="global_settings_confirm_action_delete">Διαγραφή</string>
@ -255,13 +268,14 @@
<string name="global_settings_notification_quick_delete_title">Εμφάνιση κουμπιού «Διαγραφή»</string>
<string name="global_settings_notification_quick_delete_never">Ποτέ</string>
<string name="global_settings_notification_quick_delete_when_single_msg">Για ειδοποίηση ενός μηνύματος</string>
<string name="global_settings_notification_quick_delete_always">Πάντοτε</string>
<string name="global_settings_notification_quick_delete_always">Πάντα</string>
<string name="global_settings_lock_screen_notification_visibility_title">Ειδοποιήσεις οθόνης κλειδώματος</string>
<string name="global_settings_lock_screen_notification_visibility_nothing">Χωρίς ειδοποιήσεις οθόνης κλειδώματος</string>
<string name="global_settings_lock_screen_notification_visibility_app_name">Όνομα εφαρμογής</string>
<string name="global_settings_lock_screen_notification_visibility_message_count">Αριθμός νέων μηνυμάτων</string>
<string name="global_settings_lock_screen_notification_visibility_senders">Αριθμός μηνυμάτων και αποστολείς</string>
<string name="global_settings_lock_screen_notification_visibility_everything">Ομοίως με τότε που η οθόνη είναι ξεκλείδωτη</string>
<string name="quiet_time">Ώρες Ησυχίας</string>
<string name="quiet_time">Ώρες ησυχίας</string>
<string name="quiet_time_description">Απενεργοποιηση κουδουνίσματος, βουητού και αναβοσβησίματος τη νύχτα</string>
<string name="quiet_time_notification">Απενεργοποίηση ειδοποιήσεων</string>
<string name="quiet_time_notification_description">Πλήρης απενεργοποίηση ειδοποιήσεων για όσο διαρκούν οι Ώρες Ησυχίας</string>
@ -270,8 +284,11 @@
<string name="account_setup_basics_title">Ρύθμιση νέου λογαριασμού</string>
<string name="account_setup_basics_email_hint">Διεύθυνση ηλ. ταχυδρομείου</string>
<string name="account_setup_basics_password_hint">Συνθηματικό</string>
<string name="account_setup_oauth_description">Αν θέλετε να χρησιμοποιήσετε αυτόν τον λογαριασμό ηλεκτρονικού ταχυδρομείου με το K-9 Mail πρέπει να συνδεθείτε και να παραχωρήσετε στην εφαρμογή πρόσβαση στα ηλεκτρονικά μηνύματά σας.</string>
<!--Displayed below the 'account_setup_oauth_description' text-->
<string name="account_setup_oauth_sign_in">Σύνδεση</string>
<!--Displayed below the 'account_setup_oauth_description' text-->
<string name="account_setup_oauth_sign_in_with_google">Σύνδεση μέσω Google</string>
<!--Please use the same translation for "screen lock" as is used in the 'Security' section in Android's settings app-->
<string name="account_setup_basics_show_password_need_lock">Για να δείτε τον κωδικό σας εδώ, ενεργοποιήστε το κλείδωμα οθόνης σε αυτή την συσκευή.</string>
<string name="account_setup_basics_show_password_biometrics_title">Επαλήθευση ταυτότητας</string>
@ -295,6 +312,7 @@
<string name="account_setup_auth_type_insecure_password">Συνθηματικό, μεταβιβασμένο χωρίς ασφάλεια</string>
<string name="account_setup_auth_type_encrypted_password">Κρυπτογραφημένο συνθηματικό</string>
<string name="account_setup_auth_type_tls_client_certificate">Πιστοποιητικό πελάτη</string>
<string name="account_setup_auth_type_oauth2">OAuth 2.0</string>
<string name="account_setup_incoming_title">Ρυθμίσεις εισερχόμενης αλληλογραφίας</string>
<string name="account_setup_incoming_username_label">Όνομα χρήστη</string>
<string name="account_setup_incoming_password_label">Συνθηματικό</string>
@ -313,6 +331,7 @@
<string name="account_setup_incoming_delete_policy_never_label">Να μη διαγράφεται στον εξυπηρετητή</string>
<string name="account_setup_incoming_delete_policy_delete_label">Να διαγράφεται άμεσα από τον εξυπηρετητή</string>
<string name="account_setup_incoming_delete_policy_markread_label">Επισήμανση ως αναγνωσμένο στον εξυπηρετητή</string>
<string name="account_setup_incoming_use_compression">Χρήση συμπίεσης</string>
<string name="account_setup_expunge_policy_label">Εξάλειψη διαγραμμένων μηνυμάτων</string>
<string name="account_setup_expunge_policy_immediately">Αμέσως</string>
<string name="account_setup_expunge_policy_on_poll">Κατά την ενημέρωση</string>
@ -377,6 +396,10 @@
<string name="account_setup_failed_dlg_auth_message_fmt">Το όνομα χρήστη ή ο κωδικός πρόσβασης δεν είναι σωστά.\n(<xliff:g id="error">%s</xliff:g>)</string>
<string name="account_setup_failed_dlg_certificate_message_fmt">Ο εξυπηρετητής παρουσίασε ένα μη εγκυρο πιστοποιητικό SSL. Κάποιες φορές αυτό συμβαίνει λόγω κακής ρύθμισής του. Άλλες φορές γιατί κάποιος προσπαθεί να επιτεθεί σε εσάς ή τον εξυπηρετητή ταχυδρομείου σας. Αν δεν είστε βέβαιοι τι συμβαίνει, επιλέξτε Απόρριψη και επικοινωνήστε με τους διαχειριστές του εξυπηρετητή ταχυδρομείου σας.\n\n(<xliff:g id="error">%s</xliff:g>)</string>
<string name="account_setup_failed_dlg_server_message_fmt">Αδύνατη η σύνδεση στον εξυπηρετητή.\n(<xliff:g id="error">%s</xliff:g>)</string>
<string name="account_setup_failed_dlg_oauth_flow_canceled">Η εξακρίβωση ακυρώθηκε</string>
<string name="account_setup_failed_dlg_oauth_flow_failed">Η εξακρίβωση απέτυχε με το εξής σφάλμα: <xliff:g id="error">%s</xliff:g></string>
<string name="account_setup_failed_dlg_oauth_not_supported">Το πρωτόκολο OAuth 2.0 αυτή τη στιγμή δεν υποστηρίζεται από τον συγκεκριμένο πάροχο.</string>
<string name="account_setup_failed_dlg_browser_not_found">Η εφαρμογή δεν βρήκε περιηγητή ιστού για να παράσχει πρόσβαση στον λογαριασμό σας.</string>
<string name="account_setup_failed_dlg_edit_details_action">Διόρθωση λεπτομερειών</string>
<string name="account_setup_failed_dlg_continue_action">Συνέχεια</string>
<string name="account_settings_push_advanced_title">Προχωρημένα</string>
@ -531,11 +554,29 @@
<string name="account_settings_description_label">Όνομα λογαριασμού</string>
<string name="account_settings_name_label">Το όνομά σου</string>
<string name="notifications_title">Ειδοποιήσεις</string>
<string name="account_settings_vibration">Δόνηση</string>
<string name="account_settings_vibrate_enable">Δόνηση</string>
<string name="account_settings_vibrate_pattern_label">Μοτίβο δόνησης</string>
<string name="account_settings_vibrate_pattern_default">Εξ ορισμού</string>
<string name="account_settings_vibrate_pattern_1">Μοτίβο 1</string>
<string name="account_settings_vibrate_pattern_2">Μοτίβο 2</string>
<string name="account_settings_vibrate_pattern_3">Μοτίβο 3</string>
<string name="account_settings_vibrate_pattern_4">Μοτίβο 4</string>
<string name="account_settings_vibrate_pattern_5">Μοτίβο 5</string>
<string name="account_settings_vibrate_times">Επανάληψη δόνησης</string>
<string name="account_settings_vibrate_summary_disabled">Απενεργοποιήθηκε</string>
<string name="account_settings_ringtone">Κουδούνισμα με νέο μήνυμα</string>
<string name="account_settings_notification_light_label">Φωτεινή ειδοποίηση</string>
<string name="account_settings_notification_light_disabled">Απενεργοποιήθηκε</string>
<string name="account_settings_notification_light_account_color">Χρώμα λογαριασμού</string>
<string name="account_settings_notification_light_default_color">Προεπιλεγμένο χρώμα συστήματος</string>
<string name="account_settings_notification_light_white">Λευκό</string>
<string name="account_settings_notification_light_red">Κόκκινο</string>
<string name="account_settings_notification_light_green">Πράσινο</string>
<string name="account_settings_notification_light_blue">Μπλε</string>
<string name="account_settings_notification_light_yellow">Κίτρινο</string>
<string name="account_settings_notification_light_cyan">Μωβ</string>
<string name="account_settings_notification_light_magenta">Ματζέντα</string>
<string name="account_settings_composition_title">Επιλογές σύνθεσης μηνύματος</string>
<string name="account_settings_composition_label">Εξ ορισμού σύνθεση</string>
<string name="account_settings_composition_summary">Ορισμός εξ ορισμού Αποστολέα, Ιδιωτικής κοινοποίησης και υπογραφής</string>
@ -593,8 +634,6 @@
<string name="account_setup_failed_dlg_invalid_certificate_title">Άγνωστο πιστοποιητικό</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Αποδοχή κλειδιού</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Απόρριψη κλειδιού</string>
<string name="message_view_help_key">Del (or D) - Διαγραφή\nR - Απάντηση\nA - Απάντηση Όλων\nC - Σύνθεση\nF - Προώθηση\nM - Μετακίνηση\nV - Αρχειοθέτηση\nY - Αντιγραφή\nZ - Σημείωση ως (μη) αναγνωσμένο\nG - Αστέρι\nO - Ταξινόμηση κατά τύπο\nI - Ταξινόμηση κατά σειρά\nQ - Επιστροφή στους Φακέλους\nS - Επιλογή/αποεπιλογή\nJ or P - Προηγούμενο Μήνυμα\nK or N - Επόμενο Μήνυμα</string>
<string name="message_list_help_key">Del (or D) - Διαγραφή\nC - Σύνθεση\nM - Μετακίνηση\nV - Αρχειοθέτηση\nY - Αντιγραφή\nZ - Σημείωση ως (μη) αναγνωσμένο\nG - Αστέρι\nO - Ταξινόμηση κατά τύπο\nI - Ταξινόμηση κατά σειρά\nQ - Επιστροφή στους Φακέλους\nS - Επιλογή/αποεπιλογή</string>
<string name="folder_list_filter_hint">Το όνομα του φακέλου περιέχει</string>
<string name="folder_list_display_mode_label">Φάκελοι</string>
<string name="folder_list_display_mode_all">Προβολή όλων</string>
@ -642,9 +681,7 @@
<string name="account_setup_push_limit_1000">1000 φάκελοι</string>
<string name="animations_title">Κινούμενα σχέδια</string>
<string name="animations_summary">Χρήση οπτικών εφέ gaudy</string>
<string name="volume_navigation_title">Πλοήγηση με πλήκτρο έντασης</string>
<string name="volume_navigation_message">Προβολή μηνύματος</string>
<string name="volume_navigation_list">Διάφορες προβολές λίστας</string>
<string name="volume_navigation_title">Πλοήγηση με τα πλήκτρα ήχου όταν προβάλεται μήνυμα</string>
<string name="show_unified_inbox_title">Εμφάνιση Ενιαία Εισερχόμενα</string>
<string name="show_starred_count_title">Εμφάνιση πλήθους επιλεγμένων</string>
<string name="integrated_inbox_title">Ενιαία Εισερχόμενα</string>
@ -738,13 +775,16 @@
<!--Displayed after importing accounts when one or multiple accounts require entering a password-->
<string name="settings_import_password_required">Παρακαλώ εισάγετε συνθηματικά</string>
<!--Displayed after importing accounts when one or multiple accounts require to use the OAuth authorization flow-->
<string name="settings_import_authorization_required">Παρακαλώ συνδεθείτε</string>
<!--Displayed after importing accounts when some accounts require entering a password and some to use the OAuth authorization flow-->
<string name="settings_import_authorization_and_password_required">Παρακαλώ συνδεθείτε και εισάγετε κωδικό</string>
<string name="settings_import_failure">Αποτυχία εισαγωγής ρυθμίσεων</string>
<string name="settings_import_read_failure">Αποτυχία ανάγνωσης αρχείου ρυθμίσεων</string>
<string name="settings_import_partial_failure">Αποτυχία εισαγωγής ορισμένων ρυθμίσεων</string>
<string name="settings_import_status_success">Η εισαγωγή ολοκληρώθηκε με επιτυχία</string>
<string name="settings_import_status_password_required">Απαιτείται κωδικός πρόσβασης</string>
<!--Content description for the icon that is displayed next to an imported account that requires sign-in-->
<string name="settings_import_status_log_in_required">Απαιτείται σύνδεση</string>
<string name="settings_import_status_not_imported">Δεν έχει εισαχθεί</string>
<string name="settings_import_status_error">Αποτυχία εισαγωγής</string>
<string name="settings_import_later_button">Αργότερα</string>
@ -851,6 +891,7 @@
<string name="recipient_bcc">Κρυφή Κοιν:</string>
<string name="recipient_to">Προς</string>
<string name="recipient_from">Από:</string>
<string name="reply_to_label">Απάντηση σε</string>
<string name="unknown_recipient">&lt;Άγνωστος Παραλήπτης&gt;</string>
<string name="unknown_sender">&lt;Άγνωστος Αποστολέας&gt;</string>
<string name="address_type_home">Οικία</string>

View file

@ -593,8 +593,6 @@ Bonvolu raporti erarojn, kontribui novajn eblojn kaj peti pri novaj funkcioj per
<string name="account_setup_failed_dlg_invalid_certificate_title">Nekonata atestilo</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Akcepti ŝlosilon</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Rifuzi ŝlosilon</string>
<string name="message_view_help_key">Del (aŭ D) - forigi\nR - respondi\nA - respondi al ĉiuj\nC - krei\nF - plusendi\nM - movi\nV - arĥivigi\nY - kopii\nZ - marki kiel (ne)legitan\nG - steletigi\nO - ordiga tipo\nI - ordigo\nQ - reveni al mesaĝujoj\nS - (mal)elekti\nJ aŭ P -antaŭa mesaĝo\nK aŭ N - sekva mesaĝo</string>
<string name="message_list_help_key">Del (aŭ D) - forigi\nC - krei\nM - movi\nV - arĥivigi\nY - kopii\nZ - marki kiel (ne)legitan\nG - steletigi\nO - ordiga tipo\nI - ordigo\nQ - reveni al mesaĝujoj\nS - (mal)elekti</string>
<string name="folder_list_filter_hint">Nomo de mesaĝujo enhavas</string>
<string name="folder_list_display_mode_label">Montri mesaĝujojn…</string>
<string name="folder_list_display_mode_all">Ĉiuj mesaĝujoj</string>
@ -642,9 +640,6 @@ Bonvolu raporti erarojn, kontribui novajn eblojn kaj peti pri novaj funkcioj per
<string name="account_setup_push_limit_1000">Maksimume 1000 mesaĝujoj</string>
<string name="animations_title">Movbildoj</string>
<string name="animations_summary">Uzas afablajn vidajn efektojn</string>
<string name="volume_navigation_title">Navigado per sonfortecaj butonoj</string>
<string name="volume_navigation_message">En vido de mesaĝoj</string>
<string name="volume_navigation_list">En vidoj de listoj</string>
<string name="show_unified_inbox_title">Montri unuigitan ricevujon</string>
<string name="show_starred_count_title">Montri nombron da steletoj</string>
<string name="integrated_inbox_title">Unuigita ricevujo</string>

View file

@ -633,8 +633,6 @@ Puedes informar de fallos, contribuir con su desarrollo y hacer preguntas en <a
<string name="account_setup_failed_dlg_invalid_certificate_title">Certificado desconocido</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Aceptar clave</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Rechazar clave</string>
<string name="message_view_help_key">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 - Destacar\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</string>
<string name="message_list_help_key">Supr (o D) - Borrar\nC - Redactar\nM - Mover\nV - Archivar\nY - Copiar\nZ - Marcar como (no) leído\nG - Destacar\nO - Tipo de ordenación\nI - Invertir orden\nQ - Volver a las carpetas\nS - Des/marcar</string>
<string name="folder_list_filter_hint">El nombre de la carpeta contiene</string>
<string name="folder_list_display_mode_label">Mostrar carpetas…</string>
<string name="folder_list_display_mode_all">Ver todas las carpetas</string>
@ -682,9 +680,7 @@ Puedes informar de fallos, contribuir con su desarrollo y hacer preguntas en <a
<string name="account_setup_push_limit_1000">1000 carpetas</string>
<string name="animations_title">Animaciones</string>
<string name="animations_summary">Utilizar animaciones</string>
<string name="volume_navigation_title">Navegación con teclas de volumen</string>
<string name="volume_navigation_message">Vista de mensaje</string>
<string name="volume_navigation_list">Listas de mensajes</string>
<string name="volume_navigation_title">Navegar con las teclas de volumen al leer el correo</string>
<string name="show_unified_inbox_title">Mostrar bandeja de entrada unificada</string>
<string name="show_starred_count_title">Mostrar número de mensajes destacados</string>
<string name="integrated_inbox_title">Entrada unificada</string>

View file

@ -636,8 +636,6 @@ Veateated saad saata, kaastööd teha ning küsida teavet järgmisel lehel:
<string name="account_setup_failed_dlg_invalid_certificate_title">Tunnustamata sertifikaat</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Aktsepteeri võti</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Keeldu võtmest</string>
<string name="message_view_help_key">Del (või D) - Kustuta\nR - Vasta\nA - Vasta kõigile\nC - Koosta\nF - Saada edasi\nM - Teisalda\nV - Arhiveeri\nY - Kopeeri\nZ - Märgi (mitte)loetuks\nG - Tärn\nO - Sortimise tüüp\nI - Sorteerimise järjekord\nQ - Tagasi kaustadesse\nS - Vali/Tühista valik\nJ or P - Eelmine kiri\nK or N - Järgmine kiri</string>
<string name="message_list_help_key">Del (või D) - Kustuta\nC - Koosta kiri\nM - Teisalda\nV - Arhiveri\nY - Kopeeri\nZ - Märgi (mitte)loetuks\nG - Märgi tärniga\nO - Sortimise tüüp\nI - Sortimise järjekord\nQ - Tagasi kasutade loendisse\nS - Vali/eemalda valik</string>
<string name="folder_list_filter_hint">Kausta nimi sisaldab</string>
<string name="folder_list_display_mode_label">Näita kaustu…</string>
<string name="folder_list_display_mode_all">Kõik kaustad</string>
@ -685,9 +683,6 @@ Veateated saad saata, kaastööd teha ning küsida teavet järgmisel lehel:
<string name="account_setup_push_limit_1000">1000 kausta</string>
<string name="animations_title">Animatsioon</string>
<string name="animations_summary">Kasuta erinevaid visuaalseid efekte</string>
<string name="volume_navigation_title">Helitugevuse nupuga liikumine</string>
<string name="volume_navigation_message">Kirjade vaadetes</string>
<string name="volume_navigation_list">Nimekirja vaadetes</string>
<string name="show_unified_inbox_title">Näita koondsisendkausta</string>
<string name="show_starred_count_title">Näita tärniga tähistatud kirjade arvu</string>
<string name="integrated_inbox_title">Koondsisendkaust</string>

View file

@ -632,8 +632,6 @@ Mesedez akatsen berri emateko, ezaugarri berriak gehitzeko eta galderak egiteko
<string name="account_setup_failed_dlg_invalid_certificate_title">Ziurtagiri ezezaguna</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Onartu gakoa</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Baztertu gakoa</string>
<string name="message_view_help_key">Del (edo D) - Ezabatu\nR - Erantzun\nA - Erantzun denei\nC - Idatzi\nF - Birbidali\nM - Mugitu\nV - Artxibatu\nY - Kopiatu\nZ - Markatu irakurri (gabe) gisa\nG - Izarra\nO - Ordenatze mota\nI - Ordenatzeko irizpidea\nQ - Itzuli Karpetetara\nS - Hautatu/desautatu\nJ or P - Aurreko Mezua\nK or N - Hurrengo Mezua</string>
<string name="message_list_help_key">Del (edo D) - Ezabatu\nC - Idatzi\nM - Mugitu\nV - Artxibatu\nY - Kopiatu\nZ - Markatu irakurri (gabe) gisa\nG - Izarra\nO - Ordenatze mota\nI - Ordenatzeko irizpidea\nQ - Itzuli Karpetetara\nS - Hautatu/desautatu</string>
<string name="folder_list_filter_hint">Karpetaren izenak dauka</string>
<string name="folder_list_display_mode_label">Erakutsi karpetak…</string>
<string name="folder_list_display_mode_all">Karpeta guztiak</string>
@ -681,9 +679,6 @@ Mesedez akatsen berri emateko, ezaugarri berriak gehitzeko eta galderak egiteko
<string name="account_setup_push_limit_1000">1000 karpeta</string>
<string name="animations_title">Animazioak</string>
<string name="animations_summary">Erabili bistaratze efektu nabarmenak</string>
<string name="volume_navigation_title">Bolumen teklekin nabigatu</string>
<string name="volume_navigation_message">Mezu barruko ikuspegiak</string>
<string name="volume_navigation_list">Zerrenda barruko ikuspegiak</string>
<string name="show_unified_inbox_title">Erakutsi Sarrera Ontzi Bateratua</string>
<string name="show_starred_count_title">Erakutsi kontu izardunak</string>
<string name="integrated_inbox_title">Sarrerako ontzi bateratua</string>

View file

@ -633,8 +633,6 @@
<string name="account_setup_failed_dlg_invalid_certificate_title">گواهی ناشناس</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">پذیرش کلید</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">ردکردن کلید</string>
<string name="message_view_help_key">Del (یا D) - حذف\nR - پاسخ\nA - پاسخ به همه\nC - نوشتن\nF - هدایت\nM - انتقال\nV - بایگانی\nY - کپی\nZ - نشان بزن که (نـ)خواندم\nG - ستاره\nO - نوع ترتیب\nI - ترتیب\nQ - بازگشت به پوشه‌ها\nS - انتخاب (نـ)کردن\nJ یا P - پیام قبلی\nK یا N - پیام بعدی</string>
<string name="message_list_help_key">Del (یا D) - حذف\nC - نوشتن\nM - انتقال\nV - بایگانی\nY - کپی\nZ - نشان بزن که (نـ)خواندم\nG - ستاره\nO - نوع ترتیب\nI - ترتیب\nQ - بازگشت به پوشه‌ها\nS - انتخاب (نـ)کردن</string>
<string name="folder_list_filter_hint">بخشی از نام پوشه</string>
<string name="folder_list_display_mode_label">نمایش کدام پوشه‌ها…</string>
<string name="folder_list_display_mode_all">همهٔ پوشه‌ها</string>
@ -682,9 +680,6 @@
<string name="account_setup_push_limit_1000">۱۰۰۰ پوشه</string>
<string name="animations_title">پویانمایی</string>
<string name="animations_summary">استفاده از جلوه‌های پُرزرق‌وبرق</string>
<string name="volume_navigation_title">جابه‌جایی با کلیدهای تنظیم صدا</string>
<string name="volume_navigation_message">در نماهای پیام</string>
<string name="volume_navigation_list">در نماهای لیستی</string>
<string name="show_unified_inbox_title">نمایش صندوق یکپارچه</string>
<string name="show_starred_count_title">نمایش تعداد ستاره‌دارها</string>
<string name="integrated_inbox_title">صندوق ورودی یکپارچه</string>

View file

@ -632,8 +632,6 @@ Ilmoita virheistä, ota osaa sovelluskehitykseen ja esitä kysymyksiä osoittees
<string name="account_setup_failed_dlg_invalid_certificate_title">Tunnistamaton varmenne</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Hyväksy-avain</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Hylkää-avain</string>
<string name="message_view_help_key">Del (tai D) - Poista\nR - Vastaa\nA - Vastaa Kaikille\nC - Uusi viesti\nF - Välitä\nM - Siirrä\nV - Arkistoi\nY - Kopioi\nZ - Merkitse Lukemattomaksi(luetuksi)\nG - Merkitse tähdellä\nO - Lajittelun tyyppi\nI - Lajittelun järjestys\nQ - Palaa kansioihin\nS - Valitse/Poista valinta\nJ tai P - Edellinen viesti\nK or N - Seuraava viesti</string>
<string name="message_list_help_key">Del (tai D) - Poista\nC - Uusi viesti\nM - Siirrä\nV - Arkistoi\nY - Kopioi\nZ - Merkitse (Lukemattomaksi)luetuksi\nG - Merkitse tähdellä\nO - Lajittelun tyyppi\nI - Lajittelun järjestys\nQ - Palaa kansioihin\nS - Valitse / poista valinta</string>
<string name="folder_list_filter_hint">Kansion nimi sisältää</string>
<string name="folder_list_display_mode_label">Kansiot</string>
<string name="folder_list_display_mode_all">Näytä kaikki</string>
@ -681,9 +679,7 @@ Ilmoita virheistä, ota osaa sovelluskehitykseen ja esitä kysymyksiä osoittees
<string name="account_setup_push_limit_1000">1000 kansiota</string>
<string name="animations_title">Animaatio</string>
<string name="animations_summary">Käytä koreita visuaalisia tehosteita</string>
<string name="volume_navigation_title">Navigointi äänenvoimakkuusnäppäimillä</string>
<string name="volume_navigation_message">Viestinäkymä</string>
<string name="volume_navigation_list">Erilaisia listanäkymiä</string>
<string name="volume_navigation_title">Liikkuminen äänipainikkeilla viestinäkymässä</string>
<string name="show_unified_inbox_title">Näytä \"Yhdistetty saapuneet\"</string>
<string name="show_starred_count_title">Näytä tähdellä merkittyjen viestien määrä</string>
<string name="integrated_inbox_title">Yhdistetty saapuneet</string>

View file

@ -636,8 +636,6 @@ Rapportez les bogues, recommandez de nouvelles fonctions et posez vos questions
<string name="account_setup_failed_dlg_invalid_certificate_title">Certificat non reconnu</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Accepter la clé</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Rejeter la clé</string>
<string name="message_view_help_key">Suppr (ou D) - Supprimer\nR - Répondre\nA - Répondre à tous\nC - Rédiger\nF - Transférer\nM - Déplacer\nV - Archiver\nY - Copier\nZ - Marquer comme lu ou non\nG - Étoile\nO - Type de tri\nI - Ordre de tri\nQ - Retourner aux dossiers\nS - Sélectionner/dessélectionner\nJ ou P - Courriel précédent\nK ou N - Courriel suivant</string>
<string name="message_list_help_key">Suppr (ou D) - Supprimer\nC - Rédiger\nM - Déplacer\nV - Archiver\nY - Copier\nZ - Marquer comme lu ou non\nG - Étoile\nO - Type de tri\nI - Ordre de tri\nQ - Retourner aux dossiers\nS - Sélectionner/dessélectionner</string>
<string name="folder_list_filter_hint">Le nom de dossier comprend</string>
<string name="folder_list_display_mode_label">Afficher les dossiers…</string>
<string name="folder_list_display_mode_all">Tous les dossiers</string>
@ -685,9 +683,6 @@ Rapportez les bogues, recommandez de nouvelles fonctions et posez vos questions
<string name="account_setup_push_limit_1000">1 000 dossiers</string>
<string name="animations_title">Animation</string>
<string name="animations_summary">Utiliser des effets visuels voyants</string>
<string name="volume_navigation_title">Navigation à laide de la touche de volume</string>
<string name="volume_navigation_message">Dans les vues des courriels</string>
<string name="volume_navigation_list">Dans les vues en liste</string>
<string name="show_unified_inbox_title">Afficher la boîte de réception unifiée</string>
<string name="show_starred_count_title">Afficher le compte détoilés</string>
<string name="integrated_inbox_title">Boîte de réception unifiée</string>

View file

@ -628,8 +628,6 @@ Graach flaterrapporten stjoere, bydragen foar nije funksjes en fragen stelle op
<string name="account_setup_failed_dlg_invalid_certificate_title">Unbekend sertifikaat</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Kaai akseptearje</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Kaai wegerje</string>
<string name="message_view_help_key">Del (of D) - Fuortsmite\nR - Beäntwurdzje\nA - Elkenien beäntwurdzje\nC - Opstelle\nF - Trochstjoere\nM - Ferpleatse\nV - Argivearje\nY - Kopiearje\nZ - (net)lêzen markearje\nG - Stjer\nO - Sorteartype\nI - Sortearfolchoarder\nQ - Tebek nei Mappen\nS - Selektearje/deselektearje\nJ of P - Foarich berjocht\nK of N - Folgjende berjocht</string>
<string name="message_list_help_key">Del (of D) - Fuortsmite\nC - Opstelle\nM - Ferpleatse\nV - Argivearje\nY - Kopiearje\nZ - (net)lêzen markearje\nG - Stjer\nO - Sorteartype\nI - Sortearfolchoarder\nQ - Tebek nei Mappen\nS - Selektearje/deselektearje</string>
<string name="folder_list_filter_hint">Mapnamme befettet</string>
<string name="folder_list_display_mode_label">Mappen</string>
<string name="folder_list_display_mode_all">Alle mappen</string>
@ -677,9 +675,7 @@ Graach flaterrapporten stjoere, bydragen foar nije funksjes en fragen stelle op
<string name="account_setup_push_limit_1000">1000 mappen</string>
<string name="animations_title">Animaasje</string>
<string name="animations_summary">Opsichtige fisuele effekten brûke</string>
<string name="volume_navigation_title">Folumetoetsnavigaasje</string>
<string name="volume_navigation_message">Berjochtbyld</string>
<string name="volume_navigation_list">Fariabele listwerjefte</string>
<string name="volume_navigation_title">Folumetoetsnavigaasje yn berjochtbyld</string>
<string name="show_unified_inbox_title">Kombinearre Postfek Yn werjaan</string>
<string name="show_starred_count_title">It oantal berjochten mei in stjer werjaan</string>
<string name="integrated_inbox_title">Kombinearre Postfek Yn</string>

View file

@ -545,33 +545,6 @@
<string name="account_setup_failed_dlg_invalid_certificate_title">Teisteanas nach aithne dhuinn</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Gabh ris an iuchair</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Diùlt an iuchair</string>
<string name="message_view_help_key">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</string>
<string name="message_list_help_key">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</string>
<string name="folder_list_filter_hint">Ainm a phasgain anns a bheil</string>
<string name="folder_list_display_mode_label">Seall pasganan…</string>
<string name="folder_list_display_mode_all">Na h-uile pasgan</string>
@ -617,9 +590,6 @@
<string name="account_setup_push_limit_1000">1,000 pasgan</string>
<string name="animations_title">Beòthachadh</string>
<string name="animations_summary">Cleachd èifeachdan lèirsinneach leòmach</string>
<string name="volume_navigation_title">Seòladaireachd le putanan àirde na fuaime</string>
<string name="volume_navigation_message">Ann an seallaidhean theachdaireachdan</string>
<string name="volume_navigation_list">Ann an seallaidhean liostaichean</string>
<string name="show_unified_inbox_title">Seall an t-oll-bhogsa</string>
<string name="integrated_inbox_title">An t-oll-bhogsa</string>
<string name="integrated_inbox_detail">Na h-uile teachdaireachd ann am pasganan co-aonaichte</string>

View file

@ -496,9 +496,6 @@
<string name="account_setup_push_limit_1000">1000 cartafoles</string>
<string name="animations_title">Animación</string>
<string name="animations_summary">Utilizar animacións</string>
<string name="volume_navigation_title">Navegación coas teclas de volume</string>
<string name="volume_navigation_message">Na vista de mensaxes</string>
<string name="volume_navigation_list">Nas listaxes</string>
<string name="integrated_inbox_title">Caixa de entrada unificada</string>
<string name="integrated_inbox_detail">Todas as mensaxes en cartafoles unificados</string>
<string name="folder_settings_include_in_integrated_inbox_label">Unificar</string>

View file

@ -599,8 +599,6 @@ Por favor envíen informes de fallos, contribúa con novas características e co
<string name="account_setup_failed_dlg_invalid_certificate_title">Certificado descoñecido</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Aceptar certificado</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Rexeitar certificado</string>
<string name="message_view_help_key">Del (ou D) - Eliminar\nR - Respostar\nA - Respostar a todos\nC - Compoñer\nF - Reenviar\nM - Mover\nV - Arquivar\nY - Copiar\nZ - Marcar (Non)lido\nG - Estrela\nO - Sort type\nI - Sort order\nQ - Voltar aos cartafoles\nS - Seleccionar/Non seleccionar\nJ ou P - Mensaxe anterior\nK ou N - Seguinte mensaxe</string>
<string name="message_list_help_key">Del (ou D) - Eliminar\nC - Compoñer\nM - Mover\nV - Arquivar\nY - Copiar\nZ - Marcar (Non)lido\nG - Estrela\nO - Tipo de orde\nI - Establecer orde\nQ - Voltar aos cartafoles\nS - Seleccionar/Non Seleccionar</string>
<string name="folder_list_filter_hint">Nome do cartafol contén</string>
<string name="folder_list_display_mode_label">Carpetas</string>
<string name="folder_list_display_mode_all">Ver todas as carpetas</string>
@ -648,9 +646,6 @@ Por favor envíen informes de fallos, contribúa con novas características e co
<string name="account_setup_push_limit_1000">1000 carpetas</string>
<string name="animations_title">Animacións</string>
<string name="animations_summary">Usar animacións</string>
<string name="volume_navigation_title">Navegación con teclas de volume</string>
<string name="volume_navigation_message">Vista de mensaxe</string>
<string name="volume_navigation_list">Listas de mensaxes</string>
<string name="show_unified_inbox_title">Amosar a caixa de entrada unificada</string>
<string name="show_starred_count_title">Amosar o reconto das estrelas</string>
<string name="integrated_inbox_title">Entrada unificada</string>

View file

@ -539,8 +539,6 @@
<string name="account_setup_failed_dlg_invalid_certificate_title">Nepoznat Certifikat</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Prihvati Ključ</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Odbij ključ</string>
<string name="message_view_help_key">Del (ili D) - Obriši\nR - Odgovori\nA - Odgovori svima\nC - Sastavi\nF - Proslijedi\nM - Pomakni\nV - Arhiviraj\nY - Kopiraj\nZ - Označi (Ne)pročitano\nG - Dodaj zvijezdicu\nO - Način sortiranja\nI - Poredak sortiranja\nQ - Nazad na mape\nS - Označi/odznači\nJ ili P - Prethodna poruka\nK ili N - Sljedeća poruka</string>
<string name="message_list_help_key">Del (ili D) - Obriši\nC - Sastavi\nM - Pomakni\nV - Arhiviraj\nY - Kopiraj\nZ - Označi (Ne)pročitano\nG - Dodaj zvijezdicu\nO - Način sortiranja\nI - Poredak sortiranja\nQ - Nazad na mape\nS - Označi/odznači</string>
<string name="folder_list_filter_hint">Naziv mape sadrži</string>
<string name="folder_list_display_mode_label">Prikaži mape…</string>
<string name="folder_list_display_mode_all">Sve mape</string>
@ -588,9 +586,6 @@
<string name="account_setup_push_limit_1000">1000 mapa</string>
<string name="animations_title">Animacija</string>
<string name="animations_summary">Koristi šarolike vizualne efekte</string>
<string name="volume_navigation_title">Navigacija tipkama glasnoće</string>
<string name="volume_navigation_message">U pregledu poruka</string>
<string name="volume_navigation_list">U pregledu popisa</string>
<string name="integrated_inbox_title">Objedinjena Dolazna Pošta</string>
<string name="integrated_inbox_detail">Sve poruke u objedinjenim mapama</string>
<string name="folder_settings_include_in_integrated_inbox_label">Objedini</string>

View file

@ -631,8 +631,6 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
<string name="account_setup_failed_dlg_invalid_certificate_title">Felismerhetetlen tanúsítvány</string>
<string name="account_setup_failed_dlg_invalid_certificate_accept">Kulcs elfogadása</string>
<string name="account_setup_failed_dlg_invalid_certificate_reject">Kulcs visszautasítása</string>
<string name="message_view_help_key">Del (vagy D) Törlés\nR Válasz\nA Válasz mindenkinek\nC Írás\nF Továbbítás\nM Áthelyezés\nV Archiválás\nY Másolás\nZ Megjelölés olvasottként/olvasatlanként\nG Csillagozás\nO Rendezés típusa\nI Rendezési sorrend\nQ Visszatérés a mappákhoz\nS Kijelölés/Kijelölés megszüntetése\nJ vagy P Előző üzenet\nK vagy N Következő üzenet</string>
<string name="message_list_help_key">Del (vagy D) Törlés\nC Írás\nM Áthelyezés\nV Archiválás\nY Másolás\nZ Megjelölés olvasottként/olvasatlanként\nG Csillagozás\nO Rendezés típusa\nI Rendezési sorrend\nQ Visszatérés a mappákhoz\nS Kijelölés/Kijelölés megszüntetése</string>
<string name="folder_list_filter_hint">Mappa neve tartalmazza</string>
<string name="folder_list_display_mode_label">Mappák megjelenítése…</string>
<string name="folder_list_display_mode_all">Összes mappa</string>
@ -680,9 +678,6 @@ Hibajelentések beküldésével közreműködhet az új funkciókban, és kérd
<string name="account_setup_push_limit_1000">1000 mappa</string>
<string name="animations_title">Animációk</string>
<string name="animations_summary">Rikító látható hatások használata</string>
<string name="volume_navigation_title">Hangerő gomb navigáció</string>
<string name="volume_navigation_message">Üzenetnézetekben</string>
<string name="volume_navigation_list">Listanézetekben</string>
<string name="show_unified_inbox_title">Egységes beérkezett üzenetek megjelenítése</string>
<string name="show_starred_count_title">Csillagszámláló megjelenítése</string>
<string name="integrated_inbox_title">Egységes beérkezett üzenetek</string>

Some files were not shown because too many files have changed in this diff Show more