[UI] Refactor Messages fragment.

This commit is contained in:
Kuba Szczodrzyński 2020-04-04 21:31:14 +02:00
parent c0aeb0d2f3
commit f98b174857
56 changed files with 832 additions and 669 deletions

View File

@ -816,7 +816,7 @@ fun View.findParentById(targetId: Int): View? {
return null return null
} }
fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: () -> Unit) = launch { fun CoroutineScope.startCoroutineTimer(delayMillis: Long = 0, repeatMillis: Long = 0, action: suspend CoroutineScope.() -> Unit) = launch {
delay(delayMillis) delay(delayMillis)
if (repeatMillis > 0) { if (repeatMillis > 0) {
while (true) { while (true) {

View File

@ -68,9 +68,9 @@ import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragment import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragmentOld
import pl.szczodrzynski.edziennik.ui.modules.messages.compose.MessagesComposeFragment
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsListFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
@ -889,9 +889,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
} }
app.profileLoad(id) { app.profileLoad(id) {
MessagesFragment.pageSelection = -1 MessagesFragment.pageSelection = -1
MessagesListFragment.tapPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION) MessagesListFragmentOld.tapPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
MessagesListFragment.topPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION) MessagesListFragmentOld.topPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
MessagesListFragment.bottomPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION) MessagesListFragmentOld.bottomPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
setDrawerItems() setDrawerItems()
// the drawer profile is updated automatically when the drawer item is clicked // the drawer profile is updated automatically when the drawer item is clicked

View File

@ -13,8 +13,8 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
internal const val FEATURE_TIMETABLE = 1 internal const val FEATURE_TIMETABLE = 1
internal const val FEATURE_AGENDA = 2 internal const val FEATURE_AGENDA = 2

View File

@ -11,8 +11,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_DELETED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.getBoolean import pl.szczodrzynski.edziennik.getBoolean
import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils.crc32 import pl.szczodrzynski.edziennik.utils.Utils.crc32
@ -33,11 +33,11 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
return@apiGet return@apiGet
} }
json.asJsonObjectList()?.forEach { jMessage -> json.asJsonObjectList().forEach { jMessage ->
val subject = jMessage.getString("tytul") val subject = jMessage.getString("tytul") ?: ""
if (subject?.contains("(") == true && subject.startsWith("iDziennik - ")) if (subject.contains("(") && subject.startsWith("iDziennik - "))
return@forEach return@forEach
if (subject?.startsWith("Uwaga dla ucznia (klasa:") == true) if (subject.startsWith("Uwaga dla ucznia (klasa:"))
return@forEach return@forEach
val messageIdStr = jMessage.getString("id") val messageIdStr = jMessage.getString("id")
@ -64,13 +64,12 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
rTeacher.setTeacherType(Teacher.TYPE_OTHER) rTeacher.setTeacherType(Teacher.TYPE_OTHER)
val message = Message( val message = Message(
profileId, profileId = profileId,
messageId, id = messageId,
subject, type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
body, subject = subject,
if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED, body = body,
rTeacher.id, senderId = rTeacher.id
-1
) )
val messageRecipient = MessageRecipient( val messageRecipient = MessageRecipient(
@ -81,7 +80,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
/*messageId*/ messageId /*messageId*/ messageId
) )
data.messageIgnoreList.add(message) data.messageList.add(message)
data.messageRecipientList.add(messageRecipient) data.messageRecipientList.add(messageRecipient)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
profileId, profileId,

View File

@ -13,7 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.utils.Utils.crc32 import pl.szczodrzynski.edziennik.utils.Utils.crc32
@ -46,13 +46,12 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString) val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString)
val message = Message( val message = Message(
profileId, profileId = profileId,
messageId, id = messageId,
subject, type = TYPE_SENT,
body, subject = subject,
TYPE_SENT, body = body,
-1, senderId = null
-1
) )
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) { for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
@ -76,7 +75,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
data.messageRecipientIgnoreList.add(messageRecipient) data.messageRecipientIgnoreList.add(messageRecipient)
} }
data.messageIgnoreList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
} }

View File

@ -10,8 +10,8 @@ import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_MESSAGE
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
@ -50,7 +50,11 @@ class IdziennikWebGetMessage(override val data: DataIdziennik,
message.recipients?.clear() message.recipients?.clear()
when (message.type) { when (message.type) {
TYPE_RECEIVED -> { TYPE_RECEIVED -> {
val recipientObject = MessageRecipientFull(profileId, -1, message.id) val recipientObject = MessageRecipientFull(
profileId = profileId,
id = -1,
messageId = message.id
)
val readDateString = it.getString("DataOdczytania") val readDateString = it.getString("DataOdczytania")
recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis() recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis()
@ -67,7 +71,11 @@ class IdziennikWebGetMessage(override val data: DataIdziennik,
val recipientName = recipient.getString("NazwaOdbiorcy") ?: return@forEach val recipientName = recipient.getString("NazwaOdbiorcy") ?: return@forEach
val teacher = data.getTeacherByLastFirst(recipientName) val teacher = data.getTeacherByLastFirst(recipientName)
val recipientObject = MessageRecipientFull(profileId, teacher.id, message.id) val recipientObject = MessageRecipientFull(
profileId = profileId,
id = teacher.id,
messageId = message.id
)
recipientObject.readDate = recipient.getLong("Status") ?: return@forEach recipientObject.readDate = recipient.getLong("Status") ?: return@forEach
recipientObject.fullName = teacher.fullName recipientObject.fullName = teacher.fullName
@ -91,9 +99,10 @@ class IdziennikWebGetMessage(override val data: DataIdziennik,
)) ))
} }
EventBus.getDefault().postSticky(MessageGetEvent(message))
data.messageList.add(message) data.messageList.add(message)
data.messageListReplace = true
EventBus.getDefault().postSticky(MessageGetEvent(message))
onSuccess() onSuccess()
} }
} }

View File

@ -57,7 +57,7 @@ class IdziennikWebSendMessage(override val data: DataIdziennik,
} }
IdziennikApiMessagesSent(data, null) { IdziennikApiMessagesSent(data, null) {
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)

View File

@ -12,7 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESSAGES_SENT import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESSAGES_SENT
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages
import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
import pl.szczodrzynski.edziennik.singleOrNull import pl.szczodrzynski.edziennik.singleOrNull
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
@ -78,7 +78,7 @@ class LibrusMessagesGetList(override val data: DataLibrus,
val senderId = when (type) { val senderId = when (type) {
TYPE_RECEIVED -> recipientId TYPE_RECEIVED -> recipientId
else -> -1 else -> null
} }
val receiverId = when (type) { val receiverId = when (type) {
@ -92,13 +92,12 @@ class LibrusMessagesGetList(override val data: DataLibrus,
} }
val messageObject = Message( val messageObject = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = type,
null, subject = subject,
type, body = null,
senderId, senderId = senderId
-1
) )
val messageRecipientObject = MessageRecipient( val messageRecipientObject = MessageRecipient(
@ -111,10 +110,10 @@ class LibrusMessagesGetList(override val data: DataLibrus,
element.select("isAnyFileAttached")?.text()?.let { element.select("isAnyFileAttached")?.text()?.let {
if (it == "1") if (it == "1")
messageObject.overrideHasAttachments = true messageObject.hasAttachments = true
} }
data.messageIgnoreList.add(messageObject) data.messageList.add(messageObject)
data.messageRecipientList.add(messageRecipientObject) data.messageRecipientList.add(messageRecipientObject)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
profileId, profileId,

View File

@ -9,8 +9,8 @@ import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
@ -102,11 +102,10 @@ class LibrusMessagesGetMessage(override val data: DataLibrus,
} }
val messageRecipientObject = MessageRecipientFull( val messageRecipientObject = MessageRecipientFull(
profileId, profileId = profileId,
-1, id = -1,
-1, messageId = messageObject.id,
readDate, readDate = readDate
messageObject.id
) )
messageRecipientObject.fullName = profile.accountName ?: profile.studentNameLong ?: "" messageRecipientObject.fullName = profile.accountName ?: profile.studentNameLong ?: ""
@ -132,11 +131,10 @@ class LibrusMessagesGetMessage(override val data: DataLibrus,
} }
val messageRecipientObject = MessageRecipientFull( val messageRecipientObject = MessageRecipientFull(
profileId, profileId = profileId,
receiverId, id = receiverId,
-1, messageId = messageObject.id,
readDate, readDate = readDate
messageObject.id
) )
messageRecipientObject.fullName = "$receiverFirstName $receiverLastName" messageRecipientObject.fullName = "$receiverFirstName $receiverLastName"
@ -159,7 +157,9 @@ class LibrusMessagesGetMessage(override val data: DataLibrus,
messageObject.recipients = messageRecipientList messageObject.recipients = messageRecipientList
data.messageRecipientList.addAll(messageRecipientList) data.messageRecipientList.addAll(messageRecipientList)
data.messageList.add(messageObject) data.messageList.add(messageObject)
data.messageListReplace = true
EventBus.getDefault().postSticky(MessageGetEvent(messageObject)) EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
onSuccess() onSuccess()

View File

@ -48,7 +48,7 @@ class LibrusMessagesSendMessage(override val data: DataLibrus,
} }
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) { LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) {
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)

View File

@ -11,7 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
@ -61,19 +61,17 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
} }
val recipient = MessageRecipientFull( val recipient = MessageRecipientFull(
profileId, profileId = profileId,
-1, id = -1,
-1, messageId = message.id,
readDate, readDate = readDate
message.id
) )
recipient.fullName = profile?.accountName ?: profile?.studentNameLong ?: "" recipient.fullName = profile?.accountName ?: profile?.studentNameLong ?: ""
messageRecipientList.add(recipient) messageRecipientList.add(recipient)
} else { } else {
message.senderId = -1 message.senderId = null
message.senderReplyId = -1
content.select("table.spis tr:has(td)")?.forEach { recipientEl -> content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
val senderEl = recipientEl.select("td:eq(0)").first() val senderEl = recipientEl.select("td:eq(0)").first()
@ -100,11 +98,10 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
} }
val recipient = MessageRecipientFull( val recipient = MessageRecipientFull(
profileId, profileId = profileId,
receiverId, id = receiverId,
-1, messageId = message.id,
readDate, readDate = readDate
message.id
) )
recipient.fullName = teacher?.fullName ?: "?" recipient.fullName = teacher?.fullName ?: "?"
@ -149,7 +146,9 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
message.recipients = messageRecipientList message.recipients = messageRecipientList
data.messageRecipientList.addAll(messageRecipientList) data.messageRecipientList.addAll(messageRecipientList)
data.messageList.add(message) data.messageList.add(message)
data.messageListReplace = true
EventBus.getDefault().postSticky(MessageGetEvent(message)) EventBus.getDefault().postSticky(MessageGetEvent(message))
onSuccess() onSuccess()

View File

@ -10,8 +10,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
@ -54,12 +54,12 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
type = TYPE_SENT type = TYPE_SENT
val senderEl = item.select("td:eq(3) div").first() val senderEl = item.select("td:eq(3) div").first()
var senderId: Long = -1 var senderId: Long? = null
if (type == TYPE_RECEIVED) { if (type == TYPE_RECEIVED) {
// search sender teacher // search sender teacher
val senderName = senderEl.text().fixName() val senderName = senderEl.text().fixName()
senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id ?: -1 senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id
data.messageRecipientList.add(MessageRecipient(profileId, -1, id)) data.messageRecipientList.add(MessageRecipient(profileId, -1, id))
} else { } else {
// TYPE_SENT, so multiple recipients possible // TYPE_SENT, so multiple recipients possible
@ -72,16 +72,15 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
} }
val message = Message( val message = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = type,
null, subject = subject,
type, body = null,
senderId, senderId = senderId
-1
) )
data.messageIgnoreList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate))
} }

View File

@ -52,25 +52,24 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
val senderEl = item.select("td:eq(2)").first() val senderEl = item.select("td:eq(2)").first()
val senderName = senderEl.ownText().fixName() val senderName = senderEl.ownText().fixName()
val senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id ?: -1 val senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, -1, id)) data.messageRecipientIgnoreList.add(MessageRecipient(profileId, -1, id))
val isRead = item.select("td:eq(3) span").first().hasClass("wiadomosc_przeczytana") val isRead = item.select("td:eq(3) span").first().hasClass("wiadomosc_przeczytana")
val message = Message( val message = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = Message.TYPE_RECEIVED,
null, subject = subject,
Message.TYPE_RECEIVED, body = null,
senderId, senderId = senderId
-1
) )
if (hasAttachments) if (hasAttachments)
message.setHasAttachments() message.hasAttachments = true
data.messageIgnoreList.add(message) data.messageList.add(message)
data.setSeenMetadataList.add( data.setSeenMetadataList.add(
Metadata( Metadata(
profileId, profileId,

View File

@ -73,19 +73,18 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
val addedDate = Date.fromIsoHm(addedDateEl.text()) val addedDate = Date.fromIsoHm(addedDateEl.text())
val message = Message( val message = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = Message.TYPE_SENT,
null, subject = subject,
Message.TYPE_SENT, body = null,
-1, senderId = null
-1
) )
if (hasAttachments) if (hasAttachments)
message.setHasAttachments() message.hasAttachments = true
data.messageIgnoreList.add(message) data.messageList.add(message)
data.setSeenMetadataList.add( data.setSeenMetadataList.add(
Metadata( Metadata(
profileId, profileId,

View File

@ -43,7 +43,7 @@ class MobidziennikWebSendMessage(override val data: DataMobidziennik,
// TODO create MobidziennikWebMessagesSent and replace this // TODO create MobidziennikWebMessagesSent and replace this
MobidziennikWebMessagesAll(data, null) { MobidziennikWebMessagesAll(data, null) {
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)

View File

@ -9,7 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_MESSAGES_CHANGE_S
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull

View File

@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_INBOX import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.text.replace import kotlin.text.replace
@ -44,8 +44,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
val body = message.getString("Tresc") ?: "" val body = message.getString("Tresc") ?: ""
val senderLoginId = message.getString("NadawcaId") ?: return@forEach val senderLoginId = message.getString("NadawcaId") ?: return@forEach
val senderId = data.teacherList val senderId = data.teacherList.singleOrNull { it.loginId == senderLoginId }?.id ?: {
.singleOrNull { it.loginId == senderLoginId }?.id ?: {
val senderName = message.getString("Nadawca") ?: "" val senderName = message.getString("Nadawca") ?: ""
@ -60,7 +59,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
data.teacherList.put(teacherObject.id, teacherObject) data.teacherList.put(teacherObject.id, teacherObject)
teacherObject.id teacherObject.id
} }
}.invoke() ?: -1 }.invoke()
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 }
?: -1 ?: -1
@ -68,13 +67,12 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
?: -1 ?: -1
val messageObject = Message( val messageObject = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = TYPE_RECEIVED,
body.replace("\n", "<br>"), subject = subject,
TYPE_RECEIVED, body = body.replace("\n", "<br>"),
senderId, senderId = senderId
-1
) )
val messageRecipientObject = MessageRecipient( val messageRecipientObject = MessageRecipient(
@ -85,7 +83,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan,
id id
) )
data.messageIgnoreList.add(messageObject) data.messageList.add(messageObject)
data.messageRecipientList.add(messageRecipientObject) data.messageRecipientList.add(messageRecipientObject)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
profileId, profileId,

View File

@ -11,7 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_SENT import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_MESSAGES_SENT
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
@ -92,16 +92,15 @@ class VulcanApiMessagesSent(override val data: DataVulcan,
} }
val messageObject = Message( val messageObject = Message(
profileId, profileId = profileId,
id, id = id,
subject, type = TYPE_SENT,
body.replace("\n", "<br>"), subject = subject,
TYPE_SENT, body = body.replace("\n", "<br>"),
-1, senderId = null
-1
) )
data.messageIgnoreList.add(messageObject) data.messageList.add(messageObject)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,

View File

@ -52,7 +52,7 @@ class VulcanApiSendMessage(override val data: DataVulcan,
} }
VulcanApiMessagesSent(data, null) { VulcanApiMessagesSent(data, null) {
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)

View File

@ -87,6 +87,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
var teacherOnConflictStrategy = OnConflictStrategy.IGNORE var teacherOnConflictStrategy = OnConflictStrategy.IGNORE
var eventListReplace = false var eventListReplace = false
var messageListReplace = false
val classrooms = LongSparseArray<Classroom>() val classrooms = LongSparseArray<Classroom>()
val attendanceTypes = LongSparseArray<AttendanceType>() val attendanceTypes = LongSparseArray<AttendanceType>()
@ -126,7 +127,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
val teacherAbsenceList = mutableListOf<TeacherAbsence>() val teacherAbsenceList = mutableListOf<TeacherAbsence>()
val messageList = mutableListOf<Message>() val messageList = mutableListOf<Message>()
val messageIgnoreList = mutableListOf<Message>()
val messageRecipientList = mutableListOf<MessageRecipient>() val messageRecipientList = mutableListOf<MessageRecipient>()
val messageRecipientIgnoreList = mutableListOf<MessageRecipient>() val messageRecipientIgnoreList = mutableListOf<MessageRecipient>()
@ -182,7 +182,6 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
luckyNumberList.clear() luckyNumberList.clear()
teacherAbsenceList.clear() teacherAbsenceList.clear()
messageList.clear() messageList.clear()
messageIgnoreList.clear()
messageRecipientList.clear() messageRecipientList.clear()
messageRecipientIgnoreList.clear() messageRecipientIgnoreList.clear()
metadataList.clear() metadataList.clear()
@ -305,10 +304,12 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
if (teacherAbsenceList.isNotEmpty()) if (teacherAbsenceList.isNotEmpty())
db.teacherAbsenceDao().addAll(teacherAbsenceList) db.teacherAbsenceDao().addAll(teacherAbsenceList)
if (messageList.isNotEmpty()) if (messageList.isNotEmpty()) {
db.messageDao().addAll(messageList) if (messageListReplace)
if (messageIgnoreList.isNotEmpty()) db.messageDao().replaceAll(messageList)
db.messageDao().addAllIgnore(messageIgnoreList) else
db.messageDao().upsertAll(messageList, removeNotKept = false) // TODO dataRemoveModel for messages
}
if (messageRecipientList.isNotEmpty()) if (messageRecipientList.isNotEmpty())
db.messageRecipientDao().addAll(messageRecipientList) db.messageRecipientDao().addAll(messageRecipientList)
if (messageRecipientIgnoreList.isNotEmpty()) if (messageRecipientIgnoreList.isNotEmpty())

View File

@ -227,10 +227,10 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
} }
private fun messageNotifications() { private fun messageNotifications() {
for (message in app.db.messageDao().receivedNotNotifiedNow) { for (message in app.db.messageDao().getNotNotifiedNow()) {
val text = app.getString( val text = app.getString(
R.string.notification_message_format, R.string.notification_message_format,
message.senderFullName, message.senderName,
message.subject message.subject
) )
notifications += Notification( notifications += Notification(

View File

@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
LibrusLesson::class, LibrusLesson::class,
TimetableManual::class, TimetableManual::class,
Metadata::class Metadata::class
], version = 83) ], version = 84)
@TypeConverters( @TypeConverters(
ConverterTime::class, ConverterTime::class,
ConverterDate::class, ConverterDate::class,
@ -168,7 +168,8 @@ abstract class AppDb : RoomDatabase() {
Migration80(), Migration80(),
Migration81(), Migration81(),
Migration82(), Migration82(),
Migration83() Migration83(),
Migration84()
).allowMainThreadQueries().build() ).allowMainThreadQueries().build()
} }
} }

View File

@ -1,114 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.dao;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.RawQuery;
import androidx.sqlite.db.SimpleSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteQuery;
import java.util.List;
import pl.szczodrzynski.edziennik.data.db.entity.Message;
import pl.szczodrzynski.edziennik.data.db.entity.Metadata;
import pl.szczodrzynski.edziennik.data.db.full.MessageFull;
import static pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_DELETED;
import static pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED;
import static pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT;
import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_MESSAGE;
@Dao
public abstract class MessageDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract long add(Message message);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void addAll(List<Message> messageList);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void addAllIgnore(List<Message> messageList);
@Query("DELETE FROM messages WHERE profileId = :profileId")
public abstract void clear(int profileId);
@RawQuery(observedEntities = {Message.class})
abstract LiveData<List<MessageFull>> getAll(SupportSQLiteQuery query);
@RawQuery(observedEntities = {Message.class, Metadata.class})
abstract List<MessageFull> getNow(SupportSQLiteQuery query);
@RawQuery(observedEntities = {Message.class, Metadata.class})
abstract MessageFull getOneNow(SupportSQLiteQuery query);
public LiveData<List<MessageFull>> getWithMetadataAndSenderName(int profileId, int messageType, String filter) {
return getAll(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS senderFullName\n" +
"FROM messages \n" +
"LEFT JOIN teachers ON teachers.profileId = "+profileId+" AND teacherId = senderId\n" +
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = "+profileId+"\n" +
"WHERE messages.profileId = "+profileId+" AND messageType = "+messageType+" AND "+filter+"\n" +
"ORDER BY addedDate DESC"));
}
public LiveData<List<MessageFull>> getWithMetadata(int profileId, int messageType, String filter) {
return getAll(new SimpleSQLiteQuery("SELECT \n" +
"* \n" +
"FROM messages \n" +
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = "+profileId+"\n" +
"WHERE messages.profileId = "+profileId+" AND messageType = "+messageType+" AND "+filter+"\n" +
"ORDER BY addedDate DESC"));
}
@Nullable
public MessageFull getById(int profileId, long messageId) {
return getOneNow(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS senderFullName\n" +
"FROM messages \n" +
"LEFT JOIN teachers ON teachers.profileId = "+profileId+" AND teacherId = senderId\n" +
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = "+profileId+"\n" +
"WHERE messages.profileId = "+profileId+" AND messageId = "+messageId+"\n" +
"ORDER BY addedDate DESC"));
}
public LiveData<List<MessageFull>> getReceived(int profileId) {
return getWithMetadataAndSenderName(profileId, TYPE_RECEIVED, "1");
}
public LiveData<List<MessageFull>> getDeleted(int profileId) {
return getWithMetadataAndSenderName(profileId, TYPE_DELETED, "1");
}
public LiveData<List<MessageFull>> getSent(int profileId) {
return getWithMetadata(profileId, TYPE_SENT, "1");
}
public List<MessageFull> getReceivedNow(int profileId, String filter) {
return getNow(new SimpleSQLiteQuery("SELECT \n" +
"*, \n" +
"teachers.teacherName || ' ' || teachers.teacherSurname AS senderFullName\n" +
"FROM messages \n" +
"LEFT JOIN teachers ON teachers.profileId = "+profileId+" AND teacherId = senderId\n" +
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = "+profileId+"\n" +
"WHERE messages.profileId = "+profileId+" AND messageType = 0 AND "+filter+"\n" +
"ORDER BY addedDate DESC"));
}
public List<MessageFull> getReceivedNotNotifiedNow(int profileId) {
return getReceivedNow(profileId, "notified = 0");
}
@Query("SELECT " +
"*, " +
"teachers.teacherName || ' ' || teachers.teacherSurname AS senderFullName " +
"FROM messages " +
"LEFT JOIN teachers ON teachers.profileId = messages.profileId AND teacherId = senderId " +
"LEFT JOIN metadata ON messageId = thingId AND thingType = "+TYPE_MESSAGE+" AND metadata.profileId = messages.profileId " +
"WHERE messageType = 0 AND notified = 0 " +
"ORDER BY addedDate DESC")
public abstract List<MessageFull> getReceivedNotNotifiedNow();
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.annotation.SelectiveDao
import pl.szczodrzynski.edziennik.annotation.UpdateSelective
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
@Dao
@SelectiveDao(db = AppDb::class)
abstract class MessageDao : BaseDao<Message, MessageFull> {
companion object {
private const val QUERY = """
SELECT
*,
teachers.teacherName ||" "|| teachers.teacherSurname AS senderName
FROM messages
LEFT JOIN teachers ON teachers.profileId = messages.profileId AND teacherId = senderId
LEFT JOIN metadata ON messageId = thingId AND thingType = ${Metadata.TYPE_MESSAGE} AND metadata.profileId = messages.profileId
"""
private const val ORDER_BY = """ORDER BY messageIsPinned, addedDate DESC"""
}
private val selective by lazy { MessageDaoSelective(App.db) }
@RawQuery(observedEntities = [Message::class])
abstract override fun getRaw(query: SupportSQLiteQuery): LiveData<List<MessageFull>>
@UpdateSelective(primaryKeys = ["profileId", "messageId"], skippedColumns = ["messageType", "messageBody", "messageIsPinned", "attachmentIds", "attachmentNames", "attachmentSizes"])
override fun update(item: Message) = selective.update(item)
override fun updateAll(items: List<Message>) = selective.updateAll(items)
// CLEAR
@Query("DELETE FROM messages WHERE profileId = :profileId")
abstract override fun clear(profileId: Int)
// GET ALL - LIVE DATA
fun getAll(profileId: Int) =
getRaw("$QUERY WHERE messages.profileId = $profileId $ORDER_BY")
fun getAllByType(profileId: Int, type: Int) =
getRaw("$QUERY WHERE messages.profileId = $profileId AND messageType = $type $ORDER_BY")
fun getReceived(profileId: Int) = getAllByType(profileId, Message.TYPE_RECEIVED)
fun getSent(profileId: Int) = getAllByType(profileId, Message.TYPE_SENT)
fun getDeleted(profileId: Int) = getAllByType(profileId, Message.TYPE_DELETED)
fun getDraft(profileId: Int) = getAllByType(profileId, Message.TYPE_DRAFT)
// GET ALL - NOW
fun getAllNow(profileId: Int) =
getRawNow("$QUERY WHERE messages.profileId = $profileId $ORDER_BY")
fun getNotNotifiedNow() =
getRawNow("$QUERY WHERE notified = 0 AND messageType = ${Message.TYPE_RECEIVED} $ORDER_BY")
// GET ONE - NOW
fun getByIdNow(profileId: Int, id: Long) =
getOneNow("$QUERY WHERE messages.profileId = $profileId AND messageId = $id")
}

View File

@ -93,8 +93,8 @@ public abstract class MetadataDao {
} }
} }
if (o instanceof Message) { if (o instanceof Message) {
if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).id, seen, false, 0)) == -1) { if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).getId(), seen, false, 0)) == -1) {
updateSeen(profileId, TYPE_MESSAGE, ((Message) o).id, seen); updateSeen(profileId, TYPE_MESSAGE, ((Message) o).getId(), seen);
} }
} }
} }
@ -132,8 +132,8 @@ public abstract class MetadataDao {
} }
} }
if (o instanceof Message) { if (o instanceof Message) {
if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).id, false, notified, 0)) == -1) { if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).getId(), false, notified, 0)) == -1) {
updateNotified(profileId, TYPE_MESSAGE, ((Message) o).id, notified); updateNotified(profileId, TYPE_MESSAGE, ((Message) o).getId(), notified);
} }
} }
} }

View File

@ -1,92 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.entity;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.Index;
import java.util.ArrayList;
import java.util.List;
@Entity(tableName = "messages",
primaryKeys = {"profileId", "messageId"},
indices = {@Index(value = {"profileId"})})
public class Message {
public int profileId;
@ColumnInfo(name = "messageId")
public long id;
@ColumnInfo(name = "messageSubject")
public String subject;
@Nullable
@ColumnInfo(name = "messageBody")
public String body = null;
public static final int TYPE_RECEIVED = 0;
public static final int TYPE_SENT = 1;
public static final int TYPE_DELETED = 2;
public static final int TYPE_DRAFT = 3;
@ColumnInfo(name = "messageType")
public int type = TYPE_RECEIVED;
public long senderId = -1; // -1 for sent messages
public long senderReplyId = -1;
public boolean overrideHasAttachments = false; // if the attachments are not yet downloaded but we already know there are some
public List<Long> attachmentIds = null;
public List<String> attachmentNames = null;
public List<Long> attachmentSizes = null;
@Ignore
public Message() {}
public Message(int profileId, long id, String subject, @Nullable String body, int type, long senderId, long senderReplyId) {
this.profileId = profileId;
this.id = id;
this.subject = subject;
this.body = body;
this.type = type;
this.senderId = senderId;
this.senderReplyId = senderReplyId;
}
/**
* Add an attachment
* @param id attachment ID
* @param name file name incl. extension
* @param size file size or -1 if unknown
* @return a Message to which the attachment has been added
*/
public Message addAttachment(long id, String name, long size) {
if (attachmentIds == null)
attachmentIds = new ArrayList<>();
if (attachmentNames == null)
attachmentNames = new ArrayList<>();
if (attachmentSizes == null)
attachmentSizes = new ArrayList<>();
attachmentIds.add(id);
attachmentNames.add(name);
attachmentSizes.add(size);
return this;
}
public void clearAttachments() {
attachmentIds = null;
attachmentNames = null;
attachmentSizes = null;
}
public Message setHasAttachments() {
overrideHasAttachments = true;
return this;
}
public boolean hasAttachments() {
return overrideHasAttachments || (attachmentIds != null && attachmentIds.size() > 0);
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
@Entity(tableName = "messages",
primaryKeys = ["profileId", "messageId"],
indices = [
Index(value = ["profileId", "messageType"])
])
open class Message(
val profileId: Int,
@ColumnInfo(name = "messageId")
val id: Long,
@ColumnInfo(name = "messageType")
var type: Int,
@ColumnInfo(name = "messageSubject")
var subject: String,
@ColumnInfo(name = "messageBody")
var body: String?,
/**
* Keep in mind that this being null does NOT
* necessarily mean the message is sent.
*/
var senderId: Long?
) : Keepable() {
companion object {
const val TYPE_RECEIVED = 0
const val TYPE_SENT = 1
const val TYPE_DELETED = 2
const val TYPE_DRAFT = 3
}
@ColumnInfo(name = "messageIsPinned")
var isPinned: Boolean = false
var hasAttachments = false // if the attachments are not yet downloaded but we already know there are some
get() = field || attachmentIds.isNotNullNorEmpty()
var attachmentIds: MutableList<Long>? = null
var attachmentNames: MutableList<String>? = null
var attachmentSizes: MutableList<Long>? = null
@Ignore
var showAsUnseen: Boolean? = null
/**
* Add an attachment
* @param id attachment ID
* @param name file name incl. extension
* @param size file size or -1 if unknown
* @return a Message to which the attachment has been added
*/
fun addAttachment(id: Long, name: String, size: Long): Message {
if (attachmentIds == null) attachmentIds = mutableListOf()
if (attachmentNames == null) attachmentNames = mutableListOf()
if (attachmentSizes == null) attachmentSizes = mutableListOf()
attachmentIds?.add(id)
attachmentNames?.add(name)
attachmentSizes?.add(size)
return this
}
fun clearAttachments() {
attachmentIds = null
attachmentNames = null
attachmentSizes = null
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.full;
import androidx.annotation.Nullable;
import androidx.room.Ignore;
import java.util.ArrayList;
import java.util.List;
import pl.szczodrzynski.edziennik.data.db.entity.Message;
public class MessageFull extends Message {
public String senderFullName = null;
@Ignore
@Nullable
public List<MessageRecipientFull> recipients = null;
public MessageFull addRecipient(MessageRecipientFull recipient) {
if (recipients == null)
recipients = new ArrayList<>();
recipients.add(recipient);
return this;
}
// metadata
public boolean seen;
public boolean notified;
public long addedDate;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-1-6
*/
package pl.szczodrzynski.edziennik.data.db.full
import androidx.room.Relation
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
class MessageFull(
profileId: Int, id: Long, type: Int,
subject: String, body: String?, senderId: Long?
) : Message(
profileId, id, type,
subject, body, senderId
) {
var senderName: String? = null
@Relation(parentColumn = "messageId", entityColumn = "messageId", entity = MessageRecipient::class)
var recipients: MutableList<MessageRecipientFull>? = null
fun addRecipient(recipient: MessageRecipientFull): MessageFull {
if (recipients == null) recipients = mutableListOf()
recipients?.add(recipient)
return this
}
// metadata
var seen = false
var notified = false
var addedDate: Long = 0
}

View File

@ -2,17 +2,13 @@ package pl.szczodrzynski.edziennik.data.db.full
import androidx.room.Ignore import androidx.room.Ignore
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.fixName
class MessageRecipientFull : MessageRecipient {
var fullName: String? = ""
get() {
return field?.fixName() ?: ""
}
class MessageRecipientFull(
profileId: Int,
id: Long,
messageId: Long,
readDate: Long = -1L
) : MessageRecipient(profileId, id, -1, readDate, messageId) {
@Ignore @Ignore
constructor(profileId: Int, id: Long, replyId: Long, readDate: Long, messageId: Long) : super(profileId, id, replyId, readDate, messageId) {} var fullName: String? = null
@Ignore
constructor(profileId: Int, id: Long, messageId: Long) : super(profileId, id, messageId) {}
constructor() : super() {}
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-4.
*/
package pl.szczodrzynski.edziennik.data.db.migration
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration84 : Migration(83, 84) {
override fun migrate(database: SupportSQLiteDatabase) {
// The Message Update
database.execSQL("ALTER TABLE messages RENAME TO _messages;")
database.execSQL("""CREATE TABLE messages (
profileId INTEGER NOT NULL,
messageId INTEGER NOT NULL,
messageType INTEGER NOT NULL,
messageSubject TEXT NOT NULL,
messageBody TEXT,
senderId INTEGER,
messageIsPinned INTEGER NOT NULL DEFAULT 0,
hasAttachments INTEGER NOT NULL DEFAULT 0,
attachmentIds TEXT DEFAULT NULL,
attachmentNames TEXT DEFAULT NULL,
attachmentSizes TEXT DEFAULT NULL,
keep INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY(profileId, messageId)
)""")
database.execSQL("DROP INDEX IF EXISTS index_messages_profileId")
database.execSQL("CREATE INDEX index_messages_profileId_messageType ON messages (profileId, messageType)")
database.execSQL("""
INSERT INTO messages (profileId, messageId, messageType, messageSubject, messageBody, senderId, hasAttachments, attachmentIds, attachmentNames, attachmentSizes)
SELECT profileId, messageId, messageType, messageSubject, messageBody,
CASE senderId WHEN -1 THEN NULL ELSE senderId END,
overrideHasAttachments, attachmentIds, attachmentNames, attachmentSizes
FROM _messages
""")
database.execSQL("DROP TABLE _messages")
}
}

View File

@ -12,7 +12,7 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.api.task.IApiTask
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.getLong import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.getString

View File

@ -71,7 +71,7 @@ class GradesListFragment : Fragment(), CoroutineScope {
val adapter = GradesAdapter(activity) val adapter = GradesAdapter(activity)
var firstRun = true var firstRun = true
app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this, Observer { items -> launch { app.db.gradeDao().getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()).observe(this@GradesListFragment, Observer { items -> launch {
if (!isAdded) return@launch if (!isAdded) return@launch
// load & configure the adapter // load & configure the adapter

View File

@ -94,7 +94,7 @@ class HomeworkListFragment : LazyFragment(), CoroutineScope {
} }
} }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
setSwipeToRefresh(false) // TODO setSwipeToRefresh(items.isNullOrEmpty())
// show/hide relevant views // show/hide relevant views
b.progressBar.isVisible = false b.progressBar.isVisible = false

View File

@ -37,8 +37,8 @@ import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent.Companion.T
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore.Companion.LOGIN_TYPE_IDZIENNIK import pl.szczodrzynski.edziennik.data.db.entity.LoginStore.Companion.LOGIN_TYPE_IDZIENNIK
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.databinding.MessageFragmentBinding import pl.szczodrzynski.edziennik.databinding.MessageFragmentBinding
import pl.szczodrzynski.edziennik.utils.Anim import pl.szczodrzynski.edziennik.utils.Anim
@ -127,7 +127,7 @@ class MessageFragment : Fragment(), CoroutineScope {
it.addedDate = arguments?.getLong("sentDate") ?: System.currentTimeMillis() it.addedDate = arguments?.getLong("sentDate") ?: System.currentTimeMillis()
} }
else else
app.db.messageDao().getById(App.profileId, messageId) app.db.messageDao().getByIdNow(App.profileId, messageId)
msg?.also { msg?.also {
it.recipients = app.db.messageRecipientDao().getAllByMessageId(it.profileId, it.id) it.recipients = app.db.messageRecipientDao().getAllByMessageId(it.profileId, it.id)
@ -290,10 +290,10 @@ class MessageFragment : Fragment(), CoroutineScope {
// CREATE VIEWS AND AN OBJECT FOR EVERY ATTACHMENT // CREATE VIEWS AND AN OBJECT FOR EVERY ATTACHMENT
message.attachmentNames.forEachIndexed { index, name -> message.attachmentNames?.forEachIndexed { index, name ->
val messageId = message.id val messageId = message.id
val id = message.attachmentIds[index] val id = message.attachmentIds?.getOrNull(index) ?: return@forEachIndexed
val size = message.attachmentSizes[index] val size = message.attachmentSizes?.getOrNull(index) ?: return@forEachIndexed
// create the parent // create the parent
val attachmentLayout = FrameLayout(b.root.context) val attachmentLayout = FrameLayout(b.root.context)
attachmentLayout.setPadding(16.dp, 0, 16.dp, 0) attachmentLayout.setPadding(16.dp, 0, 16.dp, 0)

View File

@ -2,73 +2,88 @@ package pl.szczodrzynski.edziennik.ui.modules.messages
import android.graphics.Typeface import android.graphics.Typeface
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView.OnItemClickListener import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.databinding.MessagesItemBinding import pl.szczodrzynski.edziennik.databinding.MessagesListItemBinding
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesAdapter.ViewHolder import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class MessagesAdapter(private val app: App, private val onItemClickListener: OnItemClickListener) : Adapter<ViewHolder>() { class MessagesAdapter(
var messageList: List<MessageFull> = ArrayList() val activity: AppCompatActivity,
fun setData(messageList: List<MessageFull>) { val teachers: List<Teacher>,
this.messageList = messageList val onItemClick: ((item: MessageFull) -> Unit)? = null
notifyDataSetChanged() ) : RecyclerView.Adapter<MessagesAdapter.ViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "TemplateAdapter"
} }
private val app = activity.applicationContext as App
// optional: place the manager here
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = listOf<MessageFull>()
private val typefaceNormal by lazy { Typeface.create(Typeface.DEFAULT, Typeface.NORMAL) }
private val typefaceBold by lazy { Typeface.create(Typeface.DEFAULT, Typeface.BOLD) }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
return ViewHolder(DataBindingUtil.inflate(inflater, R.layout.messages_item, parent, false)) val view = MessagesListItemBinding.inflate(inflater, parent, false)
return ViewHolder(view)
} }
@Suppress("DEPRECATION")
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
val b = holder.b val b = holder.b
val message = messageList[position]
b.root.setOnClickListener { v: View? -> onItemClickListener.onItemClick(null, v, position, position.toLong()) }
ViewCompat.setTransitionName(b.root, message.id.toString()) item.recipients?.forEach { recipient ->
if (recipient.fullName == null) {
b.messageSubject.text = message.subject recipient.fullName = teachers.firstOrNull { it.id == recipient.id }?.fullName ?: ""
b.messageDate.text = Date.fromMillis(message.addedDate).formattedStringShort }
b.messageAttachmentImage.visibility = if (message.hasAttachments()) View.VISIBLE else View.GONE
val text = message.body?.substring(0, message.body!!.length.coerceAtMost(200)) ?: ""
b.messageBody.text = MessagesUtils.htmlToSpannable(b.root.context, text)
if (message.type == Message.TYPE_SENT || message.type == Message.TYPE_DRAFT || message.seen) {
b.messageSender.setTextAppearance(b.messageSender.context, R.style.NavView_TextView_Small)
b.messageSender.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
b.messageSender.textSize = 16f
b.messageSubject.setTextAppearance(b.messageSubject.context, R.style.NavView_TextView_Small)
b.messageSubject.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
b.messageDate.setTextAppearance(b.messageDate.context, R.style.NavView_TextView_Small)
b.messageDate.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
} else {
b.messageSender.setTextAppearance(b.messageSender.context, R.style.NavView_TextView_Normal)
b.messageSender.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
b.messageSender.textSize = 16f
b.messageSubject.setTextAppearance(b.messageSubject.context, R.style.NavView_TextView_Normal)
b.messageSubject.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
b.messageDate.setTextAppearance(b.messageDate.context, R.style.NavView_TextView_Normal)
b.messageDate.typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
} }
val messageInfo = MessagesUtils.getMessageInfo(app, message, 48, 24, 18, 12)
b.messageSubject.text = item.subject
b.messageDate.text = Date.fromMillis(item.addedDate).formattedStringShort
b.messageAttachmentImage.isVisible = item.hasAttachments
val text = item.body?.take(200) ?: ""
b.messageBody.text = MessagesUtils.htmlToSpannable(activity, text)
val isRead = item.type == Message.TYPE_SENT || item.type == Message.TYPE_DRAFT || item.seen
val typeface = if (isRead) typefaceNormal else typefaceBold
val style = if (isRead) R.style.NavView_TextView_Small else R.style.NavView_TextView_Normal
// set text styles
b.messageSender.setTextAppearance(activity, style)
b.messageSender.typeface = typeface
b.messageSubject.setTextAppearance(activity, style)
b.messageSubject.typeface = typeface
b.messageDate.setTextAppearance(activity, style)
b.messageDate.typeface = typeface
val messageInfo = MessagesUtils.getMessageInfo(app, item, 48, 24, 18, 12)
b.messageProfileBackground.setImageBitmap(messageInfo.profileImage) b.messageProfileBackground.setImageBitmap(messageInfo.profileImage)
b.messageSender.text = messageInfo.profileName b.messageSender.text = messageInfo.profileName
onItemClick?.let { listener ->
b.root.onClick { listener(item) }
}
} }
override fun getItemCount(): Int { override fun getItemCount() = items.size
return messageList.size
}
inner class ViewHolder(var b: MessagesItemBinding) : RecyclerView.ViewHolder(b.root)
class ViewHolder(val b: MessagesListItemBinding) : RecyclerView.ViewHolder(b.root)
} }

View File

@ -5,82 +5,79 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.App import kotlinx.coroutines.CoroutineScope
import pl.szczodrzynski.edziennik.MainActivity import kotlinx.coroutines.Dispatchers
import pl.szczodrzynski.edziennik.R import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.databinding.FragmentMessagesBinding import pl.szczodrzynski.edziennik.databinding.MessagesFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyPagerAdapter import kotlin.coroutines.CoroutineContext
import pl.szczodrzynski.edziennik.utils.Themes
class MessagesFragment : Fragment() { class MessagesFragment : Fragment(), CoroutineScope {
companion object { companion object {
private const val TAG = "MessagesFragment"
var pageSelection = 0 var pageSelection = 0
} }
private lateinit var app: App private lateinit var app: App
private lateinit var activity: MainActivity private lateinit var activity: MainActivity
private lateinit var b: FragmentMessagesBinding private lateinit var b: MessagesFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null activity = (getActivity() as MainActivity?) ?: return null
if (context == null) context ?: return null
return null
app = activity.application as App app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true) b = MessagesFragmentBinding.inflate(inflater)
if (app.profile == null)
return inflater.inflate(R.layout.fragment_loading, container, false)
// activity, context and profile is valid
b = FragmentMessagesBinding.inflate(inflater)
b.refreshLayout.setParent(activity.swipeRefreshLayout) b.refreshLayout.setParent(activity.swipeRefreshLayout)
return b.root return b.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// TODO check if app, activity, b can be null if (!isAdded) return
if (app.profile == null || !isAdded)
return
val messageId = arguments?.getLong("messageId", -1L) ?: -1L val messageId = arguments?.getLong("messageId", -1L) ?: -1L
if (messageId != -1L) { if (messageId != -1L) {
val args = Bundle() val args = Bundle()
args.putLong("messageId", messageId) args.putLong("messageId", messageId)
arguments!!.remove("messageId") arguments?.remove("messageId")
activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args) activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args)
return return
} }
b.viewPager.adapter = Adapter(childFragmentManager, b.refreshLayout).also { adapter -> val pagerAdapter = FragmentLazyPagerAdapter(
fragmentManager ?: return,
b.refreshLayout,
listOf(
MessagesListFragment().apply {
arguments = Bundle("messageType" to Message.TYPE_RECEIVED)
} to getString(R.string.messages_tab_received),
adapter.addFragment(MessagesListFragment().also { fragment -> MessagesListFragment().apply {
fragment.arguments = Bundle().also { args -> arguments = Bundle("messageType" to Message.TYPE_SENT)
args.putInt("messageType", Message.TYPE_RECEIVED) } to getString(R.string.messages_tab_sent),
}
}, getString(R.string.menu_messages_inbox))
adapter.addFragment(MessagesListFragment().also { fragment -> MessagesListFragment().apply {
fragment.arguments = Bundle().also { args -> arguments = Bundle("messageType" to Message.TYPE_DELETED)
args.putInt("messageType", Message.TYPE_SENT) } to getString(R.string.messages_tab_deleted)
} )
}, getString(R.string.menu_messages_sent)) )
b.viewPager.apply {
} offscreenPageLimit = 1
adapter = pagerAdapter
b.viewPager.currentItem = pageSelection currentItem = pageSelection
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { addOnPageSelectedListener {
override fun onPageScrollStateChanged(state: Int) {} pageSelection = it
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
pageSelection = position
} }
}) b.tabLayout.setupWithViewPager(this)
}
b.tabLayout.setupWithViewPager(b.viewPager)
activity.navView.apply { activity.navView.apply {
bottomBar.apply { bottomBar.apply {
@ -95,52 +92,5 @@ class MessagesFragment : Fragment() {
} }
activity.gainAttentionFAB() activity.gainAttentionFAB()
/*if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS && app.profile.getStudentData("accountPassword", null) == null) {
MaterialDialog.Builder(activity)
.title("Wiadomości w systemie Synergia")
.content("Moduł Wiadomości w aplikacji Szkolny.eu jest przeglądarką zasobów szkolnego konta Synergia. Z tego powodu, musisz wpisać swoje hasło do tego konta, aby móc korzystać z tej funkcji.")
.positiveText(R.string.ok)
.onPositive { dialog, which ->
MaterialDialog.Builder(activity)
.title("Zaloguj się")
.content(Html.fromHtml("Podaj hasło do konta Synergia z loginem <b>" + app.profile.getStudentData("accountLogin", "???") + "</b>"))
.inputType(InputType.TYPE_TEXT_VARIATION_PASSWORD)
.input(null, null) { dialog1, input ->
app.profile.putStudentData("accountPassword", input.toString())
app.profileSaveFullAsync(app.profile)
EdziennikTask.syncProfile(App.profileId, listOf(
DRAWER_ITEM_MESSAGES to Message.TYPE_RECEIVED,
DRAWER_ITEM_MESSAGES to Message.TYPE_SENT
)).enqueue(context!!)
}
.positiveText(R.string.ok)
.negativeText(R.string.cancel)
.show()
}
.show()
}*/
}
internal class Adapter(manager: FragmentManager, swipeRefreshLayout: SwipeRefreshLayout) : LazyPagerAdapter(manager, swipeRefreshLayout) {
private val mFragmentList = mutableListOf<LazyFragment>()
private val mFragmentTitleList = mutableListOf<String>()
override fun getPage(position: Int): LazyFragment {
return mFragmentList[position]
}
override fun getCount(): Int {
return mFragmentList.size
}
fun addFragment(fragment: LazyFragment, title: String) {
mFragmentList.add(fragment)
mFragmentTitleList.add(title)
}
override fun getPageTitle(position: Int): CharSequence {
return mFragmentTitleList[position]
}
} }
} }

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-4.
*/
package pl.szczodrzynski.edziennik.ui.modules.messages
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.databinding.MessagesListFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyFragment
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
class MessagesListFragment : LazyFragment(), CoroutineScope {
companion object {
private const val TAG = "MessagesListFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: MessagesListFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
var teachers = listOf<Teacher>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: return null
app = activity.application as App
b = MessagesListFragmentBinding.inflate(inflater)
return b.root
}
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
val messageType = arguments.getInt("messageType", Message.TYPE_RECEIVED)
teachers = withContext(Dispatchers.Default) {
app.db.teacherDao().getAllNow(App.profileId)
}
val adapter = MessagesAdapter(activity, teachers) {
}
app.db.messageDao().getAllByType(App.profileId, messageType).observe(this@MessagesListFragment, Observer { items ->
if (!isAdded) return@Observer
items.forEach { message ->
message.recipients?.removeAll { it.profileId != message.profileId }
}
// load & configure the adapter
adapter.items = items
if (items.isNotNullNorEmpty() && b.list.adapter == null) {
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
if (messageType in Message.TYPE_RECEIVED..Message.TYPE_SENT)
addOnScrollListener(onScrollListener)
}
}
adapter.notifyDataSetChanged()
setSwipeToRefresh(messageType in Message.TYPE_RECEIVED..Message.TYPE_SENT && items.isNullOrEmpty())
// show/hide relevant views
b.progressBar.isVisible = false
if (items.isNullOrEmpty()) {
b.list.isVisible = false
b.noData.isVisible = true
} else {
b.list.isVisible = true
b.noData.isVisible = false
}
})
}; return true }
}

View File

@ -33,7 +33,7 @@ import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
import static pl.szczodrzynski.edziennik.utils.Utils.d; import static pl.szczodrzynski.edziennik.utils.Utils.d;
public class MessagesListFragment extends LazyFragment { public class MessagesListFragmentOld extends LazyFragment {
private App app = null; private App app = null;
private MainActivity activity = null; private MainActivity activity = null;
@ -90,19 +90,19 @@ public class MessagesListFragment extends LazyFragment {
activity.syncCurrentFeature(messageType, b.refreshLayout); activity.syncCurrentFeature(messageType, b.refreshLayout);
});*/ });*/
messagesAdapter = new MessagesAdapter(app, ((parent, view1, position, id) -> { /*messagesAdapter = new MessagesAdapter(app, ((parent, view1, position, id) -> {
// TODO ANIMATION // TODO ANIMATION
tapPositions[messageType] = position; tapPositions[messageType] = position;
topPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findFirstCompletelyVisibleItemPosition(); topPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
bottomPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findLastCompletelyVisibleItemPosition(); bottomPositions[messageType] = ((LinearLayoutManager) b.emailList.getLayoutManager()).findLastCompletelyVisibleItemPosition();
/*view1.getGlobalVisibleRect(viewRect); *//*view1.getGlobalVisibleRect(viewRect);
((Transition) MessagesListFragment.this.getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() { ((Transition) MessagesListFragment.this.getExitTransition()).setEpicenterCallback(new Transition.EpicenterCallback() {
@Override @Override
public Rect onGetEpicenter(@NonNull Transition transition) { public Rect onGetEpicenter(@NonNull Transition transition) {
return viewRect; return viewRect;
} }
});*/ });*//*
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("messageId", messagesAdapter.getMessageList().get(position).id); args.putLong("messageId", messagesAdapter.getMessageList().get(position).id);
@ -110,7 +110,7 @@ public class MessagesListFragment extends LazyFragment {
// KOD W WERSJI 2.7 // KOD W WERSJI 2.7
// TODO ANIMATION // TODO ANIMATION
/*TransitionSet sharedElementTransition = new TransitionSet() *//*TransitionSet sharedElementTransition = new TransitionSet()
.addTransition(new Fade()) .addTransition(new Fade())
.addTransition(new ChangeBounds()) .addTransition(new ChangeBounds())
.addTransition(new ChangeTransform()) .addTransition(new ChangeTransform())
@ -123,10 +123,10 @@ public class MessagesListFragment extends LazyFragment {
args.putLong("messageId", messagesAdapter.messageList.get(position).id); args.putLong("messageId", messagesAdapter.messageList.get(position).id);
fragment.setArguments(args); fragment.setArguments(args);
fragment.setSharedElementEnterTransition(sharedElementTransition); fragment.setSharedElementEnterTransition(sharedElementTransition);
fragment.setSharedElementReturnTransition(sharedElementTransition);*/ fragment.setSharedElementReturnTransition(sharedElementTransition);*//*
// JAKIS STARSZY KOD // JAKIS STARSZY KOD
/*Intent intent = new Intent(activity, MessagesDetailsActivity.class); *//*Intent intent = new Intent(activity, MessagesDetailsActivity.class);
intent.putExtra("item_id", 1); intent.putExtra("item_id", 1);
intent.putExtra("transition_name", ViewCompat.getTransitionName(view1)); intent.putExtra("transition_name", ViewCompat.getTransitionName(view1));
@ -143,17 +143,17 @@ public class MessagesListFragment extends LazyFragment {
setExitTransition(sharedElementTransition); setExitTransition(sharedElementTransition);
setSharedElementEnterTransition(sharedElementTransition); setSharedElementEnterTransition(sharedElementTransition);
setSharedElementReturnTransition(sharedElementTransition); setSharedElementReturnTransition(sharedElementTransition);
startActivity(intent, options.toBundle());*/ startActivity(intent, options.toBundle());*//*
/*activity.getSupportFragmentManager() *//*activity.getSupportFragmentManager()
.beginTransaction() .beginTransaction()
.setReorderingAllowed(true) .setReorderingAllowed(true)
.replace(R.id.fragment_container, fragment) .replace(R.id.fragment_container, fragment)
.addToBackStack(null) .addToBackStack(null)
.addSharedElement(view1, getString(R.string.transition_name)) .addSharedElement(view1, getString(R.string.transition_name))
.commit();*/ .commit();*//*
})); }));*/
//tapPosition = savedInstanceState != null ? savedInstanceState.getInt(TAP_POSITION, tapPosition) : tapPosition; //tapPosition = savedInstanceState != null ? savedInstanceState.getInt(TAP_POSITION, tapPosition) : tapPosition;
@ -195,7 +195,7 @@ public class MessagesListFragment extends LazyFragment {
List<MessageRecipientFull> messageRecipients = App.db.messageRecipientDao().getAll(App.Companion.getProfileId()); List<MessageRecipientFull> messageRecipients = App.db.messageRecipientDao().getAll(App.Companion.getProfileId());
List<Long> messageIds = new ArrayList<>(); List<Long> messageIds = new ArrayList<>();
for (MessageFull messageFull: messageFulls) { for (MessageFull messageFull: messageFulls) {
messageIds.add(messageFull.id); messageIds.add(messageFull.getId());
} }
for (MessageRecipientFull messageRecipientFull: messageRecipients) { for (MessageRecipientFull messageRecipientFull: messageRecipients) {
if (messageRecipientFull.id == -1) if (messageRecipientFull.id == -1)
@ -233,7 +233,7 @@ public class MessagesListFragment extends LazyFragment {
private void createMessageList(List<MessageFull> messageFulls) { private void createMessageList(List<MessageFull> messageFulls) {
b.progressBar.setVisibility(View.GONE); b.progressBar.setVisibility(View.GONE);
b.emailList.setVisibility(View.VISIBLE); b.emailList.setVisibility(View.VISIBLE);
messagesAdapter.setData(messageFulls); //messagesAdapter.setData(messageFulls);
LinearLayoutManager layoutManager = (LinearLayoutManager) b.emailList.getLayoutManager(); LinearLayoutManager layoutManager = (LinearLayoutManager) b.emailList.getLayoutManager();
if (tapPositions[messageType] != NO_POSITION && layoutManager != null) { if (tapPositions[messageType] != NO_POSITION && layoutManager != null) {

View File

@ -124,7 +124,7 @@ object MessagesUtils {
var profileImage: Bitmap? = null var profileImage: Bitmap? = null
var profileName: String? = null var profileName: String? = null
if (message.type == Message.TYPE_RECEIVED || message.type == Message.TYPE_DELETED) { if (message.type == Message.TYPE_RECEIVED || message.type == Message.TYPE_DELETED) {
profileName = message.senderFullName?.fixName() profileName = message.senderName?.fixName()
profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 1, profileName) profileImage = getProfileImage(diameterDp, textSizeBigDp, textSizeMediumDp, textSizeSmallDp, 1, profileName)
} else if (message.type == Message.TYPE_SENT || message.type == Message.TYPE_DRAFT && message.recipients != null) { } else if (message.type == Message.TYPE_SENT || message.type == Message.TYPE_DRAFT && message.recipients != null) {
when (val count = message.recipients?.size ?: 0) { when (val count = message.recipients?.size ?: 0) {

View File

@ -1,75 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.messages;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.transition.TransitionValues;
import androidx.transition.Visibility;
public class SlideExplode extends Visibility {
private static final String KEY_SCREEN_BOUNDS = "screenBounds";
private int[] mTempLoc = new int[2];
private void captureValues(TransitionValues transitionValues) {
View view = transitionValues.view;
view.getLocationOnScreen(mTempLoc);
int left = mTempLoc[0];
int top = mTempLoc[1];
int right = left + view.getWidth();
int bottom = top + view.getHeight();
transitionValues.values.put(KEY_SCREEN_BOUNDS, new Rect(left, top, right, bottom));
}
@Override
public void captureStartValues(@NonNull TransitionValues transitionValues) {
super.captureStartValues(transitionValues);
captureValues(transitionValues);
}
@Override
public void captureEndValues(@NonNull TransitionValues transitionValues) {
super.captureEndValues(transitionValues);
captureValues(transitionValues);
}
@Override
public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
if (endValues == null)
return null;
Rect bounds = (Rect) endValues.values.get(KEY_SCREEN_BOUNDS);
float endY = view.getTranslationY();
float startY = endY + calculateDistance(sceneRoot, bounds);
return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
}
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
if (startValues == null)
return null;
Rect bounds = (Rect) startValues.values.get(KEY_SCREEN_BOUNDS);
float startY = view.getTranslationY();
float endY = startY + calculateDistance(sceneRoot, bounds);
return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
}
private int calculateDistance(View sceneRoot, Rect viewBounds) {
sceneRoot.getLocationOnScreen(mTempLoc);
int sceneRootY = mTempLoc[1];
if (getEpicenter() == null) {
return -sceneRoot.getHeight();
}
else if (viewBounds.top <= getEpicenter().top) {
return sceneRootY - getEpicenter().top;
}
else {
return sceneRootY + sceneRoot.getHeight() - getEpicenter().bottom;
}
}
}

View File

@ -1,18 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.messages;
import android.animation.TimeInterpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.transition.TransitionSet;
public class Transitions extends TransitionSet {
@NonNull
@Override
public TransitionSet setInterpolator(@Nullable TimeInterpolator interpolator) {
for (int i = 0; i < getTransitionCount(); i++) {
getTransitionAt(i).setInterpolator(interpolator);
}
return this;
}
}

View File

@ -1,8 +1,8 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2019-12-22. * Copyright (c) Kuba Szczodrzyński 2020-4-4.
*/ */
package pl.szczodrzynski.edziennik.ui.modules.messages package pl.szczodrzynski.edziennik.ui.modules.messages.compose
import android.content.Context import android.content.Context
import android.graphics.Typeface import android.graphics.Typeface
@ -43,6 +43,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils.getProfileImage import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils.getProfileImage
import pl.szczodrzynski.edziennik.utils.Colors import pl.szczodrzynski.edziennik.utils.Colors
import pl.szczodrzynski.edziennik.utils.Themes import pl.szczodrzynski.edziennik.utils.Themes
@ -361,7 +362,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
span.appendText("W dniu ") span.appendText("W dniu ")
span.appendSpan(dateString, StyleSpan(Typeface.ITALIC), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) span.appendSpan(dateString, StyleSpan(Typeface.ITALIC), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
span.appendText(", ") span.appendText(", ")
span.appendSpan(msg.senderFullName.fixName(), StyleSpan(Typeface.ITALIC), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) span.appendSpan(msg.senderName.fixName(), StyleSpan(Typeface.ITALIC), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
span.appendText(" napisał(a):") span.appendText(" napisał(a):")
span.setSpan(StyleSpan(Typeface.BOLD), 0, span.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) span.setSpan(StyleSpan(Typeface.BOLD), 0, span.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
span.appendText("\n\n") span.appendText("\n\n")
@ -380,7 +381,8 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
span.replace(0, 0, "\n\n") span.replace(0, 0, "\n\n")
subject = "Fwd: ${msg.subject}" subject = "Fwd: ${msg.subject}"
} }
body = MessagesUtils.htmlToSpannable(activity,msg.body ?: "Nie udało się wczytać oryginalnej wiadomości.")//Html.fromHtml(msg.body?.replace("<br\\s?/?>".toRegex(), "\n") ?: "Nie udało się wczytać oryginalnej wiadomości.") body = MessagesUtils.htmlToSpannable(activity, msg.body
?: "Nie udało się wczytać oryginalnej wiadomości.")//Html.fromHtml(msg.body?.replace("<br\\s?/?>".toRegex(), "\n") ?: "Nie udało się wczytać oryginalnej wiadomości.")
} }
b.recipients.addTextWithChips(chipList) b.recipients.addTextWithChips(chipList)

View File

@ -1,4 +1,8 @@
package pl.szczodrzynski.edziennik.ui.modules.messages /*
* Copyright (c) Kuba Szczodrzyński 2020-4-4.
*/
package pl.szczodrzynski.edziennik.ui.modules.messages.compose
class MessagesComposeInfo( class MessagesComposeInfo(
/** /**
@ -18,4 +22,4 @@ class MessagesComposeInfo(
* -1 means unlimited length. * -1 means unlimited length.
*/ */
var maxBodyLength: Int var maxBodyLength: Int
) )

View File

@ -1,4 +1,4 @@
package pl.szczodrzynski.edziennik.ui.modules.messages package pl.szczodrzynski.edziennik.ui.modules.messages.compose
import android.content.Context import android.content.Context
import android.graphics.Typeface.BOLD import android.graphics.Typeface.BOLD

View File

@ -72,7 +72,7 @@ class NotificationsListFragment : Fragment(), CoroutineScope {
app.sendBroadcast(intent) app.sendBroadcast(intent)
} }
app.db.notificationDao().getAll().observe(this, Observer { items -> app.db.notificationDao().getAll().observe(this@NotificationsListFragment, Observer { items ->
if (!isAdded) return@Observer if (!isAdded) return@Observer
// load & configure the adapter // load & configure the adapter

View File

@ -12,12 +12,11 @@ import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.addOnPageSelectedListener
import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding
import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter import pl.szczodrzynski.edziennik.ui.modules.base.lazypager.FragmentLazyPagerAdapter
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkDate
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkListFragment
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class TemplateFragment : Fragment(), CoroutineScope { class TemplateFragment : Fragment(), CoroutineScope {
@ -52,6 +51,14 @@ class TemplateFragment : Fragment(), CoroutineScope {
fragmentManager ?: return, fragmentManager ?: return,
b.refreshLayout, b.refreshLayout,
listOf( listOf(
HomeworkListFragment().apply {
arguments = Bundle("homeworkDate" to HomeworkDate.CURRENT)
} to getString(R.string.homework_tab_current),
HomeworkListFragment().apply {
arguments = Bundle("homeworkDate" to HomeworkDate.PAST)
} to getString(R.string.homework_tab_past),
TemplatePageFragment() to "Pager 0", TemplatePageFragment() to "Pager 0",
TemplatePageFragment() to "Pager 1", TemplatePageFragment() to "Pager 1",
TemplatePageFragment() to "Pager 2", TemplatePageFragment() to "Pager 2",
@ -67,7 +74,7 @@ class TemplateFragment : Fragment(), CoroutineScope {
adapter = pagerAdapter adapter = pagerAdapter
currentItem = pageSelection currentItem = pageSelection
addOnPageSelectedListener { addOnPageSelectedListener {
HomeworkFragment.pageSelection = it pageSelection = it
} }
b.tabLayout.setupWithViewPager(this) b.tabLayout.setupWithViewPager(this)
} }

View File

@ -49,7 +49,7 @@ class TemplateListFragment : Fragment(), CoroutineScope {
val adapter = TemplateAdapter(activity) val adapter = TemplateAdapter(activity)
app.db.notificationDao().getAll().observe(this, Observer { items -> app.db.notificationDao().getAll().observe(this@TemplateListFragment, Observer { items ->
if (!isAdded) return@Observer if (!isAdded) return@Observer
// load & configure the adapter // load & configure the adapter

View File

@ -49,7 +49,7 @@ class TemplateListPageFragment : LazyFragment(), CoroutineScope {
override fun onPageCreated(): Boolean { startCoroutineTimer(100L) { override fun onPageCreated(): Boolean { startCoroutineTimer(100L) {
val adapter = TemplateAdapter(activity) val adapter = TemplateAdapter(activity)
app.db.notificationDao().getAll().observe(this, Observer { items -> app.db.notificationDao().getAll().observe(this@TemplateListPageFragment, Observer { items ->
if (!isAdded) return@Observer if (!isAdded) return@Observer
// load & configure the adapter // load & configure the adapter
@ -64,7 +64,7 @@ class TemplateListPageFragment : LazyFragment(), CoroutineScope {
} }
} }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
setSwipeToRefresh(false) // TODO setSwipeToRefresh(items.isNullOrEmpty())
// show/hide relevant views // show/hide relevant views
b.progressBar.isVisible = false b.progressBar.isVisible = false

View File

@ -0,0 +1,10 @@
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-4.
-->
<vector android:height="128dp" android:viewportHeight="512"
android:viewportWidth="512" android:width="128dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#f4a402" android:pathData="m440,416h-368c-22.1,0 -40,-17.9 -40,-40v-240c0,-22.1 17.9,-40 40,-40h368c22.1,0 40,17.9 40,40v240c0,22.1 -17.9,40 -40,40z"/>
<path android:fillColor="#feb600" android:pathData="m256,200 l-223,183c3.21,18.9 19.5,33.3 39.3,33.3h368c19.8,0 36.1,-14.4 39.3,-33.3l-223,-183"/>
<path android:fillColor="#ffc71c" android:pathData="m32.7,129 l206,169c10.1,8.24 24.6,8.24 34.6,0l206,-169c-3.21,-18.9 -19.5,-33.3 -39.3,-33.3h-368c-19.8,0 -36.1,14.4 -39.3,33.3z"/>
</vector>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-4.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorSurface_6dp"
app:tabIndicatorColor="?colorPrimary"
app:tabMode="auto"
app:tabSelectedTextColor="?colorPrimary"
app:tabTextColor="?android:textColorPrimary" />
<pl.szczodrzynski.edziennik.ui.modules.base.lazypager.LazyViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
</layout>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-4.
-->
<layout 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">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/noData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/messages_no_data"
android:textSize="24sp"
android:visibility="gone"
app:drawableTopCompat="@drawable/ic_no_messages"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:listitem="@layout/messages_list_item"
tools:visibility="visible" />
</FrameLayout>
</layout>

View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-4.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground">
<ImageView
android:id="@+id/messageProfileBackground"
android:layout_width="72dp"
android:layout_height="72dp"
android:padding="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/bg_circle" />
<TextView
android:id="@+id/messageProfileName"
android:layout_width="72dp"
android:layout_height="72dp"
android:gravity="center"
android:padding="12dp"
android:textColor="#ffffff"
android:textSize="24sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="JP"
tools:visibility="visible" />
<TextView
android:id="@+id/messageSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:singleLine="true"
android:textStyle="normal"
android:textAppearance="@style/NavView.TextView.Helper"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/messageProfileBackground"
app:layout_constraintTop_toBottomOf="@+id/messageSender"
tools:text="Nowe oferty w Twoich obserwowanych wyszukiwaniach" />
<TextView
android:id="@+id/messageSender"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:ellipsize="end"
android:maxLines="2"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/messageAttachmentImage"
app:layout_constraintStart_toEndOf="@+id/messageProfileBackground"
app:layout_constraintTop_toTopOf="parent"
tools:text="Allegro" />
<TextView
android:id="@+id/messageBody"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="12dp"
android:singleLine="true"
android:textAppearance="@style/NavView.TextView.Helper"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/messageProfileBackground"
app:layout_constraintTop_toBottomOf="@+id/messageSubject"
tools:text="Znajdź produkty, których szukasz. Witaj Kuba Szczodrzyński (Client" />
<TextView
android:id="@+id/messageDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="09:41" />
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/messageAttachmentImage"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:adjustViewBounds="true"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:scaleType="fitCenter"
app:iiv_color="?android:textColorSecondary"
app:iiv_icon="cmd-attachment"
app:layout_constraintBottom_toBottomOf="@+id/messageDate"
app:layout_constraintEnd_toStartOf="@+id/messageDate"
app:layout_constraintTop_toTopOf="@+id/messageDate"
tools:srcCompat="@tools:sample/avatars[4]" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -414,8 +414,8 @@
<string name="menu_manage_profiles">Manage profiles</string> <string name="menu_manage_profiles">Manage profiles</string>
<string name="menu_mark_as_read">Mark as read</string> <string name="menu_mark_as_read">Mark as read</string>
<string name="menu_messages">Messages</string> <string name="menu_messages">Messages</string>
<string name="menu_messages_inbox">Inbox</string> <string name="messages_tab_received">Inbox</string>
<string name="menu_messages_sent">Sent</string> <string name="messages_tab_sent">Sent</string>
<string name="menu_notices">Behaviour</string> <string name="menu_notices">Behaviour</string>
<string name="menu_notifications">Notifications</string> <string name="menu_notifications">Notifications</string>
<string name="menu_settings">Settings</string> <string name="menu_settings">Settings</string>

View File

@ -458,8 +458,8 @@
<string name="menu_mark_as_read">Oznacz jako przeczytane</string> <string name="menu_mark_as_read">Oznacz jako przeczytane</string>
<string name="menu_mark_everything_as_read">Oznacz wszystko jako przeczytane</string> <string name="menu_mark_everything_as_read">Oznacz wszystko jako przeczytane</string>
<string name="menu_messages">Wiadomości</string> <string name="menu_messages">Wiadomości</string>
<string name="menu_messages_inbox">Odebrane</string> <string name="messages_tab_received">Odebrane</string>
<string name="menu_messages_sent">Wysłane</string> <string name="messages_tab_sent">Wysłane</string>
<string name="menu_notices">Zachowanie</string> <string name="menu_notices">Zachowanie</string>
<string name="menu_notifications">Powiadomienia</string> <string name="menu_notifications">Powiadomienia</string>
<string name="menu_set_student_number">Ustaw numer w dzienniku</string> <string name="menu_set_student_number">Ustaw numer w dzienniku</string>
@ -1287,4 +1287,6 @@
<string name="dialog_event_details_attachments">Załączniki</string> <string name="dialog_event_details_attachments">Załączniki</string>
<string name="hint_download_again">Pobierz ponownie</string> <string name="hint_download_again">Pobierz ponownie</string>
<string name="menu_lab">Laboratorium</string> <string name="menu_lab">Laboratorium</string>
<string name="messages_no_data">Nie masz żadnych wiadomości.</string>
<string name="messages_tab_deleted">Usunięte</string>
</resources> </resources>

View File

@ -158,9 +158,12 @@ class FileGenerator : AbstractProcessor() {
allFields.removeAll { skippedColumns.contains(it.name()) } allFields.removeAll { skippedColumns.contains(it.name()) }
allFields.removeAll { it.getAnnotation(Ignore::class.java) != null } allFields.removeAll { it.getAnnotation(Ignore::class.java) != null }
allFields.removeAll { field -> field.modifiers.any { it == Modifier.STATIC || it == Modifier.FINAL } } allFields.removeAll { field -> field.modifiers.any { it == Modifier.STATIC } }
val allFieldsDistinct = allFields.distinct() val allFieldsDistinct = allFields.distinct()
// dump fields
//processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, allFieldsDistinct.joinToString())
val fields = allFieldsDistinct.filterNot { primaryKeys.contains(it.name()) } val fields = allFieldsDistinct.filterNot { primaryKeys.contains(it.name()) }
val primaryFields = allFieldsDistinct.filter { primaryKeys.contains(it.name()) } val primaryFields = allFieldsDistinct.filter { primaryKeys.contains(it.name()) }
val fieldNames = fields.map { it.name() } val fieldNames = fields.map { it.name() }