Repo created
This commit is contained in:
parent
75dc487a7a
commit
39c29d175b
6317 changed files with 388324 additions and 2 deletions
23
feature/widget/message-list-glance/build.gradle.kts
Normal file
23
feature/widget/message-list-glance/build.gradle.kts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
plugins {
|
||||
id(ThunderbirdPlugins.Library.android)
|
||||
alias(libs.plugins.compose)
|
||||
}
|
||||
|
||||
android {
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
namespace = "net.thunderbird.feature.widget.message.list"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.legacy.ui.legacy)
|
||||
implementation(projects.legacy.core)
|
||||
|
||||
implementation(libs.androidx.glance.appwidget)
|
||||
implementation(libs.androidx.glance.material3)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
|
||||
debugImplementation(libs.androidx.glance.appwidget.preview)
|
||||
debugImplementation(libs.androidx.glance.preview)
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package net.thunderbird.feature.widget.message.list.ui
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.glance.preview.ExperimentalGlancePreviewApi
|
||||
import androidx.glance.preview.Preview
|
||||
import app.k9mail.legacy.message.controller.MessageReference
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import net.thunderbird.feature.widget.message.list.MessageListItem
|
||||
|
||||
@OptIn(ExperimentalGlancePreviewApi::class)
|
||||
@Preview(widthDp = 250, heightDp = 180)
|
||||
@Composable
|
||||
internal fun MessageListWidgetContentPreview() {
|
||||
MessageListWidgetContent(
|
||||
mails = generateMessageListItems(),
|
||||
onOpenApp = {},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalGlancePreviewApi::class)
|
||||
@Preview(widthDp = 250, heightDp = 180)
|
||||
@Composable
|
||||
internal fun MessageListWidgetContentEmptyPreview() {
|
||||
MessageListWidgetContent(
|
||||
mails = persistentListOf(),
|
||||
onOpenApp = {},
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateMessageListItems(): ImmutableList<MessageListItem> {
|
||||
return persistentListOf(
|
||||
generateMessageListItem(
|
||||
displayName = "Alice",
|
||||
displayDate = "1 Jan",
|
||||
subject = "Subject 1",
|
||||
preview = "Preview 1",
|
||||
color = Color.BLUE,
|
||||
isRead = false,
|
||||
),
|
||||
generateMessageListItem(
|
||||
displayName = "Bob",
|
||||
displayDate = "2 Jan",
|
||||
subject = "Subject 2",
|
||||
preview = "Preview 2",
|
||||
color = Color.RED,
|
||||
isRead = true,
|
||||
),
|
||||
generateMessageListItem(
|
||||
displayName = "Charlie",
|
||||
displayDate = "3 Jan",
|
||||
subject = "Subject 3",
|
||||
preview = "Preview 3",
|
||||
color = Color.RED,
|
||||
isRead = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun generateMessageListItem(
|
||||
displayName: String,
|
||||
displayDate: String,
|
||||
subject: String,
|
||||
preview: String,
|
||||
color: Int,
|
||||
isRead: Boolean,
|
||||
): MessageListItem {
|
||||
return MessageListItem(
|
||||
displayName = displayName,
|
||||
displayDate = displayDate,
|
||||
subject = subject,
|
||||
preview = preview,
|
||||
isRead = isRead,
|
||||
hasAttachments = false,
|
||||
threadCount = 0,
|
||||
accountColor = color,
|
||||
uniqueId = 0,
|
||||
messageReference = MessageReference("accountUuid", 123, "messageServerId"),
|
||||
sortSubject = subject,
|
||||
sortMessageDate = 0,
|
||||
sortInternalDate = 0,
|
||||
sortIsStarred = false,
|
||||
sortDatabaseId = 0,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val featureWidgetMessageListModule = module {
|
||||
factory {
|
||||
MessageListLoader(
|
||||
preferences = get(),
|
||||
messageListRepository = get(),
|
||||
messageHelper = get(),
|
||||
generalSettingsManager = get(),
|
||||
outboxFolderManager = get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.feature.search.legacy.LocalMessageSearch
|
||||
|
||||
internal data class MessageListConfig(
|
||||
val search: LocalMessageSearch,
|
||||
val showingThreadedList: Boolean,
|
||||
val sortType: SortType,
|
||||
val sortAscending: Boolean,
|
||||
val sortDateAscending: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.message.controller.MessageReference
|
||||
|
||||
internal data class MessageListItem(
|
||||
val displayName: String,
|
||||
val displayDate: String,
|
||||
val subject: String,
|
||||
val preview: String,
|
||||
val isRead: Boolean,
|
||||
val hasAttachments: Boolean,
|
||||
val threadCount: Int,
|
||||
val accountColor: Int,
|
||||
val messageReference: MessageReference,
|
||||
val uniqueId: Long,
|
||||
|
||||
val sortSubject: String?,
|
||||
val sortMessageDate: Long,
|
||||
val sortInternalDate: Long,
|
||||
val sortIsStarred: Boolean,
|
||||
val sortDatabaseId: Long,
|
||||
)
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.mailstore.MessageDetailsAccessor
|
||||
import app.k9mail.legacy.mailstore.MessageMapper
|
||||
import app.k9mail.legacy.message.controller.MessageReference
|
||||
import com.fsck.k9.helper.MessageHelper
|
||||
import com.fsck.k9.ui.helper.DisplayAddressHelper
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.mail.folder.api.OutboxFolderManager
|
||||
|
||||
internal class MessageListItemMapper(
|
||||
private val messageHelper: MessageHelper,
|
||||
private val account: LegacyAccount,
|
||||
private val generalSettingsManager: GeneralSettingsManager,
|
||||
private val outboxFolderManager: OutboxFolderManager,
|
||||
) : MessageMapper<MessageListItem> {
|
||||
private val calendar: Calendar = Calendar.getInstance()
|
||||
|
||||
override fun map(message: MessageDetailsAccessor): MessageListItem {
|
||||
val fromAddresses = message.fromAddresses
|
||||
val toAddresses = message.toAddresses
|
||||
val previewResult = message.preview
|
||||
val previewText = if (previewResult.isPreviewTextAvailable) previewResult.previewText else ""
|
||||
val uniqueId = createUniqueId(account, message.id)
|
||||
val showRecipients = DisplayAddressHelper.shouldShowRecipients(outboxFolderManager, account, message.folderId)
|
||||
val displayAddress = if (showRecipients) toAddresses.firstOrNull() else fromAddresses.firstOrNull()
|
||||
val displayName = if (showRecipients) {
|
||||
messageHelper.getRecipientDisplayNames(
|
||||
addresses = toAddresses.toTypedArray(),
|
||||
isShowCorrespondentNames = generalSettingsManager.getConfig().display.isShowCorrespondentNames,
|
||||
isChangeContactNameColor = generalSettingsManager.getConfig().display.isChangeContactNameColor,
|
||||
).toString()
|
||||
} else {
|
||||
messageHelper.getSenderDisplayName(displayAddress).toString()
|
||||
}
|
||||
|
||||
return MessageListItem(
|
||||
displayName = displayName,
|
||||
displayDate = formatDate(message.messageDate),
|
||||
subject = message.subject.orEmpty(),
|
||||
preview = previewText,
|
||||
isRead = message.isRead,
|
||||
hasAttachments = message.hasAttachments,
|
||||
threadCount = message.threadCount,
|
||||
accountColor = account.chipColor,
|
||||
messageReference = MessageReference(account.uuid, message.folderId, message.messageServerId),
|
||||
uniqueId = uniqueId,
|
||||
sortSubject = message.subject,
|
||||
sortMessageDate = message.messageDate,
|
||||
sortInternalDate = message.internalDate,
|
||||
sortIsStarred = message.isStarred,
|
||||
sortDatabaseId = message.id,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("ImplicitDefaultLocale")
|
||||
private fun formatDate(date: Long): String {
|
||||
calendar.timeInMillis = date
|
||||
val dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
val month = calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())
|
||||
|
||||
return String.format("%d %s", dayOfMonth, month)
|
||||
}
|
||||
|
||||
private fun createUniqueId(account: LegacyAccount, messageId: Long): Long {
|
||||
return ((account.accountNumber + 1).toLong() shl ACCOUNT_NUMBER_BIT_SHIFT) + messageId
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ACCOUNT_NUMBER_BIT_SHIFT = 52
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.mailstore.MessageListRepository
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.helper.MessageHelper
|
||||
import com.fsck.k9.mailstore.MessageColumns
|
||||
import com.fsck.k9.search.getAccounts
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.core.logging.legacy.Log
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.mail.folder.api.OutboxFolderManager
|
||||
import net.thunderbird.feature.search.legacy.sql.SqlWhereClause
|
||||
|
||||
internal class MessageListLoader(
|
||||
private val preferences: Preferences,
|
||||
private val messageListRepository: MessageListRepository,
|
||||
private val messageHelper: MessageHelper,
|
||||
private val generalSettingsManager: GeneralSettingsManager,
|
||||
private val outboxFolderManager: OutboxFolderManager,
|
||||
) {
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
fun getMessageList(config: MessageListConfig): List<MessageListItem> {
|
||||
return try {
|
||||
getMessageListInfo(config)
|
||||
} catch (e: Exception) {
|
||||
Log.e(e, "Error while fetching message list")
|
||||
|
||||
// TODO: Return an error object instead of an empty list
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMessageListInfo(config: MessageListConfig): List<MessageListItem> {
|
||||
val accounts = config.search.getAccounts(preferences)
|
||||
val messageListItems = accounts
|
||||
.flatMap { account ->
|
||||
loadMessageListForAccount(account, config)
|
||||
}
|
||||
.sortedWith(config)
|
||||
|
||||
return messageListItems
|
||||
}
|
||||
|
||||
private fun loadMessageListForAccount(account: LegacyAccount, config: MessageListConfig): List<MessageListItem> {
|
||||
val accountUuid = account.uuid
|
||||
val sortOrder = buildSortOrder(config)
|
||||
val mapper = MessageListItemMapper(messageHelper, account, generalSettingsManager, outboxFolderManager)
|
||||
|
||||
return if (config.showingThreadedList) {
|
||||
val (selection, selectionArgs) = buildSelection(config)
|
||||
messageListRepository.getThreadedMessages(accountUuid, selection, selectionArgs, sortOrder, mapper)
|
||||
} else {
|
||||
val (selection, selectionArgs) = buildSelection(config)
|
||||
messageListRepository.getMessages(accountUuid, selection, selectionArgs, sortOrder, mapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildSelection(config: MessageListConfig): Pair<String, Array<String>> {
|
||||
val whereClause = SqlWhereClause.Builder()
|
||||
.withConditions(config.search.conditions)
|
||||
.build()
|
||||
|
||||
return whereClause.selection to whereClause.selectionArgs.toTypedArray()
|
||||
}
|
||||
|
||||
private fun buildSortOrder(config: MessageListConfig): String {
|
||||
val sortColumn = when (config.sortType) {
|
||||
SortType.SORT_ARRIVAL -> MessageColumns.INTERNAL_DATE
|
||||
SortType.SORT_ATTACHMENT -> "(${MessageColumns.ATTACHMENT_COUNT} < 1)"
|
||||
SortType.SORT_FLAGGED -> "(${MessageColumns.FLAGGED} != 1)"
|
||||
SortType.SORT_SENDER -> MessageColumns.SENDER_LIST // FIXME
|
||||
SortType.SORT_SUBJECT -> "${MessageColumns.SUBJECT} COLLATE NOCASE"
|
||||
SortType.SORT_UNREAD -> MessageColumns.READ
|
||||
SortType.SORT_DATE -> MessageColumns.DATE
|
||||
}
|
||||
|
||||
val sortDirection = if (config.sortAscending) " ASC" else " DESC"
|
||||
val secondarySort = if (config.sortType == SortType.SORT_DATE || config.sortType == SortType.SORT_ARRIVAL) {
|
||||
""
|
||||
} else {
|
||||
if (config.sortDateAscending) {
|
||||
"${MessageColumns.DATE} ASC, "
|
||||
} else {
|
||||
"${MessageColumns.DATE} DESC, "
|
||||
}
|
||||
}
|
||||
|
||||
return "$sortColumn$sortDirection, $secondarySort${MessageColumns.ID} DESC"
|
||||
}
|
||||
|
||||
private fun List<MessageListItem>.sortedWith(config: MessageListConfig): List<MessageListItem> {
|
||||
val comparator = when (config.sortType) {
|
||||
SortType.SORT_DATE -> {
|
||||
compareBy(config.sortAscending) { it.sortMessageDate }
|
||||
}
|
||||
|
||||
SortType.SORT_ARRIVAL -> {
|
||||
compareBy(config.sortAscending) { it.sortInternalDate }
|
||||
}
|
||||
|
||||
SortType.SORT_SUBJECT -> {
|
||||
compareStringBy<MessageListItem>(config.sortAscending) { it.sortSubject.orEmpty() }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_SENDER -> {
|
||||
compareStringBy<MessageListItem>(config.sortAscending) { it.displayName }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_UNREAD -> {
|
||||
compareBy<MessageListItem>(config.sortAscending) { it.isRead }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_FLAGGED -> {
|
||||
compareBy<MessageListItem>(!config.sortAscending) { it.sortIsStarred }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_ATTACHMENT -> {
|
||||
compareBy<MessageListItem>(!config.sortAscending) { it.hasAttachments }
|
||||
.thenByDate(config)
|
||||
}
|
||||
}.thenByDescending { it.sortDatabaseId }
|
||||
|
||||
return this.sortedWith(comparator)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> compareBy(sortAscending: Boolean, crossinline selector: (T) -> Comparable<*>?): Comparator<T> {
|
||||
return if (sortAscending) {
|
||||
compareBy(selector)
|
||||
} else {
|
||||
compareByDescending(selector)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> compareStringBy(sortAscending: Boolean, crossinline selector: (T) -> String): Comparator<T> {
|
||||
return if (sortAscending) {
|
||||
compareBy(String.CASE_INSENSITIVE_ORDER, selector)
|
||||
} else {
|
||||
compareByDescending(String.CASE_INSENSITIVE_ORDER, selector)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Comparator<MessageListItem>.thenByDate(config: MessageListConfig): Comparator<MessageListItem> {
|
||||
return if (config.sortDateAscending) {
|
||||
thenBy { it.sortMessageDate }
|
||||
} else {
|
||||
thenByDescending { it.sortMessageDate }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.glance.GlanceId
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.provideContent
|
||||
import com.fsck.k9.CoreResourceProvider
|
||||
import com.fsck.k9.activity.MessageList.Companion.intentDisplaySearch
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.search.legacy.SearchAccount.Companion.createUnifiedInboxAccount
|
||||
import net.thunderbird.feature.widget.message.list.ui.MessageListWidgetContent
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
internal class MessageListWidget : GlanceAppWidget(), KoinComponent {
|
||||
|
||||
private val messageListLoader: MessageListLoader by inject()
|
||||
private val coreResourceProvider: CoreResourceProvider by inject()
|
||||
private val generalSettingsManager: GeneralSettingsManager by inject()
|
||||
|
||||
companion object {
|
||||
private var lastMailList = emptyList<MessageListItem>()
|
||||
private const val MESSAGE_COUNT = 100
|
||||
}
|
||||
|
||||
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||
provideContent {
|
||||
var mails by remember { mutableStateOf(lastMailList) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val unifiedInboxSearch = createUnifiedInboxAccount(
|
||||
unifiedInboxTitle = coreResourceProvider.searchUnifiedInboxTitle(),
|
||||
unifiedInboxDetail = coreResourceProvider.searchUnifiedInboxDetail(),
|
||||
).relatedSearch
|
||||
val messageListConfig = MessageListConfig(
|
||||
search = unifiedInboxSearch,
|
||||
showingThreadedList = generalSettingsManager.getConfig()
|
||||
.display.inboxSettings.isThreadedViewEnabled,
|
||||
sortType = SortType.SORT_DATE,
|
||||
sortAscending = false,
|
||||
sortDateAscending = false,
|
||||
)
|
||||
val list = messageListLoader.getMessageList(messageListConfig)
|
||||
mails = list.subList(0, list.size.coerceAtMost(MESSAGE_COUNT))
|
||||
lastMailList = mails
|
||||
}
|
||||
}
|
||||
|
||||
MessageListWidgetContent(
|
||||
mails = mails.toImmutableList(),
|
||||
onOpenApp = { openApp(context) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openApp(context: Context) {
|
||||
val unifiedInboxAccount = createUnifiedInboxAccount(
|
||||
unifiedInboxTitle = coreResourceProvider.searchUnifiedInboxTitle(),
|
||||
unifiedInboxDetail = coreResourceProvider.searchUnifiedInboxDetail(),
|
||||
)
|
||||
val intent = intentDisplaySearch(
|
||||
context = context,
|
||||
search = unifiedInboxAccount.relatedSearch,
|
||||
noThreading = true,
|
||||
newTask = true,
|
||||
clearTop = true,
|
||||
).apply {
|
||||
action = nextInt().toString()
|
||||
}
|
||||
PendingIntentCompat.getActivity(
|
||||
context,
|
||||
nextInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
false,
|
||||
)!!.send()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package net.thunderbird.feature.widget.message.list
|
||||
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.GlanceAppWidgetReceiver
|
||||
|
||||
class MessageListWidgetReceiver : GlanceAppWidgetReceiver() {
|
||||
override val glanceAppWidget: GlanceAppWidget = MessageListWidget()
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package net.thunderbird.feature.widget.message.list.ui
|
||||
|
||||
import android.app.PendingIntent
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.LocalContext
|
||||
import androidx.glance.action.clickable
|
||||
import androidx.glance.appwidget.cornerRadius
|
||||
import androidx.glance.background
|
||||
import androidx.glance.layout.Alignment
|
||||
import androidx.glance.layout.Box
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.Spacer
|
||||
import androidx.glance.layout.fillMaxWidth
|
||||
import androidx.glance.layout.height
|
||||
import androidx.glance.layout.padding
|
||||
import androidx.glance.layout.width
|
||||
import androidx.glance.layout.wrapContentHeight
|
||||
import androidx.glance.text.Text
|
||||
import androidx.glance.text.TextStyle
|
||||
import com.fsck.k9.activity.MessageList
|
||||
import kotlin.random.Random
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.thunderbird.feature.widget.message.list.MessageListItem
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
internal fun MessageListItemView(item: MessageListItem) {
|
||||
val context = LocalContext.current
|
||||
Row(
|
||||
GlanceModifier.Companion.fillMaxWidth().wrapContentHeight().clickable {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val intent = MessageList.Companion.actionDisplayMessageIntent(context, item.messageReference)
|
||||
PendingIntentCompat.getActivity(
|
||||
context,
|
||||
Random.Default.nextInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
false,
|
||||
)!!
|
||||
.send()
|
||||
}
|
||||
},
|
||||
) {
|
||||
Spacer(GlanceModifier.Companion.width(8.dp).background(Color(item.accountColor)))
|
||||
Column(GlanceModifier.Companion.fillMaxWidth().padding(vertical = 4.dp, horizontal = 4.dp)) {
|
||||
Row(GlanceModifier.Companion.fillMaxWidth()) {
|
||||
Row(GlanceModifier.Companion.defaultWeight(), horizontalAlignment = Alignment.Companion.Start) {
|
||||
Text(
|
||||
item.subject,
|
||||
style = TextStyle(color = GlanceTheme.colors.primary, fontSize = 16.sp),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
Spacer(GlanceModifier.Companion.width(4.dp))
|
||||
Row(horizontalAlignment = Alignment.Companion.End) {
|
||||
Box(
|
||||
GlanceModifier.Companion.background(GlanceTheme.colors.primaryContainer).cornerRadius(8.dp)
|
||||
.padding(2.dp),
|
||||
) {
|
||||
Text(
|
||||
item.threadCount.toString(),
|
||||
style = TextStyle(color = GlanceTheme.colors.primary, fontSize = 13.sp),
|
||||
)
|
||||
}
|
||||
Spacer(GlanceModifier.Companion.width(4.dp))
|
||||
Text(item.displayDate, style = TextStyle(color = GlanceTheme.colors.primary))
|
||||
}
|
||||
}
|
||||
Spacer(GlanceModifier.Companion.height(2.dp))
|
||||
Row {
|
||||
Text(
|
||||
item.displayName,
|
||||
style = TextStyle(color = GlanceTheme.colors.primary, fontSize = 15.sp),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
Spacer(GlanceModifier.Companion.height(2.dp))
|
||||
Row {
|
||||
Text(
|
||||
item.preview,
|
||||
style = TextStyle(color = GlanceTheme.colors.primary, fontSize = 13.sp),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package net.thunderbird.feature.widget.message.list.ui
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.glance.ColorFilter
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.Image
|
||||
import androidx.glance.ImageProvider
|
||||
import androidx.glance.LocalContext
|
||||
import androidx.glance.action.clickable
|
||||
import androidx.glance.appwidget.lazy.LazyColumn
|
||||
import androidx.glance.appwidget.lazy.items
|
||||
import androidx.glance.background
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.Spacer
|
||||
import androidx.glance.layout.fillMaxSize
|
||||
import androidx.glance.layout.fillMaxWidth
|
||||
import androidx.glance.layout.height
|
||||
import androidx.glance.layout.padding
|
||||
import androidx.glance.text.Text
|
||||
import androidx.glance.text.TextStyle
|
||||
import app.k9mail.core.ui.legacy.designsystem.atom.icon.Icons
|
||||
import com.fsck.k9.activity.MessageCompose
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import net.thunderbird.feature.widget.message.list.MessageListItem
|
||||
import net.thunderbird.feature.widget.message.list.R
|
||||
|
||||
@Composable
|
||||
internal fun MessageListWidgetContent(
|
||||
mails: ImmutableList<MessageListItem>,
|
||||
onOpenApp: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
GlanceTheme(GlanceTheme.colors) {
|
||||
Column(GlanceModifier.fillMaxSize().background(GlanceTheme.colors.surface)) {
|
||||
Row(
|
||||
GlanceModifier.padding(horizontal = 8.dp, vertical = 12.dp).fillMaxWidth()
|
||||
.background(GlanceTheme.colors.primaryContainer)
|
||||
.clickable {
|
||||
onOpenApp()
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
context.getString(R.string.message_list_glance_widget_inbox_title),
|
||||
style = TextStyle(color = GlanceTheme.colors.primary, fontSize = 20.sp),
|
||||
)
|
||||
Spacer(GlanceModifier.defaultWeight())
|
||||
Image(
|
||||
ImageProvider(Icons.Outlined.Edit),
|
||||
context.getString(R.string.message_list_glance_widget_compose_action),
|
||||
GlanceModifier.padding(2.dp).padding(end = 6.dp).clickable {
|
||||
val intent = Intent(context, MessageCompose::class.java).apply {
|
||||
action = MessageCompose.ACTION_COMPOSE
|
||||
}
|
||||
PendingIntentCompat.getActivity(
|
||||
context,
|
||||
nextInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
false,
|
||||
)!!.send()
|
||||
},
|
||||
colorFilter = ColorFilter.tint(GlanceTheme.colors.primary),
|
||||
)
|
||||
}
|
||||
LazyColumn(GlanceModifier.fillMaxSize()) {
|
||||
items(mails) {
|
||||
Column {
|
||||
MessageListItemView(it)
|
||||
Spacer(
|
||||
GlanceModifier.height(2.dp).fillMaxWidth()
|
||||
.background(GlanceTheme.colors.surfaceVariant),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_glance_widget_compose_action">Compose</string>
|
||||
<string name="message_list_glance_widget_inbox_title">Unified Inbox</string>
|
||||
<string name="message_list_glance_widget_label">Message List</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:initialLayout="@layout/glance_default_loading_layout"
|
||||
android:minHeight="180dp"
|
||||
android:minWidth="250dp"
|
||||
android:minResizeWidth="110dp"
|
||||
android:minResizeHeight="110dp"
|
||||
android:previewImage="@drawable/message_list_glance_widget_preview"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:updatePeriodMillis="86400000"
|
||||
android:widgetCategory="home_screen|keyguard"
|
||||
/>
|
||||
12
feature/widget/message-list/build.gradle.kts
Normal file
12
feature/widget/message-list/build.gradle.kts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
plugins {
|
||||
id(ThunderbirdPlugins.Library.android)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.legacy.ui.legacy)
|
||||
implementation(projects.legacy.core)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.k9mail.feature.widget.message.list"
|
||||
}
|
||||
11
feature/widget/message-list/src/main/AndroidManifest.xml
Normal file
11
feature/widget/message-list/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
|
||||
<service
|
||||
android:name=".MessageListWidgetService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS"
|
||||
/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViews
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import com.fsck.k9.CoreResourceProvider
|
||||
import com.fsck.k9.activity.MessageCompose
|
||||
import com.fsck.k9.activity.MessageList
|
||||
import com.fsck.k9.activity.MessageList.Companion.intentDisplaySearch
|
||||
import net.thunderbird.feature.search.legacy.SearchAccount.Companion.createUnifiedInboxAccount
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
abstract class BaseMessageListWidgetProvider : AppWidgetProvider(), KoinComponent {
|
||||
private val messageListWidgetManager: MessageListWidgetManager by inject()
|
||||
private val coreResourceProvider: CoreResourceProvider by inject()
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
messageListWidgetManager.onWidgetAdded()
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) {
|
||||
messageListWidgetManager.onWidgetRemoved()
|
||||
}
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
|
||||
val views = RemoteViews(context.packageName, R.layout.message_list_widget_layout)
|
||||
|
||||
views.setTextViewText(R.id.folder, context.getString(R.string.message_list_widget_inbox_title))
|
||||
|
||||
val intent = Intent(context, MessageListWidgetService::class.java)
|
||||
views.setRemoteAdapter(R.id.listView, intent)
|
||||
|
||||
val viewAction = viewActionTemplatePendingIntent(context)
|
||||
views.setPendingIntentTemplate(R.id.listView, viewAction)
|
||||
|
||||
val composeAction = composeActionPendingIntent(context)
|
||||
views.setOnClickPendingIntent(R.id.new_message, composeAction)
|
||||
|
||||
val headerClickAction = viewUnifiedInboxPendingIntent(context)
|
||||
views.setOnClickPendingIntent(R.id.top_controls, headerClickAction)
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
}
|
||||
|
||||
private fun viewActionTemplatePendingIntent(context: Context): PendingIntent {
|
||||
val intent = MessageList.actionDisplayMessageTemplateIntent(
|
||||
context,
|
||||
openInUnifiedInbox = true,
|
||||
messageViewOnly = true,
|
||||
)
|
||||
return PendingIntentCompat.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT, true)!!
|
||||
}
|
||||
|
||||
private fun viewUnifiedInboxPendingIntent(context: Context): PendingIntent {
|
||||
val unifiedInboxAccount = createUnifiedInboxAccount(
|
||||
unifiedInboxTitle = coreResourceProvider.searchUnifiedInboxTitle(),
|
||||
unifiedInboxDetail = coreResourceProvider.searchUnifiedInboxDetail(),
|
||||
)
|
||||
val intent = intentDisplaySearch(
|
||||
context = context,
|
||||
search = unifiedInboxAccount.relatedSearch,
|
||||
noThreading = true,
|
||||
newTask = true,
|
||||
clearTop = true,
|
||||
)
|
||||
return PendingIntentCompat.getActivity(context, -1, intent, PendingIntent.FLAG_UPDATE_CURRENT, false)!!
|
||||
}
|
||||
|
||||
private fun composeActionPendingIntent(context: Context): PendingIntent {
|
||||
val intent = Intent(context, MessageCompose::class.java).apply {
|
||||
action = MessageCompose.ACTION_COMPOSE
|
||||
}
|
||||
return PendingIntentCompat.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, false)!!
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import org.koin.dsl.module
|
||||
|
||||
val messageListWidgetModule = module {
|
||||
single { MessageListWidgetManager(context = get(), messageListRepository = get(), config = get()) }
|
||||
factory {
|
||||
MessageListLoader(
|
||||
preferences = get(),
|
||||
messageListRepository = get(),
|
||||
messageHelper = get(),
|
||||
generalSettingsManager = get(),
|
||||
outboxFolderManager = get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.feature.search.legacy.LocalMessageSearch
|
||||
|
||||
internal data class MessageListConfig(
|
||||
val search: LocalMessageSearch,
|
||||
val showingThreadedList: Boolean,
|
||||
val sortType: SortType,
|
||||
val sortAscending: Boolean,
|
||||
val sortDateAscending: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.message.controller.MessageReference
|
||||
|
||||
internal data class MessageListItem(
|
||||
val displayName: String,
|
||||
val displayDate: String,
|
||||
val subject: String,
|
||||
val preview: String,
|
||||
val isRead: Boolean,
|
||||
val hasAttachments: Boolean,
|
||||
val threadCount: Int,
|
||||
val accountColor: Int,
|
||||
val messageReference: MessageReference,
|
||||
val uniqueId: Long,
|
||||
|
||||
val sortSubject: String?,
|
||||
val sortMessageDate: Long,
|
||||
val sortInternalDate: Long,
|
||||
val sortIsStarred: Boolean,
|
||||
val sortDatabaseId: Long,
|
||||
)
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.mailstore.MessageDetailsAccessor
|
||||
import app.k9mail.legacy.mailstore.MessageMapper
|
||||
import app.k9mail.legacy.message.controller.MessageReference
|
||||
import com.fsck.k9.helper.MessageHelper
|
||||
import com.fsck.k9.ui.helper.DisplayAddressHelper
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.mail.folder.api.OutboxFolderManager
|
||||
|
||||
internal class MessageListItemMapper(
|
||||
private val messageHelper: MessageHelper,
|
||||
private val account: LegacyAccount,
|
||||
private val generalSettingsManager: GeneralSettingsManager,
|
||||
private val outboxFolderManager: OutboxFolderManager,
|
||||
) : MessageMapper<MessageListItem> {
|
||||
private val calendar: Calendar = Calendar.getInstance()
|
||||
|
||||
override fun map(message: MessageDetailsAccessor): MessageListItem {
|
||||
val fromAddresses = message.fromAddresses
|
||||
val toAddresses = message.toAddresses
|
||||
val previewResult = message.preview
|
||||
val previewText = if (previewResult.isPreviewTextAvailable) previewResult.previewText else ""
|
||||
val uniqueId = createUniqueId(account, message.id)
|
||||
val showRecipients = DisplayAddressHelper.shouldShowRecipients(outboxFolderManager, account, message.folderId)
|
||||
val displayAddress = if (showRecipients) toAddresses.firstOrNull() else fromAddresses.firstOrNull()
|
||||
val displayName = if (showRecipients) {
|
||||
messageHelper.getRecipientDisplayNames(
|
||||
addresses = toAddresses.toTypedArray(),
|
||||
isShowCorrespondentNames = generalSettingsManager.getConfig().display.isShowCorrespondentNames,
|
||||
isChangeContactNameColor = generalSettingsManager.getConfig().display.isChangeContactNameColor,
|
||||
).toString()
|
||||
} else {
|
||||
messageHelper.getSenderDisplayName(displayAddress).toString()
|
||||
}
|
||||
|
||||
return MessageListItem(
|
||||
displayName = displayName,
|
||||
displayDate = formatDate(message.messageDate),
|
||||
subject = message.subject.orEmpty(),
|
||||
preview = previewText,
|
||||
isRead = message.isRead,
|
||||
hasAttachments = message.hasAttachments,
|
||||
threadCount = message.threadCount,
|
||||
accountColor = account.chipColor,
|
||||
messageReference = MessageReference(account.uuid, message.folderId, message.messageServerId),
|
||||
uniqueId = uniqueId,
|
||||
sortSubject = message.subject,
|
||||
sortMessageDate = message.messageDate,
|
||||
sortInternalDate = message.internalDate,
|
||||
sortIsStarred = message.isStarred,
|
||||
sortDatabaseId = message.id,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("ImplicitDefaultLocale")
|
||||
private fun formatDate(date: Long): String {
|
||||
calendar.timeInMillis = date
|
||||
val dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
val month = calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())
|
||||
|
||||
return String.format("%d %s", dayOfMonth, month)
|
||||
}
|
||||
|
||||
private fun createUniqueId(account: LegacyAccount, messageId: Long): Long {
|
||||
return ((account.accountNumber + 1).toLong() shl ACCOUNT_NUMBER_BIT_SHIFT) + messageId
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ACCOUNT_NUMBER_BIT_SHIFT = 52
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import app.k9mail.legacy.mailstore.MessageListRepository
|
||||
import com.fsck.k9.Preferences
|
||||
import com.fsck.k9.helper.MessageHelper
|
||||
import com.fsck.k9.mailstore.MessageColumns
|
||||
import com.fsck.k9.search.getAccounts
|
||||
import net.thunderbird.core.android.account.LegacyAccount
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.core.logging.legacy.Log
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.mail.folder.api.OutboxFolderManager
|
||||
import net.thunderbird.feature.search.legacy.sql.SqlWhereClause
|
||||
|
||||
internal class MessageListLoader(
|
||||
private val preferences: Preferences,
|
||||
private val messageListRepository: MessageListRepository,
|
||||
private val messageHelper: MessageHelper,
|
||||
private val generalSettingsManager: GeneralSettingsManager,
|
||||
private val outboxFolderManager: OutboxFolderManager,
|
||||
) {
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
fun getMessageList(config: MessageListConfig): List<MessageListItem> {
|
||||
return try {
|
||||
getMessageListInfo(config)
|
||||
} catch (e: Exception) {
|
||||
Log.e(e, "Error while fetching message list")
|
||||
|
||||
// TODO: Return an error object instead of an empty list
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMessageListInfo(config: MessageListConfig): List<MessageListItem> {
|
||||
val accounts = config.search.getAccounts(preferences)
|
||||
val messageListItems = accounts
|
||||
.flatMap { account ->
|
||||
loadMessageListForAccount(account, config)
|
||||
}
|
||||
.sortedWith(config)
|
||||
|
||||
return messageListItems
|
||||
}
|
||||
|
||||
private fun loadMessageListForAccount(account: LegacyAccount, config: MessageListConfig): List<MessageListItem> {
|
||||
val accountUuid = account.uuid
|
||||
val sortOrder = buildSortOrder(config)
|
||||
val mapper = MessageListItemMapper(messageHelper, account, generalSettingsManager, outboxFolderManager)
|
||||
|
||||
return if (config.showingThreadedList) {
|
||||
val (selection, selectionArgs) = buildSelection(config)
|
||||
messageListRepository.getThreadedMessages(accountUuid, selection, selectionArgs, sortOrder, mapper)
|
||||
} else {
|
||||
val (selection, selectionArgs) = buildSelection(config)
|
||||
messageListRepository.getMessages(accountUuid, selection, selectionArgs, sortOrder, mapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildSelection(config: MessageListConfig): Pair<String, Array<String>> {
|
||||
val whereClause = SqlWhereClause.Builder()
|
||||
.withConditions(config.search.conditions)
|
||||
.build()
|
||||
|
||||
return whereClause.selection to whereClause.selectionArgs.toTypedArray()
|
||||
}
|
||||
|
||||
private fun buildSortOrder(config: MessageListConfig): String {
|
||||
val sortColumn = when (config.sortType) {
|
||||
SortType.SORT_ARRIVAL -> MessageColumns.INTERNAL_DATE
|
||||
SortType.SORT_ATTACHMENT -> "(${MessageColumns.ATTACHMENT_COUNT} < 1)"
|
||||
SortType.SORT_FLAGGED -> "(${MessageColumns.FLAGGED} != 1)"
|
||||
SortType.SORT_SENDER -> MessageColumns.SENDER_LIST // FIXME
|
||||
SortType.SORT_SUBJECT -> "${MessageColumns.SUBJECT} COLLATE NOCASE"
|
||||
SortType.SORT_UNREAD -> MessageColumns.READ
|
||||
SortType.SORT_DATE -> MessageColumns.DATE
|
||||
else -> MessageColumns.DATE
|
||||
}
|
||||
|
||||
val sortDirection = if (config.sortAscending) " ASC" else " DESC"
|
||||
val secondarySort = if (config.sortType == SortType.SORT_DATE || config.sortType == SortType.SORT_ARRIVAL) {
|
||||
""
|
||||
} else {
|
||||
if (config.sortDateAscending) {
|
||||
"${MessageColumns.DATE} ASC, "
|
||||
} else {
|
||||
"${MessageColumns.DATE} DESC, "
|
||||
}
|
||||
}
|
||||
|
||||
return "$sortColumn$sortDirection, $secondarySort${MessageColumns.ID} DESC"
|
||||
}
|
||||
|
||||
private fun List<MessageListItem>.sortedWith(config: MessageListConfig): List<MessageListItem> {
|
||||
val comparator = when (config.sortType) {
|
||||
SortType.SORT_DATE -> {
|
||||
compareBy(config.sortAscending) { it.sortMessageDate }
|
||||
}
|
||||
|
||||
SortType.SORT_ARRIVAL -> {
|
||||
compareBy(config.sortAscending) { it.sortInternalDate }
|
||||
}
|
||||
|
||||
SortType.SORT_SUBJECT -> {
|
||||
compareStringBy<MessageListItem>(config.sortAscending) { it.sortSubject.orEmpty() }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_SENDER -> {
|
||||
compareStringBy<MessageListItem>(config.sortAscending) { it.displayName }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_UNREAD -> {
|
||||
compareBy<MessageListItem>(config.sortAscending) { it.isRead }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_FLAGGED -> {
|
||||
compareBy<MessageListItem>(!config.sortAscending) { it.sortIsStarred }
|
||||
.thenByDate(config)
|
||||
}
|
||||
|
||||
SortType.SORT_ATTACHMENT -> {
|
||||
compareBy<MessageListItem>(!config.sortAscending) { it.hasAttachments }
|
||||
.thenByDate(config)
|
||||
}
|
||||
}.thenByDescending { it.sortDatabaseId }
|
||||
|
||||
return this.sortedWith(comparator)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> compareBy(sortAscending: Boolean, crossinline selector: (T) -> Comparable<*>?): Comparator<T> {
|
||||
return if (sortAscending) {
|
||||
compareBy(selector)
|
||||
} else {
|
||||
compareByDescending(selector)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> compareStringBy(sortAscending: Boolean, crossinline selector: (T) -> String): Comparator<T> {
|
||||
return if (sortAscending) {
|
||||
compareBy(String.CASE_INSENSITIVE_ORDER, selector)
|
||||
} else {
|
||||
compareByDescending(String.CASE_INSENSITIVE_ORDER, selector)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Comparator<MessageListItem>.thenByDate(config: MessageListConfig): Comparator<MessageListItem> {
|
||||
return if (config.sortDateAscending) {
|
||||
thenBy { it.sortMessageDate }
|
||||
} else {
|
||||
thenByDescending { it.sortMessageDate }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.text.SpannableString
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.fsck.k9.CoreResourceProvider
|
||||
import com.fsck.k9.activity.MessageList
|
||||
import net.thunderbird.core.android.account.SortType
|
||||
import net.thunderbird.core.preference.GeneralSettingsManager
|
||||
import net.thunderbird.feature.search.legacy.LocalMessageSearch
|
||||
import net.thunderbird.feature.search.legacy.SearchAccount
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class MessageListRemoteViewFactory(private val context: Context) : RemoteViewsFactory, KoinComponent {
|
||||
private val messageListLoader: MessageListLoader by inject()
|
||||
private val coreResourceProvider: CoreResourceProvider by inject()
|
||||
private val generalSettingsManager: GeneralSettingsManager by inject()
|
||||
|
||||
private lateinit var unifiedInboxSearch: LocalMessageSearch
|
||||
|
||||
private var messageListItems = emptyList<MessageListItem>()
|
||||
private var senderAboveSubject = false
|
||||
private var readTextColor = 0
|
||||
private var unreadTextColor = 0
|
||||
|
||||
override fun onCreate() {
|
||||
unifiedInboxSearch = SearchAccount.createUnifiedInboxAccount(
|
||||
unifiedInboxTitle = coreResourceProvider.searchUnifiedInboxTitle(),
|
||||
unifiedInboxDetail = coreResourceProvider.searchUnifiedInboxDetail(),
|
||||
).relatedSearch
|
||||
|
||||
senderAboveSubject = generalSettingsManager.getConfig().display.inboxSettings.isMessageListSenderAboveSubject
|
||||
readTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_read)
|
||||
unreadTextColor = ContextCompat.getColor(context, R.color.message_list_widget_text_unread)
|
||||
}
|
||||
|
||||
override fun onDataSetChanged() {
|
||||
loadMessageList()
|
||||
}
|
||||
|
||||
private fun loadMessageList() {
|
||||
// TODO: Use same sort order that is used for the Unified Inbox inside the app
|
||||
val messageListConfig = MessageListConfig(
|
||||
search = unifiedInboxSearch,
|
||||
showingThreadedList = generalSettingsManager.getConfig()
|
||||
.display
|
||||
.inboxSettings
|
||||
.isThreadedViewEnabled,
|
||||
sortType = SortType.SORT_DATE,
|
||||
sortAscending = false,
|
||||
sortDateAscending = false,
|
||||
)
|
||||
|
||||
messageListItems = messageListLoader.getMessageList(messageListConfig)
|
||||
}
|
||||
|
||||
override fun onDestroy() = Unit
|
||||
|
||||
override fun getCount(): Int = messageListItems.size
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews {
|
||||
val remoteView = RemoteViews(context.packageName, R.layout.message_list_widget_list_item)
|
||||
|
||||
val item = messageListItems[position]
|
||||
|
||||
val displayName = if (item.isRead) item.displayName else bold(item.displayName)
|
||||
val subject = if (item.isRead) item.subject else bold(item.subject)
|
||||
|
||||
if (senderAboveSubject) {
|
||||
remoteView.setTextViewText(R.id.sender, displayName)
|
||||
remoteView.setTextViewText(R.id.mail_subject, subject)
|
||||
} else {
|
||||
remoteView.setTextViewText(R.id.sender, subject)
|
||||
remoteView.setTextViewText(R.id.mail_subject, displayName)
|
||||
}
|
||||
|
||||
remoteView.setTextViewText(R.id.mail_date, item.displayDate)
|
||||
remoteView.setTextViewText(R.id.mail_preview, item.preview)
|
||||
|
||||
if (item.threadCount > 1) {
|
||||
remoteView.setTextViewText(R.id.thread_count, item.threadCount.toString())
|
||||
remoteView.setInt(R.id.thread_count, "setVisibility", View.VISIBLE)
|
||||
} else {
|
||||
remoteView.setInt(R.id.thread_count, "setVisibility", View.GONE)
|
||||
}
|
||||
|
||||
val textColor = getTextColor(item)
|
||||
remoteView.setTextColor(R.id.sender, textColor)
|
||||
remoteView.setTextColor(R.id.mail_subject, textColor)
|
||||
remoteView.setTextColor(R.id.mail_date, textColor)
|
||||
remoteView.setTextColor(R.id.mail_preview, textColor)
|
||||
|
||||
if (item.hasAttachments) {
|
||||
remoteView.setInt(R.id.attachment, "setVisibility", View.VISIBLE)
|
||||
} else {
|
||||
remoteView.setInt(R.id.attachment, "setVisibility", View.GONE)
|
||||
}
|
||||
|
||||
val intent = MessageList.actionDisplayMessageTemplateFillIntent(item.messageReference)
|
||||
remoteView.setOnClickFillInIntent(R.id.mail_list_item, intent)
|
||||
|
||||
remoteView.setInt(R.id.chip, "setBackgroundColor", item.accountColor)
|
||||
|
||||
return remoteView
|
||||
}
|
||||
|
||||
override fun getLoadingView(): RemoteViews {
|
||||
return RemoteViews(context.packageName, R.layout.message_list_widget_list_item_loading).apply {
|
||||
// Set the text here instead of in the layout so the app language override is used
|
||||
setTextViewText(R.id.loadingText, context.getString(R.string.message_list_widget_list_item_loading))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getViewTypeCount(): Int = 2
|
||||
|
||||
override fun getItemId(position: Int): Long = messageListItems[position].uniqueId
|
||||
|
||||
override fun hasStableIds(): Boolean = true
|
||||
|
||||
private fun bold(text: String): CharSequence {
|
||||
return SpannableString(text).apply {
|
||||
setSpan(StyleSpan(Typeface.BOLD), 0, text.length, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTextColor(messageListItem: MessageListItem): Int {
|
||||
return if (messageListItem.isRead) readTextColor else unreadTextColor
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
interface MessageListWidgetConfig {
|
||||
val providerClass: Class<out BaseMessageListWidgetProvider>
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import app.k9mail.legacy.mailstore.MessageListChangedListener
|
||||
import app.k9mail.legacy.mailstore.MessageListRepository
|
||||
import com.fsck.k9.core.BuildConfig
|
||||
import net.thunderbird.core.logging.legacy.Log
|
||||
|
||||
class MessageListWidgetManager(
|
||||
private val context: Context,
|
||||
private val messageListRepository: MessageListRepository,
|
||||
private val config: MessageListWidgetConfig,
|
||||
) {
|
||||
private var appWidgetManager: AppWidgetManager? = null
|
||||
|
||||
private var listenerAdded = false
|
||||
private val listener = MessageListChangedListener {
|
||||
onMessageListChanged()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
appWidgetManager = AppWidgetManager.getInstance(context)
|
||||
if (appWidgetManager == null) {
|
||||
Log.v("Message list widget is not supported on this device.")
|
||||
}
|
||||
|
||||
if (isAtLeastOneMessageListWidgetAdded()) {
|
||||
resetMessageListWidget()
|
||||
registerMessageListChangedListener()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
private fun onMessageListChanged() {
|
||||
try {
|
||||
triggerMessageListWidgetUpdate()
|
||||
} catch (e: RuntimeException) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
throw e
|
||||
} else {
|
||||
Log.e(e, "Error while updating message list widget")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun onWidgetAdded() {
|
||||
Log.v("Message list widget added")
|
||||
|
||||
registerMessageListChangedListener()
|
||||
}
|
||||
|
||||
internal fun onWidgetRemoved() {
|
||||
Log.v("Message list widget removed")
|
||||
|
||||
if (!isAtLeastOneMessageListWidgetAdded()) {
|
||||
unregisterMessageListChangedListener()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun registerMessageListChangedListener() {
|
||||
if (!listenerAdded) {
|
||||
listenerAdded = true
|
||||
messageListRepository.addListener(listener)
|
||||
|
||||
Log.v("Message list widget is now listening for message list changes…")
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun unregisterMessageListChangedListener() {
|
||||
if (listenerAdded) {
|
||||
listenerAdded = false
|
||||
messageListRepository.removeListener(listener)
|
||||
|
||||
Log.v("Message list widget stopped listening for message list changes.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAtLeastOneMessageListWidgetAdded(): Boolean {
|
||||
return getAppWidgetIds().isNotEmpty()
|
||||
}
|
||||
|
||||
private fun triggerMessageListWidgetUpdate() {
|
||||
val appWidgetIds = getAppWidgetIds()
|
||||
if (appWidgetIds.isNotEmpty()) {
|
||||
appWidgetManager?.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetMessageListWidget() {
|
||||
val appWidgetIds = getAppWidgetIds()
|
||||
if (appWidgetIds.isNotEmpty()) {
|
||||
val intent = Intent(context, config.providerClass).apply {
|
||||
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
|
||||
}
|
||||
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAppWidgetIds(): IntArray {
|
||||
val componentName = ComponentName(context, config.providerClass)
|
||||
return appWidgetManager?.getAppWidgetIds(componentName) ?: intArrayOf()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package app.k9mail.feature.widget.message.list
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
|
||||
class MessageListWidgetService : RemoteViewsService() {
|
||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||
return MessageListRemoteViewFactory(applicationContext)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
|
|
@ -0,0 +1,53 @@
|
|||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/top_controls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/message_list_widget_header_background"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/folder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingTop="12dp"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/message_list_widget_header_text"
|
||||
tools:text="Unified Inbox"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/new_message"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/message_list_widget_compose_action"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_edit"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:divider="@color/message_list_widget_divider"
|
||||
android:dividerHeight="0.5dp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/mail_list_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:background="#fff"
|
||||
>
|
||||
|
||||
<!-- A regular View breaks things for some reason, but a TextView does the job -->
|
||||
<TextView
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="8dip"
|
||||
android:layout_height="match_parent"
|
||||
tools:background="#0099CC"
|
||||
android:visibility="visible"
|
||||
/>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/widget_padding"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mail_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="4dp"
|
||||
tools:text="25 May"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/attachment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/mail_date"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_toStartOf="@+id/mail_date"
|
||||
android:src="@drawable/ic_attachment"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/thread_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/attachment"
|
||||
android:layout_marginStart="4dp"
|
||||
android:maxLines="1"
|
||||
android:paddingRight="4dip"
|
||||
android:paddingBottom="1dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?android:attr/colorBackground"
|
||||
android:background="@drawable/thread_count_box_light"
|
||||
tools:text="3"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sender"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_gravity="start"
|
||||
android:layout_toStartOf="@id/thread_count"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="16sp"
|
||||
tools:text="Kinda long subject that should be long enough to exceed the available display space"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mail_subject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/sender"
|
||||
android:layout_alignParentStart="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingBottom="2dp"
|
||||
android:textSize="15sp"
|
||||
tools:text="Wikipedia"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mail_preview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/mail_subject"
|
||||
android:layout_alignParentStart="true"
|
||||
android:maxLines="1"
|
||||
android:textSize="13sp"
|
||||
tools:text="Towel Day is celebrated every year on 25 May as a tribute to the author Douglas Adams by his fans."
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/loadingText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:padding="16dp"
|
||||
android:textSize="15sp"
|
||||
tools:text="@string/message_list_widget_list_item_loading"
|
||||
/>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:gravity="center"
|
||||
android:padding="16dp"
|
||||
android:text="@string/message_list_widget_initializing"
|
||||
android:textSize="18sp"
|
||||
/>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">أنشِئ</string>
|
||||
<string name="message_list_widget_list_item_loading">يُحمل…</string>
|
||||
<string name="message_list_widget_initializing">يُحمل…</string>
|
||||
<string name="message_list_widget_inbox_title">البريد الوارد الموحَّد</string>
|
||||
<string name="message_list_widget_label">قائمة الرسائل</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Tərtib et</string>
|
||||
<string name="message_list_widget_label">Mesaj siyahısı</string>
|
||||
<string name="message_list_widget_initializing">Yüklənir…</string>
|
||||
<string name="message_list_widget_list_item_loading">Yüklənir…</string>
|
||||
<string name="message_list_widget_inbox_title">Ümumi Gələnlər Qutusu</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Напісаць</string>
|
||||
<string name="message_list_widget_list_item_loading">Загрузка…</string>
|
||||
<string name="message_list_widget_initializing">Загрузка…</string>
|
||||
<string name="message_list_widget_inbox_title">Усе атрыманыя</string>
|
||||
<string name="message_list_widget_label">Спіс лістоў</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Съставяне</string>
|
||||
<string name="message_list_widget_list_item_loading">Зареждане…</string>
|
||||
<string name="message_list_widget_initializing">Зареждане…</string>
|
||||
<string name="message_list_widget_inbox_title">Обединена кутия</string>
|
||||
<string name="message_list_widget_label">Списък със съобщения</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="message_list_widget_list_item_loading">প্রক্রিয়ারত…</string>
|
||||
<string name="message_list_widget_initializing">প্রক্রিয়ারত…</string>
|
||||
<string name="message_list_widget_compose_action">তৈরি</string>
|
||||
<string name="message_list_widget_inbox_title">সমন্বিত ইনবক্স</string>
|
||||
<string name="message_list_widget_label">বার্তা তালিকা</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Skridaozañ</string>
|
||||
<string name="message_list_widget_list_item_loading">O kargañ…</string>
|
||||
<string name="message_list_widget_initializing">O kargañ…</string>
|
||||
<string name="message_list_widget_inbox_title">Boest degemer unanet</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Sastavi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Redacta</string>
|
||||
<string name="message_list_widget_list_item_loading">S\'està carregant…</string>
|
||||
<string name="message_list_widget_initializing">S\'està carregant…</string>
|
||||
<string name="message_list_widget_inbox_title">Bústia d\'entrada unificada</string>
|
||||
<string name="message_list_widget_label">Llista de missatges</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Cumpone</string>
|
||||
<string name="message_list_widget_list_item_loading">Caricamentu…</string>
|
||||
<string name="message_list_widget_initializing">Caricamentu…</string>
|
||||
<string name="message_list_widget_inbox_title">Ricezzione cuncolta</string>
|
||||
<string name="message_list_widget_label">Lista di i messaghji</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Nová</string>
|
||||
<string name="message_list_widget_list_item_loading">Načítání…</string>
|
||||
<string name="message_list_widget_initializing">Načítání…</string>
|
||||
<string name="message_list_widget_inbox_title">Integrovaná doručená pošta</string>
|
||||
<string name="message_list_widget_label">Seznam zpráv</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Ysgrifennu</string>
|
||||
<string name="message_list_widget_list_item_loading">Yn llwytho…</string>
|
||||
<string name="message_list_widget_initializing">Yn llwytho…</string>
|
||||
<string name="message_list_widget_inbox_title">Mewnflwch Unedig</string>
|
||||
<string name="message_list_widget_label">Rhestr Negeseuon</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Skriv</string>
|
||||
<string name="message_list_widget_list_item_loading">Indlæser…</string>
|
||||
<string name="message_list_widget_initializing">Indlæser…</string>
|
||||
<string name="message_list_widget_inbox_title">Fælles indbakke</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Verfassen</string>
|
||||
<string name="message_list_widget_list_item_loading">Ladevorgang…</string>
|
||||
<string name="message_list_widget_initializing">Ladevorgang…</string>
|
||||
<string name="message_list_widget_inbox_title">Gemeinsamer Posteingang</string>
|
||||
<string name="message_list_widget_label">Nachrichtenliste</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Σύνθεση</string>
|
||||
<string name="message_list_widget_list_item_loading">Φόρτωση…</string>
|
||||
<string name="message_list_widget_initializing">Φόρτωση…</string>
|
||||
<string name="message_list_widget_inbox_title">Ενιαία Εισερχόμενα</string>
|
||||
<string name="message_list_widget_label">Λίστα μηνυμάτων</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Compose</string>
|
||||
<string name="message_list_widget_list_item_loading">Loading…</string>
|
||||
<string name="message_list_widget_initializing">Loading…</string>
|
||||
<string name="message_list_widget_inbox_title">Unified Inbox</string>
|
||||
<string name="message_list_widget_label">Message List</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Krei</string>
|
||||
<string name="message_list_widget_list_item_loading">Ŝargado…</string>
|
||||
<string name="message_list_widget_initializing">Ŝargado…</string>
|
||||
<string name="message_list_widget_inbox_title">Unuigita ricevujo</string>
|
||||
<string name="message_list_widget_label">Listo de la mesaĝoj</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Redactar</string>
|
||||
<string name="message_list_widget_list_item_loading">Cargando…</string>
|
||||
<string name="message_list_widget_initializing">Cargando…</string>
|
||||
<string name="message_list_widget_inbox_title">Entrada unificada</string>
|
||||
<string name="message_list_widget_label">Lista de mensajes</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Koosta</string>
|
||||
<string name="message_list_widget_list_item_loading">Laadime…</string>
|
||||
<string name="message_list_widget_initializing">Laadime…</string>
|
||||
<string name="message_list_widget_inbox_title">Koondsisendkaust</string>
|
||||
<string name="message_list_widget_label">Kirjade loend</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Idatzi</string>
|
||||
<string name="message_list_widget_list_item_loading">Kargatzen…</string>
|
||||
<string name="message_list_widget_initializing">Kargatzen…</string>
|
||||
<string name="message_list_widget_inbox_title">Sarrerako ontzi bateratua</string>
|
||||
<string name="message_list_widget_label">Mezuen zerrenda</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">نوشتن</string>
|
||||
<string name="message_list_widget_list_item_loading">بارگیری…</string>
|
||||
<string name="message_list_widget_initializing">بارگیری…</string>
|
||||
<string name="message_list_widget_inbox_title">صندوق ورودی یکپارچه</string>
|
||||
<string name="message_list_widget_label">سیاههٔ پیامها</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Kirjoita</string>
|
||||
<string name="message_list_widget_list_item_loading">Ladataan…</string>
|
||||
<string name="message_list_widget_initializing">Ladataan…</string>
|
||||
<string name="message_list_widget_inbox_title">Yhdistetty saapuneet</string>
|
||||
<string name="message_list_widget_label">Viestilista</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Rédiger</string>
|
||||
<string name="message_list_widget_list_item_loading">Chargement…</string>
|
||||
<string name="message_list_widget_initializing">Chargement…</string>
|
||||
<string name="message_list_widget_inbox_title">Boîte de réception unifiée</string>
|
||||
<string name="message_list_widget_label">Liste des courriels</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Opstelle</string>
|
||||
<string name="message_list_widget_list_item_loading">Lade…</string>
|
||||
<string name="message_list_widget_initializing">Lade…</string>
|
||||
<string name="message_list_widget_inbox_title">Gearfoege Postfek YN</string>
|
||||
<string name="message_list_widget_label">Berjochtelist</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="message_list_widget_list_item_loading">Á lódáil…</string>
|
||||
<string name="message_list_widget_label">Liosta Teachtaireachtaí</string>
|
||||
<string name="message_list_widget_compose_action">Cum</string>
|
||||
<string name="message_list_widget_initializing">Á lódáil…</string>
|
||||
<string name="message_list_widget_inbox_title">Bosca Isteach Aontaithe</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Sgrìobh</string>
|
||||
<string name="message_list_widget_list_item_loading">’Ga luchdadh…</string>
|
||||
<string name="message_list_widget_initializing">’Ga luchdadh…</string>
|
||||
<string name="message_list_widget_inbox_title">An t-oll-bhogsa</string>
|
||||
<string name="message_list_widget_label">Liosta nan teachdaireachdan</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Redactar</string>
|
||||
<string name="message_list_widget_list_item_loading">A cargar…</string>
|
||||
<string name="message_list_widget_initializing">A cargar…</string>
|
||||
<string name="message_list_widget_inbox_title">Entrada unificada</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">बनाएं</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Nova poruka</string>
|
||||
<string name="message_list_widget_list_item_loading">Učitavanje…</string>
|
||||
<string name="message_list_widget_initializing">Učitavanje…</string>
|
||||
<string name="message_list_widget_inbox_title">Objedinjena dolazna pošta</string>
|
||||
<string name="message_list_widget_label">Popis poruka</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Írás</string>
|
||||
<string name="message_list_widget_list_item_loading">Betöltés…</string>
|
||||
<string name="message_list_widget_initializing">Betöltés…</string>
|
||||
<string name="message_list_widget_inbox_title">Egységes beérkezett üzenetek</string>
|
||||
<string name="message_list_widget_label">Üzenetlista</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Գրել</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Menyusun</string>
|
||||
<string name="message_list_widget_list_item_loading">Memuat…</string>
|
||||
<string name="message_list_widget_initializing">Memuat…</string>
|
||||
<string name="message_list_widget_inbox_title">Kotak Masuk Terpadu</string>
|
||||
<string name="message_list_widget_label">Daftar Pesan</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Semja</string>
|
||||
<string name="message_list_widget_list_item_loading">Hleður…</string>
|
||||
<string name="message_list_widget_initializing">Hleður…</string>
|
||||
<string name="message_list_widget_inbox_title">Sameinað innhólf</string>
|
||||
<string name="message_list_widget_label">Skilaboðalisti</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Componi</string>
|
||||
<string name="message_list_widget_list_item_loading">Caricamento…</string>
|
||||
<string name="message_list_widget_initializing">Caricamento…</string>
|
||||
<string name="message_list_widget_inbox_title">Posta combinata</string>
|
||||
<string name="message_list_widget_label">Elenco messaggi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">חבר</string>
|
||||
<string name="message_list_widget_list_item_loading">טוען…</string>
|
||||
<string name="message_list_widget_initializing">טוען…</string>
|
||||
<string name="message_list_widget_inbox_title">תיבת דואר נכנס מאוחדת</string>
|
||||
<string name="message_list_widget_label">רשימת הודעות</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">作成</string>
|
||||
<string name="message_list_widget_list_item_loading">読み込み中…</string>
|
||||
<string name="message_list_widget_initializing">読み込み中…</string>
|
||||
<string name="message_list_widget_inbox_title">統合受信トレイ</string>
|
||||
<string name="message_list_widget_label">メッセージ一覧</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">შექმნა</string>
|
||||
<string name="message_list_widget_list_item_loading">ჩატვირთვა…</string>
|
||||
<string name="message_list_widget_initializing">ჩატვირთვა…</string>
|
||||
<string name="message_list_widget_inbox_title">გაერთიანებული შემავალი</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="message_list_widget_compose_action">Құрастыру</string>
|
||||
<string name="message_list_widget_list_item_loading">Жүктелуде…</string>
|
||||
<string name="message_list_widget_initializing">Жүктелуде…</string>
|
||||
<string name="message_list_widget_label">Хабарламалар тізімі</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">작성</string>
|
||||
<string name="message_list_widget_list_item_loading">로딩 중…</string>
|
||||
<string name="message_list_widget_initializing">로딩 중…</string>
|
||||
<string name="message_list_widget_inbox_title">통합 편지함</string>
|
||||
<string name="message_list_widget_label">메시지 목록</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Sukurti</string>
|
||||
<string name="message_list_widget_list_item_loading">Įkeliama…</string>
|
||||
<string name="message_list_widget_initializing">Įkeliama…</string>
|
||||
<string name="message_list_widget_inbox_title">Suvestiniai gautieji</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Rakstīt ziņu</string>
|
||||
<string name="message_list_widget_list_item_loading">Ielādē…</string>
|
||||
<string name="message_list_widget_initializing">Ielādē…</string>
|
||||
<string name="message_list_widget_inbox_title">Apvienotā Iesūtne</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">രചിക്കുക</string>
|
||||
<string name="message_list_widget_list_item_loading">ലോഡുചെയ്യുന്നു…</string>
|
||||
<string name="message_list_widget_initializing">ലോഡുചെയ്യുന്നു…</string>
|
||||
<string name="message_list_widget_inbox_title">ഏകീകൃത ഇൻബോക്സ്</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Skriv</string>
|
||||
<string name="message_list_widget_list_item_loading">Laster…</string>
|
||||
<string name="message_list_widget_initializing">Laster…</string>
|
||||
<string name="message_list_widget_inbox_title">Samlet innboks</string>
|
||||
<string name="message_list_widget_label">Meldingsliste</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Opstellen</string>
|
||||
<string name="message_list_widget_list_item_loading">Laden…</string>
|
||||
<string name="message_list_widget_initializing">Laden…</string>
|
||||
<string name="message_list_widget_inbox_title">Samengevoegd Postvak IN</string>
|
||||
<string name="message_list_widget_label">Berichtenlijst</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Skriv</string>
|
||||
<string name="message_list_widget_list_item_loading">Lastar …</string>
|
||||
<string name="message_list_widget_initializing">Lastar …</string>
|
||||
<string name="message_list_widget_label">Meldingsliste</string>
|
||||
<string name="message_list_widget_inbox_title">Samla innboks</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Nowa wiadomość</string>
|
||||
<string name="message_list_widget_list_item_loading">Wczytywanie…</string>
|
||||
<string name="message_list_widget_initializing">Wczytywanie…</string>
|
||||
<string name="message_list_widget_inbox_title">Zintegrowana odbiorcza</string>
|
||||
<string name="message_list_widget_label">Lista wiadomości</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Escrever</string>
|
||||
<string name="message_list_widget_list_item_loading">Carregando…</string>
|
||||
<string name="message_list_widget_initializing">Carregando…</string>
|
||||
<string name="message_list_widget_inbox_title">Caixa de Entrada Unificada</string>
|
||||
<string name="message_list_widget_label">Lista de Mensagens</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Compor</string>
|
||||
<string name="message_list_widget_list_item_loading">A carregar…</string>
|
||||
<string name="message_list_widget_initializing">A carregar…</string>
|
||||
<string name="message_list_widget_inbox_title">Caixa de entrada unificada</string>
|
||||
<string name="message_list_widget_label">Lista de mensagens</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Compune</string>
|
||||
<string name="message_list_widget_list_item_loading">Se încarcă…</string>
|
||||
<string name="message_list_widget_initializing">Se încarcă…</string>
|
||||
<string name="message_list_widget_inbox_title">Căsuță poștală unificată</string>
|
||||
<string name="message_list_widget_label">Lista de mesaje</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Создать</string>
|
||||
<string name="message_list_widget_list_item_loading">Загрузка…</string>
|
||||
<string name="message_list_widget_initializing">Загрузка…</string>
|
||||
<string name="message_list_widget_inbox_title">Общие входящие</string>
|
||||
<string name="message_list_widget_label">Список сообщений</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Napísať</string>
|
||||
<string name="message_list_widget_list_item_loading">Načítavam…</string>
|
||||
<string name="message_list_widget_initializing">Načítavam…</string>
|
||||
<string name="message_list_widget_inbox_title">Jednotná schránka</string>
|
||||
<string name="message_list_widget_label">Zoznam Správ</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Sestavi sporočilo</string>
|
||||
<string name="message_list_widget_list_item_loading">Poteka nalaganje …</string>
|
||||
<string name="message_list_widget_initializing">Poteka nalaganje …</string>
|
||||
<string name="message_list_widget_inbox_title">Skupna mapa prejetih sporočil</string>
|
||||
<string name="message_list_widget_label">Seznam sporočil</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Hartoni</string>
|
||||
<string name="message_list_widget_list_item_loading">Po ngarkohet…</string>
|
||||
<string name="message_list_widget_initializing">Po ngarkohet…</string>
|
||||
<string name="message_list_widget_inbox_title">Kuti Poste e Njësuar</string>
|
||||
<string name="message_list_widget_label">Listë Mesazhesh</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Састави</string>
|
||||
<string name="message_list_widget_list_item_loading">Учитавање…</string>
|
||||
<string name="message_list_widget_initializing">Учитавање…</string>
|
||||
<string name="message_list_widget_inbox_title">Обједињено сандуче</string>
|
||||
<string name="message_list_widget_label">Листа порука</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Skriv</string>
|
||||
<string name="message_list_widget_list_item_loading">Läser in…</string>
|
||||
<string name="message_list_widget_initializing">Läser in…</string>
|
||||
<string name="message_list_widget_inbox_title">Samlad inkorg</string>
|
||||
<string name="message_list_widget_label">Meddelandelista</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">எழுது</string>
|
||||
<string name="message_list_widget_inbox_title">ஒருங்கிணைந்த இன்பாக்ச்</string>
|
||||
<string name="message_list_widget_label">செய்தி பட்டியல்</string>
|
||||
<string name="message_list_widget_list_item_loading">ஏற்றுகிறது…</string>
|
||||
<string name="message_list_widget_initializing">ஏற்றுகிறது…</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Oluştur</string>
|
||||
<string name="message_list_widget_list_item_loading">Yükleniyor…</string>
|
||||
<string name="message_list_widget_initializing">Yükleniyor…</string>
|
||||
<string name="message_list_widget_inbox_title">Birleşik Gelen Kutusu</string>
|
||||
<string name="message_list_widget_label">İleti Listesi</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Написати</string>
|
||||
<string name="message_list_widget_list_item_loading">Завантаження…</string>
|
||||
<string name="message_list_widget_initializing">Завантаження…</string>
|
||||
<string name="message_list_widget_inbox_title">Об\'єднані Вхідні</string>
|
||||
<string name="message_list_widget_label">Список повідомлень</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">Soạn thư</string>
|
||||
<string name="message_list_widget_list_item_loading">Đang tải…</string>
|
||||
<string name="message_list_widget_initializing">Đang tải…</string>
|
||||
<string name="message_list_widget_inbox_title">Hộp thư đồng nhất</string>
|
||||
<string name="message_list_widget_label">Danh sách tin nhắn</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">撰写</string>
|
||||
<string name="message_list_widget_list_item_loading">正在加载…</string>
|
||||
<string name="message_list_widget_initializing">正在加载…</string>
|
||||
<string name="message_list_widget_inbox_title">统一收件箱</string>
|
||||
<string name="message_list_widget_label">邮件列表</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="message_list_widget_compose_action">新郵件</string>
|
||||
<string name="message_list_widget_list_item_loading">載入中…</string>
|
||||
<string name="message_list_widget_initializing">載入中…</string>
|
||||
<string name="message_list_widget_inbox_title">全域收件匣</string>
|
||||
<string name="message_list_widget_label">訊息清單</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="message_list_widget_header_background">#737373</color>
|
||||
<color name="message_list_widget_header_text">#e4e4e4</color>
|
||||
<color name="message_list_widget_divider">#e5e5e5</color>
|
||||
<color name="message_list_widget_text_read">#444444</color>
|
||||
<color name="message_list_widget_text_unread">#000000</color>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue