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() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 52
|
||||
const val VERSION_SCHEMA = 53
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
@ -106,6 +106,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration49(),
|
||||
Migration50(),
|
||||
Migration51(),
|
||||
Migration53(),
|
||||
)
|
||||
|
||||
fun newInstance(
|
||||
|
@ -3,12 +3,16 @@ package io.github.wulkanowy.data.db.dao
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface MailboxDao : BaseDao<Mailbox> {
|
||||
|
||||
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
|
||||
suspend fun loadAll(userLoginId: Int): List<Mailbox>
|
||||
@Query("SELECT * FROM Mailboxes WHERE email = :email")
|
||||
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")
|
||||
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
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@Entity(tableName = "Mailboxes")
|
||||
data class Mailbox(
|
||||
|
||||
@PrimaryKey
|
||||
val globalKey: String,
|
||||
|
||||
val email: String,
|
||||
val symbol: String,
|
||||
val schoolId: String,
|
||||
|
||||
val fullName: String,
|
||||
val userName: String,
|
||||
val userLoginId: Int,
|
||||
val studentName: String,
|
||||
val schoolNameShort: String,
|
||||
val type: MailboxType,
|
||||
)
|
||||
) : java.io.Serializable, Parcelable
|
||||
|
||||
enum class MailboxType {
|
||||
STUDENT,
|
||||
|
@ -9,6 +9,9 @@ import java.time.Instant
|
||||
@Entity(tableName = "Messages")
|
||||
data class Message(
|
||||
|
||||
@ColumnInfo(name = "email")
|
||||
val email: String,
|
||||
|
||||
@ColumnInfo(name = "message_global_key")
|
||||
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,
|
||||
fullName = it.fullName,
|
||||
userName = it.userName,
|
||||
userLoginId = student.userLoginId,
|
||||
studentName = it.studentName,
|
||||
schoolNameShort = it.schoolNameShort,
|
||||
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.Recipient as SdkRecipient
|
||||
|
||||
fun List<SdkMessage>.mapToEntities(mailbox: Mailbox) = map {
|
||||
fun List<SdkMessage>.mapToEntities(student: Student, mailbox: Mailbox?, allMailboxes: List<Mailbox>) = map {
|
||||
Message(
|
||||
messageGlobalKey = it.globalKey,
|
||||
mailboxKey = mailbox.globalKey,
|
||||
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
|
||||
box.fullName == it.mailbox
|
||||
}?.globalKey!!,
|
||||
email = student.email,
|
||||
messageId = it.id,
|
||||
correspondents = it.correspondents,
|
||||
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.data.Resource
|
||||
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.MessagesDao
|
||||
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.networkBoundResource
|
||||
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.pojo.Folder
|
||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||
@ -40,16 +43,18 @@ class MessageRepository @Inject constructor(
|
||||
private val refreshHelper: AutoRefreshHelper,
|
||||
private val sharedPrefProvider: SharedPrefProvider,
|
||||
private val json: Json,
|
||||
private val mailboxDao: MailboxDao,
|
||||
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
||||
) {
|
||||
|
||||
private val saveFetchResultMutex = Mutex()
|
||||
|
||||
private val cacheKey = "message"
|
||||
private val messagesCacheKey = "message"
|
||||
private val mailboxCacheKey = "mailboxes"
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun getMessages(
|
||||
student: Student,
|
||||
mailbox: Mailbox,
|
||||
mailbox: Mailbox?,
|
||||
folder: MessageFolder,
|
||||
forceRefresh: Boolean,
|
||||
notify: Boolean = false,
|
||||
@ -58,16 +63,20 @@ class MessageRepository @Inject constructor(
|
||||
isResultEmpty = { it.isEmpty() },
|
||||
shouldFetch = {
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||
key = getRefreshKey(cacheKey, student, folder)
|
||||
key = getRefreshKey(messagesCacheKey, mailbox, folder)
|
||||
)
|
||||
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 = {
|
||||
sdk.init(student).getMessages(
|
||||
folder = Folder.valueOf(folder.name),
|
||||
mailboxKey = mailbox.globalKey,
|
||||
).mapToEntities(mailbox)
|
||||
mailboxKey = mailbox?.globalKey,
|
||||
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
||||
},
|
||||
saveFetchResult = { old, new ->
|
||||
messagesDb.deleteAll(old uniqueSubtract new)
|
||||
@ -75,7 +84,9 @@ class MessageRepository @Inject constructor(
|
||||
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()}")
|
||||
it.message.unread || it.message.content.isBlank()
|
||||
},
|
||||
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
|
||||
query = {
|
||||
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
||||
},
|
||||
fetch = {
|
||||
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
|
||||
},
|
||||
@ -113,8 +126,10 @@ class MessageRepository @Inject constructor(
|
||||
}
|
||||
)
|
||||
|
||||
fun getMessagesFromDatabase(mailbox: Mailbox): Flow<List<Message>> {
|
||||
return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
||||
fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow<List<Message>> {
|
||||
return if (mailbox == null) {
|
||||
messagesDb.loadAll(RECEIVED.id, student.email)
|
||||
} else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
|
||||
}
|
||||
|
||||
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()
|
||||
sdk.init(student).deleteMessages(
|
||||
messages = messages.map { it.messageGlobalKey },
|
||||
@ -169,6 +184,34 @@ class MessageRepository @Inject constructor(
|
||||
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?
|
||||
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
|
||||
?.let { json.decodeFromString(it) }
|
||||
|
@ -33,9 +33,11 @@ class RecipientRepository @Inject constructor(
|
||||
|
||||
suspend fun getRecipients(
|
||||
student: Student,
|
||||
mailbox: Mailbox,
|
||||
type: MailboxType
|
||||
mailbox: Mailbox?,
|
||||
type: MailboxType,
|
||||
): List<Recipient> {
|
||||
mailbox ?: return emptyList()
|
||||
|
||||
val cached = recipientDb.loadAll(type, mailbox.globalKey)
|
||||
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||
@ -47,11 +49,15 @@ class RecipientRepository @Inject constructor(
|
||||
|
||||
suspend fun getMessageSender(
|
||||
student: Student,
|
||||
mailbox: Mailbox,
|
||||
message: Message
|
||||
): List<Recipient> = sdk.init(student)
|
||||
mailbox: Mailbox?,
|
||||
message: Message,
|
||||
): List<Recipient> {
|
||||
mailbox ?: return emptyList()
|
||||
|
||||
return sdk.init(student)
|
||||
.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.NotificationData
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||
import io.github.wulkanowy.utils.getPlural
|
||||
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.Student
|
||||
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.waitForResult
|
||||
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
|
||||
@ -12,12 +11,11 @@ import javax.inject.Inject
|
||||
|
||||
class MessageWork @Inject constructor(
|
||||
private val messageRepository: MessageRepository,
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val newMessageNotification: NewMessageNotification,
|
||||
) : Work {
|
||||
|
||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||
messageRepository.getMessages(
|
||||
student = student,
|
||||
mailbox = mailbox,
|
||||
@ -26,7 +24,7 @@ class MessageWork @Inject constructor(
|
||||
notify = notify
|
||||
).waitForResult()
|
||||
|
||||
messageRepository.getMessagesFromDatabase(mailbox).first()
|
||||
messageRepository.getMessagesFromDatabase(student, mailbox).first()
|
||||
.filter { !it.isNotified && it.unread }.let {
|
||||
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
|
||||
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
|
||||
|
@ -1,22 +1,23 @@
|
||||
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.Semester
|
||||
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.toFirstResult
|
||||
import javax.inject.Inject
|
||||
|
||||
class RecipientWork @Inject constructor(
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val recipientRepository: RecipientRepository
|
||||
) : Work {
|
||||
|
||||
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
|
||||
mailboxRepository.refreshMailboxes(student)
|
||||
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
|
||||
recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
|
||||
val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult()
|
||||
mailboxes.dataOrNull?.forEach {
|
||||
recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ class DashboardPresenter @Inject constructor(
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val attendanceSummaryRepository: AttendanceSummaryRepository,
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val homeworkRepository: HomeworkRepository,
|
||||
@ -228,7 +227,7 @@ class DashboardPresenter @Inject constructor(
|
||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||
flow {
|
||||
val semester = semesterRepository.getCurrentSemester(student)
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||
val selectedTiles = preferencesRepository.selectedDashboardTiles
|
||||
|
||||
val flowSuccess = flowOf(Resource.Success(null))
|
||||
|
@ -19,6 +19,7 @@ val debugMessageItems = listOf(
|
||||
private fun generateMessage(sender: String, subject: String) = Message(
|
||||
subject = subject,
|
||||
messageId = 123,
|
||||
email = "",
|
||||
date = Instant.now(),
|
||||
folderId = 0,
|
||||
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.MessageAttachment
|
||||
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.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
@ -21,7 +20,6 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -187,8 +185,8 @@ class MessagePreviewPresenter @Inject constructor(
|
||||
presenterScope.launch {
|
||||
runCatching {
|
||||
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
messageRepository.deleteMessage(student, mailbox, message!!)
|
||||
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||
messageRepository.deleteMessage(student, mailbox!!, message!!)
|
||||
}
|
||||
.onFailure {
|
||||
retryCallback = { onMessageDelete() }
|
||||
|
@ -19,9 +19,13 @@ import androidx.core.text.toHtml
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
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.databinding.ActivitySendMessageBinding
|
||||
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.hideSoftInput
|
||||
import io.github.wulkanowy.utils.showSoftInput
|
||||
@ -100,6 +104,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
||||
formSubjectValue = binding.sendMessageSubject.text.toString()
|
||||
formContentValue =
|
||||
binding.sendMessageMessageContent.text.toString().parseAsHtml().toString()
|
||||
binding.sendMessageFrom.setOnClickListener { presenter.onOpenMailboxChooser() }
|
||||
|
||||
presenter.onAttachView(
|
||||
view = this,
|
||||
@ -107,6 +112,9 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter, ActivitySendMessa
|
||||
message = intent.getSerializableExtra(EXTRA_MESSAGE) as? Message,
|
||||
reply = intent.getSerializableExtra(EXTRA_REPLY) as? Boolean
|
||||
)
|
||||
supportFragmentManager.setFragmentResultListener(LISTENER_KEY, this) { _, bundle ->
|
||||
presenter.onMailboxSelected(bundle.getSerializable(MAILBOX_KEY) as? Mailbox)
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
finish()
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
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.MailboxType
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
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.repositories.*
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||
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.ErrorHandler
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
@ -28,7 +28,6 @@ class SendMessagePresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val recipientRepository: RecipientRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
@ -36,10 +35,19 @@ class SendMessagePresenter @Inject constructor(
|
||||
|
||||
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?) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
initializeSubjectStream()
|
||||
this.message = message
|
||||
this.isReplay = reply
|
||||
|
||||
Timber.i("Send message view was initialized")
|
||||
loadData(message, reply)
|
||||
with(view) {
|
||||
@ -110,16 +118,31 @@ class SendMessagePresenter @Inject constructor(
|
||||
return false
|
||||
}
|
||||
|
||||
fun onOpenMailboxChooser() {
|
||||
view?.showMailboxChooser(mailboxes)
|
||||
}
|
||||
|
||||
fun onMailboxSelected(mailbox: Mailbox?) {
|
||||
selectedMailbox = mailbox
|
||||
|
||||
loadData(message, isReplay)
|
||||
}
|
||||
|
||||
private fun loadData(message: Message?, reply: Boolean?) {
|
||||
resourceFlow {
|
||||
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")
|
||||
val recipients = createChips(
|
||||
recipients = recipientRepository.getRecipients(
|
||||
student = student,
|
||||
mailbox = mailbox,
|
||||
mailbox = selectedMailbox,
|
||||
type = MailboxType.EMPLOYEE,
|
||||
)
|
||||
)
|
||||
@ -130,7 +153,7 @@ class SendMessagePresenter @Inject constructor(
|
||||
message != null && reply == true -> recipientRepository.getMessageSender(
|
||||
student = student,
|
||||
message = message,
|
||||
mailbox = mailbox,
|
||||
mailbox = selectedMailbox,
|
||||
)
|
||||
else -> emptyList()
|
||||
}.let { createChips(it) }
|
||||
@ -139,18 +162,26 @@ class SendMessagePresenter @Inject constructor(
|
||||
messageRecipients.size
|
||||
)
|
||||
|
||||
Triple(mailbox, recipients, messageRecipients)
|
||||
recipients to messageRecipients
|
||||
}
|
||||
.logResourceStatus("load recipients")
|
||||
.onEach {
|
||||
when (it) {
|
||||
is Resource.Loading -> view?.run {
|
||||
.onResourceLoading {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
is Resource.Success -> it.data.let { (mailbox, recipientChips, selectedRecipientChips) ->
|
||||
}
|
||||
.onResourceNotLoading {
|
||||
view?.run { showProgress(false) }
|
||||
}
|
||||
.onResourceError {
|
||||
view?.showContent(true)
|
||||
errorHandler.dispatch(it)
|
||||
}
|
||||
.onResourceSuccess {
|
||||
it.let { (recipientChips, selectedRecipientChips) ->
|
||||
view?.run {
|
||||
setMailbox(getMailboxName(mailbox))
|
||||
setMailbox(getMailboxName(selectedMailbox))
|
||||
setRecipients(recipientChips)
|
||||
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(
|
||||
selectedRecipientChips
|
||||
@ -158,20 +189,15 @@ class SendMessagePresenter @Inject constructor(
|
||||
showContent(true)
|
||||
}
|
||||
}
|
||||
is Resource.Error -> {
|
||||
view?.showContent(true)
|
||||
errorHandler.dispatch(it.error)
|
||||
}
|
||||
}
|
||||
}.onResourceNotLoading {
|
||||
view?.run { showProgress(false) }
|
||||
}.launch()
|
||||
.launch()
|
||||
}
|
||||
|
||||
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
|
||||
val mailbox = selectedMailbox ?: return
|
||||
|
||||
resourceFlow {
|
||||
val student = studentRepository.getCurrentStudent()
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
messageRepository.sendMessage(
|
||||
student = student,
|
||||
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 {
|
||||
append(mailbox.userName)
|
||||
append(" - ")
|
||||
append(getMailboxType(mailbox.type))
|
||||
appendLine()
|
||||
|
||||
if (mailbox.type == MailboxType.PARENT) {
|
||||
append(" - ")
|
||||
append(mailbox.studentName)
|
||||
append(" - ")
|
||||
}
|
||||
|
||||
append(" - ")
|
||||
append("(${mailbox.schoolNameShort})")
|
||||
}
|
||||
}
|
||||
@ -267,9 +296,9 @@ class SendMessagePresenter @Inject constructor(
|
||||
|
||||
private fun saveDraftMessage() {
|
||||
messageRepository.draftMessage = MessageDraft(
|
||||
view?.formRecipientsData!!,
|
||||
view?.formSubjectValue!!,
|
||||
view?.formContentValue!!
|
||||
recipients = view?.formRecipientsData!!,
|
||||
subject = view?.formSubjectValue!!,
|
||||
content = view?.formContentValue!!,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -61,4 +61,5 @@ interface SendMessageView : BaseView {
|
||||
fun getMessageBackupDialogStringWithRecipients(recipients: String): String
|
||||
|
||||
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.databinding.ItemMessageBinding
|
||||
import io.github.wulkanowy.databinding.ItemMessageChipsBinding
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import javax.inject.Inject
|
||||
@ -19,13 +20,15 @@ import javax.inject.Inject
|
||||
class MessageTabAdapter @Inject constructor() :
|
||||
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>()
|
||||
|
||||
@ -49,12 +52,12 @@ class MessageTabAdapter @Inject constructor() :
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (MessageItemViewType.values()[viewType]) {
|
||||
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
||||
ItemMessageBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
||||
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
|
||||
|
||||
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) {
|
||||
chipUnread.isVisible = false
|
||||
} else {
|
||||
@ -77,6 +94,7 @@ class MessageTabAdapter @Inject constructor() :
|
||||
chipUnread.setOnCheckedChangeListener(onHeaderClickListener)
|
||||
}
|
||||
chipUnread.isEnabled = item.isEnabled
|
||||
|
||||
chipAttachments.isEnabled = item.isEnabled
|
||||
chipAttachments.isChecked = item.onlyWithAttachments
|
||||
chipAttachments.setOnCheckedChangeListener(onHeaderClickListener)
|
||||
|
@ -11,6 +11,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
|
||||
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
||||
|
||||
data class FilterHeader(
|
||||
val selectedMailbox: String?,
|
||||
val onlyUnread: Boolean?,
|
||||
val onlyWithAttachments: Boolean,
|
||||
val isEnabled: Boolean
|
||||
|
@ -10,15 +10,18 @@ import android.widget.CompoundButton
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
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.enums.MessageFolder
|
||||
import io.github.wulkanowy.databinding.FragmentMessageTabBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
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.widgets.DividerItemDecoration
|
||||
import io.github.wulkanowy.utils.dpToPx
|
||||
@ -104,6 +107,7 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
onItemClickListener = presenter::onMessageItemSelected
|
||||
onLongItemClickListener = presenter::onMessageItemLongSelected
|
||||
onHeaderClickListener = ::onChipChecked
|
||||
onMailboxClickListener = presenter::onMailboxFilterSelected
|
||||
onChangesDetectedListener = ::resetListPosition
|
||||
}
|
||||
|
||||
@ -123,6 +127,12 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
||||
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||
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) {
|
||||
@ -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() {
|
||||
activity?.hideSoftInput()
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package io.github.wulkanowy.ui.modules.message.tab
|
||||
|
||||
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.enums.MessageFolder
|
||||
import io.github.wulkanowy.data.repositories.MailboxRepository
|
||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
@ -26,7 +26,6 @@ class MessageTabPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val messageRepository: MessageRepository,
|
||||
private val mailboxRepository: MailboxRepository,
|
||||
private val analytics: AnalyticsHelper
|
||||
) : BasePresenter<MessageTabView>(errorHandler, studentRepository) {
|
||||
|
||||
@ -36,6 +35,9 @@ class MessageTabPresenter @Inject constructor(
|
||||
|
||||
private var lastSearchQuery = ""
|
||||
|
||||
private var mailboxes: List<Mailbox> = emptyList()
|
||||
private var selectedMailbox: Mailbox? = null
|
||||
|
||||
private var messages = emptyList<Message>()
|
||||
|
||||
private val searchChannel = Channel<String>()
|
||||
@ -122,8 +124,7 @@ class MessageTabPresenter @Inject constructor(
|
||||
|
||||
runCatching {
|
||||
val student = studentRepository.getCurrentStudent(true)
|
||||
val mailbox = mailboxRepository.getMailbox(student)
|
||||
messageRepository.deleteMessages(student, mailbox, messageList)
|
||||
messageRepository.deleteMessages(student, selectedMailbox, messageList)
|
||||
}
|
||||
.onFailure(errorHandler::dispatch)
|
||||
.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) {
|
||||
Timber.i("Loading $folder message data started")
|
||||
|
||||
flatResourceFlow {
|
||||
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")
|
||||
.onResourceData {
|
||||
@ -327,7 +343,16 @@ class MessageTabPresenter @Inject constructor(
|
||||
MessageTabDataItem.FilterHeader(
|
||||
onlyUnread = onlyUnread.takeIf { folder != MessageFolder.SENT },
|
||||
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
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
@ -46,4 +47,6 @@ interface MessageTabView : BaseView {
|
||||
fun showActionMode(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 io.github.wulkanowy.R
|
||||
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.Student
|
||||
import io.github.wulkanowy.data.enums.MessageFolder
|
||||
@ -25,8 +26,8 @@ fun getRefreshKey(name: String, student: Student): String {
|
||||
return "${name}_${student.userLoginId}"
|
||||
}
|
||||
|
||||
fun getRefreshKey(name: String, student: Student, folder: MessageFolder): String {
|
||||
return "${name}_${student.id}_${folder.id}"
|
||||
fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): String {
|
||||
return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}"
|
||||
}
|
||||
|
||||
class AutoRefreshHelper @Inject constructor(
|
||||
|
@ -55,17 +55,29 @@
|
||||
android:id="@+id/sendMessageFrom"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="58dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/sendMessageFromHint"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
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
|
||||
android:id="@+id/sendMessageFromDivider"
|
||||
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:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/messageChipsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="16dp"
|
||||
tools:context=".ui.modules.message.tab.MessageTabAdapter">
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/messageChipGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="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_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
|
||||
android:id="@+id/chip_unread"
|
||||
@ -37,4 +46,4 @@
|
||||
app:checkedIconEnabled="true"
|
||||
app:checkedIconTint="@color/mtrl_choice_chip_text_color" />
|
||||
</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_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_chip_all_mailboxes">Wszystkie skrzynki</string>
|
||||
<string name="message_chip_only_unread">Only unread</string>
|
||||
<string name="message_chip_only_with_attachments">Only with attachments</string>
|
||||
<string name="message_read">Read: %s</string>
|
||||
@ -324,6 +325,7 @@
|
||||
<item quantity="other">%1$d selected</item>
|
||||
</plurals>
|
||||
<string name="message_messages_deleted">Messages deleted</string>
|
||||
<string name="message_mailbox_chooser_title">Choose mailbox</string>
|
||||
|
||||
|
||||
<!--Note-->
|
||||
|
@ -27,7 +27,9 @@ fun getMailboxEntity() = Mailbox(
|
||||
globalKey = "v4",
|
||||
fullName = "",
|
||||
userName = "",
|
||||
userLoginId = 0,
|
||||
email = "test",
|
||||
symbol = "powiatwulkanowy",
|
||||
schoolId = "123456",
|
||||
studentName = "",
|
||||
schoolNameShort = "",
|
||||
type = MailboxType.UNKNOWN,
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories
|
||||
import android.content.Context
|
||||
import io.github.wulkanowy.data.dataOrNull
|
||||
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.MessagesDao
|
||||
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.errorOrNull
|
||||
import io.github.wulkanowy.data.toFirstResult
|
||||
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
|
||||
import io.github.wulkanowy.getMailboxEntity
|
||||
import io.github.wulkanowy.getStudentEntity
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
@ -55,6 +57,12 @@ class MessageRepositoryTest {
|
||||
@MockK
|
||||
private lateinit var sharedPrefProvider: SharedPrefProvider
|
||||
|
||||
@MockK
|
||||
private lateinit var mailboxDao: MailboxDao
|
||||
|
||||
@MockK
|
||||
private lateinit var getMailboxByStudentUseCase: GetMailboxByStudentUseCase
|
||||
|
||||
private val student = getStudentEntity()
|
||||
|
||||
private val mailbox = getMailboxEntity()
|
||||
@ -74,26 +82,33 @@ class MessageRepositoryTest {
|
||||
refreshHelper = refreshHelper,
|
||||
sharedPrefProvider = sharedPrefProvider,
|
||||
json = Json,
|
||||
mailboxDao = mailboxDao,
|
||||
getMailboxByStudentUseCase = getMailboxByStudentUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
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(
|
||||
getMessageDto()
|
||||
getMessageDto().copy(
|
||||
unreadBy = 5,
|
||||
readBy = 10,
|
||||
)
|
||||
)
|
||||
coEvery { messageDb.deleteAll(any()) } just Runs
|
||||
coEvery { messageDb.insertAll(any()) } returns listOf()
|
||||
|
||||
repository.getMessages(
|
||||
val res = repository.getMessages(
|
||||
student = student,
|
||||
mailbox = mailbox,
|
||||
folder = MessageFolder.RECEIVED,
|
||||
forceRefresh = true,
|
||||
notify = false,
|
||||
).toFirstResult().dataOrNull.orEmpty()
|
||||
).toFirstResult()
|
||||
|
||||
assertEquals(null, res.errorOrNull)
|
||||
coVerify(exactly = 1) { messageDb.deleteAll(withArg { checkEquals(emptyList<Message>()) }) }
|
||||
coVerify {
|
||||
messageDb.insertAll(withArg {
|
||||
@ -187,6 +202,7 @@ class MessageRepositoryTest {
|
||||
) = Message(
|
||||
messageGlobalKey = "v4",
|
||||
mailboxKey = "",
|
||||
email = "",
|
||||
correspondents = "",
|
||||
messageId = messageId,
|
||||
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.entities.Mailbox
|
||||
import io.github.wulkanowy.data.db.entities.MailboxType
|
||||
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.utils.AutoRefreshHelper
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.impl.annotations.SpyK
|
||||
import io.mockk.just
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class MailboxRepositoryTest {
|
||||
|
||||
@SpyK
|
||||
private var sdk = Sdk()
|
||||
class GetMailboxByStudentUseCaseTest {
|
||||
|
||||
@MockK
|
||||
private lateinit var mailboxDao: MailboxDao
|
||||
|
||||
@MockK
|
||||
private lateinit var refreshHelper: AutoRefreshHelper
|
||||
|
||||
private lateinit var systemUnderTest: MailboxRepository
|
||||
private lateinit var systemUnderTest: GetMailboxByStudentUseCase
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockKAnnotations.init(this)
|
||||
|
||||
coEvery { refreshHelper.shouldBeRefreshed(any()) } returns false
|
||||
coEvery { refreshHelper.updateLastRefreshTimestamp(any()) } just Runs
|
||||
coEvery { mailboxDao.deleteAll(any()) } just Runs
|
||||
coEvery { mailboxDao.insertAll(any()) } returns emptyList()
|
||||
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
|
||||
coEvery { sdk.getMailboxes() } returns emptyList()
|
||||
|
||||
systemUnderTest = MailboxRepository(
|
||||
mailboxDao = mailboxDao,
|
||||
sdk = sdk,
|
||||
refreshHelper = refreshHelper,
|
||||
)
|
||||
systemUnderTest = GetMailboxByStudentUseCase(mailboxDao = mailboxDao)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
@Test
|
||||
fun `get mailbox that doesn't exist`() = runTest {
|
||||
val student = getStudentEntity(
|
||||
userName = "Stanisław Kowalski",
|
||||
studentName = "Jan Kowalski",
|
||||
)
|
||||
coEvery { sdk.getMailboxes() } returns emptyList()
|
||||
coEvery { mailboxDao.loadAll(any()) } returns emptyList()
|
||||
|
||||
systemUnderTest.getMailbox(student)
|
||||
assertNull(systemUnderTest(student))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -73,7 +60,7 @@ class MailboxRepositoryTest {
|
||||
expectedMailbox,
|
||||
)
|
||||
|
||||
val selectedMailbox = systemUnderTest.getMailbox(student)
|
||||
val selectedMailbox = systemUnderTest(student)
|
||||
assertEquals(expectedMailbox, selectedMailbox)
|
||||
}
|
||||
|
||||
@ -88,7 +75,7 @@ class MailboxRepositoryTest {
|
||||
expectedMailbox,
|
||||
)
|
||||
|
||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
||||
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -102,10 +89,10 @@ class MailboxRepositoryTest {
|
||||
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 {
|
||||
val student = getStudentEntity(
|
||||
userName = "Stanisław Kowalski",
|
||||
@ -116,7 +103,7 @@ class MailboxRepositoryTest {
|
||||
getMailboxEntity("Jan Kurowski"),
|
||||
)
|
||||
|
||||
systemUnderTest.getMailbox(student)
|
||||
assertNull(systemUnderTest(student))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -130,7 +117,7 @@ class MailboxRepositoryTest {
|
||||
expectedMailbox,
|
||||
)
|
||||
|
||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
||||
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -144,7 +131,7 @@ class MailboxRepositoryTest {
|
||||
expectedMailbox,
|
||||
)
|
||||
|
||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
||||
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -158,7 +145,7 @@ class MailboxRepositoryTest {
|
||||
expectedMailbox,
|
||||
)
|
||||
|
||||
assertEquals(expectedMailbox, systemUnderTest.getMailbox(student))
|
||||
assertEquals(expectedMailbox, systemUnderTest(student))
|
||||
}
|
||||
|
||||
private fun getMailboxEntity(
|
||||
@ -167,7 +154,9 @@ class MailboxRepositoryTest {
|
||||
globalKey = "",
|
||||
fullName = "",
|
||||
userName = "",
|
||||
userLoginId = 123,
|
||||
email = "",
|
||||
schoolId = "",
|
||||
symbol = "",
|
||||
studentName = studentName,
|
||||
schoolNameShort = "",
|
||||
type = MailboxType.STUDENT,
|
Loading…
x
Reference in New Issue
Block a user