forked from github/wulkanowy-mirror
Add mailbox chooser to messages (#2002)
This commit is contained in:
parent
db4f172fb8
commit
51a1097bb4
2439
app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
Normal file
2439
app/schemas/io.github.wulkanowy.data.db.AppDatabase/53.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 52
|
const val VERSION_SCHEMA = 53
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -106,6 +106,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration49(),
|
Migration49(),
|
||||||
Migration50(),
|
Migration50(),
|
||||||
Migration51(),
|
Migration51(),
|
||||||
|
Migration53(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
|
@ -3,12 +3,16 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Dao
|
@Dao
|
||||||
interface MailboxDao : BaseDao<Mailbox> {
|
interface MailboxDao : BaseDao<Mailbox> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
|
@Query("SELECT * FROM Mailboxes WHERE email = :email")
|
||||||
suspend fun loadAll(userLoginId: Int): List<Mailbox>
|
suspend fun loadAll(email: String): List<Mailbox>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Mailboxes WHERE email = :email AND symbol = :symbol AND schoolId = :schoolId")
|
||||||
|
fun loadAll(email: String, symbol: String, schoolId: String): Flow<List<Mailbox>>
|
||||||
}
|
}
|
||||||
|
@ -16,4 +16,7 @@ interface MessagesDao : BaseDao<Message> {
|
|||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadAll(folder: Int, email: String): Flow<List<Message>>
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,27 @@
|
|||||||
package io.github.wulkanowy.data.db.entities
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
@Entity(tableName = "Mailboxes")
|
@Entity(tableName = "Mailboxes")
|
||||||
data class Mailbox(
|
data class Mailbox(
|
||||||
|
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
val globalKey: String,
|
val globalKey: String,
|
||||||
|
|
||||||
|
val email: String,
|
||||||
|
val symbol: String,
|
||||||
|
val schoolId: String,
|
||||||
|
|
||||||
val fullName: String,
|
val fullName: String,
|
||||||
val userName: String,
|
val userName: String,
|
||||||
val userLoginId: Int,
|
|
||||||
val studentName: String,
|
val studentName: String,
|
||||||
val schoolNameShort: String,
|
val schoolNameShort: String,
|
||||||
val type: MailboxType,
|
val type: MailboxType,
|
||||||
)
|
) : java.io.Serializable, Parcelable
|
||||||
|
|
||||||
enum class MailboxType {
|
enum class MailboxType {
|
||||||
STUDENT,
|
STUDENT,
|
||||||
|
@ -9,6 +9,9 @@ import java.time.Instant
|
|||||||
@Entity(tableName = "Messages")
|
@Entity(tableName = "Messages")
|
||||||
data class Message(
|
data class Message(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "email")
|
||||||
|
val email: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "message_global_key")
|
@ColumnInfo(name = "message_global_key")
|
||||||
val messageGlobalKey: String,
|
val messageGlobalKey: String,
|
||||||
|
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration53 : Migration(52, 53) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
createMailboxTable(database)
|
||||||
|
recreateMessagesTable(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMailboxTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Mailboxes` (
|
||||||
|
`globalKey` TEXT NOT NULL,
|
||||||
|
`email` TEXT NOT NULL,
|
||||||
|
`symbol` TEXT NOT NULL,
|
||||||
|
`schoolId` TEXT NOT NULL,
|
||||||
|
`fullName` TEXT NOT NULL,
|
||||||
|
`userName` TEXT NOT NULL,
|
||||||
|
`studentName` TEXT NOT NULL,
|
||||||
|
`schoolNameShort` TEXT NOT NULL,
|
||||||
|
`type` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`globalKey`)
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("DROP TABLE IF EXISTS Messages")
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Messages` (
|
||||||
|
`email` TEXT NOT NULL,
|
||||||
|
`message_global_key` TEXT NOT NULL,
|
||||||
|
`mailbox_key` TEXT NOT NULL,
|
||||||
|
`message_id` INTEGER NOT NULL,
|
||||||
|
`correspondents` TEXT NOT NULL,
|
||||||
|
`subject` TEXT NOT NULL,
|
||||||
|
`date` INTEGER NOT NULL,
|
||||||
|
`folder_id` INTEGER NOT NULL,
|
||||||
|
`unread` INTEGER NOT NULL,
|
||||||
|
`read_by` INTEGER,
|
||||||
|
`unread_by` INTEGER,
|
||||||
|
`has_attachments` INTEGER NOT NULL,
|
||||||
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
`is_notified` INTEGER NOT NULL,
|
||||||
|
`content` TEXT NOT NULL,
|
||||||
|
`sender` TEXT,
|
||||||
|
`recipients` TEXT
|
||||||
|
)""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,11 @@ fun List<SdkMailbox>.mapToEntities(student: Student) = map {
|
|||||||
globalKey = it.globalKey,
|
globalKey = it.globalKey,
|
||||||
fullName = it.fullName,
|
fullName = it.fullName,
|
||||||
userName = it.userName,
|
userName = it.userName,
|
||||||
userLoginId = student.userLoginId,
|
|
||||||
studentName = it.studentName,
|
studentName = it.studentName,
|
||||||
schoolNameShort = it.schoolNameShort,
|
schoolNameShort = it.schoolNameShort,
|
||||||
type = MailboxType.valueOf(it.type.name),
|
type = MailboxType.valueOf(it.type.name),
|
||||||
|
email = student.email,
|
||||||
|
symbol = student.symbol,
|
||||||
|
schoolId = student.schoolSymbol,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,13 @@ import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
|
|||||||
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
|
||||||
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
||||||
|
|
||||||
fun List<SdkMessage>.mapToEntities(mailbox: Mailbox) = map {
|
fun List<SdkMessage>.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List<Mailbox>) = map {
|
||||||
Message(
|
Message(
|
||||||
messageGlobalKey = it.globalKey,
|
messageGlobalKey = it.globalKey,
|
||||||
mailboxKey = mailbox.globalKey,
|
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
|
||||||
|
box.fullName == it.mailbox
|
||||||
|
}?.globalKey!!,
|
||||||
|
email = student.email,
|
||||||
messageId = it.id,
|
messageId = it.id,
|
||||||
correspondents = it.correspondents,
|
correspondents = it.correspondents,
|
||||||
subject = it.subject.trim(),
|
subject = it.subject.trim(),
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
|
||||||
import io.github.wulkanowy.utils.getRefreshKey
|
|
||||||
import io.github.wulkanowy.utils.init
|
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class MailboxRepository @Inject constructor(
|
|
||||||
private val mailboxDao: MailboxDao,
|
|
||||||
private val sdk: Sdk,
|
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
|
||||||
) {
|
|
||||||
private val cacheKey = "mailboxes"
|
|
||||||
|
|
||||||
suspend fun refreshMailboxes(student: Student) {
|
|
||||||
val new = sdk.init(student).getMailboxes().mapToEntities(student)
|
|
||||||
val old = mailboxDao.loadAll(student.userLoginId)
|
|
||||||
|
|
||||||
mailboxDao.deleteAll(old uniqueSubtract new)
|
|
||||||
mailboxDao.insertAll(new uniqueSubtract old)
|
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getMailbox(student: Student): Mailbox {
|
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
|
||||||
val mailboxes = mailboxDao.loadAll(student.userLoginId)
|
|
||||||
val mailbox = mailboxes.filterByStudent(student)
|
|
||||||
|
|
||||||
return if (isExpired || mailbox == null) {
|
|
||||||
refreshMailboxes(student)
|
|
||||||
val newMailbox = mailboxDao.loadAll(student.userLoginId).filterByStudent(student)
|
|
||||||
|
|
||||||
requireNotNull(newMailbox) {
|
|
||||||
"Mailbox for ${student.userName} - ${student.studentName} not found! Saved mailboxes: $mailboxes"
|
|
||||||
}
|
|
||||||
|
|
||||||
newMailbox
|
|
||||||
} else mailbox
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<Mailbox>.filterByStudent(student: Student): Mailbox? {
|
|
||||||
val normalizedStudentName = student.studentName.normalizeStudentName()
|
|
||||||
|
|
||||||
return find {
|
|
||||||
it.studentName.normalizeStudentName() == normalizedStudentName
|
|
||||||
} ?: singleOrNull {
|
|
||||||
it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
|
|
||||||
} ?: singleOrNull {
|
|
||||||
it.studentName.getUnauthorizedVersion() == normalizedStudentName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.normalizeStudentName(): String {
|
|
||||||
return trim().split(" ")
|
|
||||||
.filter { it.isNotBlank() }
|
|
||||||
.joinToString(" ") { part ->
|
|
||||||
part.lowercase().replaceFirstChar { it.uppercase() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.getFirstAndLastPart(): String {
|
|
||||||
val parts = normalizeStudentName().split(" ")
|
|
||||||
|
|
||||||
val endParts = parts.filterIndexed { i, _ ->
|
|
||||||
i == 0 || parts.size - 1 == i
|
|
||||||
}
|
|
||||||
return endParts.joinToString(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String.getUnauthorizedVersion(): String {
|
|
||||||
return normalizeStudentName().split(" ")
|
|
||||||
.joinToString(" ") {
|
|
||||||
it.first() + "*".repeat(it.length - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,6 +5,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.entities.*
|
import io.github.wulkanowy.data.db.entities.*
|
||||||
@ -15,6 +16,8 @@ import io.github.wulkanowy.data.mappers.mapFromEntities
|
|||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||||
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
|
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.pojo.Folder
|
import io.github.wulkanowy.sdk.pojo.Folder
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
@ -40,16 +43,18 @@ class MessageRepository @Inject constructor(
|
|||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
private val sharedPrefProvider: SharedPrefProvider,
|
private val sharedPrefProvider: SharedPrefProvider,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
|
private val mailboxDao: MailboxDao,
|
||||||
|
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "message"
|
private val messagesCacheKey = "message"
|
||||||
|
private val mailboxCacheKey = "mailboxes"
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
fun getMessages(
|
fun getMessages(
|
||||||
student: Student,
|
student: Student,
|
||||||
mailbox: Mailbox,
|
mailbox: Mailbox?,
|
||||||
folder: MessageFolder,
|
folder: MessageFolder,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
notify: Boolean = false,
|
notify: Boolean = false,
|
||||||
@ -58,16 +63,20 @@ class MessageRepository @Inject constructor(
|
|||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||||
key = getRefreshKey(cacheKey, student, folder)
|
key = getRefreshKey(messagesCacheKey, mailbox, folder)
|
||||||
)
|
)
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
|
query = {
|
||||||
|
if (mailbox == null) {
|
||||||
|
messagesDb.loadAll(folder.id, student.email)
|
||||||
|
} else messagesDb.loadAll(mailbox.globalKey, folder.id)
|
||||||
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessages(
|
sdk.init(student).getMessages(
|
||||||
folder = Folder.valueOf(folder.name),
|
folder = Folder.valueOf(folder.name),
|
||||||
mailboxKey = mailbox.globalKey,
|
mailboxKey = mailbox?.globalKey,
|
||||||
).mapToEntities(mailbox)
|
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
messagesDb.deleteAll(old uniqueSubtract new)
|
messagesDb.deleteAll(old uniqueSubtract new)
|
||||||
@ -75,7 +84,9 @@ class MessageRepository @Inject constructor(
|
|||||||
it.isNotified = !notify
|
it.isNotified = !notify
|
||||||
})
|
})
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
|
refreshHelper.updateLastRefreshTimestamp(
|
||||||
|
getRefreshKey(messagesCacheKey, mailbox, folder)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,7 +101,9 @@ class MessageRepository @Inject constructor(
|
|||||||
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
|
||||||
it.message.unread || it.message.content.isBlank()
|
it.message.unread || it.message.content.isBlank()
|
||||||
},
|
},
|
||||||
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
|
query = {
|
||||||
|
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
||||||
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
|
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
|
||||||
},
|
},
|
||||||
@ -113,8 +126,10 @@ class MessageRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getMessagesFromDatabase(mailbox: Mailbox): Flow<List<Message>> {
|
fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow<List<Message>> {
|
||||||
return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
return if (mailbox == null) {
|
||||||
|
messagesDb.loadAll(RECEIVED.id, student.email)
|
||||||
|
} else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateMessages(messages: List<Message>) {
|
suspend fun updateMessages(messages: List<Message>) {
|
||||||
@ -136,7 +151,7 @@ class MessageRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List<Message>) {
|
suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
|
||||||
val firstMessage = messages.first()
|
val firstMessage = messages.first()
|
||||||
sdk.init(student).deleteMessages(
|
sdk.init(student).deleteMessages(
|
||||||
messages = messages.map { it.messageGlobalKey },
|
messages = messages.map { it.messageGlobalKey },
|
||||||
@ -169,6 +184,34 @@ class MessageRepository @Inject constructor(
|
|||||||
deleteMessages(student, mailbox, listOf(message))
|
deleteMessages(student, mailbox, listOf(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
|
isResultEmpty = { it.isEmpty() },
|
||||||
|
shouldFetch = {
|
||||||
|
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||||
|
key = getRefreshKey(mailboxCacheKey, student),
|
||||||
|
)
|
||||||
|
it.isEmpty() || isExpired || forceRefresh
|
||||||
|
},
|
||||||
|
query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
|
||||||
|
fetch = { sdk.init(student).getMailboxes().mapToEntities(student) },
|
||||||
|
saveFetchResult = { old, new ->
|
||||||
|
mailboxDao.deleteAll(old uniqueSubtract new)
|
||||||
|
mailboxDao.insertAll(new uniqueSubtract old)
|
||||||
|
|
||||||
|
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(mailboxCacheKey, student))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun getMailboxByStudent(student: Student): Mailbox? {
|
||||||
|
val mailbox = getMailboxByStudentUseCase(student)
|
||||||
|
|
||||||
|
return if (mailbox == null) {
|
||||||
|
getMailboxes(student, forceRefresh = true).toFirstResult()
|
||||||
|
getMailboxByStudentUseCase(student)
|
||||||
|
} else mailbox
|
||||||
|
}
|
||||||
|
|
||||||
var draftMessage: MessageDraft?
|
var draftMessage: MessageDraft?
|
||||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
|
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
|
||||||
?.let { json.decodeFromString(it) }
|
?.let { json.decodeFromString(it) }
|
||||||
|
@ -33,9 +33,11 @@ class RecipientRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun getRecipients(
|
suspend fun getRecipients(
|
||||||
student: Student,
|
student: Student,
|
||||||
mailbox: Mailbox,
|
mailbox: Mailbox?,
|
||||||
type: MailboxType
|
type: MailboxType,
|
||||||
): List<Recipient> {
|
): List<Recipient> {
|
||||||
|
mailbox ?: return emptyList()
|
||||||
|
|
||||||
val cached = recipientDb.loadAll(type, mailbox.globalKey)
|
val cached = recipientDb.loadAll(type, mailbox.globalKey)
|
||||||
|
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||||
@ -47,11 +49,15 @@ class RecipientRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun getMessageSender(
|
suspend fun getMessageSender(
|
||||||
student: Student,
|
student: Student,
|
||||||
mailbox: Mailbox,
|
mailbox: Mailbox?,
|
||||||
message: Message
|
message: Message,
|
||||||
): List<Recipient> = sdk.init(student)
|
): List<Recipient> {
|
||||||
.getMessageReplayDetails(message.messageGlobalKey)
|
mailbox ?: return emptyList()
|
||||||
.sender
|
|
||||||
.let(::listOf)
|
return sdk.init(student)
|
||||||
.mapToEntities(mailbox.globalKey)
|
.getMessageReplayDetails(message.messageGlobalKey)
|
||||||
|
.sender
|
||||||
|
.let(::listOf)
|
||||||
|
.mapToEntities(mailbox.globalKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package io.github.wulkanowy.domain.messages
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GetMailboxByStudentUseCase @Inject constructor(
|
||||||
|
private val mailboxDao: MailboxDao,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend operator fun invoke(student: Student): Mailbox? {
|
||||||
|
return mailboxDao.loadAll(student.email)
|
||||||
|
.filterByStudent(student)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<Mailbox>.filterByStudent(student: Student): Mailbox? {
|
||||||
|
val normalizedStudentName = student.studentName.normalizeStudentName()
|
||||||
|
|
||||||
|
return find {
|
||||||
|
it.studentName.normalizeStudentName() == normalizedStudentName
|
||||||
|
} ?: singleOrNull {
|
||||||
|
it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
|
||||||
|
} ?: singleOrNull {
|
||||||
|
it.studentName.getUnauthorizedVersion() == normalizedStudentName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.normalizeStudentName(): String {
|
||||||
|
return trim().split(" ")
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
.joinToString(" ") { part ->
|
||||||
|
part.lowercase().replaceFirstChar { it.uppercase() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.getFirstAndLastPart(): String {
|
||||||
|
val parts = normalizeStudentName().split(" ")
|
||||||
|
|
||||||
|
val endParts = parts.filterIndexed { i, _ ->
|
||||||
|
i == 0 || parts.size - 1 == i
|
||||||
|
}
|
||||||
|
return endParts.joinToString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.getUnauthorizedVersion(): String {
|
||||||
|
return normalizeStudentName().split(" ")
|
||||||
|
.joinToString(" ") {
|
||||||
|
it.first() + "*".repeat(it.length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
import io.github.wulkanowy.data.pojos.GroupNotificationData
|
||||||
import io.github.wulkanowy.data.pojos.NotificationData
|
import io.github.wulkanowy.data.pojos.NotificationData
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
|
||||||
import io.github.wulkanowy.utils.getPlural
|
import io.github.wulkanowy.utils.getPlural
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
|
||||||
import io.github.wulkanowy.data.repositories.MailboxRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.waitForResult
|
import io.github.wulkanowy.data.waitForResult
|
||||||
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
||||||
@ -12,12 +11,11 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class MessageWork @Inject constructor(
|
class MessageWork @Inject constructor(
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val mailboxRepository: MailboxRepository,
|
|
||||||
private val newMessageNotification: NewMessageNotification,
|
private val newMessageNotification: NewMessageNotification,
|
||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
messageRepository.getMessages(
|
messageRepository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
mailbox = mailbox,
|
mailbox = mailbox,
|
||||||
@ -26,7 +24,7 @@ class MessageWork @Inject constructor(
|
|||||||
notify = notify
|
notify = notify
|
||||||
).waitForResult()
|
).waitForResult()
|
||||||
|
|
||||||
messageRepository.getMessagesFromDatabase(mailbox).first()
|
messageRepository.getMessagesFromDatabase(student, mailbox).first()
|
||||||
.filter { !it.isNotified && it.unread }.let {
|
.filter { !it.isNotified && it.unread }.let {
|
||||||
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
||||||
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
package io.github.wulkanowy.services.sync.works
|
package io.github.wulkanowy.services.sync.works
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.dataOrNull
|
||||||
import io.github.wulkanowy.data.db.entities.MailboxType
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.repositories.MailboxRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.RecipientRepository
|
import io.github.wulkanowy.data.repositories.RecipientRepository
|
||||||
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RecipientWork @Inject constructor(
|
class RecipientWork @Inject constructor(
|
||||||
private val mailboxRepository: MailboxRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val recipientRepository: RecipientRepository
|
private val recipientRepository: RecipientRepository
|
||||||
) : Work {
|
) : Work {
|
||||||
|
|
||||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||||
mailboxRepository.refreshMailboxes(student)
|
val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult()
|
||||||
|
mailboxes.dataOrNull?.forEach {
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE)
|
||||||
|
}
|
||||||
recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private val gradeRepository: GradeRepository,
|
private val gradeRepository: GradeRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val mailboxRepository: MailboxRepository,
|
|
||||||
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
||||||
private val timetableRepository: TimetableRepository,
|
private val timetableRepository: TimetableRepository,
|
||||||
private val homeworkRepository: HomeworkRepository,
|
private val homeworkRepository: HomeworkRepository,
|
||||||
@ -228,7 +227,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||||
flow {
|
flow {
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||||
|
|
||||||
val flowSuccess = flowOf(Resource.Success(null))
|
val flowSuccess = flowOf(Resource.Success(null))
|
||||||
|
@ -19,6 +19,7 @@ val debugMessageItems = listOf(
|
|||||||
private fun generateMessage(sender: String, subject: String) = Message(
|
private fun generateMessage(sender: String, subject: String) = Message(
|
||||||
subject = subject,
|
subject = subject,
|
||||||
messageId = 123,
|
messageId = 123,
|
||||||
|
email = "",
|
||||||
date = Instant.now(),
|
date = Instant.now(),
|
||||||
folderId = 0,
|
folderId = 0,
|
||||||
unread = true,
|
unread = true,
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
|
import io.github.wulkanowy.databinding.ItemMailboxChooserBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MailboxChooserAdapter @Inject constructor() :
|
||||||
|
ListAdapter<MailboxChooserItem, MailboxChooserAdapter.ItemViewHolder>(Differ) {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||||
|
ItemMailboxChooserBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context), parent, false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
|
holder.bind(getItem(position))
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemViewHolder(
|
||||||
|
private val binding: ItemMailboxChooserBinding,
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(item: MailboxChooserItem) {
|
||||||
|
with(binding) {
|
||||||
|
mailboxItemName.text = item.mailbox?.getFirstLine()
|
||||||
|
?: root.resources.getString(R.string.message_chip_all_mailboxes)
|
||||||
|
mailboxItemSchool.text = item.mailbox?.getSecondLine()
|
||||||
|
mailboxItemSchool.isVisible = !item.isAll
|
||||||
|
|
||||||
|
root.setOnClickListener { item.onClickListener(item.mailbox) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Mailbox.getFirstLine() = buildString {
|
||||||
|
if (studentName.isNotBlank() && studentName != userName) {
|
||||||
|
append(studentName)
|
||||||
|
append(" - ")
|
||||||
|
}
|
||||||
|
append(userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Mailbox.getSecondLine() = buildString {
|
||||||
|
append(schoolNameShort)
|
||||||
|
append(" - ")
|
||||||
|
append(getMailboxType(type))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMailboxType(type: MailboxType): String = when (type) {
|
||||||
|
MailboxType.STUDENT -> R.string.message_mailbox_type_student
|
||||||
|
MailboxType.PARENT -> R.string.message_mailbox_type_parent
|
||||||
|
MailboxType.GUARDIAN -> R.string.message_mailbox_type_guardian
|
||||||
|
MailboxType.EMPLOYEE -> R.string.message_mailbox_type_employee
|
||||||
|
MailboxType.UNKNOWN -> null
|
||||||
|
}.let { it?.let { it1 -> binding.root.resources.getString(it1) }.orEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private object Differ : ItemCallback<MailboxChooserItem>() {
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: MailboxChooserItem,
|
||||||
|
newItem: MailboxChooserItem
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.mailbox?.globalKey == newItem.mailbox?.globalKey
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: MailboxChooserItem,
|
||||||
|
newItem: MailboxChooserItem
|
||||||
|
): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.databinding.DialogMailboxChooserBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class MailboxChooserDialog : BaseDialogFragment<DialogMailboxChooserBinding>(), MailboxChooserView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: MailboxChooserPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var mailboxAdapter: MailboxChooserAdapter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LISTENER_KEY = "mailbox_selected"
|
||||||
|
const val MAILBOX_KEY = "selected_mailbox"
|
||||||
|
const val REQUIRED_KEY = "is_mailbox_required"
|
||||||
|
|
||||||
|
fun newInstance(mailboxes: List<Mailbox>, isMailboxRequired: Boolean, folder: String) =
|
||||||
|
MailboxChooserDialog().apply {
|
||||||
|
arguments = bundleOf(
|
||||||
|
MAILBOX_KEY to mailboxes.toTypedArray(),
|
||||||
|
REQUIRED_KEY to isMailboxRequired,
|
||||||
|
LISTENER_KEY to folder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogMailboxChooserBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
presenter.onAttachView(
|
||||||
|
view = this,
|
||||||
|
requireMailbox = requireArguments().getBoolean(REQUIRED_KEY, false),
|
||||||
|
mailboxes = requireArguments().getParcelableArray(MAILBOX_KEY).orEmpty()
|
||||||
|
.toList() as List<Mailbox>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
binding.accountQuickDialogRecycler.adapter = mailboxAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun submitData(items: List<MailboxChooserItem>) {
|
||||||
|
mailboxAdapter.submitList(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMailboxSelected(item: Mailbox?) {
|
||||||
|
setFragmentResult(
|
||||||
|
requestKey = requireArguments().getString(LISTENER_KEY).orEmpty(),
|
||||||
|
result = bundleOf(MAILBOX_KEY to item),
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
|
||||||
|
data class MailboxChooserItem(
|
||||||
|
val mailbox: Mailbox? = null,
|
||||||
|
val isAll: Boolean = false,
|
||||||
|
val onClickListener: (Mailbox?) -> Unit,
|
||||||
|
)
|
@ -0,0 +1,38 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MailboxChooserPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository
|
||||||
|
) : BasePresenter<MailboxChooserView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
fun onAttachView(view: MailboxChooserView, mailboxes: List<Mailbox>, requireMailbox: Boolean) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Mailbox chooser view was initialized")
|
||||||
|
view.submitData(getMailboxItems(mailboxes, requireMailbox))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMailboxItems(
|
||||||
|
mailboxes: List<Mailbox>,
|
||||||
|
requireMailbox: Boolean,
|
||||||
|
): List<MailboxChooserItem> = buildList {
|
||||||
|
if (!requireMailbox) {
|
||||||
|
add(MailboxChooserItem(isAll = true, onClickListener = ::onMailboxSelect))
|
||||||
|
}
|
||||||
|
addAll(mailboxes.map {
|
||||||
|
MailboxChooserItem(mailbox = it, isAll = false, onClickListener = ::onMailboxSelect)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMailboxSelect(item: Mailbox?) {
|
||||||
|
view?.onMailboxSelected(item)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.message.mailboxchooser
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface MailboxChooserView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun submitData(items: List<MailboxChooserItem>)
|
||||||
|
|
||||||
|
fun onMailboxSelected(item: Mailbox?)
|
||||||
|
}
|
@ -6,7 +6,6 @@ import io.github.wulkanowy.data.*
|
|||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.MailboxRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -21,7 +20,6 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val mailboxRepository: MailboxRepository,
|
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -187,8 +185,8 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
messageRepository.deleteMessage(student, mailbox, message!!)
|
messageRepository.deleteMessage(student, mailbox!!, message!!)
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
retryCallback = { onMessageDelete() }
|
retryCallback = { onMessageDelete() }
|
||||||
|
@ -19,9 +19,13 @@ import androidx.core.text.toHtml
|
|||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
import io.github.wulkanowy.databinding.ActivitySendMessageBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
||||||
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.MAILBOX_KEY
|
||||||
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog.Companion.LISTENER_KEY
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
import io.github.wulkanowy.utils.hideSoftInput
|
import io.github.wulkanowy.utils.hideSoftInput
|
||||||
import io.github.wulkanowy.utils.showSoftInput
|
import io.github.wulkanowy.utils.showSoftInput
|
||||||
@ -100,6 +104,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
formSubjectValue = binding.sendMessageSubject.text.toString()
|
formSubjectValue = binding.sendMessageSubject.text.toString()
|
||||||
formContentValue =
|
formContentValue =
|
||||||
binding.sendMessageMessageContent.text.toString().parseAsHtml().toString()
|
binding.sendMessageMessageContent.text.toString().parseAsHtml().toString()
|
||||||
|
binding.sendMessageFrom.setOnClickListener { presenter.onOpenMailboxChooser() }
|
||||||
|
|
||||||
presenter.onAttachView(
|
presenter.onAttachView(
|
||||||
view = this,
|
view = this,
|
||||||
@ -107,6 +112,9 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
message = intent.getSerializableExtra(EXTRA_MESSAGE) as? Message,
|
message = intent.getSerializableExtra(EXTRA_MESSAGE) as? Message,
|
||||||
reply = intent.getSerializableExtra(EXTRA_REPLY) as? Boolean
|
reply = intent.getSerializableExtra(EXTRA_REPLY) as? Boolean
|
||||||
)
|
)
|
||||||
|
supportFragmentManager.setFragmentResultListener(LISTENER_KEY, this) { _, bundle ->
|
||||||
|
presenter.onMailboxSelected(bundle.getSerializable(MAILBOX_KEY) as? Mailbox)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@ -205,6 +213,14 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showMailboxChooser(mailboxes: List<Mailbox>) {
|
||||||
|
MailboxChooserDialog.newInstance(
|
||||||
|
mailboxes = mailboxes,
|
||||||
|
isMailboxRequired = true,
|
||||||
|
folder = LISTENER_KEY,
|
||||||
|
).show(supportFragmentManager, "chooser")
|
||||||
|
}
|
||||||
|
|
||||||
override fun popView() {
|
override fun popView() {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.send
|
package io.github.wulkanowy.ui.modules.message.send
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.MailboxType
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.logResourceStatus
|
|
||||||
import io.github.wulkanowy.data.onResourceNotLoading
|
|
||||||
import io.github.wulkanowy.data.pojos.MessageDraft
|
import io.github.wulkanowy.data.pojos.MessageDraft
|
||||||
import io.github.wulkanowy.data.repositories.*
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.RecipientRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
@ -28,7 +28,6 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val mailboxRepository: MailboxRepository,
|
|
||||||
private val recipientRepository: RecipientRepository,
|
private val recipientRepository: RecipientRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
@ -36,10 +35,19 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
|
|
||||||
private val messageUpdateChannel = Channel<Unit>()
|
private val messageUpdateChannel = Channel<Unit>()
|
||||||
|
|
||||||
|
private var message: Message? = null
|
||||||
|
private var isReplay: Boolean? = null
|
||||||
|
|
||||||
|
private var mailboxes: List<Mailbox> = emptyList()
|
||||||
|
private var selectedMailbox: Mailbox? = null
|
||||||
|
|
||||||
fun onAttachView(view: SendMessageView, reason: String?, message: Message?, reply: Boolean?) {
|
fun onAttachView(view: SendMessageView, reason: String?, message: Message?, reply: Boolean?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
initializeSubjectStream()
|
initializeSubjectStream()
|
||||||
|
this.message = message
|
||||||
|
this.isReplay = reply
|
||||||
|
|
||||||
Timber.i("Send message view was initialized")
|
Timber.i("Send message view was initialized")
|
||||||
loadData(message, reply)
|
loadData(message, reply)
|
||||||
with(view) {
|
with(view) {
|
||||||
@ -110,16 +118,31 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onOpenMailboxChooser() {
|
||||||
|
view?.showMailboxChooser(mailboxes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMailboxSelected(mailbox: Mailbox?) {
|
||||||
|
selectedMailbox = mailbox
|
||||||
|
|
||||||
|
loadData(message, isReplay)
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadData(message: Message?, reply: Boolean?) {
|
private fun loadData(message: Message?, reply: Boolean?) {
|
||||||
resourceFlow {
|
resourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
|
||||||
|
if (selectedMailbox == null && mailboxes.isEmpty()) {
|
||||||
|
selectedMailbox = messageRepository.getMailboxByStudent(student)
|
||||||
|
mailboxes = messageRepository.getMailboxes(student, false).toFirstResult()
|
||||||
|
.dataOrNull.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
Timber.i("Loading recipients started")
|
Timber.i("Loading recipients started")
|
||||||
val recipients = createChips(
|
val recipients = createChips(
|
||||||
recipients = recipientRepository.getRecipients(
|
recipients = recipientRepository.getRecipients(
|
||||||
student = student,
|
student = student,
|
||||||
mailbox = mailbox,
|
mailbox = selectedMailbox,
|
||||||
type = MailboxType.EMPLOYEE,
|
type = MailboxType.EMPLOYEE,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -130,7 +153,7 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
message != null && reply == true -> recipientRepository.getMessageSender(
|
message != null && reply == true -> recipientRepository.getMessageSender(
|
||||||
student = student,
|
student = student,
|
||||||
message = message,
|
message = message,
|
||||||
mailbox = mailbox,
|
mailbox = selectedMailbox,
|
||||||
)
|
)
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}.let { createChips(it) }
|
}.let { createChips(it) }
|
||||||
@ -139,39 +162,42 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
messageRecipients.size
|
messageRecipients.size
|
||||||
)
|
)
|
||||||
|
|
||||||
Triple(mailbox, recipients, messageRecipients)
|
recipients to messageRecipients
|
||||||
}
|
}
|
||||||
.logResourceStatus("load recipients")
|
.logResourceStatus("load recipients")
|
||||||
.onEach {
|
.onResourceLoading {
|
||||||
when (it) {
|
view?.run {
|
||||||
is Resource.Loading -> view?.run {
|
showProgress(true)
|
||||||
showProgress(true)
|
showContent(false)
|
||||||
showContent(false)
|
}
|
||||||
}
|
}
|
||||||
is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) ->
|
.onResourceNotLoading {
|
||||||
view?.run {
|
view?.run { showProgress(false) }
|
||||||
setMailbox(getMailboxName(mailbox))
|
}
|
||||||
setRecipients(recipientChips)
|
.onResourceError {
|
||||||
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
|
view?.showContent(true)
|
||||||
selectedRecipientChips
|
errorHandler.dispatch(it)
|
||||||
)
|
}
|
||||||
showContent(true)
|
.onResourceSuccess {
|
||||||
}
|
it.let { (recipientChips, selectedRecipientChips) ->
|
||||||
}
|
view?.run {
|
||||||
is Resource.Error -> {
|
setMailbox(getMailboxName(selectedMailbox))
|
||||||
view?.showContent(true)
|
setRecipients(recipientChips)
|
||||||
errorHandler.dispatch(it.error)
|
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
|
||||||
|
selectedRecipientChips
|
||||||
|
)
|
||||||
|
showContent(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onResourceNotLoading {
|
}
|
||||||
view?.run { showProgress(false) }
|
.launch()
|
||||||
}.launch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
||||||
|
val mailbox = selectedMailbox ?: return
|
||||||
|
|
||||||
resourceFlow {
|
resourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
|
||||||
messageRepository.sendMessage(
|
messageRepository.sendMessage(
|
||||||
student = student,
|
student = student,
|
||||||
subject = subject,
|
subject = subject,
|
||||||
@ -222,18 +248,21 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMailboxName(mailbox: Mailbox): String {
|
private fun getMailboxName(mailbox: Mailbox?): String {
|
||||||
|
mailbox ?: return ""
|
||||||
|
|
||||||
|
// username - accountType [\n student name - ] (school short name)
|
||||||
return buildString {
|
return buildString {
|
||||||
append(mailbox.userName)
|
append(mailbox.userName)
|
||||||
append(" - ")
|
append(" - ")
|
||||||
append(getMailboxType(mailbox.type))
|
append(getMailboxType(mailbox.type))
|
||||||
|
appendLine()
|
||||||
|
|
||||||
if (mailbox.type == MailboxType.PARENT) {
|
if (mailbox.type == MailboxType.PARENT) {
|
||||||
append(" - ")
|
|
||||||
append(mailbox.studentName)
|
append(mailbox.studentName)
|
||||||
|
append(" - ")
|
||||||
}
|
}
|
||||||
|
|
||||||
append(" - ")
|
|
||||||
append("(${mailbox.schoolNameShort})")
|
append("(${mailbox.schoolNameShort})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,9 +296,9 @@ class SendMessagePresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun saveDraftMessage() {
|
private fun saveDraftMessage() {
|
||||||
messageRepository.draftMessage = MessageDraft(
|
messageRepository.draftMessage = MessageDraft(
|
||||||
view?.formRecipientsData!!,
|
recipients = view?.formRecipientsData!!,
|
||||||
view?.formSubjectValue!!,
|
subject = view?.formSubjectValue!!,
|
||||||
view?.formContentValue!!
|
content = view?.formContentValue!!,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,4 +61,5 @@ interface SendMessageView : BaseView {
|
|||||||
fun getMessageBackupDialogStringWithRecipients(recipients: String): String
|
fun getMessageBackupDialogStringWithRecipients(recipients: String): String
|
||||||
|
|
||||||
fun clearDraft()
|
fun clearDraft()
|
||||||
|
fun showMailboxChooser(mailboxes: List<Mailbox>)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.ItemMessageBinding
|
import io.github.wulkanowy.databinding.ItemMessageBinding
|
||||||
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
|
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
|
||||||
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import io.github.wulkanowy.utils.toFormattedString
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -19,13 +20,15 @@ import javax.inject.Inject
|
|||||||
class MessageTabAdapter @Inject constructor() :
|
class MessageTabAdapter @Inject constructor() :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit = { _, _ -> }
|
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
|
||||||
|
|
||||||
var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit = {}
|
lateinit var onLongItemClickListener: (MessageTabDataItem.MessageItem) -> Unit
|
||||||
|
|
||||||
var onHeaderClickListener: (CompoundButton, Boolean) -> Unit = { _, _ -> }
|
lateinit var onHeaderClickListener: (CompoundButton, Boolean) -> Unit
|
||||||
|
|
||||||
var onChangesDetectedListener = {}
|
lateinit var onMailboxClickListener: () -> Unit
|
||||||
|
|
||||||
|
lateinit var onChangesDetectedListener: () -> Unit
|
||||||
|
|
||||||
private var items = mutableListOf<MessageTabDataItem>()
|
private var items = mutableListOf<MessageTabDataItem>()
|
||||||
|
|
||||||
@ -49,12 +52,12 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|
||||||
return when (MessageItemViewType.values()[viewType]) {
|
return when (MessageItemViewType.values()[viewType]) {
|
||||||
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
|
||||||
ItemMessageBinding.inflate(inflater, parent, false)
|
|
||||||
)
|
|
||||||
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
||||||
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
||||||
|
ItemMessageBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +72,20 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
val item = items[position] as MessageTabDataItem.FilterHeader
|
val item = items[position] as MessageTabDataItem.FilterHeader
|
||||||
|
|
||||||
with(holder.binding) {
|
with(holder.binding) {
|
||||||
|
chipMailbox.text = item.selectedMailbox
|
||||||
|
?: root.context.getString(R.string.message_chip_all_mailboxes)
|
||||||
|
chipMailbox.chipBackgroundColor = ColorStateList.valueOf(
|
||||||
|
if (item.selectedMailbox == null) {
|
||||||
|
root.context.getCompatColor(R.color.mtrl_choice_chip_background_color)
|
||||||
|
} else root.context.getThemeAttrColor(android.R.attr.colorPrimary, 64)
|
||||||
|
)
|
||||||
|
chipMailbox.setTextColor(
|
||||||
|
if (item.selectedMailbox == null) {
|
||||||
|
root.context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
} else root.context.getThemeAttrColor(android.R.attr.colorPrimary)
|
||||||
|
)
|
||||||
|
chipMailbox.setOnClickListener { onMailboxClickListener() }
|
||||||
|
|
||||||
if (item.onlyUnread == null) {
|
if (item.onlyUnread == null) {
|
||||||
chipUnread.isVisible = false
|
chipUnread.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
@ -77,6 +94,7 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
chipUnread.setOnCheckedChangeListener(onHeaderClickListener)
|
chipUnread.setOnCheckedChangeListener(onHeaderClickListener)
|
||||||
}
|
}
|
||||||
chipUnread.isEnabled = item.isEnabled
|
chipUnread.isEnabled = item.isEnabled
|
||||||
|
|
||||||
chipAttachments.isEnabled = item.isEnabled
|
chipAttachments.isEnabled = item.isEnabled
|
||||||
chipAttachments.isChecked = item.onlyWithAttachments
|
chipAttachments.isChecked = item.onlyWithAttachments
|
||||||
chipAttachments.setOnCheckedChangeListener(onHeaderClickListener)
|
chipAttachments.setOnCheckedChangeListener(onHeaderClickListener)
|
||||||
|
@ -11,6 +11,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
|
|||||||
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
||||||
|
|
||||||
data class FilterHeader(
|
data class FilterHeader(
|
||||||
|
val selectedMailbox: String?,
|
||||||
val onlyUnread: Boolean?,
|
val onlyUnread: Boolean?,
|
||||||
val onlyWithAttachments: Boolean,
|
val onlyWithAttachments: Boolean,
|
||||||
val isEnabled: Boolean
|
val isEnabled: Boolean
|
||||||
|
@ -10,15 +10,18 @@ import android.widget.CompoundButton
|
|||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
import androidx.fragment.app.setFragmentResultListener
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.databinding.FragmentMessageTabBinding
|
import io.github.wulkanowy.databinding.FragmentMessageTabBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
||||||
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
||||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
@ -104,6 +107,7 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
onItemClickListener = presenter::onMessageItemSelected
|
onItemClickListener = presenter::onMessageItemSelected
|
||||||
onLongItemClickListener = presenter::onMessageItemLongSelected
|
onLongItemClickListener = presenter::onMessageItemLongSelected
|
||||||
onHeaderClickListener = ::onChipChecked
|
onHeaderClickListener = ::onChipChecked
|
||||||
|
onMailboxClickListener = presenter::onMailboxFilterSelected
|
||||||
onChangesDetectedListener = ::resetListPosition
|
onChangesDetectedListener = ::resetListPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +127,12 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
|
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setFragmentResultListener(requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!) { _, bundle ->
|
||||||
|
presenter.onMailboxSelected(
|
||||||
|
mailbox = bundle.getSerializable(MailboxChooserDialog.MAILBOX_KEY) as? Mailbox,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
@ -246,6 +256,16 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showMailboxChooser(mailboxes: List<Mailbox>) {
|
||||||
|
(activity as? MainActivity)?.showDialogFragment(
|
||||||
|
MailboxChooserDialog.newInstance(
|
||||||
|
mailboxes = mailboxes,
|
||||||
|
isMailboxRequired = false,
|
||||||
|
folder = requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun hideKeyboard() {
|
override fun hideKeyboard() {
|
||||||
activity?.hideSoftInput()
|
activity?.hideSoftInput()
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.tab
|
package io.github.wulkanowy.ui.modules.message.tab
|
||||||
|
|
||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.MailboxRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -26,7 +26,6 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val messageRepository: MessageRepository,
|
private val messageRepository: MessageRepository,
|
||||||
private val mailboxRepository: MailboxRepository,
|
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -36,6 +35,9 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
private var lastSearchQuery = ""
|
private var lastSearchQuery = ""
|
||||||
|
|
||||||
|
private var mailboxes: List<Mailbox> = emptyList()
|
||||||
|
private var selectedMailbox: Mailbox? = null
|
||||||
|
|
||||||
private var messages = emptyList<Message>()
|
private var messages = emptyList<Message>()
|
||||||
|
|
||||||
private val searchChannel = Channel<String>()
|
private val searchChannel = Channel<String>()
|
||||||
@ -122,8 +124,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(true)
|
val student = studentRepository.getCurrentStudent(true)
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
messageRepository.deleteMessages(student, selectedMailbox, messageList)
|
||||||
messageRepository.deleteMessages(student, mailbox, messageList)
|
|
||||||
}
|
}
|
||||||
.onFailure(errorHandler::dispatch)
|
.onFailure(errorHandler::dispatch)
|
||||||
.onSuccess { view?.showMessagesDeleted() }
|
.onSuccess { view?.showMessagesDeleted() }
|
||||||
@ -202,13 +203,28 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onMailboxFilterSelected() {
|
||||||
|
view?.showMailboxChooser(mailboxes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMailboxSelected(mailbox: Mailbox?) {
|
||||||
|
selectedMailbox = mailbox
|
||||||
|
loadData(false)
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadData(forceRefresh: Boolean) {
|
private fun loadData(forceRefresh: Boolean) {
|
||||||
Timber.i("Loading $folder message data started")
|
Timber.i("Loading $folder message data started")
|
||||||
|
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val mailbox = mailboxRepository.getMailbox(student)
|
|
||||||
messageRepository.getMessages(student, mailbox, folder, forceRefresh)
|
if (selectedMailbox == null && mailboxes.isEmpty()) {
|
||||||
|
selectedMailbox = messageRepository.getMailboxByStudent(student)
|
||||||
|
mailboxes = messageRepository.getMailboxes(student, forceRefresh).toFirstResult()
|
||||||
|
.dataOrNull.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
messageRepository.getMessages(student, selectedMailbox, folder, forceRefresh)
|
||||||
}
|
}
|
||||||
.logResourceStatus("load $folder message")
|
.logResourceStatus("load $folder message")
|
||||||
.onResourceData {
|
.onResourceData {
|
||||||
@ -327,7 +343,16 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
MessageTabDataItem.FilterHeader(
|
MessageTabDataItem.FilterHeader(
|
||||||
onlyUnread = onlyUnread.takeIf { folder != MessageFolder.SENT },
|
onlyUnread = onlyUnread.takeIf { folder != MessageFolder.SENT },
|
||||||
onlyWithAttachments = onlyWithAttachments,
|
onlyWithAttachments = onlyWithAttachments,
|
||||||
isEnabled = !isActionMode
|
isEnabled = !isActionMode,
|
||||||
|
selectedMailbox = selectedMailbox?.let {
|
||||||
|
buildString {
|
||||||
|
if (it.studentName.isNotBlank() && it.studentName != it.userName) {
|
||||||
|
append(it.studentName)
|
||||||
|
append(" - ")
|
||||||
|
}
|
||||||
|
append(it.userName)
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.message.tab
|
package io.github.wulkanowy.ui.modules.message.tab
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
@ -46,4 +47,6 @@ interface MessageTabView : BaseView {
|
|||||||
fun showActionMode(show: Boolean)
|
fun showActionMode(show: Boolean)
|
||||||
|
|
||||||
fun showRecyclerBottomPadding(show: Boolean)
|
fun showRecyclerBottomPadding(show: Boolean)
|
||||||
|
|
||||||
|
fun showMailboxChooser(mailboxes: List<Mailbox>)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
@ -25,8 +26,8 @@ fun getRefreshKey(name: String, student: Student): String {
|
|||||||
return "${name}_${student.userLoginId}"
|
return "${name}_${student.userLoginId}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRefreshKey(name: String, student: Student, folder: MessageFolder): String {
|
fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): String {
|
||||||
return "${name}_${student.id}_${folder.id}"
|
return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutoRefreshHelper @Inject constructor(
|
class AutoRefreshHelper @Inject constructor(
|
||||||
|
@ -55,17 +55,29 @@
|
|||||||
android:id="@+id/sendMessageFrom"
|
android:id="@+id/sendMessageFrom"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="58dp"
|
android:layout_height="58dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="16dp"
|
android:background="?selectableItemBackground"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="32dp"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/sendMessageFromHint"
|
app:layout_constraintStart_toEndOf="@id/sendMessageFromHint"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Jan Kowalski" />
|
tools:text="Jan Kowalski" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:rotation="270"
|
||||||
|
android:src="@drawable/ic_chevron_left"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/sendMessageFrom"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/sendMessageFrom"
|
||||||
|
app:tint="?android:textColorSecondary"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/sendMessageFromDivider"
|
android:id="@+id/sendMessageFromDivider"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
40
app/src/main/res/layout/dialog_mailbox_chooser.xml
Normal file
40
app/src/main/res/layout/dialog_mailbox_chooser.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout 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:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/account_quick_dialog_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="24dp"
|
||||||
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingEnd="24dp"
|
||||||
|
android:paddingRight="24dp"
|
||||||
|
android:text="@string/message_mailbox_chooser_title"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:firstBaselineToTopHeight="40dp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/account_quick_dialog_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="3"
|
||||||
|
tools:listitem="@layout/item_mailbox_chooser" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
43
app/src/main/res/layout/item_mailbox_chooser.xml
Normal file
43
app/src/main/res/layout/item_mailbox_chooser.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="8dp"
|
||||||
|
tools:context=".ui.modules.message.mailboxchooser.MailboxChooserAdapter">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/mailboxItemName"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/full_names" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/mailboxItemSchool"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/mailboxItemName"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,21 +1,30 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/messageChipsLayout"
|
android:id="@+id/messageChipsLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="16dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:paddingRight="16dp"
|
|
||||||
tools:context=".ui.modules.message.tab.MessageTabAdapter">
|
tools:context=".ui.modules.message.tab.MessageTabAdapter">
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/messageChipGroup"
|
android:id="@+id/messageChipGroup"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:singleLine="true">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_mailbox"
|
||||||
|
style="@style/Widget.MaterialComponents.Chip.Action"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/message_chip_all_mailboxes" />
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
<com.google.android.material.chip.Chip
|
||||||
android:id="@+id/chip_unread"
|
android:id="@+id/chip_unread"
|
||||||
@ -37,4 +46,4 @@
|
|||||||
app:checkedIconEnabled="true"
|
app:checkedIconEnabled="true"
|
||||||
app:checkedIconTint="@color/mtrl_choice_chip_text_color" />
|
app:checkedIconTint="@color/mtrl_choice_chip_text_color" />
|
||||||
</com.google.android.material.chip.ChipGroup>
|
</com.google.android.material.chip.ChipGroup>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</HorizontalScrollView>
|
||||||
|
@ -301,6 +301,7 @@
|
|||||||
<string name="message_not_exists">Message does not exist</string>
|
<string name="message_not_exists">Message does not exist</string>
|
||||||
<string name="message_required_recipients">You need to choose at least 1 recipient</string>
|
<string name="message_required_recipients">You need to choose at least 1 recipient</string>
|
||||||
<string name="message_content_min_length">The message content must be at least 3 characters</string>
|
<string name="message_content_min_length">The message content must be at least 3 characters</string>
|
||||||
|
<string name="message_chip_all_mailboxes">Wszystkie skrzynki</string>
|
||||||
<string name="message_chip_only_unread">Only unread</string>
|
<string name="message_chip_only_unread">Only unread</string>
|
||||||
<string name="message_chip_only_with_attachments">Only with attachments</string>
|
<string name="message_chip_only_with_attachments">Only with attachments</string>
|
||||||
<string name="message_read">Read: %s</string>
|
<string name="message_read">Read: %s</string>
|
||||||
@ -324,6 +325,7 @@
|
|||||||
<item quantity="other">%1$d selected</item>
|
<item quantity="other">%1$d selected</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="message_messages_deleted">Messages deleted</string>
|
<string name="message_messages_deleted">Messages deleted</string>
|
||||||
|
<string name="message_mailbox_chooser_title">Choose mailbox</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Note-->
|
<!--Note-->
|
||||||
|
@ -27,7 +27,9 @@ fun getMailboxEntity() = Mailbox(
|
|||||||
globalKey = "v4",
|
globalKey = "v4",
|
||||||
fullName = "",
|
fullName = "",
|
||||||
userName = "",
|
userName = "",
|
||||||
userLoginId = 0,
|
email = "test",
|
||||||
|
symbol = "powiatwulkanowy",
|
||||||
|
schoolId = "123456",
|
||||||
studentName = "",
|
studentName = "",
|
||||||
schoolNameShort = "",
|
schoolNameShort = "",
|
||||||
type = MailboxType.UNKNOWN,
|
type = MailboxType.UNKNOWN,
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.github.wulkanowy.data.dataOrNull
|
import io.github.wulkanowy.data.dataOrNull
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
|
||||||
import io.github.wulkanowy.data.db.dao.MessagesDao
|
import io.github.wulkanowy.data.db.dao.MessagesDao
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
@ -10,6 +11,7 @@ import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
|||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.errorOrNull
|
import io.github.wulkanowy.data.errorOrNull
|
||||||
import io.github.wulkanowy.data.toFirstResult
|
import io.github.wulkanowy.data.toFirstResult
|
||||||
|
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||||
import io.github.wulkanowy.getMailboxEntity
|
import io.github.wulkanowy.getMailboxEntity
|
||||||
import io.github.wulkanowy.getStudentEntity
|
import io.github.wulkanowy.getStudentEntity
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
@ -55,6 +57,12 @@ class MessageRepositoryTest {
|
|||||||
@MockK
|
@MockK
|
||||||
private lateinit var sharedPrefProvider: SharedPrefProvider
|
private lateinit var sharedPrefProvider: SharedPrefProvider
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var mailboxDao: MailboxDao
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var getMailboxByStudentUseCase: GetMailboxByStudentUseCase
|
||||||
|
|
||||||
private val student = getStudentEntity()
|
private val student = getStudentEntity()
|
||||||
|
|
||||||
private val mailbox = getMailboxEntity()
|
private val mailbox = getMailboxEntity()
|
||||||
@ -74,26 +82,33 @@ class MessageRepositoryTest {
|
|||||||
refreshHelper = refreshHelper,
|
refreshHelper = refreshHelper,
|
||||||
sharedPrefProvider = sharedPrefProvider,
|
sharedPrefProvider = sharedPrefProvider,
|
||||||
json = Json,
|
json = Json,
|
||||||
|
mailboxDao = mailboxDao,
|
||||||
|
getMailboxByStudentUseCase = getMailboxByStudentUseCase,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get messages when fetched completely new message without notify`() = runBlocking {
|
fun `get messages when fetched completely new message without notify`() = runBlocking {
|
||||||
every { messageDb.loadAll(any(), any()) } returns flowOf(emptyList())
|
coEvery { mailboxDao.loadAll(any()) } returns listOf(mailbox)
|
||||||
|
every { messageDb.loadAll(mailbox.globalKey, any()) } returns flowOf(emptyList())
|
||||||
coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf(
|
coEvery { sdk.getMessages(Folder.RECEIVED, any()) } returns listOf(
|
||||||
getMessageDto()
|
getMessageDto().copy(
|
||||||
|
unreadBy = 5,
|
||||||
|
readBy = 10,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
coEvery { messageDb.deleteAll(any()) } just Runs
|
coEvery { messageDb.deleteAll(any()) } just Runs
|
||||||
coEvery { messageDb.insertAll(any()) } returns listOf()
|
coEvery { messageDb.insertAll(any()) } returns listOf()
|
||||||
|
|
||||||
repository.getMessages(
|
val res = repository.getMessages(
|
||||||
student = student,
|
student = student,
|
||||||
mailbox = mailbox,
|
mailbox = mailbox,
|
||||||
folder = MessageFolder.RECEIVED,
|
folder = MessageFolder.RECEIVED,
|
||||||
forceRefresh = true,
|
forceRefresh = true,
|
||||||
notify = false,
|
notify = false,
|
||||||
).toFirstResult().dataOrNull.orEmpty()
|
).toFirstResult()
|
||||||
|
|
||||||
|
assertEquals(null, res.errorOrNull)
|
||||||
coVerify(exactly = 1) { messageDb.deleteAll(withArg { checkEquals(emptyList<Message>()) }) }
|
coVerify(exactly = 1) { messageDb.deleteAll(withArg { checkEquals(emptyList<Message>()) }) }
|
||||||
coVerify {
|
coVerify {
|
||||||
messageDb.insertAll(withArg {
|
messageDb.insertAll(withArg {
|
||||||
@ -187,6 +202,7 @@ class MessageRepositoryTest {
|
|||||||
) = Message(
|
) = Message(
|
||||||
messageGlobalKey = "v4",
|
messageGlobalKey = "v4",
|
||||||
mailboxKey = "",
|
mailboxKey = "",
|
||||||
|
email = "",
|
||||||
correspondents = "",
|
correspondents = "",
|
||||||
messageId = messageId,
|
messageId = messageId,
|
||||||
subject = "",
|
subject = "",
|
||||||
|
@ -1,65 +1,52 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.domain
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
import io.github.wulkanowy.data.db.dao.MailboxDao
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.MailboxType
|
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
|
||||||
import io.mockk.MockKAnnotations
|
import io.mockk.MockKAnnotations
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.impl.annotations.SpyK
|
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class MailboxRepositoryTest {
|
class GetMailboxByStudentUseCaseTest {
|
||||||
|
|
||||||
@SpyK
|
|
||||||
private var sdk = Sdk()
|
|
||||||
|
|
||||||
@MockK
|
@MockK
|
||||||
private lateinit var mailboxDao: MailboxDao
|
private lateinit var mailboxDao: MailboxDao
|
||||||
|
|
||||||
@MockK
|
private lateinit var systemUnderTest: GetMailboxByStudentUseCase
|
||||||
private lateinit var refreshHelper: AutoRefreshHelper
|
|
||||||
|
|
||||||
private lateinit var systemUnderTest: MailboxRepository
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
|
|
||||||
coEvery { refreshHelper.shouldBeRefreshed(any()) } returns false
|
|
||||||
coEvery { refreshHelper.updateLastRefreshTimestamp(any()) } just Runs
|
|
||||||
coEvery { mailboxDao.deleteAll(any()) } just Runs
|
coEvery { mailboxDao.deleteAll(any()) } just Runs
|
||||||
coEvery { mailboxDao.insertAll(any()) } returns emptyList()
|
coEvery { mailboxDao.insertAll(any()) } returns emptyList()
|
||||||
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
|
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
|
||||||
coEvery { sdk.getMailboxes() } returns emptyList()
|
|
||||||
|
|
||||||
systemUnderTest = MailboxRepository(
|
systemUnderTest = GetMailboxByStudentUseCase(mailboxDao = mailboxDao)
|
||||||
mailboxDao = mailboxDao,
|
|
||||||
sdk = sdk,
|
|
||||||
refreshHelper = refreshHelper,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
@Test
|
||||||
fun `get mailbox that doesn't exist`() = runTest {
|
fun `get mailbox that doesn't exist`() = runTest {
|
||||||
val student = getStudentEntity(
|
val student = getStudentEntity(
|
||||||
userName = "Stanisław Kowalski",
|
userName = "Stanisław Kowalski",
|
||||||
studentName = "Jan Kowalski",
|
studentName = "Jan Kowalski",
|
||||||
)
|
)
|
||||||
coEvery { sdk.getMailboxes() } returns emptyList()
|
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
|
||||||
|
|
||||||
systemUnderTest.getMailbox(student)
|
assertNull(systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -73,7 +60,7 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
val selectedMailbox = systemUnderTest.getMailbox(student)
|
val selectedMailbox = systemUnderTest(student)
|
||||||
assertEquals(expectedMailbox, selectedMailbox)
|
assertEquals(expectedMailbox, selectedMailbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +75,7 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -102,10 +89,10 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
@Test
|
||||||
fun `get mailbox for not-unique non-authorized student`() = runTest {
|
fun `get mailbox for not-unique non-authorized student`() = runTest {
|
||||||
val student = getStudentEntity(
|
val student = getStudentEntity(
|
||||||
userName = "Stanisław Kowalski",
|
userName = "Stanisław Kowalski",
|
||||||
@ -116,7 +103,7 @@ class MailboxRepositoryTest {
|
|||||||
getMailboxEntity("Jan Kurowski"),
|
getMailboxEntity("Jan Kurowski"),
|
||||||
)
|
)
|
||||||
|
|
||||||
systemUnderTest.getMailbox(student)
|
assertNull(systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -130,7 +117,7 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -144,7 +131,7 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -158,7 +145,7 @@ class MailboxRepositoryTest {
|
|||||||
expectedMailbox,
|
expectedMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMailboxEntity(
|
private fun getMailboxEntity(
|
||||||
@ -167,7 +154,9 @@ class MailboxRepositoryTest {
|
|||||||
globalKey = "",
|
globalKey = "",
|
||||||
fullName = "",
|
fullName = "",
|
||||||
userName = "",
|
userName = "",
|
||||||
userLoginId = 123,
|
email = "",
|
||||||
|
schoolId = "",
|
||||||
|
symbol = "",
|
||||||
studentName = studentName,
|
studentName = studentName,
|
||||||
schoolNameShort = "",
|
schoolNameShort = "",
|
||||||
type = MailboxType.STUDENT,
|
type = MailboxType.STUDENT,
|
Loading…
x
Reference in New Issue
Block a user