forked from github/wulkanowy-mirror
Fix messages after 20.09 update (#916)
This commit is contained in:
parent
36984e08b5
commit
7e2de594a4
@ -126,7 +126,7 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:b919b96"
|
implementation "io.github.wulkanowy:sdk:cbcc640"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
|
||||||
|
|
||||||
|
1774
app/schemas/io.github.wulkanowy.data.db.AppDatabase/27.json
Normal file
1774
app/schemas/io.github.wulkanowy.data.db.AppDatabase/27.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,124 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class Migration27Test : AbstractMigrationTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userWithoutCorrespondingUnit() {
|
||||||
|
with(helper.createDatabase(dbName, 26)) {
|
||||||
|
createStudent(this, 321, 123, "Jan Student")
|
||||||
|
createUnit(this, 9999, "Unit Jan")
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
|
||||||
|
|
||||||
|
val db = getMigratedRoomDatabase()
|
||||||
|
val students = runBlocking { db.studentDao.loadAll() }
|
||||||
|
|
||||||
|
assertEquals(1, students.size)
|
||||||
|
|
||||||
|
with(students[0]) {
|
||||||
|
assertEquals(321, id)
|
||||||
|
assertEquals(123, userLoginId)
|
||||||
|
assertEquals("Student Jan", userName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun userWithCorrespondingUnit() {
|
||||||
|
with(helper.createDatabase(dbName, 26)) {
|
||||||
|
createStudent(this, 1, 2, "Jan Kowalski Student")
|
||||||
|
createUnit(this, 2, "Unit Jan")
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
|
||||||
|
|
||||||
|
val db = getMigratedRoomDatabase()
|
||||||
|
val students = runBlocking { db.studentDao.loadAll() }
|
||||||
|
|
||||||
|
assertEquals(1, students.size)
|
||||||
|
|
||||||
|
with(students[0]) {
|
||||||
|
assertEquals(1, id)
|
||||||
|
assertEquals(2, userLoginId)
|
||||||
|
assertEquals("Unit Jan", userName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun studentAccountAndParentAccountWithCorrespondingUnits() {
|
||||||
|
with(helper.createDatabase(dbName, 26)) {
|
||||||
|
createStudent(this, 1, 222, "Jan Student")
|
||||||
|
createStudent(this, 2, 333, "Jan Parent")
|
||||||
|
createUnit(this, 222, "Unit Jan")
|
||||||
|
createUnit(this, 333, "Unit Tomasz")
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
|
||||||
|
|
||||||
|
val db = getMigratedRoomDatabase()
|
||||||
|
val students = runBlocking { db.studentDao.loadAll() }
|
||||||
|
|
||||||
|
assertEquals(2, students.size)
|
||||||
|
|
||||||
|
with(students[0]) {
|
||||||
|
assertEquals(1, id)
|
||||||
|
assertEquals(222, userLoginId)
|
||||||
|
assertEquals("Unit Jan", userName)
|
||||||
|
}
|
||||||
|
with(students[1]) {
|
||||||
|
assertEquals(2, id)
|
||||||
|
assertEquals(333, userLoginId)
|
||||||
|
assertEquals("Unit Tomasz", userName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStudent(db: SupportSQLiteDatabase, id: Long, userLoginId: Int, studentName: String) {
|
||||||
|
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||||
|
put("id", id)
|
||||||
|
put("scrapper_base_url", "https://fakelog.cf")
|
||||||
|
put("mobile_base_url", "")
|
||||||
|
put("login_mode", "SCRAPPER")
|
||||||
|
put("login_type", "STANDARD")
|
||||||
|
put("certificate_key", "")
|
||||||
|
put("private_key", "")
|
||||||
|
put("is_parent", false)
|
||||||
|
put("email", "jan@fakelog.cf")
|
||||||
|
put("password", "******")
|
||||||
|
put("symbol", "Default")
|
||||||
|
put("school_short", "")
|
||||||
|
put("class_name", "")
|
||||||
|
put("student_id", Random.nextInt())
|
||||||
|
put("class_id", Random.nextInt())
|
||||||
|
put("school_id", "123")
|
||||||
|
put("school_name", "Wulkan first class school")
|
||||||
|
put("is_current", false)
|
||||||
|
put("registration_date", "0")
|
||||||
|
|
||||||
|
put("user_login_id", userLoginId)
|
||||||
|
put("student_name", studentName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createUnit(db: SupportSQLiteDatabase, senderId: Int, senderName: String) {
|
||||||
|
db.insert("ReportingUnits", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||||
|
put("student_id", Random.nextInt())
|
||||||
|
put("real_id", Random.nextInt())
|
||||||
|
put("short", "SHORT")
|
||||||
|
put("roles", "[0]")
|
||||||
|
|
||||||
|
put("sender_id", senderId)
|
||||||
|
put("sender_name", senderName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ fun getStudent(): Student {
|
|||||||
scrapperBaseUrl = "fakelog.cf",
|
scrapperBaseUrl = "fakelog.cf",
|
||||||
loginType = "AUTO",
|
loginType = "AUTO",
|
||||||
isCurrent = true,
|
isCurrent = true,
|
||||||
|
userName = "",
|
||||||
studentName = "",
|
studentName = "",
|
||||||
schoolShortName = "",
|
schoolShortName = "",
|
||||||
schoolName = "",
|
schoolName = "",
|
||||||
|
@ -215,6 +215,7 @@ class GradeRepositoryTest {
|
|||||||
studentId = 0,
|
studentId = 0,
|
||||||
studentName = "",
|
studentName = "",
|
||||||
symbol = "",
|
symbol = "",
|
||||||
userLoginId = 0
|
userLoginId = 0,
|
||||||
|
userName = ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class LuckyNumberLocalTest {
|
|||||||
val number = LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)
|
val number = LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)
|
||||||
runBlocking { luckyNumberLocal.saveLuckyNumber(number) }
|
runBlocking { luckyNumberLocal.saveLuckyNumber(number) }
|
||||||
|
|
||||||
val student = Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", 1, false, now())
|
val student = Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", "", 1, false, now())
|
||||||
val luckyNumber = runBlocking { luckyNumberLocal.getLuckyNumber(student, LocalDate.of(2019, 1, 20)).first() }
|
val luckyNumber = runBlocking { luckyNumberLocal.getLuckyNumber(student, LocalDate.of(2019, 1, 20)).first() }
|
||||||
|
|
||||||
assertEquals(1, luckyNumber?.studentId)
|
assertEquals(1, luckyNumber?.studentId)
|
||||||
|
@ -43,7 +43,7 @@ class RecipientLocalTest {
|
|||||||
)
|
)
|
||||||
runBlocking { recipientLocal.saveRecipients(list) }
|
runBlocking { recipientLocal.saveRecipients(list) }
|
||||||
|
|
||||||
val student = Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", 1, true, LocalDateTime.now())
|
val student = Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
|
||||||
val recipients = runBlocking {
|
val recipients = runBlocking {
|
||||||
recipientLocal.getRecipients(
|
recipientLocal.getRecipients(
|
||||||
student = student,
|
student = student,
|
||||||
|
@ -69,6 +69,7 @@ import io.github.wulkanowy.data.db.migrations.Migration23
|
|||||||
import io.github.wulkanowy.data.db.migrations.Migration24
|
import io.github.wulkanowy.data.db.migrations.Migration24
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration25
|
import io.github.wulkanowy.data.db.migrations.Migration25
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration26
|
import io.github.wulkanowy.data.db.migrations.Migration26
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration27
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
@ -111,7 +112,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 26
|
const val VERSION_SCHEMA = 27
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
||||||
return arrayOf(
|
return arrayOf(
|
||||||
@ -139,7 +140,8 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration23(),
|
Migration23(),
|
||||||
Migration24(),
|
Migration24(),
|
||||||
Migration25(),
|
Migration25(),
|
||||||
Migration26()
|
Migration26(),
|
||||||
|
Migration27(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,6 @@ interface MessagesDao : BaseDao<Message> {
|
|||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
|
||||||
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment>
|
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
|
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
|
||||||
fun loadDeleted(studentId: Int): Flow<List<Message>>
|
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,6 @@ data class Message(
|
|||||||
|
|
||||||
val subject: String,
|
val subject: String,
|
||||||
|
|
||||||
var content: String,
|
|
||||||
|
|
||||||
val date: LocalDateTime,
|
val date: LocalDateTime,
|
||||||
|
|
||||||
@ColumnInfo(name = "folder_id")
|
@ColumnInfo(name = "folder_id")
|
||||||
@ -55,4 +53,6 @@ data class Message(
|
|||||||
|
|
||||||
@ColumnInfo(name = "is_notified")
|
@ColumnInfo(name = "is_notified")
|
||||||
var isNotified: Boolean = true
|
var isNotified: Boolean = true
|
||||||
|
|
||||||
|
var content: String = ""
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ data class Student(
|
|||||||
@ColumnInfo(name = "user_login_id")
|
@ColumnInfo(name = "user_login_id")
|
||||||
val userLoginId: Int,
|
val userLoginId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "user_name")
|
||||||
|
val userName: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "student_name")
|
@ColumnInfo(name = "student_name")
|
||||||
val studentName: String,
|
val studentName: String,
|
||||||
|
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration27 : Migration(26, 27) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"")
|
||||||
|
|
||||||
|
val students = getStudentsIdsAndNames(database)
|
||||||
|
val units = getReportingUnits(database)
|
||||||
|
|
||||||
|
students.forEach { (id, userLoginId, studentName) ->
|
||||||
|
val userNameFromUnits = units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second
|
||||||
|
val normalizedStudentName = studentName.split(" ").asReversed().joinToString(" ")
|
||||||
|
|
||||||
|
val userName = userNameFromUnits ?: normalizedStudentName
|
||||||
|
database.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
|
||||||
|
val students = mutableListOf<Triple<Long, Int, String>>()
|
||||||
|
val studentsCursor = database.query("SELECT id, user_login_id, student_name FROM Students")
|
||||||
|
if (studentsCursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
students.add(Triple(studentsCursor.getLong(0), studentsCursor.getInt(1), studentsCursor.getString(2)))
|
||||||
|
} while (studentsCursor.moveToNext())
|
||||||
|
}
|
||||||
|
return students
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
|
||||||
|
val units = mutableListOf<Pair<Int, String>>()
|
||||||
|
val unitsCursor = database.query("SELECT sender_id, sender_name FROM ReportingUnits")
|
||||||
|
if (unitsCursor.moveToFirst()) {
|
||||||
|
do {
|
||||||
|
units.add(unitsCursor.getInt(0) to unitsCursor.getString(1))
|
||||||
|
} while (unitsCursor.moveToNext())
|
||||||
|
}
|
||||||
|
|
||||||
|
return units
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ fun List<SdkStudent>.mapToEntities(password: String = "") = map {
|
|||||||
symbol = it.symbol,
|
symbol = it.symbol,
|
||||||
studentId = it.studentId,
|
studentId = it.studentId,
|
||||||
userLoginId = it.userLoginId,
|
userLoginId = it.userLoginId,
|
||||||
|
userName = it.userName,
|
||||||
studentName = it.studentName + " " + it.studentSurname,
|
studentName = it.studentName + " " + it.studentSurname,
|
||||||
schoolSymbol = it.schoolSymbol,
|
schoolSymbol = it.schoolSymbol,
|
||||||
schoolShortName = it.schoolShortName,
|
schoolShortName = it.schoolShortName,
|
||||||
|
@ -38,9 +38,6 @@ class MessageLocal @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getMessages(student: Student, folder: MessageFolder): Flow<List<Message>> {
|
fun getMessages(student: Student, folder: MessageFolder): Flow<List<Message>> {
|
||||||
return when (folder) {
|
return messagesDb.loadAll(student.id.toInt(), folder.id)
|
||||||
TRASHED -> messagesDb.loadDeleted(student.id.toInt())
|
|
||||||
else -> messagesDb.loadAll(student.id.toInt(), folder.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,24 +18,25 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
|
|||||||
class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
||||||
|
|
||||||
suspend fun getMessages(student: Student, semester: Semester, folder: MessageFolder): List<Message> {
|
suspend fun getMessages(student: Student, semester: Semester, folder: MessageFolder): List<Message> {
|
||||||
return sdk.init(student).getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map {
|
return sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).map {
|
||||||
Message(
|
Message(
|
||||||
studentId = student.id.toInt(),
|
studentId = student.id.toInt(),
|
||||||
realId = it.id ?: 0,
|
realId = it.id ?: 0,
|
||||||
messageId = it.messageId ?: 0,
|
messageId = it.messageId ?: 0,
|
||||||
sender = it.sender.orEmpty(),
|
sender = it.sender?.name.orEmpty(),
|
||||||
senderId = it.senderId ?: 0,
|
senderId = it.sender?.loginId ?: 0,
|
||||||
recipient = it.recipient.orEmpty(),
|
recipient = it.recipients.singleOrNull()?.name ?: "Wielu adresatów",
|
||||||
subject = it.subject.trim(),
|
subject = it.subject.trim(),
|
||||||
date = it.date ?: now(),
|
date = it.date ?: now(),
|
||||||
content = it.content.orEmpty(),
|
|
||||||
folderId = it.folderId,
|
folderId = it.folderId,
|
||||||
unread = it.unread ?: false,
|
unread = it.unread ?: false,
|
||||||
unreadBy = it.unreadBy ?: 0,
|
unreadBy = it.unreadBy ?: 0,
|
||||||
readBy = it.readBy ?: 0,
|
readBy = it.readBy ?: 0,
|
||||||
removed = it.removed,
|
removed = it.removed,
|
||||||
hasAttachments = it.hasAttachments
|
hasAttachments = it.hasAttachments
|
||||||
)
|
).apply {
|
||||||
|
content = it.content.orEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +73,6 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteMessage(student: Student, message: Message): Boolean {
|
suspend fun deleteMessage(student: Student, message: Message): Boolean {
|
||||||
return sdk.init(student).deleteMessages(listOf(message.messageId to message.folderId))
|
return sdk.init(student).deleteMessages(listOf(message.messageId), message.folderId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,11 @@ class MessageRepository @Inject constructor(
|
|||||||
suspend fun deleteMessage(student: Student, message: Message) {
|
suspend fun deleteMessage(student: Student, message: Message) {
|
||||||
val isDeleted = remote.deleteMessage(student, message)
|
val isDeleted = remote.deleteMessage(student, message)
|
||||||
|
|
||||||
if (!message.removed) local.updateMessages(listOf(message.copy(removed = isDeleted).apply {
|
if (message.folderId != MessageFolder.TRASHED.id) {
|
||||||
id = message.id
|
if (isDeleted) local.updateMessages(listOf(message.copy(folderId = MessageFolder.TRASHED.id).apply {
|
||||||
content = message.content
|
id = message.id
|
||||||
})) else local.deleteMessages(listOf(message))
|
content = message.content
|
||||||
|
}))
|
||||||
|
} else local.deleteMessages(listOf(message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,6 @@ class ContributorPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
Status.ERROR -> errorHandler.dispatch(it.error!!)
|
Status.ERROR -> errorHandler.dispatch(it.error!!)
|
||||||
}
|
}
|
||||||
}
|
}.launch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import io.github.wulkanowy.R
|
|||||||
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.MessageWithAttachment
|
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder
|
|
||||||
import io.github.wulkanowy.databinding.ItemMessageAttachmentBinding
|
import io.github.wulkanowy.databinding.ItemMessageAttachmentBinding
|
||||||
import io.github.wulkanowy.databinding.ItemMessageDividerBinding
|
import io.github.wulkanowy.databinding.ItemMessageDividerBinding
|
||||||
import io.github.wulkanowy.databinding.ItemMessagePreviewBinding
|
import io.github.wulkanowy.databinding.ItemMessagePreviewBinding
|
||||||
@ -66,8 +65,8 @@ class MessagePreviewAdapter @Inject constructor() :
|
|||||||
messagePreviewSubject.text = message.subject.ifBlank { root.context.getString(R.string.message_no_subject) }
|
messagePreviewSubject.text = message.subject.ifBlank { root.context.getString(R.string.message_no_subject) }
|
||||||
messagePreviewDate.text = root.context.getString(R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
messagePreviewDate.text = root.context.getString(R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
|
||||||
messagePreviewContent.text = message.content
|
messagePreviewContent.text = message.content
|
||||||
messagePreviewAuthor.text = if (message.folderId == MessageFolder.SENT.id) "${root.context.getString(R.string.message_to)} ${message.recipient}"
|
messagePreviewFromSender.text = message.sender
|
||||||
else "${root.context.getString(R.string.message_from)} ${message.sender}"
|
messagePreviewToRecipient.text = message.recipient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import android.os.Build
|
|||||||
import io.github.wulkanowy.data.Status
|
import io.github.wulkanowy.data.Status
|
||||||
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.repositories.message.MessageFolder
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
import io.github.wulkanowy.data.repositories.message.MessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -207,7 +208,7 @@ class MessagePreviewPresenter @Inject constructor(
|
|||||||
view?.apply {
|
view?.apply {
|
||||||
showOptions(message != null)
|
showOptions(message != null)
|
||||||
message?.let {
|
message?.let {
|
||||||
when (it.removed) {
|
when (it.folderId == MessageFolder.TRASHED.id) {
|
||||||
true -> setDeletedOptionsLabels()
|
true -> setDeletedOptionsLabels()
|
||||||
false -> setNotDeletedOptionsLabels()
|
false -> setNotDeletedOptionsLabels()
|
||||||
}
|
}
|
||||||
|
@ -19,22 +19,17 @@ class MessageTabAdapter @Inject constructor() :
|
|||||||
|
|
||||||
var onClickListener: (Message, position: Int) -> Unit = { _, _ -> }
|
var onClickListener: (Message, position: Int) -> Unit = { _, _ -> }
|
||||||
|
|
||||||
|
var onChangesDetectedListener = {}
|
||||||
|
|
||||||
private var items = mutableListOf<Message>()
|
private var items = mutableListOf<Message>()
|
||||||
|
|
||||||
fun setDataItems(data: List<Message>) {
|
fun setDataItems(data: List<Message>) {
|
||||||
|
if (items.size != data.size) onChangesDetectedListener()
|
||||||
val diffResult = DiffUtil.calculateDiff(MessageTabDiffUtil(items, data))
|
val diffResult = DiffUtil.calculateDiff(MessageTabDiffUtil(items, data))
|
||||||
items = data.toMutableList()
|
items = data.toMutableList()
|
||||||
diffResult.dispatchUpdatesTo(this)
|
diffResult.dispatchUpdatesTo(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateItem(position: Int, item: Message) {
|
|
||||||
val currentItem = items[position]
|
|
||||||
items[position] = item
|
|
||||||
if (item != currentItem) {
|
|
||||||
notifyItemChanged(position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||||
|
@ -63,7 +63,10 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
tabAdapter.onClickListener = presenter::onMessageItemSelected
|
with(tabAdapter) {
|
||||||
|
onClickListener = presenter::onMessageItemSelected
|
||||||
|
onChangesDetectedListener = ::resetListPosition
|
||||||
|
}
|
||||||
|
|
||||||
with(binding.messageTabRecycler) {
|
with(binding.messageTabRecycler) {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
@ -97,10 +100,6 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
tabAdapter.setDataItems(data)
|
tabAdapter.setDataItems(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateItem(item: Message, position: Int) {
|
|
||||||
tabAdapter.updateItem(position, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
binding.messageTabProgress.visibility = if (show) VISIBLE else GONE
|
binding.messageTabProgress.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
@ -81,13 +81,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onMessageItemSelected(message: Message, position: Int) {
|
fun onMessageItemSelected(message: Message, position: Int) {
|
||||||
Timber.i("Select message ${message.id} item (position: $position)")
|
Timber.i("Select message ${message.id} item (position: $position)")
|
||||||
view?.run {
|
view?.openMessage(message)
|
||||||
openMessage(message)
|
|
||||||
if (message.unread) {
|
|
||||||
message.unread = false
|
|
||||||
updateItem(message, position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData(forceRefresh: Boolean) {
|
private fun loadData(forceRefresh: Boolean) {
|
||||||
@ -154,6 +148,7 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
.collect {
|
.collect {
|
||||||
Timber.d("Applying filter. Full list: ${messages.size}, filtered: ${it.size}")
|
Timber.d("Applying filter. Full list: ${messages.size}, filtered: ${it.size}")
|
||||||
updateData(it)
|
updateData(it)
|
||||||
|
view?.resetListPosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +171,6 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
showContent(data.isNotEmpty())
|
showContent(data.isNotEmpty())
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
updateData(data)
|
updateData(data)
|
||||||
resetListPosition()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@ interface MessageTabView : BaseView {
|
|||||||
|
|
||||||
fun updateData(data: List<Message>)
|
fun updateData(data: List<Message>)
|
||||||
|
|
||||||
fun updateItem(item: Message, position: Int)
|
|
||||||
|
|
||||||
fun showProgress(show: Boolean)
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
fun enableSwipe(enable: Boolean)
|
fun enableSwipe(enable: Boolean)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/messagePreviewContentContainer"
|
android:id="@+id/messagePreviewContentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -9,37 +10,84 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messagePreviewSubject"
|
android:id="@+id/messagePreviewSubject"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="15dp"
|
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:textSize="22sp"
|
android:textSize="22sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="@tools:sample/lorem" />
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messagePreviewAuthor"
|
android:id="@+id/messagePreviewFromLabel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="@string/message_from"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/messagePreviewSubject" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewFromSender"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
tools:text="@tools:sample/full_names" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/messagePreviewFromLabel"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/messagePreviewFromLabel"
|
||||||
|
tools:text="@tools:sample/full_names[0]" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewToLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="@string/message_to"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/messagePreviewFromLabel" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/messagePreviewToRecipient"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/messagePreviewToLabel"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/messagePreviewToLabel"
|
||||||
|
tools:text="@tools:sample/full_names[1]" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messagePreviewDate"
|
android:id="@+id/messagePreviewDate"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="15dp"
|
android:layout_marginTop="4dp"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/messagePreviewToLabel"
|
||||||
tools:text="@tools:sample/date/ddmmyy" />
|
tools:text="@tools:sample/date/ddmmyy" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/messagePreviewContent"
|
android:id="@+id/messagePreviewContent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
android:autoLink="web"
|
android:autoLink="web"
|
||||||
android:lineSpacingMultiplier="1.2"
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/messagePreviewDate"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
</LinearLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -45,7 +45,8 @@ fun getStudentEntity(mode: Sdk.Mode = Sdk.Mode.API): Student {
|
|||||||
studentId = 0,
|
studentId = 0,
|
||||||
studentName = "",
|
studentName = "",
|
||||||
symbol = "",
|
symbol = "",
|
||||||
userLoginId = 0
|
userLoginId = 0,
|
||||||
|
userName = "",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +87,6 @@ fun getMessageEntity(
|
|||||||
senderId = 1,
|
senderId = 1,
|
||||||
recipient = "",
|
recipient = "",
|
||||||
subject = "",
|
subject = "",
|
||||||
content = content,
|
|
||||||
date = now(),
|
date = now(),
|
||||||
folderId = 1,
|
folderId = 1,
|
||||||
unread = unread,
|
unread = unread,
|
||||||
@ -94,4 +94,6 @@ fun getMessageEntity(
|
|||||||
readBy = 1,
|
readBy = 1,
|
||||||
removed = false,
|
removed = false,
|
||||||
hasAttachments = false
|
hasAttachments = false
|
||||||
)
|
).apply {
|
||||||
|
this.content = content
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import io.mockk.MockKAnnotations
|
|||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
@ -35,6 +36,7 @@ class MessageRepositoryTest {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
|
|
||||||
|
every { student.userName } returns "Jan"
|
||||||
repo = MessageRepository(local, remote)
|
repo = MessageRepository(local, remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +65,7 @@ class MessageRepositoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `get message when content in db is empty`() {
|
fun `get message when content in db is empty`() {
|
||||||
val testMessage = getMessageEntity(123, "", true)
|
val testMessage = getMessageEntity(123, "", true)
|
||||||
val testMessageWithContent = testMessage.copy(content = "Test")
|
val testMessageWithContent = testMessage.copy().apply { content = "Test" }
|
||||||
|
|
||||||
val mWa = MessageWithAttachment(testMessage, emptyList())
|
val mWa = MessageWithAttachment(testMessage, emptyList())
|
||||||
val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList())
|
val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList())
|
||||||
|
@ -39,7 +39,7 @@ class GradeAverageProviderTest {
|
|||||||
|
|
||||||
private lateinit var gradeAverageProvider: GradeAverageProvider
|
private lateinit var gradeAverageProvider: GradeAverageProvider
|
||||||
|
|
||||||
private val student = Student("", "", "", "SCRAPPER", "", "", false, "", "", "", 101, 0, "", "", "", "", "", 1, true, LocalDateTime.now())
|
private val student = Student("", "", "", "SCRAPPER", "", "", false, "", "", "", 101, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
|
||||||
|
|
||||||
private val semesters = mutableListOf(
|
private val semesters = mutableListOf(
|
||||||
createSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)),
|
createSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)),
|
||||||
|
@ -99,7 +99,7 @@ class LoginFormPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun loginTest() {
|
fun loginTest() {
|
||||||
val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf/", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false)
|
val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf/", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false, userName = "")
|
||||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(StudentWithSemesters(studentTest, emptyList()))
|
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(StudentWithSemesters(studentTest, emptyList()))
|
||||||
|
|
||||||
every { loginFormView.formUsernameValue } returns "@"
|
every { loginFormView.formUsernameValue } returns "@"
|
||||||
|
@ -38,7 +38,7 @@ class LoginStudentSelectPresenterTest {
|
|||||||
|
|
||||||
private lateinit var presenter: LoginStudentSelectPresenter
|
private lateinit var presenter: LoginStudentSelectPresenter
|
||||||
|
|
||||||
private val testStudent by lazy { Student(email = "test", password = "test123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "", loginMode = "", certificateKey = "", privateKey = "", mobileBaseUrl = "", schoolShortName = "", userLoginId = 1, isParent = false) }
|
private val testStudent by lazy { Student(email = "test", password = "test123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "", loginMode = "", certificateKey = "", privateKey = "", mobileBaseUrl = "", schoolShortName = "", userLoginId = 1, isParent = false, userName = "") }
|
||||||
|
|
||||||
private val testException by lazy { RuntimeException("Problem") }
|
private val testException by lazy { RuntimeException("Problem") }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user