forked from github/wulkanowy-mirror
Merge branch 'develop' into feature/attendance-excuse-whole-day
This commit is contained in:
commit
f8c9122686
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: wulkanowy
|
||||||
|
custom: https://www.paypal.com/paypalme/wulkanowy
|
@ -187,7 +187,7 @@ huaweiPublish {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.9.0"
|
work_manager = "2.9.0"
|
||||||
android_hilt = "1.1.0"
|
android_hilt = "1.2.0"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
chucker = "4.0.0"
|
chucker = "4.0.0"
|
||||||
mockk = "1.13.9"
|
mockk = "1.13.9"
|
||||||
@ -246,7 +246,7 @@ dependencies {
|
|||||||
implementation 'com.github.Faierbel:slf4j-timber:2.0'
|
implementation 'com.github.Faierbel:slf4j-timber:2.0'
|
||||||
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
|
||||||
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
|
||||||
implementation 'io.coil-kt:coil:2.5.0'
|
implementation 'io.coil-kt:coil:2.6.0'
|
||||||
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
|
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
|
||||||
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
|
||||||
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
|
||||||
|
2527
app/schemas/io.github.wulkanowy.data.db.AppDatabase/60.json
Normal file
2527
app/schemas/io.github.wulkanowy.data.db.AppDatabase/60.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -54,5 +54,9 @@
|
|||||||
{
|
{
|
||||||
"displayName": "Antoni Paduch",
|
"displayName": "Antoni Paduch",
|
||||||
"githubUsername": "janAte1"
|
"githubUsername": "janAte1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Kamil Wąsik",
|
||||||
|
"githubUsername": "JestemKamil"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -254,6 +254,10 @@ internal class DataModule {
|
|||||||
@Provides
|
@Provides
|
||||||
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
|
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideMutesDao(database: AppDatabase) = database.mutedMessageSendersDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideGradeDescriptiveDao(database: AppDatabase) = database.gradeDescriptiveDao
|
fun provideGradeDescriptiveDao(database: AppDatabase) = database.gradeDescriptiveDao
|
||||||
|
@ -25,6 +25,7 @@ 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.dao.MobileDeviceDao
|
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.MutedMessageSendersDao
|
||||||
import io.github.wulkanowy.data.db.dao.NoteDao
|
import io.github.wulkanowy.data.db.dao.NoteDao
|
||||||
import io.github.wulkanowy.data.db.dao.NotificationDao
|
import io.github.wulkanowy.data.db.dao.NotificationDao
|
||||||
import io.github.wulkanowy.data.db.dao.RecipientDao
|
import io.github.wulkanowy.data.db.dao.RecipientDao
|
||||||
@ -56,6 +57,7 @@ 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.db.entities.MessageAttachment
|
import io.github.wulkanowy.data.db.entities.MessageAttachment
|
||||||
import io.github.wulkanowy.data.db.entities.MobileDevice
|
import io.github.wulkanowy.data.db.entities.MobileDevice
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Notification
|
import io.github.wulkanowy.data.db.entities.Notification
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
@ -157,6 +159,7 @@ import javax.inject.Singleton
|
|||||||
SchoolAnnouncement::class,
|
SchoolAnnouncement::class,
|
||||||
Notification::class,
|
Notification::class,
|
||||||
AdminMessage::class,
|
AdminMessage::class,
|
||||||
|
MutedMessageSender::class,
|
||||||
GradeDescriptive::class,
|
GradeDescriptive::class,
|
||||||
],
|
],
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
@ -169,6 +172,7 @@ import javax.inject.Singleton
|
|||||||
AutoMigration(from = 56, to = 57, spec = Migration57::class),
|
AutoMigration(from = 56, to = 57, spec = Migration57::class),
|
||||||
AutoMigration(from = 57, to = 58, spec = Migration58::class),
|
AutoMigration(from = 57, to = 58, spec = Migration58::class),
|
||||||
AutoMigration(from = 58, to = 59),
|
AutoMigration(from = 58, to = 59),
|
||||||
|
AutoMigration(from = 59, to = 60),
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
@ -177,7 +181,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 59
|
const val VERSION_SCHEMA = 60
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||||
Migration2(),
|
Migration2(),
|
||||||
@ -303,5 +307,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
|
|
||||||
abstract val adminMessagesDao: AdminMessageDao
|
abstract val adminMessagesDao: AdminMessageDao
|
||||||
|
|
||||||
|
abstract val mutedMessageSendersDao: MutedMessageSendersDao
|
||||||
|
|
||||||
abstract val gradeDescriptiveDao: GradeDescriptiveDao
|
abstract val gradeDescriptiveDao: GradeDescriptiveDao
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,23 @@ import androidx.room.Query
|
|||||||
import androidx.room.Transaction
|
import androidx.room.Transaction
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface MessagesDao : BaseDao<Message> {
|
interface MessagesDao : BaseDao<Message> {
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
|
||||||
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadMessagesWithMutedAuthor(mailboxKey: String, folder: Int): Flow<List<MessageWithMutedAuthor>>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
|
||||||
|
fun loadMessagesWithMutedAuthor(folder: Int, email: String): Flow<List<MessageWithMutedAuthor>>
|
||||||
|
|
||||||
@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>>
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface MutedMessageSendersDao : BaseDao<MutedMessageSender> {
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM MutedMessageSenders WHERE author = :author")
|
||||||
|
suspend fun checkMute(author: String): Boolean
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
suspend fun insertMute(mute: MutedMessageSender): Long
|
||||||
|
|
||||||
|
@Query("DELETE FROM MutedMessageSenders WHERE author = :author")
|
||||||
|
suspend fun deleteMute(author: String)
|
||||||
|
}
|
@ -2,11 +2,15 @@ package io.github.wulkanowy.data.db.entities
|
|||||||
|
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
import androidx.room.Relation
|
import androidx.room.Relation
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
data class MessageWithAttachment(
|
data class MessageWithAttachment(
|
||||||
@Embedded
|
@Embedded
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
|
||||||
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
|
||||||
val attachments: List<MessageAttachment>
|
val attachments: List<MessageAttachment>,
|
||||||
)
|
|
||||||
|
@Relation(parentColumn = "correspondents", entityColumn = "author")
|
||||||
|
val mutedMessageSender: MutedMessageSender?,
|
||||||
|
) : Serializable
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
|
||||||
|
data class MessageWithMutedAuthor(
|
||||||
|
@Embedded
|
||||||
|
val message: Message,
|
||||||
|
|
||||||
|
@Relation(parentColumn = "correspondents", entityColumn = "author")
|
||||||
|
val mutedMessageSender: MutedMessageSender?,
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Entity(tableName = "MutedMessageSenders")
|
||||||
|
data class MutedMessageSender(
|
||||||
|
@ColumnInfo(name = "author")
|
||||||
|
val author: String,
|
||||||
|
) : Serializable {
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
}
|
@ -8,9 +8,12 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
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.dao.MutedMessageSendersDao
|
||||||
import io.github.wulkanowy.data.db.entities.Mailbox
|
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.db.entities.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
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
|
||||||
@ -42,6 +45,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
class MessageRepository @Inject constructor(
|
class MessageRepository @Inject constructor(
|
||||||
private val messagesDb: MessagesDao,
|
private val messagesDb: MessagesDao,
|
||||||
|
private val mutedMessageSendersDao: MutedMessageSendersDao,
|
||||||
private val messageAttachmentDao: MessageAttachmentDao,
|
private val messageAttachmentDao: MessageAttachmentDao,
|
||||||
private val sdk: Sdk,
|
private val sdk: Sdk,
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
@ -51,7 +55,6 @@ class MessageRepository @Inject constructor(
|
|||||||
private val mailboxDao: MailboxDao,
|
private val mailboxDao: MailboxDao,
|
||||||
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val messagesCacheKey = "message"
|
private val messagesCacheKey = "message"
|
||||||
@ -63,7 +66,7 @@ class MessageRepository @Inject constructor(
|
|||||||
folder: MessageFolder,
|
folder: MessageFolder,
|
||||||
forceRefresh: Boolean,
|
forceRefresh: Boolean,
|
||||||
notify: Boolean = false,
|
notify: Boolean = false,
|
||||||
): Flow<Resource<List<Message>>> = networkBoundResource(
|
): Flow<Resource<List<MessageWithMutedAuthor>>> = networkBoundResource(
|
||||||
mutex = saveFetchResultMutex,
|
mutex = saveFetchResultMutex,
|
||||||
isResultEmpty = { it.isEmpty() },
|
isResultEmpty = { it.isEmpty() },
|
||||||
shouldFetch = {
|
shouldFetch = {
|
||||||
@ -74,8 +77,8 @@ class MessageRepository @Inject constructor(
|
|||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
if (mailbox == null) {
|
if (mailbox == null) {
|
||||||
messagesDb.loadAll(folder.id, student.email)
|
messagesDb.loadMessagesWithMutedAuthor(folder.id, student.email)
|
||||||
} else messagesDb.loadAll(mailbox.globalKey, folder.id)
|
} else messagesDb.loadMessagesWithMutedAuthor(mailbox.globalKey, folder.id)
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessages(
|
sdk.init(student).getMessages(
|
||||||
@ -83,10 +86,12 @@ class MessageRepository @Inject constructor(
|
|||||||
mailboxKey = mailbox?.globalKey,
|
mailboxKey = mailbox?.globalKey,
|
||||||
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { oldWithAuthors, new ->
|
||||||
|
val old = oldWithAuthors.map { it.message }
|
||||||
messagesDb.deleteAll(old uniqueSubtract new)
|
messagesDb.deleteAll(old uniqueSubtract new)
|
||||||
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
messagesDb.insertAll((new uniqueSubtract old).onEach {
|
||||||
it.isNotified = !notify
|
val muted = isMuted(it.correspondents)
|
||||||
|
it.isNotified = !notify || muted
|
||||||
})
|
})
|
||||||
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(
|
refreshHelper.updateLastRefreshTimestamp(
|
||||||
@ -106,9 +111,7 @@ 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 && markAsRead) || it.message.content.isBlank()
|
(it.message.unread && markAsRead) || it.message.content.isBlank()
|
||||||
},
|
},
|
||||||
query = {
|
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
|
||||||
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
|
|
||||||
},
|
|
||||||
fetch = {
|
fetch = {
|
||||||
sdk.init(student).getMessageDetails(
|
sdk.init(student).getMessageDetails(
|
||||||
messageKey = it!!.message.messageGlobalKey,
|
messageKey = it!!.message.messageGlobalKey,
|
||||||
@ -236,4 +239,18 @@ class MessageRepository @Inject constructor(
|
|||||||
context.getString(R.string.pref_key_message_draft),
|
context.getString(R.string.pref_key_message_draft),
|
||||||
value?.let { json.encodeToString(it) }
|
value?.let { json.encodeToString(it) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
suspend fun isMuted(author: String): Boolean {
|
||||||
|
return mutedMessageSendersDao.checkMute(author)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun muteMessage(author: String) {
|
||||||
|
if (isMuted(author)) return
|
||||||
|
mutedMessageSendersDao.insertMute(MutedMessageSender(author))
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun unmuteMessage(author: String) {
|
||||||
|
if (!isMuted(author)) return
|
||||||
|
mutedMessageSendersDao.deleteMute(author)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,6 +304,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
forceRefresh = forceRefresh
|
forceRefresh = forceRefresh
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.mapResourceData { it.map { messageWithAuthor -> messageWithAuthor.message } }
|
||||||
.onResourceError { errorHandler.dispatch(it) }
|
.onResourceError { errorHandler.dispatch(it) }
|
||||||
.takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
.takeIf { DashboardItem.Tile.MESSAGES in selectedTiles } ?: flowSuccess
|
||||||
|
|
||||||
|
@ -50,12 +50,15 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
ViewType.MESSAGE.id -> MessageViewHolder(
|
ViewType.MESSAGE.id -> MessageViewHolder(
|
||||||
ItemMessagePreviewBinding.inflate(inflater, parent, false)
|
ItemMessagePreviewBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewType.DIVIDER.id -> DividerViewHolder(
|
ViewType.DIVIDER.id -> DividerViewHolder(
|
||||||
ItemMessageDividerBinding.inflate(inflater, parent, false)
|
ItemMessageDividerBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewType.ATTACHMENT.id -> AttachmentViewHolder(
|
ViewType.ATTACHMENT.id -> AttachmentViewHolder(
|
||||||
ItemMessageAttachmentBinding.inflate(inflater, parent, false)
|
ItemMessageAttachmentBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +69,7 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
holder,
|
holder,
|
||||||
requireNotNull(messageWithAttachment).message
|
requireNotNull(messageWithAttachment).message
|
||||||
)
|
)
|
||||||
|
|
||||||
is AttachmentViewHolder -> bindAttachment(
|
is AttachmentViewHolder -> bindAttachment(
|
||||||
holder,
|
holder,
|
||||||
requireNotNull(messageWithAttachment).attachments[position - 2]
|
requireNotNull(messageWithAttachment).attachments[position - 2]
|
||||||
@ -82,9 +86,11 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
recipientCount > 1 -> {
|
recipientCount > 1 -> {
|
||||||
context.getString(R.string.message_read_by, message.readBy, recipientCount)
|
context.getString(R.string.message_read_by, message.readBy, recipientCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
message.readBy == 1 || (isReceived && !message.unread) -> {
|
message.readBy == 1 || (isReceived && !message.unread) -> {
|
||||||
context.getString(R.string.message_read, context.getString(R.string.all_yes))
|
context.getString(R.string.message_read, context.getString(R.string.all_yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
|
else -> context.getString(R.string.message_read, context.getString(R.string.all_no))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,12 +50,20 @@ class MessagePreviewFragment :
|
|||||||
|
|
||||||
private var menuPrintButton: MenuItem? = null
|
private var menuPrintButton: MenuItem? = null
|
||||||
|
|
||||||
|
private var menuMuteButton: MenuItem? = null
|
||||||
|
|
||||||
override val titleStringId: Int
|
override val titleStringId: Int
|
||||||
get() = R.string.message_title
|
get() = R.string.message_title
|
||||||
|
|
||||||
override val deleteMessageSuccessString: String
|
override val deleteMessageSuccessString: String
|
||||||
get() = getString(R.string.message_delete_success)
|
get() = getString(R.string.message_delete_success)
|
||||||
|
|
||||||
|
override val muteMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_mute_success)
|
||||||
|
|
||||||
|
override val unmuteMessageSuccessString: String
|
||||||
|
get() = getString(R.string.message_unmute_success)
|
||||||
|
|
||||||
override val messageNoSubjectString: String
|
override val messageNoSubjectString: String
|
||||||
get() = getString(R.string.message_no_subject)
|
get() = getString(R.string.message_no_subject)
|
||||||
|
|
||||||
@ -106,6 +114,7 @@ class MessagePreviewFragment :
|
|||||||
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
|
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
|
||||||
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
|
||||||
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
|
||||||
|
menuMuteButton = menu.findItem(R.id.messagePreviewMenuMute)
|
||||||
presenter.onCreateOptionsMenu()
|
presenter.onCreateOptionsMenu()
|
||||||
|
|
||||||
menu.findItem(R.id.mainMenuAccount).isVisible = false
|
menu.findItem(R.id.mainMenuAccount).isVisible = false
|
||||||
@ -118,6 +127,7 @@ class MessagePreviewFragment :
|
|||||||
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
|
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
|
||||||
R.id.messagePreviewMenuShare -> presenter.onShare()
|
R.id.messagePreviewMenuShare -> presenter.onShare()
|
||||||
R.id.messagePreviewMenuPrint -> presenter.onPrint()
|
R.id.messagePreviewMenuPrint -> presenter.onPrint()
|
||||||
|
R.id.messagePreviewMenuMute -> presenter.onMute()
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,6 +139,11 @@ class MessagePreviewFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateMuteToggleButton(isMuted: Boolean) {
|
||||||
|
menuMuteButton?.setTitle(if (isMuted) R.string.message_unmute else R.string.message_mute)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
binding.messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
binding.messagePreviewProgress.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
@ -143,6 +158,7 @@ class MessagePreviewFragment :
|
|||||||
menuDeleteButton?.isVisible = show
|
menuDeleteButton?.isVisible = show
|
||||||
menuShareButton?.isVisible = show
|
menuShareButton?.isVisible = show
|
||||||
menuPrintButton?.isVisible = show
|
menuPrintButton?.isVisible = show
|
||||||
|
menuMuteButton?.isVisible = show && isReplayable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setDeletedOptionsLabels() {
|
override fun setDeletedOptionsLabels() {
|
||||||
@ -213,7 +229,7 @@ class MessagePreviewFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
outState.putSerializable(MESSAGE_ID_KEY, presenter.message)
|
outState.putSerializable(MESSAGE_ID_KEY, presenter.messageWithAttachments)
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import androidx.core.text.parseAsHtml
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.*
|
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.MessageWithAttachment
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.MessageRepository
|
import io.github.wulkanowy.data.repositories.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -26,9 +26,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
var message: Message? = null
|
var messageWithAttachments: MessageWithAttachment? = null
|
||||||
|
|
||||||
var attachments: List<MessageAttachment>? = null
|
|
||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
@ -38,7 +36,6 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
this.message = message
|
|
||||||
loadData(requireNotNull(message))
|
loadData(requireNotNull(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +63,12 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
.logResourceStatus("message ${messageToLoad.messageId} preview")
|
||||||
.onResourceData {
|
.onResourceData {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
message = it.message
|
messageWithAttachments = it
|
||||||
attachments = it.attachments
|
|
||||||
view?.apply {
|
view?.apply {
|
||||||
setMessageWithAttachment(it)
|
setMessageWithAttachment(it)
|
||||||
showContent(true)
|
showContent(true)
|
||||||
initOptions()
|
initOptions()
|
||||||
|
updateMuteToggleButton(isMuted = it.mutedMessageSender != null)
|
||||||
if (preferencesRepository.isIncognitoMode && it.message.unread) {
|
if (preferencesRepository.isIncognitoMode && it.message.unread) {
|
||||||
showMessage(R.string.message_incognito_description)
|
showMessage(R.string.message_incognito_description)
|
||||||
}
|
}
|
||||||
@ -83,8 +79,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
popView()
|
popView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.onResourceSuccess {
|
||||||
.onResourceSuccess {
|
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
"load_item",
|
"load_item",
|
||||||
@ -92,31 +87,28 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
"length" to it.message.content.length
|
"length" to it.message.content.length
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}.onResourceNotLoading { view?.showProgress(false) }.onResourceError {
|
||||||
.onResourceNotLoading { view?.showProgress(false) }
|
|
||||||
.onResourceError {
|
|
||||||
retryCallback = { onMessageLoadRetry(messageToLoad) }
|
retryCallback = { onMessageLoadRetry(messageToLoad) }
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
}
|
}.launch()
|
||||||
.launch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onReply(): Boolean {
|
fun onReply(): Boolean {
|
||||||
return if (message != null) {
|
return if (messageWithAttachments?.message != null) {
|
||||||
view?.openMessageReply(message)
|
view?.openMessageReply(messageWithAttachments?.message)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onForward(): Boolean {
|
fun onForward(): Boolean {
|
||||||
return if (message != null) {
|
return if (messageWithAttachments?.message != null) {
|
||||||
view?.openMessageForward(message)
|
view?.openMessageForward(messageWithAttachments?.message)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onShare(): Boolean {
|
fun onShare(): Boolean {
|
||||||
val message = message ?: return false
|
val message = messageWithAttachments?.message ?: return false
|
||||||
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
|
|
||||||
val text = buildString {
|
val text = buildString {
|
||||||
@ -129,13 +121,15 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
appendLine(message.content.parseAsHtml())
|
appendLine(message.content.parseAsHtml())
|
||||||
|
|
||||||
if (!attachments.isNullOrEmpty()) {
|
if (!messageWithAttachments?.attachments.isNullOrEmpty()) {
|
||||||
appendLine()
|
appendLine()
|
||||||
appendLine("Załączniki:")
|
appendLine("Załączniki:")
|
||||||
|
|
||||||
append(attachments.orEmpty().joinToString(separator = "\n") { attachment ->
|
append(
|
||||||
"${attachment.filename}: ${attachment.url}"
|
messageWithAttachments?.attachments.orEmpty()
|
||||||
})
|
.joinToString(separator = "\n") { attachment ->
|
||||||
|
"${attachment.filename}: ${attachment.url}"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +142,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
fun onPrint(): Boolean {
|
fun onPrint(): Boolean {
|
||||||
val message = message ?: return false
|
val message = messageWithAttachments?.message ?: return false
|
||||||
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
val subject = message.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }
|
||||||
|
|
||||||
val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
val dateString = message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
|
||||||
@ -159,8 +153,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
append("<div><h4>Od</h4>${message.sender}</div>")
|
append("<div><h4>Od</h4>${message.sender}</div>")
|
||||||
append("<div><h4>DO</h4>${message.recipients}</div>")
|
append("<div><h4>DO</h4>${message.recipients}</div>")
|
||||||
}
|
}
|
||||||
val messageContent = "<p>${message.content}</p>"
|
val messageContent = "<p>${message.content}</p>".replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
||||||
.replace(Regex("[\\n\\r]{2,}"), "</p><p>")
|
|
||||||
.replace(Regex("[\\n\\r]"), "<br>")
|
.replace(Regex("[\\n\\r]"), "<br>")
|
||||||
|
|
||||||
val jobName = buildString {
|
val jobName = buildString {
|
||||||
@ -171,9 +164,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
view?.apply {
|
view?.apply {
|
||||||
val html = printHTML
|
val html = printHTML.replace("%SUBJECT%", subject).replace("%CONTENT%", messageContent)
|
||||||
.replace("%SUBJECT%", subject)
|
|
||||||
.replace("%CONTENT%", messageContent)
|
|
||||||
.replace("%INFO%", infoContent)
|
.replace("%INFO%", infoContent)
|
||||||
printDocument(html, jobName)
|
printDocument(html, jobName)
|
||||||
}
|
}
|
||||||
@ -182,7 +173,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteMessage() {
|
private fun deleteMessage() {
|
||||||
message ?: return
|
messageWithAttachments?.message ?: return
|
||||||
|
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
showContent(false)
|
||||||
@ -191,24 +182,22 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timber.i("Delete message ${message?.messageGlobalKey}")
|
Timber.i("Delete message ${messageWithAttachments?.message?.messageGlobalKey}")
|
||||||
|
|
||||||
presenterScope.launch {
|
presenterScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
val student = studentRepository.getCurrentStudent(decryptPass = true)
|
||||||
val mailbox = messageRepository.getMailboxByStudent(student)
|
val mailbox = messageRepository.getMailboxByStudent(student)
|
||||||
messageRepository.deleteMessage(student, mailbox, message!!)
|
messageRepository.deleteMessage(student, mailbox, messageWithAttachments?.message!!)
|
||||||
|
}.onFailure {
|
||||||
|
retryCallback = { onMessageDelete() }
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}.onSuccess {
|
||||||
|
view?.run {
|
||||||
|
showMessage(deleteMessageSuccessString)
|
||||||
|
popView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onFailure {
|
|
||||||
retryCallback = { onMessageDelete() }
|
|
||||||
errorHandler.dispatch(it)
|
|
||||||
}
|
|
||||||
.onSuccess {
|
|
||||||
view?.run {
|
|
||||||
showMessage(deleteMessageSuccessString)
|
|
||||||
popView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view?.showProgress(false)
|
view?.showProgress(false)
|
||||||
}
|
}
|
||||||
@ -232,10 +221,10 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
private fun initOptions() {
|
private fun initOptions() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showOptions(
|
showOptions(
|
||||||
show = message != null,
|
show = messageWithAttachments?.message != null,
|
||||||
isReplayable = message?.folderId != MessageFolder.SENT.id,
|
isReplayable = messageWithAttachments?.message?.folderId != MessageFolder.SENT.id,
|
||||||
)
|
)
|
||||||
message?.let {
|
messageWithAttachments?.message?.let {
|
||||||
when (it.folderId == MessageFolder.TRASHED.id) {
|
when (it.folderId == MessageFolder.TRASHED.id) {
|
||||||
true -> setDeletedOptionsLabels()
|
true -> setDeletedOptionsLabels()
|
||||||
false -> setNotDeletedOptionsLabels()
|
false -> setNotDeletedOptionsLabels()
|
||||||
@ -248,4 +237,29 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
fun onCreateOptionsMenu() {
|
fun onCreateOptionsMenu() {
|
||||||
initOptions()
|
initOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onMute(): Boolean {
|
||||||
|
val message = messageWithAttachments?.message ?: return false
|
||||||
|
val isMuted = messageWithAttachments?.mutedMessageSender != null
|
||||||
|
|
||||||
|
presenterScope.launch {
|
||||||
|
runCatching {
|
||||||
|
when (isMuted) {
|
||||||
|
true -> {
|
||||||
|
messageRepository.unmuteMessage(message.correspondents)
|
||||||
|
view?.run { showMessage(unmuteMessageSuccessString) }
|
||||||
|
}
|
||||||
|
|
||||||
|
false -> {
|
||||||
|
messageRepository.muteMessage(message.correspondents)
|
||||||
|
view?.run { showMessage(muteMessageSuccessString) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
errorHandler.dispatch(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view?.updateMuteToggleButton(isMuted)
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
val deleteMessageSuccessString: String
|
val deleteMessageSuccessString: String
|
||||||
|
|
||||||
|
val muteMessageSuccessString: String
|
||||||
|
|
||||||
|
val unmuteMessageSuccessString: String
|
||||||
|
|
||||||
val messageNoSubjectString: String
|
val messageNoSubjectString: String
|
||||||
|
|
||||||
val printHTML: String
|
val printHTML: String
|
||||||
@ -19,6 +23,8 @@ interface MessagePreviewView : BaseView {
|
|||||||
|
|
||||||
fun setMessageWithAttachment(item: MessageWithAttachment)
|
fun setMessageWithAttachment(item: MessageWithAttachment)
|
||||||
|
|
||||||
|
fun updateMuteToggleButton(isMuted: Boolean)
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
@ -18,8 +18,7 @@ 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
|
||||||
|
|
||||||
class MessageTabAdapter @Inject constructor() :
|
class MessageTabAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
||||||
|
|
||||||
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
|
lateinit var onItemClickListener: (MessageTabDataItem.MessageItem, position: Int) -> Unit
|
||||||
|
|
||||||
@ -52,10 +51,11 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|
||||||
return when (MessageItemViewType.values()[viewType]) {
|
return when (MessageItemViewType.entries[viewType]) {
|
||||||
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
MessageItemViewType.FILTERS -> HeaderViewHolder(
|
||||||
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
ItemMessageChipsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
MessageItemViewType.MESSAGE -> ItemViewHolder(
|
||||||
ItemMessageBinding.inflate(inflater, parent, false)
|
ItemMessageBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
@ -137,7 +137,12 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
|
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(currentTextColor))
|
||||||
isVisible = message.hasAttachments
|
isVisible = message.hasAttachments
|
||||||
}
|
}
|
||||||
messageItemUnreadIndicator.isVisible = message.unread
|
messageItemUnreadIndicator.isVisible = message.unread || item.isMuted
|
||||||
|
|
||||||
|
when (item.isMuted) {
|
||||||
|
true -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_notifications_off)
|
||||||
|
else -> messageItemUnreadIndicator.setImageResource(R.drawable.ic_circle_notification)
|
||||||
|
}
|
||||||
|
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
holder.bindingAdapterPosition.let {
|
holder.bindingAdapterPosition.let {
|
||||||
@ -165,8 +170,7 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
private class MessageTabDiffUtil(
|
private class MessageTabDiffUtil(
|
||||||
private val old: List<MessageTabDataItem>,
|
private val old: List<MessageTabDataItem>, private val new: List<MessageTabDataItem>
|
||||||
private val new: List<MessageTabDataItem>
|
|
||||||
) : DiffUtil.Callback() {
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
override fun getOldListSize(): Int = old.size
|
override fun getOldListSize(): Int = old.size
|
||||||
|
@ -6,6 +6,7 @@ sealed class MessageTabDataItem(val viewType: MessageItemViewType) {
|
|||||||
|
|
||||||
data class MessageItem(
|
data class MessageItem(
|
||||||
val message: Message,
|
val message: Message,
|
||||||
|
val isMuted: Boolean,
|
||||||
val isSelected: Boolean,
|
val isSelected: Boolean,
|
||||||
val isActionMode: Boolean
|
val isActionMode: Boolean
|
||||||
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
) : MessageTabDataItem(MessageItemViewType.MESSAGE)
|
||||||
|
@ -4,6 +4,7 @@ import io.github.wulkanowy.R
|
|||||||
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.Mailbox
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
|
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
|
||||||
import io.github.wulkanowy.data.enums.MessageFolder
|
import io.github.wulkanowy.data.enums.MessageFolder
|
||||||
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
|
||||||
@ -39,7 +40,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
private var mailboxes: List<Mailbox> = emptyList()
|
private var mailboxes: List<Mailbox> = emptyList()
|
||||||
private var selectedMailbox: Mailbox? = null
|
private var selectedMailbox: Mailbox? = null
|
||||||
|
|
||||||
private var messages = emptyList<Message>()
|
private var messages = emptyList<MessageWithMutedAuthor>()
|
||||||
|
|
||||||
private val searchChannel = Channel<String>()
|
private val searchChannel = Channel<String>()
|
||||||
|
|
||||||
@ -141,7 +142,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onActionModeSelectCheckAll() {
|
fun onActionModeSelectCheckAll() {
|
||||||
val messagesToSelect = getFilteredData()
|
val messagesToSelect = getFilteredData().map { it.message }
|
||||||
val isAllSelected = messagesToDelete.containsAll(messagesToSelect)
|
val isAllSelected = messagesToDelete.containsAll(messagesToSelect)
|
||||||
|
|
||||||
if (isAllSelected) {
|
if (isAllSelected) {
|
||||||
@ -188,7 +189,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
view?.showActionMode(false)
|
view?.showActionMode(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val filteredData = getFilteredData()
|
val filteredData = getFilteredData().map { it.message }
|
||||||
|
|
||||||
view?.run {
|
view?.run {
|
||||||
updateActionModeTitle(messagesToDelete.size)
|
updateActionModeTitle(messagesToDelete.size)
|
||||||
@ -320,25 +321,31 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFilteredData(): List<Message> {
|
private fun getFilteredData(): List<MessageWithMutedAuthor> {
|
||||||
if (lastSearchQuery.trim().isEmpty()) {
|
if (lastSearchQuery.trim().isEmpty()) {
|
||||||
val sortedMessages = messages.sortedByDescending { it.date }
|
val sortedMessages = messages.sortedByDescending { it.message.date }
|
||||||
return when {
|
return when {
|
||||||
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
|
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
|
||||||
(onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
|
it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
|
||||||
onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
|
}
|
||||||
|
|
||||||
|
(onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
|
||||||
|
onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
|
||||||
else -> sortedMessages
|
else -> sortedMessages
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val sortedMessages = messages
|
val sortedMessages = messages
|
||||||
.map { it to calculateMatchRatio(it, lastSearchQuery) }
|
.map { it to calculateMatchRatio(it.message, lastSearchQuery) }
|
||||||
.sortedWith(compareBy<Pair<Message, Int>> { -it.second }.thenByDescending { it.first.date })
|
.sortedWith(compareBy<Pair<MessageWithMutedAuthor, Int>> { -it.second }.thenByDescending { it.first.message.date })
|
||||||
.filter { it.second > 6000 }
|
.filter { it.second > 6000 }
|
||||||
.map { it.first }
|
.map { it.first }
|
||||||
return when {
|
return when {
|
||||||
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter { it.unread == onlyUnread && it.hasAttachments == onlyWithAttachments }
|
(onlyUnread == true) && onlyWithAttachments -> sortedMessages.filter {
|
||||||
(onlyUnread == true) -> sortedMessages.filter { it.unread == onlyUnread }
|
it.message.unread == onlyUnread && it.message.hasAttachments == onlyWithAttachments
|
||||||
onlyWithAttachments -> sortedMessages.filter { it.hasAttachments == onlyWithAttachments }
|
}
|
||||||
|
|
||||||
|
(onlyUnread == true) -> sortedMessages.filter { it.message.unread == onlyUnread }
|
||||||
|
onlyWithAttachments -> sortedMessages.filter { it.message.hasAttachments == onlyWithAttachments }
|
||||||
else -> sortedMessages
|
else -> sortedMessages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,8 +374,9 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
addAll(data.map { message ->
|
addAll(data.map { message ->
|
||||||
MessageTabDataItem.MessageItem(
|
MessageTabDataItem.MessageItem(
|
||||||
message = message,
|
message = message.message,
|
||||||
isSelected = messagesToDelete.any { it.messageGlobalKey == message.messageGlobalKey },
|
isMuted = message.mutedMessageSender != null,
|
||||||
|
isSelected = messagesToDelete.any { it.messageGlobalKey == message.message.messageGlobalKey },
|
||||||
isActionMode = isActionMode
|
isActionMode = isActionMode
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
10
app/src/main/res/drawable/ic_circle_notification.xml
Normal file
10
app/src/main/res/drawable/ic_circle_notification.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
|
||||||
|
<solid android:color="@color/colorPrimary" />
|
||||||
|
|
||||||
|
<size
|
||||||
|
android:width="10dp"
|
||||||
|
android:height="10dp" />
|
||||||
|
</shape>
|
5
app/src/main/res/drawable/ic_notifications_off.xml
Normal file
5
app/src/main/res/drawable/ic_notifications_off.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="17dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="17dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,18.69L7.84,6.14 5.27,3.49 4,4.76l2.8,2.8v0.01c-0.52,0.99 -0.8,2.16 -0.8,3.42v5l-2,2v1h13.73l2,2L21,19.72l-1,-1.03zM12,22c1.11,0 2,-0.89 2,-2h-4c0,1.11 0.89,2 2,2zM18,14.68L18,11c0,-3.08 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.15,0.03 -0.29,0.08 -0.42,0.12 -0.1,0.03 -0.2,0.07 -0.3,0.11h-0.01c-0.01,0 -0.01,0 -0.02,0.01 -0.23,0.09 -0.46,0.2 -0.68,0.31 0,0 -0.01,0 -0.01,0.01L18,14.68z"/>
|
||||||
|
</vector>
|
@ -81,9 +81,9 @@
|
|||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/messageItemUnreadIndicator"
|
android:id="@+id/messageItemUnreadIndicator"
|
||||||
android:layout_width="10dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="10dp"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_circle"
|
android:src="@drawable/ic_circle_notification"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/messageItemDate"
|
app:layout_constraintBottom_toBottomOf="@id/messageItemDate"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/messageItemDate"
|
app:layout_constraintTop_toTopOf="@id/messageItemDate"
|
||||||
|
@ -36,4 +36,11 @@
|
|||||||
android:title="@string/message_move_to_trash"
|
android:title="@string/message_move_to_trash"
|
||||||
app:iconTint="@color/material_on_surface_emphasis_medium"
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/messagePreviewMenuMute"
|
||||||
|
android:icon="@drawable/ic_settings_notifications"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/message_mute"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -854,6 +854,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Žádné internetové připojení</string>
|
<string name="error_no_internet">Žádné internetové připojení</string>
|
||||||
<string name="error_invalid_device_datetime">Vyskytla se chyba. Zkontrolujte hodiny svého zařízení</string>
|
<string name="error_invalid_device_datetime">Vyskytla se chyba. Zkontrolujte hodiny svého zařízení</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později</string>
|
<string name="error_timeout">Nelze se připojit ke deníku. Servery mohou být přetíženy. Prosím zkuste to znovu později</string>
|
||||||
<string name="error_login_failed">Načítání dat se nezdařilo. Prosím zkuste to znovu později</string>
|
<string name="error_login_failed">Načítání dat se nezdařilo. Prosím zkuste to znovu později</string>
|
||||||
<string name="error_password_change_required">Je vyžadována změna hesla pro deník</string>
|
<string name="error_password_change_required">Je vyžadována změna hesla pro deník</string>
|
||||||
|
@ -760,6 +760,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Keine Internetverbindung</string>
|
<string name="error_no_internet">Keine Internetverbindung</string>
|
||||||
<string name="error_invalid_device_datetime">Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr</string>
|
<string name="error_invalid_device_datetime">Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre Geräteuhr</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal</string>
|
<string name="error_timeout">Registrierungsverbindung fehlgeschlagen. Server können überlastet sein. Bitte versuchen Sie es später noch einmal</string>
|
||||||
<string name="error_login_failed">Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal</string>
|
<string name="error_login_failed">Das Laden der Daten ist fehlgeschlagen. Bitte versuchen Sie es später noch einmal</string>
|
||||||
<string name="error_password_change_required">Passwortänderung für Registrierung erforderlich</string>
|
<string name="error_password_change_required">Passwortänderung für Registrierung erforderlich</string>
|
||||||
|
@ -854,6 +854,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Brak połączenia z internetem</string>
|
<string name="error_no_internet">Brak połączenia z internetem</string>
|
||||||
<string name="error_invalid_device_datetime">Wystąpił błąd. Sprawdź poprawność daty w urządzeniu</string>
|
<string name="error_invalid_device_datetime">Wystąpił błąd. Sprawdź poprawność daty w urządzeniu</string>
|
||||||
|
<string name="error_account_inactive">Konto jest nieaktywne. Spróbuj zalogować się ponownie</string>
|
||||||
<string name="error_timeout">Nie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie później</string>
|
<string name="error_timeout">Nie udało się połączyć z dziennikiem. Serwery mogą być przeciążone. Spróbuj ponownie później</string>
|
||||||
<string name="error_login_failed">Ładowanie danych nie powiodło się. Spróbuj ponownie później</string>
|
<string name="error_login_failed">Ładowanie danych nie powiodło się. Spróbuj ponownie później</string>
|
||||||
<string name="error_password_change_required">Wymagana zmiana hasła do dziennika</string>
|
<string name="error_password_change_required">Wymagana zmiana hasła do dziennika</string>
|
||||||
|
@ -854,6 +854,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Интернет-соединение отсутствует</string>
|
<string name="error_no_internet">Интернет-соединение отсутствует</string>
|
||||||
<string name="error_invalid_device_datetime">Произошла ошибка. Проверьте время на вашем устройстве</string>
|
<string name="error_invalid_device_datetime">Произошла ошибка. Проверьте время на вашем устройстве</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Не удалось подключиться к дневнику. Возможно, сервера перегружены, повторите попытку позже</string>
|
<string name="error_timeout">Не удалось подключиться к дневнику. Возможно, сервера перегружены, повторите попытку позже</string>
|
||||||
<string name="error_login_failed">Не удалось загрузить данные, повторите попытку позже</string>
|
<string name="error_login_failed">Не удалось загрузить данные, повторите попытку позже</string>
|
||||||
<string name="error_password_change_required">Необходимо изменить пароль дневника</string>
|
<string name="error_password_change_required">Необходимо изменить пароль дневника</string>
|
||||||
|
@ -854,6 +854,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Žiadne internetové pripojenie</string>
|
<string name="error_no_internet">Žiadne internetové pripojenie</string>
|
||||||
<string name="error_invalid_device_datetime">Vyskytla sa chyba. Skontrolujte hodiny svojho zariadenia</string>
|
<string name="error_invalid_device_datetime">Vyskytla sa chyba. Skontrolujte hodiny svojho zariadenia</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Nedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôr</string>
|
<string name="error_timeout">Nedá sa pripojiť ku denníku. Servery môžu byť preťažené. Prosím skúste to znova neskôr</string>
|
||||||
<string name="error_login_failed">Načítanie údajov zlyhalo. Skúste neskôr prosím</string>
|
<string name="error_login_failed">Načítanie údajov zlyhalo. Skúste neskôr prosím</string>
|
||||||
<string name="error_password_change_required">Je vyžadovaná zmena hesla pre denník</string>
|
<string name="error_password_change_required">Je vyžadovaná zmena hesla pre denník</string>
|
||||||
|
@ -854,6 +854,7 @@
|
|||||||
<!--Errors-->
|
<!--Errors-->
|
||||||
<string name="error_no_internet">Немає з\'єднання з інтернетом</string>
|
<string name="error_no_internet">Немає з\'єднання з інтернетом</string>
|
||||||
<string name="error_invalid_device_datetime">Сталася помилка. Перевірте годинник пристрою</string>
|
<string name="error_invalid_device_datetime">Сталася помилка. Перевірте годинник пристрою</string>
|
||||||
|
<string name="error_account_inactive">This account is inactive. Try logging in again</string>
|
||||||
<string name="error_timeout">Помилка підключення до щоденнику. Сервери можуть бути перевантажені, спробуйте пізніше</string>
|
<string name="error_timeout">Помилка підключення до щоденнику. Сервери можуть бути перевантажені, спробуйте пізніше</string>
|
||||||
<string name="error_login_failed">Помилка завантаження даних, спробуйте пізніше</string>
|
<string name="error_login_failed">Помилка завантаження даних, спробуйте пізніше</string>
|
||||||
<string name="error_password_change_required">Необхідна зміна пароля щоденника</string>
|
<string name="error_password_change_required">Необхідна зміна пароля щоденника</string>
|
||||||
|
@ -866,4 +866,10 @@
|
|||||||
<string name="error_feature_disabled">Feature disabled by your school</string>
|
<string name="error_feature_disabled">Feature disabled by your school</string>
|
||||||
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
||||||
<string name="error_field_required">This field is required</string>
|
<string name="error_field_required">This field is required</string>
|
||||||
|
|
||||||
|
<!-- Mute system -->
|
||||||
|
<string name="message_mute">Mute</string>
|
||||||
|
<string name="message_unmute">Unmute</string>
|
||||||
|
<string name="message_mute_success">You have muted this user</string>
|
||||||
|
<string name="message_unmute_success">You have unmuted this user</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -6,8 +6,10 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
|
|||||||
import io.github.wulkanowy.data.db.dao.MailboxDao
|
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.dao.MutedMessageSendersDao
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
|
import io.github.wulkanowy.data.db.entities.MutedMessageSender
|
||||||
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
|
||||||
@ -19,9 +21,16 @@ import io.github.wulkanowy.sdk.pojo.Folder
|
|||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.github.wulkanowy.utils.Status
|
import io.github.wulkanowy.utils.Status
|
||||||
import io.github.wulkanowy.utils.status
|
import io.github.wulkanowy.utils.status
|
||||||
import io.mockk.*
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.checkEquals
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.impl.annotations.SpyK
|
import io.mockk.impl.annotations.SpyK
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
@ -45,6 +54,9 @@ class MessageRepositoryTest {
|
|||||||
@MockK
|
@MockK
|
||||||
private lateinit var messageDb: MessagesDao
|
private lateinit var messageDb: MessagesDao
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
private lateinit var mutesDb: MutedMessageSendersDao
|
||||||
|
|
||||||
@MockK
|
@MockK
|
||||||
private lateinit var messageAttachmentDao: MessageAttachmentDao
|
private lateinit var messageAttachmentDao: MessageAttachmentDao
|
||||||
|
|
||||||
@ -73,9 +85,22 @@ class MessageRepositoryTest {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
every { refreshHelper.shouldBeRefreshed(any()) } returns false
|
every { refreshHelper.shouldBeRefreshed(any()) } returns false
|
||||||
|
coEvery { mutesDb.checkMute(any()) } returns false
|
||||||
|
coEvery {
|
||||||
|
messageDb.loadMessagesWithMutedAuthor(
|
||||||
|
mailboxKey = any(),
|
||||||
|
folder = any()
|
||||||
|
)
|
||||||
|
} returns flowOf(emptyList())
|
||||||
|
coEvery {
|
||||||
|
messageDb.loadMessagesWithMutedAuthor(
|
||||||
|
folder = any(),
|
||||||
|
email = any()
|
||||||
|
)
|
||||||
|
} returns flowOf(emptyList())
|
||||||
repository = MessageRepository(
|
repository = MessageRepository(
|
||||||
messagesDb = messageDb,
|
messagesDb = messageDb,
|
||||||
|
mutedMessageSendersDao = mutesDb,
|
||||||
messageAttachmentDao = messageAttachmentDao,
|
messageAttachmentDao = messageAttachmentDao,
|
||||||
sdk = sdk,
|
sdk = sdk,
|
||||||
context = context,
|
context = context,
|
||||||
@ -131,7 +156,11 @@ class MessageRepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `get message when content already in db`() {
|
fun `get message when content already in db`() {
|
||||||
val testMessage = getMessageEntity(123, "Test", false)
|
val testMessage = getMessageEntity(123, "Test", false)
|
||||||
val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
|
val messageWithAttachment = MessageWithAttachment(
|
||||||
|
testMessage,
|
||||||
|
emptyList(),
|
||||||
|
MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
|
||||||
|
)
|
||||||
|
|
||||||
coEvery { messageDb.loadMessageWithAttachment("v4") } returns flowOf(
|
coEvery { messageDb.loadMessageWithAttachment("v4") } returns flowOf(
|
||||||
messageWithAttachment
|
messageWithAttachment
|
||||||
@ -149,8 +178,16 @@ class MessageRepositoryTest {
|
|||||||
val testMessage = getMessageEntity(123, "", true)
|
val testMessage = getMessageEntity(123, "", true)
|
||||||
val testMessageWithContent = testMessage.copy().apply { content = "Test" }
|
val testMessageWithContent = testMessage.copy().apply { content = "Test" }
|
||||||
|
|
||||||
val mWa = MessageWithAttachment(testMessage, emptyList())
|
val mWa = MessageWithAttachment(
|
||||||
val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList())
|
testMessage,
|
||||||
|
emptyList(),
|
||||||
|
MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
|
||||||
|
)
|
||||||
|
val mWaWithContent = MessageWithAttachment(
|
||||||
|
testMessageWithContent,
|
||||||
|
emptyList(),
|
||||||
|
MutedMessageSender("Jan Kowalski - P - (WULKANOWY)")
|
||||||
|
)
|
||||||
|
|
||||||
coEvery {
|
coEvery {
|
||||||
messageDb.loadMessageWithAttachment("v4")
|
messageDb.loadMessageWithAttachment("v4")
|
||||||
|
Loading…
Reference in New Issue
Block a user